Show a Compressor's panel in its node, its tab on a double-click (#380)
The panel of #379 opened in a window of its own and replaced the tab. The user wanted the device in the graph instead, and the tab of #378 back on a double-click. The switch Hardware look goes again. - A node can show a face instead of its rows (`NodeFace`). Its inputs sit on the left of it and its outputs on the right, in the middle of the height. Each side is as wide as its longest port name. - A Compressor node shows the panel at full size, 820x280 graph units. Its settings and numbers are not listed as rows, the panel has them. - The knobs and the lever work in the node. A drag, a notch of the wheel and a double-click are one undo step each. A press on them neither picks nor moves the node, and the wheel does not zoom the graph. The number below a knob is only shown, typing stays in the tab and the inspector. - The meter and the LEDs run while the node is in the picture of a sound FX or instrument graph that is seen. Out of the picture, folded or hidden, the node lets go of its taps. - The window of one size, `fixedSize`, `refit`, `keptSize` and the rule that kept a Compressor out of the tab row are gone again. - A knob's drag as one undo step lives in `nodeParamDrag.ts` now, for the tab and the node. The numbers of a node and what auto-gain says moved to `compressorView.ts`. Found and fixed on the way: - The tab and the node listen to the same taps. The tab let go of them on every frame it was not seen, so the node's meter stood still while the tab was open. Now the tab lets go once, and in a frame everything unseen lets go before anything seen listens. Tests: - Unit: compressor-view (2 new), documents (the test of `keptSize` is gone with it) - e2e 34 (stein2, melektaus-atx was off): ALL PASSED, 122 checks. The four checks of #379 are now four of the node: ports beside the panel, knobs and lever in the node, the needle when played (21.7 dB with the tab open), and the double-click opening the tab. - Gate (stein2): CHECK EXIT 0, 283 files, 4356 tests - Counter-checks: an old auto-gain number read as off turns exactly its unit test red. A tab that lets go on every frame leaves the node's needle at 0 dB and no LED lit (probe on stein2). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9917253751
commit
1f2b64fb4c
18 files changed
+490
-285
No files matched your search
+67
-65
@@ -691,7 +691,6 @@ export async function sound(t) {
|
||||
threshold: -30,
|
||||
ratio: 4,
|
||||
knee: 0,
|
||||
hardwareLook: false,
|
||||
}),
|
||||
)});
|
||||
graph.edges = graph.edges.filter((e) => e.id !== 'fx-e3');
|
||||
@@ -837,7 +836,8 @@ export async function sound(t) {
|
||||
const graph = __gm.state.project.assets.find((a) => a.id === ${JSON.stringify(fxId)}).graph;
|
||||
graph.edges.push(${JSON.stringify(edge('fx-e14', 'fx-in', 'depth', 'fx-comp', 'ratio'))});`);
|
||||
const compLinked = await json('__gm.compressor.knobs()');
|
||||
await evaluate(`__gm.openDocument(${JSON.stringify(`asset:${fxId}`)})`);
|
||||
// Not the sound FX graph: the node there listens to the same taps (#380).
|
||||
await showTab('scene');
|
||||
await sleep(100);
|
||||
const compUnseen = await json('__gm.compressor.levels()');
|
||||
await mutate(`
|
||||
@@ -854,10 +854,10 @@ export async function sound(t) {
|
||||
!compDocsAfter.docs.some((doc) => doc.startsWith('compressor:')),
|
||||
JSON.stringify({ compLinked, unseen: compUnseen.taps, compDocsAfter }),
|
||||
);
|
||||
// #379: in its hardware look – a Compressor's default – the double-click opens a window of one
|
||||
// size, with no corner to size it, no Dock and no tab. Its knobs and lever work as the tab's,
|
||||
// and played, the meter's needle swings and the LEDs light. The look switched off, the
|
||||
// window can be docked; switched on again, the tab leaves the row for a window.
|
||||
// #379, #380: a Compressor node is drawn as its device – its inputs on the left, its output on the
|
||||
// right, the panel between them. Its knobs and its lever work right in the graph, and
|
||||
// played, the meter's needle swings and the LEDs light. A double-click opens the tab of #378.
|
||||
await evaluate(`__gm.openDocument(${JSON.stringify(`asset:${fxId}`)})`);
|
||||
await mutate(`
|
||||
const graph = __gm.state.project.assets.find((a) => a.id === ${JSON.stringify(fxId)}).graph;
|
||||
graph.nodes.push(${JSON.stringify(node('fx-hw', 'SoundFxCompressor', -240, 0, { threshold: -50, ratio: 8, knee: 0, makeup: 20 }))});
|
||||
@@ -866,87 +866,89 @@ export async function sound(t) {
|
||||
${JSON.stringify(edge('fx-e15', 'fx-gain', 'out', 'fx-hw', 'in'))},
|
||||
${JSON.stringify(edge('fx-e16', 'fx-hw', 'out', 'fx-out', 'in'))},
|
||||
);`);
|
||||
const hwDoc = `compressor:${fxId}:fx-hw`;
|
||||
const hwNode = await json("__gm.soundfx.nodeAt('fx-hw')");
|
||||
await t.doubleClick(hwNode.x, hwNode.y);
|
||||
await evaluate('__gm.soundfx.fit()');
|
||||
await sleep(100);
|
||||
const hwWindow = async () => (await json('__gm.floatWindows()')).find((w) => w.kind === 'compressor');
|
||||
const hwOpened = {
|
||||
window: await hwWindow(),
|
||||
docs: await json('__gm.documents()'),
|
||||
panel: await json('__gm.compressor.panel()'),
|
||||
};
|
||||
await t.drag(
|
||||
hwOpened.window.grip.x,
|
||||
hwOpened.window.grip.y,
|
||||
hwOpened.window.grip.x + 300,
|
||||
hwOpened.window.grip.y + 200,
|
||||
);
|
||||
const hwSized = await hwWindow();
|
||||
const hwPanel = () => json("__gm.compressor.panel('fx-hw')");
|
||||
const hwShown = await hwPanel();
|
||||
const hwRect = hwShown.rect;
|
||||
const hwInputs = Object.values(hwShown.inputs);
|
||||
const hwOutputs = Object.values(hwShown.outputs);
|
||||
const besideThePanel = (p) => p.y > hwRect.y && p.y < hwRect.y + hwRect.h;
|
||||
check(
|
||||
'a Compressor in its hardware look opens in a window of one size, with no tab, no Dock and no corner to size it',
|
||||
hwOpened.window?.doc === hwDoc &&
|
||||
hwOpened.window.fixed &&
|
||||
hwOpened.window.box.w === hwOpened.panel.rect.w + 2 &&
|
||||
hwOpened.panel.shown &&
|
||||
hwOpened.panel.rect.w === 820 &&
|
||||
hwOpened.panel.rect.h === 280 &&
|
||||
!hwOpened.docs.docs.includes(hwDoc) &&
|
||||
hwSized.box.w === hwOpened.window.box.w &&
|
||||
hwSized.box.h === hwOpened.window.box.h,
|
||||
JSON.stringify({ hwOpened, hwSized: hwSized.box }),
|
||||
'a Compressor node shows its panel at full size, its inputs on the left of it and its output on the right',
|
||||
hwShown.shown &&
|
||||
hwShown.size.w === 820 &&
|
||||
hwShown.size.h === 280 &&
|
||||
hwInputs.length === 8 &&
|
||||
hwInputs.every((p) => p.x < hwRect.x && besideThePanel(p)) &&
|
||||
hwOutputs.length === 1 &&
|
||||
hwOutputs.every((p) => p.x > hwRect.x + hwRect.w && besideThePanel(p)) &&
|
||||
hwShown.node.w > hwRect.w &&
|
||||
hwShown.node.h > hwRect.h,
|
||||
JSON.stringify(hwShown),
|
||||
);
|
||||
const hwThreshold = hwOpened.panel.dials.threshold;
|
||||
const hwThreshold = hwShown.dials.threshold;
|
||||
await drag(hwThreshold.x, hwThreshold.y, hwThreshold.x, hwThreshold.y - 20);
|
||||
const hwDragged = await json('__gm.compressor.numbers()');
|
||||
const hwNumbers = () =>
|
||||
json(
|
||||
`__gm.state.project.assets.find((a) => a.id === ${JSON.stringify(fxId)}).graph.nodes.find((n) => n.id === 'fx-hw').params`,
|
||||
);
|
||||
const hwDragged = await hwNumbers();
|
||||
await press('z', { ctrl: true });
|
||||
const hwUndone = await json('__gm.compressor.numbers()');
|
||||
await click(hwOpened.panel.autoGain.at.x, hwOpened.panel.autoGain.at.y);
|
||||
const hwUndone = await hwNumbers();
|
||||
const hwRatio = hwShown.dials.ratio;
|
||||
await t.wheel(hwRatio.x, hwRatio.y, -100);
|
||||
const hwWheeled = { numbers: await hwNumbers(), panel: await hwPanel() };
|
||||
await t.doubleClick(hwRatio.x, hwRatio.y);
|
||||
const hwReset = { numbers: await hwNumbers(), docs: await json('__gm.documents()') };
|
||||
await click(hwShown.autoGain.at.x, hwShown.autoGain.at.y);
|
||||
await sleep(100);
|
||||
const hwLever = await json('({ numbers: __gm.compressor.numbers(), panel: __gm.compressor.panel() })');
|
||||
const hwLever = { numbers: await hwNumbers(), panel: await hwPanel() };
|
||||
check(
|
||||
'a chrome knob turns with a drag up as one undo step, and the lever switches auto-gain and says what it gives',
|
||||
'in the node, a knob turns with a drag up as one undo step and a notch of the wheel without zooming the graph, a double-click resets it without opening the tab, and the lever switches auto-gain',
|
||||
hwDragged.threshold > -50 &&
|
||||
hwUndone.threshold === -50 &&
|
||||
hwWheeled.numbers.ratio > 8 &&
|
||||
Math.abs(hwWheeled.panel.rect.w - hwRect.w) < 0.5 &&
|
||||
hwReset.numbers.ratio === 4 &&
|
||||
hwReset.docs.active === `asset:${fxId}` &&
|
||||
hwLever.numbers.autoGain === true &&
|
||||
hwLever.panel.autoGain.on &&
|
||||
/^\+\d+\.\d dB$/.test(hwLever.panel.autoGain.says),
|
||||
JSON.stringify({ hwDragged, hwUndone, hwLever }),
|
||||
JSON.stringify({ hwDragged, hwUndone, hwWheeled, hwReset, hwLever }),
|
||||
);
|
||||
await press('z', { ctrl: true });
|
||||
await evaluate('__gm.sound.stopAll()');
|
||||
await evaluate('__gm.soundfx.play()');
|
||||
const hwPlayed = await waitFor(
|
||||
() => json('__gm.compressor.panel()'),
|
||||
(p) => p.seen.needle > 3 && p.seen.leds > 0,
|
||||
);
|
||||
await shot('34-compressor-hardware');
|
||||
const hwPlayed = await waitFor(hwPanel, (p) => p.seen.needle > 3 && p.seen.leds > 0);
|
||||
await shot('34-compressor-node');
|
||||
check(
|
||||
'played, the needle swings towards what is taken away and the LEDs light with the level going out',
|
||||
'played, the needle in the node swings towards what is taken away and the LEDs light with the level going out',
|
||||
hwPlayed.seen.needle > 3 && hwPlayed.seen.leds > 0 && /GR +\d+\.\d dB/.test(hwPlayed.lcd),
|
||||
JSON.stringify(hwPlayed),
|
||||
);
|
||||
await evaluate('__gm.sound.stopAll()');
|
||||
await mutate(`
|
||||
const graph = __gm.state.project.assets.find((a) => a.id === ${JSON.stringify(fxId)}).graph;
|
||||
graph.nodes.find((n) => n.id === 'fx-hw').params.hardwareLook = false;`);
|
||||
const hwStandard = { window: await hwWindow(), panel: await json('__gm.compressor.panel()') };
|
||||
await click(hwStandard.window.dock.x, hwStandard.window.dock.y);
|
||||
const hwDocked = { windows: await json('__gm.floatWindows()'), docs: await json('__gm.documents()') };
|
||||
await mutate(`
|
||||
const graph = __gm.state.project.assets.find((a) => a.id === ${JSON.stringify(fxId)}).graph;
|
||||
graph.nodes.find((n) => n.id === 'fx-hw').params.hardwareLook = true;`);
|
||||
const hwBack = { window: await hwWindow(), docs: await json('__gm.documents()') };
|
||||
const hwTitle = await json("__gm.soundfx.nodeAt('fx-hw')");
|
||||
await t.doubleClick(hwTitle.x, hwTitle.y);
|
||||
await sleep(100);
|
||||
const hwTab = {
|
||||
docs: await json('__gm.documents()'),
|
||||
windows: await json('__gm.floatWindows()'),
|
||||
shown: await json('__gm.compressor.shown()'),
|
||||
};
|
||||
// The tab and the node listen to the same taps: the tab, open but not seen, must leave them be.
|
||||
await evaluate(`__gm.openDocument(${JSON.stringify(`asset:${fxId}`)})`);
|
||||
await sleep(100);
|
||||
await evaluate('__gm.soundfx.play()');
|
||||
const hwBesideTab = await waitFor(hwPanel, (p) => p.seen.needle > 3);
|
||||
await evaluate('__gm.sound.stopAll()');
|
||||
check(
|
||||
'the look switched off, the window can be sized and docked; switched on again, the tab leaves the row for a window',
|
||||
!hwStandard.window.fixed &&
|
||||
!hwStandard.panel.shown &&
|
||||
hwDocked.windows.length === 0 &&
|
||||
hwDocked.docs.active === hwDoc &&
|
||||
hwBack.window?.doc === hwDoc &&
|
||||
hwBack.window.fixed &&
|
||||
!hwBack.docs.docs.includes(hwDoc),
|
||||
JSON.stringify({ hwStandard, hwDocked, hwBack }),
|
||||
'a double-click on the node opens its tab in the row, and with the tab open the node’s needle still swings',
|
||||
hwTab.docs.active === `compressor:${fxId}:fx-hw` &&
|
||||
hwTab.windows.length === 0 &&
|
||||
hwTab.shown?.nodeId === 'fx-hw' &&
|
||||
hwBesideTab.seen.needle > 3,
|
||||
JSON.stringify({ hwTab, seen: hwBesideTab.seen }),
|
||||
);
|
||||
await mutate(`
|
||||
const graph = __gm.state.project.assets.find((a) => a.id === ${JSON.stringify(fxId)}).graph;
|
||||
|
||||
Reference in new issue
Block a user