fix(align): render at 44.1k and resample; finite guard; pre-zero tests

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Sonnet 5.5 committed 2026-10-30 06:38:31 +01:00
1 parent 63b32a488d
commit b614244e4d
2 files changed
+40 -6

No files matched your search

+27 -1
View File
@@ -7,7 +7,7 @@ import type { RefTrack, RefNote } from "../../src/align/smf.ts";
const SF2 = new Uint8Array(await Bun.file("node_modules/@coderline/alphatab/dist/soundfont/sonivox.sf2").arrayBuffer());
const note = (onset: number, offset: number, pitch: number): RefNote => ({ onset, offset, pitch, velocity: 100, channel: 0 });
const track = (notes: RefNote[], isDrums = false): RefTrack => ({ index: 0, name: "t", program: 25, isDrums, notes });
const SR = 44100; // alphaSynth yields NaN at 22050 Hz
const SR = 44100;
function firstAbove(x: Float32Array, thr: number): number {
for (let i = 0; i < x.length; i++) if (Math.abs(x[i]!) > thr) return i;
@@ -49,3 +49,29 @@ test("peaks of a known sine", () => {
expect([...q.max]).toEqual([0.5, 0]);
expect([...q.min]).toEqual([0.25, -0.75]);
});
test("sampleRate 22050 is finite, at 22050 Hz, onset preserved", () => {
const a = renderMidi([track([note(1, 2, 60)])], makeWarp([{ midiSec: 0, audioSec: 0.5, kind: "manual" }]), SF2, { sampleRate: 22050, mono: true, durationSec: 4 });
expect(a.sampleRate).toBe(22050);
expect(a.channels[0]!.length).toBe(4 * 22050);
expect(a.channels[0]!.every(Number.isFinite)).toBe(true);
const t = firstAbove(a.channels[0]!, 0.02) / 22050;
expect(t).toBeGreaterThan(1.48);
expect(t).toBeLessThan(1.52);
});
test("notes before audio zero: clamped when overlapping, dropped when entirely before", () => {
const w = makeWarp([{ midiSec: 1, audioSec: 0, kind: "manual" }]); // audio = midi - 1
const dropped = renderMidi([track([note(0, 0.5, 60)]), track([note(2, 2.5, 64)])], w, SF2, { durationSec: 3 });
const t = firstAbove(dropped.channels[0]!, 0.02) / 44100;
expect(t).toBeGreaterThan(0.98);
const clamped = renderMidi([track([note(0.5, 2, 60)])], w, SF2, { durationSec: 3 });
expect(firstAbove(clamped.channels[0]!, 0.02) / 44100).toBeLessThan(0.05);
});
test("stereo with durationSec has two channels of exact length", () => {
const a = renderMidi([track([note(0, 0.5, 60)])], makeWarp([]), SF2, { durationSec: 2 });
expect(a.channels.length).toBe(2);
expect(a.channels[0]!.length).toBe(88200);
expect(a.channels[1]!.length).toBe(88200);
});