/** * Float32 [-1, 1] PCM → WAV blob (mono, 16-bit, заданная частота). * Используется браузером для отправки записанной фразы в STT. */ export function floatToWav(audio: Float32Array, sampleRate = 16000): Blob { const numSamples = audio.length const buffer = new ArrayBuffer(44 + numSamples * 2) const view = new DataView(buffer) writeStr(view, 0, 'RIFF') view.setUint32(4, 36 + numSamples * 2, true) writeStr(view, 8, 'WAVE') writeStr(view, 12, 'fmt ') view.setUint32(16, 16, true) // fmt chunk size view.setUint16(20, 1, true) // PCM view.setUint16(22, 1, true) // channels view.setUint32(24, sampleRate, true) view.setUint32(28, sampleRate * 2, true) // byte rate view.setUint16(32, 2, true) // block align view.setUint16(34, 16, true) // bits per sample writeStr(view, 36, 'data') view.setUint32(40, numSamples * 2, true) let offset = 44 for (let i = 0; i < numSamples; i++, offset += 2) { const s = Math.max(-1, Math.min(1, audio[i])) view.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true) } return new Blob([buffer], { type: 'audio/wav' }) } function writeStr(view: DataView, offset: number, s: string): void { for (let i = 0; i < s.length; i++) view.setUint8(offset + i, s.charCodeAt(i)) }