Newer
Older
rpg / packages / engine / tools / wav.mjs
/**
 * WAV-тулкит без зависимостей: энкодер поверх чистых примитивов синтеза
 * (сами примитивы — в synth.mjs, они же используются в рантайме браузера).
 * Формат: моно, RATE Гц, 16-бит PCM.
 */
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);
}