42 lines
1.5 KiB
TypeScript
42 lines
1.5 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { SpectrumAnalyzer } from "../src/fft.ts";
|
|
|
|
function sineFrame(freqHz: number, sampleRate = 48000, samples = 1024): Buffer {
|
|
const buf = Buffer.alloc(samples * 2 * 2); // s16le stereo
|
|
for (let i = 0; i < samples; i++) {
|
|
const v = Math.round(Math.sin((2 * Math.PI * freqHz * i) / sampleRate) * 16000);
|
|
buf.writeInt16LE(v, i * 4);
|
|
buf.writeInt16LE(v, i * 4 + 2);
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
describe("SpectrumAnalyzer", () => {
|
|
it("produces N bars of normalized [0..1] floats", () => {
|
|
const a = new SpectrumAnalyzer({ bars: 48, sampleRate: 48000 });
|
|
a.feed(sineFrame(1000));
|
|
const bars = a.bars();
|
|
expect(bars).toHaveLength(48);
|
|
bars.forEach((v) => {
|
|
expect(v).toBeGreaterThanOrEqual(0);
|
|
expect(v).toBeLessThanOrEqual(1);
|
|
});
|
|
});
|
|
|
|
it("a 200hz sine puts most energy in low bars (logarithmic binning)", () => {
|
|
const a = new SpectrumAnalyzer({ bars: 48, sampleRate: 48000 });
|
|
for (let n = 0; n < 4; n++) a.feed(sineFrame(200));
|
|
const bars = a.bars();
|
|
const lowSum = bars.slice(0, 16).reduce((s, v) => s + v, 0);
|
|
const highSum = bars.slice(32).reduce((s, v) => s + v, 0);
|
|
expect(lowSum).toBeGreaterThan(0.1);
|
|
expect(lowSum).toBeGreaterThan(highSum + 0.1);
|
|
});
|
|
|
|
it("silence produces all-near-zero bars", () => {
|
|
const a = new SpectrumAnalyzer({ bars: 72, sampleRate: 48000 });
|
|
a.feed(Buffer.alloc(1024 * 4));
|
|
const bars = a.bars();
|
|
bars.forEach((v) => expect(v).toBeLessThan(0.01));
|
|
});
|
|
});
|