/ proof-of-concept / steelsim21
Sign in
proof-of-concept / steelsim21
steelsim21 / src / audio / wav.ts
33 lines · 1.3 KBCodeBlameHistory
f8a8a6cNonlinear steel sheet gong simulator with WebGPUJeremy Magland 1// 16-bit PCM mono WAV encoder.
b9a5a7eSelf-equilibrated release force and loudness normalizationJeremy Magland 3import { normalize, type LevelMode } from "./level.ts";
c8442c5Command-line renderer (Node WebGPU via Dawn) and gallery generatorJeremy Magland 5/** Encodes the scaled signal as WAV bytes. */
6export function encodeWavBytes(samples: Float32Array, fs: number, mode: LevelMode = "peak", gainDb = 0): Uint8Array<ArrayBuffer> {
de24345Absolute playback level with gain slider and peak readoutJeremy Magland 7 const scaled = normalize(samples, fs, mode, gainDb, 0.99);
f8a8a6cNonlinear steel sheet gong simulator with WebGPUJeremy Magland 8 const buf = new ArrayBuffer(44 + samples.length * 2);
9 const v = new DataView(buf);
10 const str = (o: number, s: string) => { for (let k = 0; k < s.length; k++) v.setUint8(o + k, s.charCodeAt(k)); };
11 str(0, "RIFF");
12 v.setUint32(4, 36 + samples.length * 2, true);
13 str(8, "WAVE");
14 str(12, "fmt ");
15 v.setUint32(16, 16, true);
16 v.setUint16(20, 1, true);
17 v.setUint16(22, 1, true);
18 v.setUint32(24, fs, true);
19 v.setUint32(28, fs * 2, true);
20 v.setUint16(32, 2, true);
21 v.setUint16(34, 16, true);
22 str(36, "data");
23 v.setUint32(40, samples.length * 2, true);
24 for (let k = 0; k < samples.length; k++) {
b9a5a7eSelf-equilibrated release force and loudness normalizationJeremy Magland 25 const s = Math.max(-1, Math.min(1, scaled[k]));
f8a8a6cNonlinear steel sheet gong simulator with WebGPUJeremy Magland 26 v.setInt16(44 + 2 * k, Math.round(s * 32767), true);
27 }
c8442c5Command-line renderer (Node WebGPU via Dawn) and gallery generatorJeremy Magland 28 return new Uint8Array(buf);
31export function encodeWav(samples: Float32Array, fs: number, mode: LevelMode = "peak", gainDb = 0): Blob {
32 return new Blob([encodeWavBytes(samples, fs, mode, gainDb)], { type: "audio/wav" });
↑↓ move↵openescclose