Show a Chip node as a device with its wave and its pitch (#386)
game-maker / gate (push) Successful in 4m5s
game-maker / suite (push) Failing after 16m5s

The Chip had eleven numbers in rows and nothing that showed what they
do to a note. Its node is now a device of one size like the
Compressor's, and two screens draw the wave and the pitch from the
settings, worked right in the instrument graph.

- ChipPanel is 840x280 in the warm grey of a handheld console. A
  button per wave, the "follow note" lever and a chrome knob per
  number, grouped Oscillator, Slide, Vibrato, Arpeggio and Repeat.
- The wave screen draws two periods as loud as the Chip plays them,
  a square at its duty. toneValue and periodicSteps come out of
  chip.ts, so the screen and the worklet share one formula.
- The pitch screen draws what slide, delta slide, vibrato, arpeggio
  and repeat make of the pitch over a note. It ends where the note
  falls below "min frequency" and starts from A4 while the Chip
  follows the note.
- Idle settings are faded, wired ones greyed and locked, as the rows
  were. Every change is one undo step.
- Knobs take a bipolar range: 0 straight up, the taper bends each
  half. Slide, delta slide, duty sweep and arpeggio use it.
- The Compressor's auto-gain lever is now a Lever with a name of its
  own, which the Chip uses for "follow note".
- Presets give a Chip five columns, as a Filter has four since #385.

Found on the way:

- With the Chip this wide the Laser preset is about 3060 units. In a
  1280 px window Fit stops at the least zoom of 0.25 and cuts the
  Notes node off. The zoom limit is left as it is.

Tests:
- Unit: chip-view (9 new), knob (1 new), chip, chip-presets and
  hardware-view, 53 green
- e2e 34 on melektaus-atx: ALL PASSED, 131 checks (1 new). The
  first run was red on the check itself: a Laser's "min frequency"
  can lie above A4, and the screen then rightly says the note ends
  at once.
- Gate on melektaus-atx: CHECK EXIT 0, 285 files, 4377 tests
- Counter-check: a square drawn with its duty mirrored turns the wave
  test red

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-10-10 14:55:35 +02:00
1 parent c087993000
commit eb78f3cbf3
14 files changed
+1190 -26

No files matched your search

+55
View File
@@ -2290,6 +2290,61 @@ export async function sound(t) {
);
await shot('34-instrument-preset');
// #386: the Laser's Chip is drawn as a device between its ports: a button per wave, the "follow
// note" lever and a knob per number, each change one undo step, and its screens drawn from
// it. A Laser falls: its pitch ends lower than it starts. Three undos bring the Laser back.
await clickText('Fit');
await sleep(300);
const chipId = (
await json(
`__gm.state.project.assets.find((a) => a.id === ${JSON.stringify(insId)}).graph.nodes.find((n) => n.type === 'InstrumentChip')`,
)
).id;
const chipPanel = () => json(`__gm.chip.panel('${chipId}')`);
const chipShown = await chipPanel();
const chipRect = chipShown.rect;
const chipBeside = (p) => p.y > chipRect.y && p.y < chipRect.y + chipRect.h;
await click(chipShown.waves.triangle.x, chipShown.waves.triangle.y);
const chipPicked = { params: (await insGraph()).chip, panel: await chipPanel() };
await click(chipShown.follow.at.x, chipShown.follow.at.y);
const chipFollowed = { params: (await insGraph()).chip, panel: await chipPanel() };
const slideDial = chipShown.knobs.slide.dial;
await drag(slideDial.x, slideDial.y, slideDial.x, slideDial.y - 20);
const chipSlid = (await insGraph()).chip;
for (let i = 0; i < 3; i++) await press('z', { ctrl: true });
const chipUndone = (await insGraph()).chip;
check(
'a Chip node shows its device between its ports; a wave button, the lever and a knob each change it as one undo step, and its screens follow',
chipShown.shown &&
chipShown.size.w === 840 &&
chipShown.size.h === 280 &&
Object.values(chipShown.inputs).length === 12 &&
Object.values(chipShown.inputs).every((p) => p.x < chipRect.x && chipBeside(p)) &&
Object.values(chipShown.outputs).every((p) => p.x > chipRect.x + chipRect.w && chipBeside(p)) &&
chipShown.wave === laser.chip.wave &&
chipShown.follow.on === false &&
chipShown.knobs.slide.value === laser.chip.slide &&
chipShown.pitch.from.startsWith(chipShown.knobs.frequency.number) &&
chipShown.pitch.last < 0 &&
chipPicked.params.wave === 'triangle' &&
chipPicked.panel.waveScreen === 'TRIANGLE' &&
chipPicked.panel.idle.includes('duty') &&
chipFollowed.params.followNote === true &&
chipFollowed.panel.follow.on &&
chipFollowed.panel.idle.includes('frequency') &&
// A Laser's "min frequency" may lie above A4: then it says the note ends at once.
chipFollowed.panel.pitch.from.startsWith('A4 440 Hz') &&
chipSlid.slide > laser.chip.slide &&
JSON.stringify(chipUndone) === JSON.stringify(laser.chip),
JSON.stringify({
chipShown,
chipPicked,
chipFollowed,
slide: [laser.chip.slide, chipSlid.slide],
chipUndone,
}),
);
const beforeRandom = await stats();
await clickHook('randomizeAt');
const randomized = await waitFor(stats, (s) => s.started > beforeRandom.started);