Show a Saturation node as a device that glows with its drive (#396)
A Saturation in the graph was a stack of rows. The user wanted a device of its own style and size, like the Delay and the Reverb, that shows warmth and heat the harder the sound is driven. - The node is a copper plate of 720x280 with a button per type, the auto-gain lever, a big drive knob and small knobs for tone, output and wet. Each change is one undo step, wired numbers lock their knob. - The screen draws a sine at -12 dBFS, the level auto-gain is reckoned at, as a grey ghost. Over it is the wave that comes out: bent by the type, its DC taken out, auto-gain and output after it, blended by wet. Under it stand the auto-gain and the peak. - The heat is the drive over 48 dB, as far as wet lets it be heard. The wave goes from cold steel through ember red to white, a glow rises from below and flickers, and embers fly up from about 8 dB on. A lamp beside the name glows with it. - The node keeps the editor drawing only while there is heat. Without drive it draws nothing, unlike the Delay, which always animates. - The Reverb's private type button is now PickButton with its own colours, and the Saturation's type buttons use it as well. - No instrument preset uses a Saturation, so no preset needs more columns. Tests: - Unit saturation-view: 14 new tests. - Counter-check: without taking out the DC, exactly the DC test fails. - e2e 34 (atx): ALL PASSED, 137 checks, one new for type, lever and drive with undo. - Gate (atx): CHECK EXIT 0, 289 files, 4431 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8c53ce0cbe
commit
80b25488ce
11 files changed
+1092
-21
No files matched your search
@@ -1443,6 +1443,58 @@ export async function sound(t) {
|
||||
await mutate(`
|
||||
const graph = __gm.state.project.assets.find((a) => a.id === ${JSON.stringify(fxId)}).graph;
|
||||
graph.nodes = graph.nodes.filter((n) => n.id !== 'fx-dl');`);
|
||||
// #396: a Saturation is a device of its own size with the wave a sine comes out as on a screen,
|
||||
// glowing hotter the more it is driven. A type button, the auto-gain lever and the drive
|
||||
// knob are one undo step each.
|
||||
await mutate(`
|
||||
const graph = __gm.state.project.assets.find((a) => a.id === ${JSON.stringify(fxId)}).graph;
|
||||
graph.nodes.push(${JSON.stringify(node('fx-st', 'SoundFxSaturation', 0, 400, { drive: 12 }))});`);
|
||||
await evaluate('__gm.soundfx.fit()');
|
||||
await sleep(100);
|
||||
const stShown = await json("__gm.saturation.panel('fx-st')");
|
||||
await sleep(150);
|
||||
const stLater = (await json("__gm.saturation.panel('fx-st')")).scope.flare;
|
||||
await click(stShown.types.hard.x, stShown.types.hard.y);
|
||||
const stHard = { params: await knobParams('fx-st'), panel: await json("__gm.saturation.panel('fx-st')") };
|
||||
await click(stShown.autoGain.at.x, stShown.autoGain.at.y);
|
||||
const stOff = { params: await knobParams('fx-st'), panel: await json("__gm.saturation.panel('fx-st')") };
|
||||
const stDrive = stShown.knobs.drive.dial;
|
||||
await drag(stDrive.x, stDrive.y, stDrive.x, stDrive.y - 40);
|
||||
const stHot = { params: await knobParams('fx-st'), panel: await json("__gm.saturation.panel('fx-st')") };
|
||||
for (let i = 0; i < 3; i++) await press('z', { ctrl: true });
|
||||
const stUndone = { params: await knobParams('fx-st'), panel: await json("__gm.saturation.panel('fx-st')") };
|
||||
check(
|
||||
'a Saturation node is a device whose screen glows hotter with the drive; a type, auto-gain and the drive knob are one undo step each',
|
||||
stShown.size.w === 720 &&
|
||||
stShown.size.h === 280 &&
|
||||
Object.values(stShown.inputs).length === 5 &&
|
||||
Object.values(stShown.inputs).every((p) => p.x < stShown.rect.x) &&
|
||||
Object.values(stShown.outputs).every((p) => p.x > stShown.rect.x + stShown.rect.w) &&
|
||||
stShown.type === 'soft' &&
|
||||
stShown.knobs.drive.number === '12 dB' &&
|
||||
stShown.heat.word === 'WARM' &&
|
||||
stShown.heat.burning &&
|
||||
stShown.autoGain.lit &&
|
||||
stShown.scope.says.auto.startsWith('AUTO-GAIN ') &&
|
||||
// The glow flickers by itself.
|
||||
stLater !== stShown.scope.flare &&
|
||||
stHard.params.curve === 'hard' &&
|
||||
stHard.panel.type === 'hard' &&
|
||||
stOff.params.autoGain === false &&
|
||||
stOff.panel.scope.says.auto === 'AUTO-GAIN OFF' &&
|
||||
stHot.params.drive > 12 &&
|
||||
stHot.panel.heat.share > stShown.heat.share &&
|
||||
stHot.panel.scope.embers > 0 &&
|
||||
stUndone.params.drive === 12 &&
|
||||
stUndone.params.curve !== 'hard' &&
|
||||
stUndone.params.autoGain !== false &&
|
||||
stUndone.panel.type === 'soft' &&
|
||||
stUndone.panel.heat.word === 'WARM',
|
||||
JSON.stringify({ stShown, stLater, stHard, stOff, stHot, stUndone }),
|
||||
);
|
||||
await mutate(`
|
||||
const graph = __gm.state.project.assets.find((a) => a.id === ${JSON.stringify(fxId)}).graph;
|
||||
graph.nodes = graph.nodes.filter((n) => n.id !== 'fx-st');`);
|
||||
await showTab('scene');
|
||||
await mutate(`
|
||||
const graph = __gm.state.project.assets.find((a) => a.id === 'sn-logic').graph;
|
||||
|
||||
Reference in new issue
Block a user