Give a song, a track or an item a sound FX of its own (#355)
A sound FX for one place in a song had to be a project asset, which then stood in every picker. Now every pick of a sound FX in a song can make one the song keeps for that place alone, on top of the embedded assets of the first two parts. - Create sound FX sits at the end of the Sound FX row of the song, a track and an item, and of the menu of a track's FX button. It makes "Sound FX 1", 2, … per song with the Input wired to the Output, picks it and opens it. That is one undo step. - Embed a copy, while the place names a project FX, gives the place a copy under the same name. - While the place names its own, the menu shows it with the mark and offers Edit sound FX and Make project asset. - Picking anything else lets it go in the same undo step. For a track or an item `settleEmbedded` did that already. For the song's own row `AssetPropertyCommand` now settles the song after `fx`. - The mark `•` moved to the core. `assetRefLabel` puts it in front of an embedded asset, so the inspector rows show it like the timeline. - `FieldHandlers.moreChoices` lets a caller end a reference menu with entries of its own. `embeddedPatternName` is `embeddedName` with a base now. Tests: - Unit own-fx (new): 6 green, 6 counter-checks each red - Unit embedded and 80 neighbouring files: 1434 green - e2e 65 (melektaus-atx): ALL PASSED, 51 checks (2 new) - Gate (melektaus-atx): CHECK EXIT 0, 270 files, 4178 tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
49669017b1
commit
668682c4ff
11 files changed
+339
-37
No files matched your search
@@ -1129,6 +1129,62 @@ export async function song(t) {
|
||||
JSON.stringify((await model()).items.map((item) => item.id)),
|
||||
);
|
||||
|
||||
// 65p. A sound FX of the track's own (#355), from the menu of its FX button: it lets the sound
|
||||
// through, is opened in its tab and named there with a mark. Picking another lets it go, and
|
||||
// a Ctrl+Z brings it back.
|
||||
const fxTrackBefore = (await model()).tracks[0].fx;
|
||||
p = await json("__gm.song.headAt(0, 'fx')");
|
||||
await click(p.x, p.y);
|
||||
await sleep(150);
|
||||
const createRows = await json('__gm.menuRows()');
|
||||
await clickText('Create sound FX');
|
||||
await sleep(250);
|
||||
const ownFxId = JSON.stringify((await model()).tracks[0].fx);
|
||||
const ownFx = await json(
|
||||
`(() => { const a = __gm.state.project.assets.find((x) => x.id === ${ownFxId}); return a ? { name: a.name, owner: a.owner, type: a.type, nodes: a.graph.nodes.map((n) => n.type), edges: a.graph.edges.length } : null; })()`,
|
||||
);
|
||||
const ownFxTab = await json(
|
||||
`{ tab: __gm.tab(), title: __gm.tabRow().labels['asset:' + ${ownFxId}], row: __gm.assetRow(${ownFxId}) }`,
|
||||
);
|
||||
check(
|
||||
"Create sound FX on a track's FX button: one of the song's own, Input to Output, opened in its tab",
|
||||
createRows?.includes('Create sound FX') &&
|
||||
ownFxId !== JSON.stringify(fxTrackBefore) &&
|
||||
ownFx?.type === 'soundfx' &&
|
||||
ownFx.owner === id &&
|
||||
ownFx.name === 'Sound FX 1' &&
|
||||
JSON.stringify(ownFx.nodes) === JSON.stringify(['SoundFxInput', 'SoundFxOutput']) &&
|
||||
ownFx.edges === 1 &&
|
||||
ownFxTab.title === `${songName} › Sound FX 1` &&
|
||||
ownFxTab.row === null,
|
||||
JSON.stringify({ createRows, ownFx, ownFxTab }),
|
||||
);
|
||||
await evaluate(`__gm.state.openAsset(${JSON.stringify(id)})`);
|
||||
await sleep(200);
|
||||
p = await json("__gm.song.headAt(0, 'fx')");
|
||||
await click(p.x, p.y);
|
||||
await sleep(150);
|
||||
const ownRows = await json('__gm.menuRows()');
|
||||
await clickText('No sound FX');
|
||||
await sleep(150);
|
||||
const letGo = await json(`__gm.state.project.assets.some((a) => a.id === ${ownFxId})`);
|
||||
await press('z', { ctrl: true });
|
||||
await sleep(150);
|
||||
const backAgain = await json(
|
||||
`{ fx: __gm.state.project.assets.find((a) => a.id === ${JSON.stringify(id)}).tracks[0].fx, owner: __gm.state.project.assets.find((a) => a.id === ${ownFxId})?.owner }`,
|
||||
);
|
||||
check(
|
||||
'its menu names it with Edit and Make project asset, No sound FX lets it go, Ctrl+Z brings it back',
|
||||
ownRows?.includes('• Sound FX 1') &&
|
||||
ownRows.includes('Edit sound FX') &&
|
||||
ownRows.includes('Make project asset') &&
|
||||
!ownRows.includes('Create sound FX') &&
|
||||
letGo === false &&
|
||||
JSON.stringify(backAgain.fx) === ownFxId &&
|
||||
backAgain.owner === id,
|
||||
JSON.stringify({ ownRows, letGo, backAgain }),
|
||||
);
|
||||
|
||||
// 65j. The step takes back everything it made.
|
||||
await evaluate('__gm.sound.stopAll()');
|
||||
await mutate(`
|
||||
|
||||
Reference in new issue
Block a user