Files
suaveplan/packages/media/audio-fx/audio-fx-plugin-spessasynth/tests/integration.test.ts
2026-05-27 23:47:53 +01:00

94 lines
2.7 KiB
TypeScript

import { readFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";
import type { BlockContext, ProcessorConfig } from "@suaveplan/audio-core";
import type {
ChainContext,
ChainHandle,
} from "@suaveplan/audio-fx-plugin-base/base";
import { defaultAmbientState } from "@suaveplan/audio-fx-plugin-base/chain";
import { describe, expect, it } from "@suaveplan/testing/runner";
import { SpessaSynthPlugin } from "../src/plugin/spessasynth-plugin.js";
const FIXTURE_URL = new URL("./fixtures/tiny-piano.sf2", import.meta.url);
const FIXTURE_PATH = fileURLToPath(FIXTURE_URL);
const SR = 48_000;
const BLOCK = 512;
function newCtx(): ChainContext {
const chain: ChainHandle = {
id: "integration",
name: "integration",
channels: 2,
sampleRate: SR,
blockSize: BLOCK,
slotCount: 1,
};
return {
chain,
position: { index: 0, total: 1 },
predecessors: [],
successors: [],
ambient: defaultAmbientState(),
buses: { get: () => undefined, list: () => [] },
};
}
function newConfig(): ProcessorConfig {
return { sampleRate: SR, channels: 2, blockSize: BLOCK };
}
function blockCtx(): BlockContext {
return {
blockOffsetSamples: 0,
sampleRate: SR,
channels: 2,
opts: {},
};
}
function rms(buf: Float32Array): number {
let sum = 0;
for (let i = 0; i < buf.length; i++) sum += buf[i]! ** 2;
return Math.sqrt(sum / buf.length);
}
describe("integration: render via the vendored tiny-piano SF2 fixture", () => {
it("renders a C-major chord with non-zero RMS through process()", {
timeout: 30_000,
}, async () => {
const bytes = new Uint8Array(await readFile(FIXTURE_PATH));
const plugin = new SpessaSynthPlugin();
await plugin.init({
soundFontBytes: bytes,
sampleRate: SR,
});
await plugin.setup(newConfig(), newCtx());
// C major: C4, E4, G4.
for (const note of [60, 64, 67]) {
plugin.sendMidi({
type: "noteOn",
channel: 0,
note,
velocity: 100,
});
}
// Render half a second.
const blocks = Math.ceil(SR / 2 / BLOCK);
const merged = new Float32Array(blocks * BLOCK);
for (let b = 0; b < blocks; b++) {
const out: Float32Array[] = [
new Float32Array(BLOCK),
new Float32Array(BLOCK),
];
plugin.process([], out, blockCtx());
merged.set(out[0]!, b * BLOCK);
}
const r = rms(merged);
expect(r).toBeGreaterThan(0);
plugin.dispose();
});
});