38 lines
1.9 KiB
TypeScript
38 lines
1.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { ENVIRONMENTS, LEVELS } from "../src/content";
|
|
import { dbToGain, normalizeRms, synthesizeBackground } from "../src/audio/dsp";
|
|
|
|
// 청감이나 실제 음압은 장치마다 다르므로 테스트 대상은 디지털 RMS와 gain
|
|
// 비율이다. 배경·음성을 같은 기준으로 정규화해야 표기한 상대 dB가 성립한다.
|
|
const rms = (a: Float32Array) =>
|
|
Math.sqrt(a.reduce((sum, n) => sum + n * n, 0) / a.length);
|
|
describe("상대 dB와 결정론적 배경 합성", () => {
|
|
it("20 log10(음성 gain / 배경 gain)이 표시 dB와 일치한다", () => {
|
|
for (const level of LEVELS)
|
|
expect(20 * Math.log10(dbToGain(level.db))).toBeCloseTo(level.db, 10);
|
|
expect(dbToGain(-6)).toBeCloseTo(0.501187, 5);
|
|
});
|
|
it("평균 전력을 맞추고 원본 배열을 변경하지 않으며 무음은 오류로 알린다", () => {
|
|
const input = new Float32Array([0.4, -0.2, 0.1, -0.3]);
|
|
const output = normalizeRms(input);
|
|
expect(rms(output)).toBeCloseTo(0.12, 6);
|
|
expect(output).not.toBe(input);
|
|
expect(() => normalizeRms(new Float32Array(4))).toThrow("무음");
|
|
});
|
|
it("여덟 환경이 서로 다르고 같은 seed는 같은 안전 범위 신호를 만든다", () => {
|
|
const signatures = new Set<string>();
|
|
for (const preset of ENVIRONMENTS) {
|
|
const signal = synthesizeBackground(preset, 16000, 1);
|
|
expect(signal).toHaveLength(16000);
|
|
expect(signal).toEqual(synthesizeBackground(preset, 16000, 1));
|
|
expect(rms(signal)).toBeCloseTo(0.12, 5);
|
|
expect(Math.max(...signal.map(Math.abs))).toBeLessThan(1);
|
|
// 루프 경계에서 불연속 클릭이 생기지 않도록 양 끝을 0으로 감싼다.
|
|
expect(signal[0]).toBe(0);
|
|
expect(signal.at(-1)).toBe(0);
|
|
signatures.add([...signal.slice(0, 100)].join(","));
|
|
}
|
|
expect(signatures.size).toBe(8);
|
|
});
|
|
});
|