Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions packages/engine/src/services/audioMixer.grouping.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,17 @@ const track = (id: string, end: number, volume = 1) => ({
type: "audio" as const,
});

// Each case here runs at least two real ffmpeg mixes — the one under test plus
// a reference mix to compare it against — so it is seconds of work, not
// milliseconds. On the Windows runner `routing isolation` measures ~10s when the
// host is healthy (19.4s for the whole file) and blew the previous 30s cap on a
// noisy one, which is variance rather than a hang: nothing in the failing PRs
// touched engine code. 120s is ~12x the healthy time, so a timeout here should
// mean a genuine stall again.
//
// Per-test arguments rather than `vi.setConfig({ testTimeout })`: an explicit
// argument OVERRIDES the file-level config, so a setConfig line alongside these
// would silently do nothing.
describe.skipIf(!HAS_FFMPEG)("mix level arithmetic", () => {
afterEach(() => {
for (const dir of tempDirs.splice(0)) rmSync(dir, { recursive: true, force: true });
Expand Down Expand Up @@ -108,7 +119,7 @@ describe.skipIf(!HAS_FFMPEG)("mix level arithmetic", () => {
// Two coherent copies of one tone = +6.02 dB. If amix's 1/N ever survives
// the correction, this lands at 0 dB instead.
expect(meanVolumeDb(twoUp) - meanVolumeDb(oneUp)).toBeCloseTo(6.02, 0);
}, 30_000);
}, 120_000);

it("does not lift the survivors when a shorter track ends", async () => {
// amix with normalize=true rescales by the number of CURRENTLY ACTIVE
Expand Down Expand Up @@ -145,7 +156,7 @@ describe.skipIf(!HAS_FFMPEG)("mix level arithmetic", () => {
const tailTogether = meanVolumeDb(together, 1.5, 3);
const tailAlone = meanVolumeDb(alone, 1.5, 3);
expect(Math.abs(tailTogether - tailAlone)).toBeLessThan(0.5);
}, 30_000);
}, 120_000);

/**
* The gate for group buses (plans/audio-mixer-groups.md §1).
Expand Down Expand Up @@ -193,7 +204,7 @@ describe.skipIf(!HAS_FFMPEG)("mix level arithmetic", () => {
// An empty group chain is pure routing — the export must read the same
// whether or not the two tones happened to share a group.
expect(Math.abs(meanVolumeDb(groupedOut) - meanVolumeDb(flatOut))).toBeLessThan(0.3);
}, 30_000);
}, 120_000);

it("a group FX chain fully cutting its members leaves an ungrouped track untouched (routing isolation)", async () => {
const projectDir = mkdtempSync(join(tmpdir(), "hf-grp-fx-"));
Expand Down Expand Up @@ -231,7 +242,7 @@ describe.skipIf(!HAS_FFMPEG)("mix level arithmetic", () => {
// and the ungrouped sfx track's own processing is unaffected by the
// group existing at all.
expect(Math.abs(meanVolumeDb(mixedOut) - meanVolumeDb(sfxAloneOut))).toBeLessThan(0.5);
}, 30_000);
}, 120_000);

it("a member's own volume envelope still applies inside a group", async () => {
const projectDir = mkdtempSync(join(tmpdir(), "hf-grp-env-"));
Expand Down Expand Up @@ -267,5 +278,5 @@ describe.skipIf(!HAS_FFMPEG)("mix level arithmetic", () => {
const groupedTail = meanVolumeDb(groupedOut, 3, 4);
const flatTail = meanVolumeDb(flatOut, 3, 4);
expect(Math.abs(groupedTail - flatTail)).toBeLessThan(0.5);
}, 30_000);
}, 120_000);
});
Loading