test: tighten demucs separation assertions (ruling R7)
Bass absolute SDR floor, guitar/piano order pinned by stem energy, finite + non-silent checks on the mono and 3 s slice paths, and the test.failing comment cites ruling R7. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
86416f7637
commit
b5e6f63881
@@ -45,6 +45,23 @@ let out: Record<Stem, Audio>;
|
||||
let secsPerMin = 0;
|
||||
const sdrs: Record<string, number> = {};
|
||||
|
||||
function energy(a: Audio): number {
|
||||
let e = 0;
|
||||
for (const ch of a.channels) for (const v of ch) e += v * v;
|
||||
return e;
|
||||
}
|
||||
|
||||
/** Every sample finite, and the stems together carry a real share of the input's energy (not silence). */
|
||||
function expectFiniteNonSilent(input: Audio, stems: Record<Stem, Audio>): void {
|
||||
let total = 0;
|
||||
for (const s of STEMS) {
|
||||
for (const ch of stems[s].channels) for (const v of ch) if (!Number.isFinite(v)) throw new Error(`${s}: non-finite sample ${v}`);
|
||||
total += energy(stems[s]);
|
||||
}
|
||||
expect(energy(input)).toBeGreaterThan(0);
|
||||
expect(total).toBeGreaterThan(0.1 * energy(input));
|
||||
}
|
||||
|
||||
function sum(...as: Audio[]): Audio {
|
||||
const len = as[0]!.channels[0]!.length;
|
||||
return { sampleRate: 44100, channels: [0, 1].map((c) => {
|
||||
@@ -64,6 +81,9 @@ beforeAll(async () => {
|
||||
sdrs[`${stem}_mixBaseline`] = sdr(oracle(role), data.mix);
|
||||
}
|
||||
sdrs.guitarPlusPiano = sdr(oracle("guitar"), sum(out.guitar, out.piano));
|
||||
sdrs.guitarRefVsPianoStem = sdr(oracle("guitar"), out.piano);
|
||||
sdrs.guitarStemEnergy = energy(out.guitar);
|
||||
sdrs.pianoStemEnergy = energy(out.piano);
|
||||
console.log(`separation t1b/1: ${secsPerMin.toFixed(1)} s per minute of audio`, sdrs);
|
||||
}, SLOW);
|
||||
|
||||
@@ -82,12 +102,21 @@ test("separates t1b/1: drums > 3 dB, bass beats the mix, guitar(+piano) > 3 dB a
|
||||
expect(sdrs.drums!).toBeGreaterThan(3);
|
||||
expect(sdrs.drums!).toBeGreaterThan(sdrs.drums_mixBaseline!);
|
||||
expect(sdrs.bass!).toBeGreaterThan(sdrs.bass_mixBaseline!);
|
||||
expect(sdrs.bass!).toBeGreaterThan(0.5); // absolute floor: a silent estimate scores 0 dB
|
||||
expect(sdrs.guitarPlusPiano!).toBeGreaterThan(3);
|
||||
expect(sdrs.guitarPlusPiano!).toBeGreaterThan(sdrs.guitar_mixBaseline!);
|
||||
});
|
||||
|
||||
// Brief's literal criterion. Unmet by the model on this song (guitar 1.85 dB, bass 1.67 dB); kept as an
|
||||
// expected failure so it flips loudly if separation improves. Needs a controller ruling.
|
||||
test("separates t1b/1: guitar and piano stems are not swapped (guitar stem carries more energy)", () => {
|
||||
// Pins the manifest stem order (… guitar, piano). Energy, not SDR: the piano stem's SDR against the oracle
|
||||
// guitar (2.55 dB measured) exceeds the guitar stem's (1.85 dB) because both hold parts of the same guitar.
|
||||
// Measured energies: guitar 19521, piano 12721.
|
||||
expect(sdrs.guitarStemEnergy!).toBeGreaterThan(sdrs.pianoStemEnergy!);
|
||||
});
|
||||
|
||||
// Brief's literal criterion, relaxed by controller ruling R7: HTDemucs-6s routes part of the SONiVOX GM guitar
|
||||
// into its piano stem (synthetic-timbre gap), so guitar is 1.85 dB and bass 1.67 dB on t1b/1. Kept as an expected
|
||||
// failure so it flips loudly if separation improves.
|
||||
test.failing("brief criterion: guitar and bass stems each > 3 dB and > mix baseline", () => {
|
||||
expect(sdrs.guitar!).toBeGreaterThan(3);
|
||||
expect(sdrs.guitar!).toBeGreaterThan(sdrs.guitar_mixBaseline!);
|
||||
@@ -100,6 +129,7 @@ test("a 3-second slice (shorter than one segment) returns 3 s stems", async () =
|
||||
const slice: Audio = { sampleRate: 44100, channels: data.mix.channels.map((c) => c.slice(44100, 44100 + n)) };
|
||||
const out = await separate(slice);
|
||||
for (const s of STEMS) for (const ch of out[s].channels) expect(ch.length).toBe(n);
|
||||
expectFiniteNonSilent(slice, out);
|
||||
}, SLOW);
|
||||
|
||||
test("mono input is accepted and returns stereo stems of the same length", async () => {
|
||||
@@ -110,6 +140,7 @@ test("mono input is accepted and returns stereo stems of the same length", async
|
||||
expect(out[s].channels.length).toBe(2);
|
||||
expect(out[s].channels[0]!.length).toBe(n);
|
||||
}
|
||||
expectFiniteNonSilent(mono, out);
|
||||
}, SLOW);
|
||||
|
||||
test("rejects sample rates other than 44100", async () => {
|
||||
|
||||
Reference in New Issue
Block a user