94 lines
2.7 KiB
TypeScript
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();
|
|
});
|
|
});
|