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: [], }); }