66 lines
1.9 KiB
TypeScript
66 lines
1.9 KiB
TypeScript
import { AudioDocument } from "@suaveplan/audio-core";
|
|
|
|
const PAGE_SIZE = 1024;
|
|
|
|
/**
|
|
* Build an `AudioDocument` from pre-computed channel data. Splits each
|
|
* channel into pages of `PAGE_SIZE` samples.
|
|
*/
|
|
export function buildDoc(
|
|
channels: Float32Array[],
|
|
sampleRate: number
|
|
): AudioDocument {
|
|
const sourceLength = channels[0]?.length ?? 0;
|
|
const pages: { channelData: Float32Array[]; startSample: number }[] = [];
|
|
for (let start = 0; start < sourceLength; start += PAGE_SIZE) {
|
|
const len = Math.min(PAGE_SIZE, sourceLength - start);
|
|
const pageData: Float32Array[] = channels.map((ch) =>
|
|
ch.subarray(start, start + len)
|
|
);
|
|
pages.push({ channelData: pageData, startSample: start });
|
|
}
|
|
return new AudioDocument({
|
|
sampleRate,
|
|
channels: channels.length,
|
|
sourceLength,
|
|
pages,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Generate a sine-wave channel buffer at the given amplitude, frequency, and
|
|
* duration. Amplitude is linear (1.0 = 0 dBFS).
|
|
*/
|
|
export function sine(
|
|
amplitude: number,
|
|
frequencyHz: number,
|
|
sampleRate: number,
|
|
durationSeconds: number
|
|
): Float32Array {
|
|
const n = Math.round(durationSeconds * sampleRate);
|
|
const out = new Float32Array(n);
|
|
const w = (2 * Math.PI * frequencyHz) / sampleRate;
|
|
for (let i = 0; i < n; i++) out[i] = amplitude * Math.sin(w * i);
|
|
return out;
|
|
}
|
|
|
|
/** Constant-DC channel. */
|
|
export function constant(value: number, n: number): Float32Array {
|
|
const out = new Float32Array(n);
|
|
out.fill(value);
|
|
return out;
|
|
}
|
|
|
|
/** Concatenate channel segments. */
|
|
export function concat(...segments: Float32Array[]): Float32Array {
|
|
let total = 0;
|
|
for (const s of segments) total += s.length;
|
|
const out = new Float32Array(total);
|
|
let p = 0;
|
|
for (const s of segments) {
|
|
out.set(s, p);
|
|
p += s.length;
|
|
}
|
|
return out;
|
|
}
|