/ simulated_instruments / recorder
Sign in
simulated_instruments / recorder
recorder / webapp / src / lib / wav.ts
40 lines · 1.3 KBBlameHistoryRaw
1// Mono PCM WAV encoding (16- or 24-bit).
3export function encodeWav(y: Float32Array, sampleRate: number, bitDepth: 16 | 24): Blob {
4 const bytesPerSample = bitDepth / 8;
5 const dataSize = y.length * bytesPerSample;
6 const buf = new ArrayBuffer(44 + dataSize);
7 const dv = new DataView(buf);
8 const writeStr = (off: number, s: string) => {
9 for (let i = 0; i < s.length; i++) dv.setUint8(off + i, s.charCodeAt(i));
10 };
11 writeStr(0, 'RIFF');
12 dv.setUint32(4, 36 + dataSize, true);
13 writeStr(8, 'WAVE');
14 writeStr(12, 'fmt ');
15 dv.setUint32(16, 16, true);
16 dv.setUint16(20, 1, true); // PCM
17 dv.setUint16(22, 1, true); // mono
18 dv.setUint32(24, sampleRate, true);
19 dv.setUint32(28, sampleRate * bytesPerSample, true);
20 dv.setUint16(32, bytesPerSample, true);
21 dv.setUint16(34, bitDepth, true);
22 writeStr(36, 'data');
23 dv.setUint32(40, dataSize, true);
25 let off = 44;
26 for (let i = 0; i < y.length; i++) {
27 const v = Math.max(-1, Math.min(1, y[i]));
28 if (bitDepth === 16) {
29 dv.setInt16(off, Math.round(v * 32767), true);
30 off += 2;
31 } else {
32 const iv = Math.round(v * 8388607);
33 dv.setUint8(off, iv & 0xff);
34 dv.setUint8(off + 1, (iv >> 8) & 0xff);
35 dv.setUint8(off + 2, (iv >> 16) & 0xff);
36 off += 3;
37 }
38 }
39 return new Blob([buf], { type: 'audio/wav' });
↑↓ move↵openescclose