Files
2026-05-27 23:47:53 +01:00

57 lines
1.8 KiB
TypeScript

import { AudioDocument } from "@suaveplan/audio-core";
/** Build a synthetic metronome audio document. */
export function makeMetronome(opts: {
bpm: number;
durationSeconds: number;
sampleRate?: number;
clickSamples?: number;
clickFreq?: number;
}): AudioDocument {
const sampleRate = opts.sampleRate ?? 8000;
const total = Math.floor(opts.durationSeconds * sampleRate);
const data = new Float32Array(total);
const beatPeriodSamples = Math.floor((60 / opts.bpm) * sampleRate);
const clickSamples = opts.clickSamples ?? 200;
const clickFreq = opts.clickFreq ?? 1000;
for (let beat = 0; beat * beatPeriodSamples < total; beat++) {
const start = beat * beatPeriodSamples;
for (let i = 0; i < clickSamples && start + i < total; i++) {
const env = Math.exp(-i / (clickSamples / 4));
data[start + i] =
env * Math.sin((2 * Math.PI * clickFreq * i) / sampleRate);
}
}
return new AudioDocument({
sampleRate,
channels: 1,
sourceLength: total,
pages: [{ channelData: [data], startSample: 0 }],
});
}
/** Build a silent audio document. */
export function makeSilence(opts: {
durationSeconds: number;
sampleRate?: number;
}): AudioDocument {
const sampleRate = opts.sampleRate ?? 8000;
const total = Math.floor(opts.durationSeconds * sampleRate);
return new AudioDocument({
sampleRate,
channels: 1,
sourceLength: total,
pages: [{ channelData: [new Float32Array(total)], startSample: 0 }],
});
}
/** Empty document. */
export function makeEmpty(): AudioDocument {
return new AudioDocument({
sampleRate: 8000,
channels: 1,
sourceLength: 0,
pages: [],
});
}