Size notes by either end and pan before bar one in music tabs
A round of small fixes to the Pattern and Song tabs: what the ruler and a pan do in both, and a few things the tabs carried that were in the way. - A middle-drag can take bar 1 up to half the grid or lanes in. The time before it is drawn dark on the ruler, the grid and the lanes. Nothing lands there: a click draws no note, a drop shows no frame. - A press or drag on the ruler puts the start on the nearest grid line, no longer on the one before the pointer. - A new song has one track instead of four. The "+ Track" row under the heads is gone, a head's menu adds tracks above or below. A song still keeps at least one, so that menu is always there. - A note can be sized by its left end too: the start goes to the nearest grid line and the end stays put, never before tick 0. - An end of a note under the pointer lights up and shows a resize cursor, as on an item of the Song tab. Tests: - Unit: piano-roll, song-edit, song, song-play 52 tests. Two new cases for the left end and the pan, the song fixtures add their tracks themselves now. - e2e 64+65 on melektaus-atx: ALL PASSED - 50 checks (+2). e2e 65 adds its tracks through the head's menu and clicks the ruler three quarters into a bar, which only the nearest line passes. - Gate on melektaus-atx: 251 files, 3909 tests, CHECK EXIT 0. - A probe shot of the piano roll panned in: the time before bar 1 dark, the left end of a note lit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
aa097bd076
commit
a3101c590c
15 files changed
+260
-89
No files matched your search
@@ -3,8 +3,8 @@ import { LANES, pickAssetType, scaffoldBehavior } from './lib/scaffold.mjs';
|
||||
|
||||
/**
|
||||
* Patterns and their piano roll (#333). "+ → Pattern" opens the tab; with an instrument picked its
|
||||
* keys sound where the instrument plays. A click draws a note on the grid, its right end lengthens
|
||||
* it, its body moves it – with Alt off the grid –, a band picks notes, Ctrl+D puts a copy behind
|
||||
* keys sound where the instrument plays. A click draws a note on the grid, either end sizes it and
|
||||
* lights up under the pointer, its body moves it – with Alt off the grid –, a band picks notes, Ctrl+D puts a copy behind
|
||||
* them, the arrows transpose, Delete and a right-click take notes away, Ctrl+C/V copies them to the
|
||||
* start set on the ruler, the lane sets a velocity, a drag on the ruler moves the start and one on
|
||||
* the strip above it sets the loop, the wheel zooms the time or the rows. Space plays the
|
||||
@@ -148,6 +148,30 @@ export async function pattern(t) {
|
||||
);
|
||||
const second = lengths.find((n) => n.id !== first)?.id;
|
||||
|
||||
// 64c'. Its left end lights up under the pointer and takes its start to the nearest grid line, the
|
||||
// end staying put; Ctrl+Z takes it back.
|
||||
const startEdge = await json('__gm.pattern.gridAt(960, 64)');
|
||||
await t.mouse('mouseMoved', startEdge.x + 2, startEdge.y);
|
||||
await sleep(100);
|
||||
const hovered = await json('__gm.pattern.view()');
|
||||
const earlier = await json('__gm.pattern.gridAt(850, 64)');
|
||||
await drag(startEdge.x + 2, startEdge.y, earlier.x, earlier.y);
|
||||
await sleep(300);
|
||||
const trimmedNote = (await notes()).find((n) => n.id === second);
|
||||
await press('z', { ctrl: true });
|
||||
const untrimmed = (await notes()).find((n) => n.id === second);
|
||||
check(
|
||||
'the left end of a note lights up with a resize cursor and takes its start to the nearest grid line, the end kept',
|
||||
hovered.hover?.id === second &&
|
||||
hovered.hover?.part === 'start' &&
|
||||
hovered.cursor === 'ew-resize' &&
|
||||
trimmedNote?.tick === 840 &&
|
||||
trimmedNote?.length === 600 &&
|
||||
untrimmed?.tick === 960 &&
|
||||
untrimmed?.length === 480,
|
||||
JSON.stringify({ hover: hovered.hover, cursor: hovered.cursor, trimmedNote, untrimmed }),
|
||||
);
|
||||
|
||||
// 64d. Its body moves it onto the grid and to another key, silent with Audition off; with Alt it
|
||||
// lands on the tick.
|
||||
await sleep(500);
|
||||
@@ -283,6 +307,23 @@ export async function pattern(t) {
|
||||
keysWheel.panX === gridWheel.panX,
|
||||
JSON.stringify({ scrubbed, wheelFrom, gridWheel, keysWheel }),
|
||||
);
|
||||
// A middle-drag far to the right pans tick 0 in from the left edge, but only half the grid in; a
|
||||
// click left of it draws nothing. Fit takes the view back.
|
||||
const area = await json('__gm.pattern.rect()');
|
||||
p = await json('__gm.pattern.gridAt(960, 62)');
|
||||
for (let i = 0; i < 4; i++) await drag(area.x + 120, p.y, area.x + area.w - 20, p.y, { button: 'middle' });
|
||||
const panned = await json('__gm.pattern.view()');
|
||||
const zero = await json('__gm.pattern.gridAt(0, 62)');
|
||||
const countPanned = (await notes()).length;
|
||||
await click(zero.x - 20, zero.y);
|
||||
const countLeft = (await notes()).length;
|
||||
p = await json('__gm.pattern.fitAt()');
|
||||
await click(p.x, p.y);
|
||||
check(
|
||||
'a middle-drag pans bar 1 in from the left edge, half the grid at most, and a click left of it draws nothing',
|
||||
Math.abs(panned.panX - (area.w - 84) / 2) < 1 && countLeft === countPanned,
|
||||
JSON.stringify({ panned, area, countPanned, countLeft }),
|
||||
);
|
||||
p = await json('__gm.pattern.loopAt(1920)');
|
||||
to = await json('__gm.pattern.loopAt(2880)');
|
||||
await drag(p.x, p.y, to.x, to.y);
|
||||
|
||||
Reference in new issue
Block a user