Play every tab's preview straight into the master (#368)

Since #351 the tabs played their asset along its links in the Master
routing, as the game does. A song linked into a reverb bus was heard
through that bus while it was edited. A preview should sound like the
asset itself, so the tabs leave the Master routing out again.

- The Sound, Sound FX, Instrument, Pattern and Song tab play into the
  master. The sound FX of the asset still applies, and so does the
  master's own volume and FX.
- Inside a song its own routing of tracks and sends still counts.
- The game is unchanged: Play nodes go along the routing as before.

Tests:
- e2e 34 (melektaus-atx): ALL PASSED, 96 checks. The routing check
  now holds the mix of the two buses as before, and the Sound tab on
  the master with the bus silent.
- Counter-probe e2e: the Sound tab along the routing again, the
  routing check red.
- Gate (melektaus-atx): CHECK EXIT 0, 274 files, 4230 tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-10-09 13:09:36 +02:00
1 parent 1f13794b0c
commit af2312a5e7
7 files changed
+30 -25

No files matched your search

+12 -7
View File
@@ -2339,8 +2339,9 @@ export async function sound(t) {
// 34h-3. Buses and the master (#325), routed in the Master routing tab (#351). "+ → Bus" makes
// one; the tab has a node for it and for the sound, each linked to the master. Links drawn
// there and one deleted send the sound into a bus and that bus into the other, as the Sound
// tab then plays it. A click on a node shows its asset, on the master the master's volume.
// there and one deleted send the sound into a bus and that bus into the other; the Sound
// tab still plays it on the master (#368). A click on a node shows its asset, on the
// master the master's volume.
for (let i = 0; i < 2; i++) {
await clickText('+');
await pickAssetType(t, 'Bus');
@@ -2395,6 +2396,9 @@ export async function sound(t) {
await mutate(`
__gm.state.project.assets.find((a) => a.id === ${JSON.stringify(busA.id)}).props.volume = 0.5;`);
await evaluate(`__gm.state.openAsset(${JSON.stringify(droneId)})`);
// The preview of a tab leaves the routing out (#368): heard on the master, the buses stay silent.
const tapped = JSON.stringify(['mix', `mix:${busB.id}`]);
await json(`__gm.routing.peaks(${tapped})`);
const startedBefore = (await stats()).started;
await click(tabPlay.x, tabPlay.y);
await waitFor(stats, (s) => s.started > startedBefore, 10);
@@ -2402,22 +2406,23 @@ export async function sound(t) {
const buses = await json('__gm.sound.buses()');
const heardOn = (await stats()).last?.bus;
const peak = await waitFor(
() => json(`__gm.routing.peaks([${JSON.stringify(`mix:${busB.id}`)}])`),
(peaks) => Math.max(...(peaks[`mix:${busB.id}`] ?? [0])) > 0.01,
() => json(`__gm.routing.peaks(${tapped})`),
(peaks) => Math.max(...(peaks.mix ?? [0])) > 0.01,
);
await click(tabPlay.x, tabPlay.y);
const levelOf = (name) => buses.find((bus) => bus.name === name);
check(
'linked in the routing, the Sound tab plays the sound on its bus, into the bus that one goes to, on into the master',
'linked in the routing, the mix sends the sound’s bus into the other; the Sound tab plays it on the master, past both',
links(await routing())
.filter((l) => l.startsWith(droneId) || l.startsWith(busB.id))
.join() === `${droneId}>${busB.id},${busB.id}>${busA.id}` &&
heardOn === `mix:${busB.id}` &&
heardOn === 'mix' &&
levelOf(`mix:${busB.id}`)?.into === `mix:${busA.id}` &&
levelOf(`mix:${busA.id}`)?.into === 'mix' &&
levelOf(`mix:${busA.id}`)?.gain === 0.5 &&
levelOf('mix')?.into === null &&
Math.max(...(peak?.[`mix:${busB.id}`] ?? [0])) > 0.01,
Math.max(...(peak?.mix ?? [0])) > 0.01 &&
Math.max(...(peak?.[`mix:${busB.id}`] ?? [0])) < 0.001,
JSON.stringify({ links: links(await routing()), heardOn, buses, peak }),
);