| 135 | }; |
| 136 | |
| 137 | const base64ToFloat32Array = ( |
| 138 | base64: string, |
| 139 | isLittleEndian: boolean, |
| 140 | isSigned: boolean |
| 141 | ): Float32Array => { |
| 142 | const binaryString = atob(base64); |
| 143 | const len = binaryString.length; |
| 144 | const buffer = new ArrayBuffer(len); |
| 145 | const view = new Uint8Array(buffer); |
| 146 | |
| 147 | for (let i = 0; i < len; i++) { |
| 148 | view[i] = binaryString.charCodeAt(i); |
| 149 | } |
| 150 | |
| 151 | const dataView = new DataView(buffer); |
| 152 | const length = len / 2; // Assuming 16-bit PCM |
| 153 | const floatArray = new Float32Array(length); |
| 154 | |
| 155 | for (let i = 0; i < length; i++) { |
| 156 | let sample: number; |
| 157 | |
| 158 | if (isSigned) { |
| 159 | // Read 16-bit signed integer |
| 160 | sample = dataView.getInt16(i * 2, isLittleEndian); |
| 161 | } else { |
| 162 | // Read 16-bit unsigned integer and convert to signed |
| 163 | sample = dataView.getUint16(i * 2, isLittleEndian) - 32768; |
| 164 | } |
| 165 | |
| 166 | // Normalize the sample to -1.0 to 1.0 |
| 167 | floatArray[i] = sample / 32768; |
| 168 | } |
| 169 | |
| 170 | return floatArray; |
| 171 | }; |
| 172 | |
| 173 | export const playAudio = async ( |
| 174 | base64Audio: string, |