/**
* WAV-тулкит без зависимостей: энкодер поверх чистых примитивов синтеза
* (сами примитивы — в synth.mjs, они же используются в рантайме браузера).
* Формат: моно, RATE Гц, 16-бит PCM.
*/
import { writeFileSync } from 'node:fs';
import {
RATE,
bandNoise,
bellPartial,
decay,
loopify,
makeRng,
normalize,
synth
} from './synth.mjs';
export { RATE, bandNoise, bellPartial, decay, loopify, makeRng, normalize, synth };
/** Собрать WAV-файл из Float32 сэмплов (-1..1). */
export function encodeWav(samples, rate = RATE) {
const n = samples.length;
const data = new ArrayBuffer(44 + n * 2);
const view = new DataView(data);
const str = (offset, s) => {
for (let i = 0; i < s.length; i++) view.setUint8(offset + i, s.charCodeAt(i));
};
str(0, 'RIFF');
view.setUint32(4, 36 + n * 2, true);
str(8, 'WAVE');
str(12, 'fmt ');
view.setUint32(16, 16, true); // размер fmt
view.setUint16(20, 1, true); // PCM
view.setUint16(22, 1, true); // моно
view.setUint32(24, rate, true);
view.setUint32(28, rate * 2, true); // байт/сек
view.setUint16(32, 2, true); // блок
view.setUint16(34, 16, true); // бит
str(36, 'data');
view.setUint32(40, n * 2, true);
for (let i = 0; i < n; i++) {
const s = Math.max(-1, Math.min(1, samples[i]));
view.setInt16(44 + i * 2, Math.round(s * 32767), true);
}
return Buffer.from(data);
}
/** Записать WAV на диск (хелпер типового пайплайна «синтез -> файл»). */
export function writeWav(path, samples, rate = RATE) {
writeFileSync(path, encodeWav(samples, rate));
}