export const encodeWav = (pcm: Float32Array, sampleRate: number): Blob => { const length = pcm.length const buffer = new ArrayBuffer(44 + length * 2) const view = new DataView(buffer) const writeStr = (off: number, s: string) => { for (let i = 0; i < s.length; i++) view.setUint8(off + i, s.charCodeAt(i)) } writeStr(0, 'RIFF') view.setUint32(4, 36 + length * 2, true) writeStr(8, 'WAVE') writeStr(12, 'fmt ') view.setUint32(16, 16, true) view.setUint16(20, 1, true) view.setUint16(22, 1, true) view.setUint32(24, sampleRate, true) view.setUint32(28, sampleRate * 2, true) view.setUint16(32, 2, true) view.setUint16(34, 16, true) writeStr(36, 'data') view.setUint32(40, length * 2, true) let off = 44 for (let i = 0; i < length; i++) { const s = Math.max(-1, Math.min(1, pcm[i])) view.setInt16(off, s < 0 ? s * 0x8000 : s * 0x7FFF, true) off += 2 } return new Blob([buffer], { type: 'audio/wav' }) }