/** * Encode PCM Int16 samples into a WAV file blob. * Assumes mono channel at the given sample rate. */ export function encodeWav(samples: Int16Array, sampleRate: number): Blob { const byteLength = samples.length * 2; const buffer = new ArrayBuffer(44 + byteLength); const view = new DataView(buffer); // RIFF header writeString(view, 0, "RIFF"); view.setUint32(4, 36 + byteLength, true); writeString(view, 8, "WAVE"); // fmt chunk writeString(view, 12, "fmt "); view.setUint32(16, 16, true); // chunk size view.setUint16(20, 1, true); // PCM format view.setUint16(22, 1, true); // mono 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 // data chunk writeString(view, 36, "data"); view.setUint32(40, byteLength, true); // PCM samples const output = new Int16Array(buffer, 44); output.set(samples); return new Blob([buffer], { type: "audio/wav" }); } function writeString(view: DataView, offset: number, str: string) { for (let i = 0; i < str.length; i++) { view.setUint8(offset + i, str.charCodeAt(i)); } }