Snap a new song to 1/16, and route new assets as the others (#365)
game-maker / gate (push) Successful in 4m3s
game-maker / suite (push) Failing after 14m40s

A new song snapped to whole bars, too coarse to lay out a beat. And a
new or duplicated sound, instrument, pattern or song went to the
master alone, so every one had to be linked into the buses by hand
again.

- A song without a grid of its own snaps to 1/16. The songs in the
  user's project have Bar written in and keep it.
- A new or duplicated sound, instrument, pattern or song gets the links
  of the one whose targets most others of its type share, at their
  volume. On a tie the latest of them decides, so a single song decides
  for the next one.
- Where nothing of its type is linked yet, it goes as most of all that
  plays, and where nothing is, to the master. A new bus still goes to
  the master alone.
- Assets made at once are matched against what stood before, not
  against each other. A project from before the routing still opens
  with everything on the master.
- The song tab has a gridAt hook. e2e 65 checks the new grid and sets
  Bar, which its checks go by.

Tests:

- Unit master-routing (1 new) and song (1 rewritten): 26 green. Counter
  checks (rule off, grid back to Bar) red.
- e2e 65 (melektaus-atx): ALL PASSED, 58 checks (1 new).
- Gate (melektaus-atx): CHECK EXIT 0, 273 files, 4226 tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-10-09 09:37:44 +02:00
1 parent 0e73fd85b9
commit f840ec3c44
7 files changed
+131 -11

No files matched your search

+45
View File
@@ -7,6 +7,7 @@ import {
CreateAssetCommand,
CreateSoundCommand,
DeleteAssetCommand,
DuplicateAssetCommand,
RenameAssetCommand,
} from '../../src/core/commands/assetCommands';
import type { Command } from '../../src/core/commands/Command';
@@ -80,6 +81,50 @@ describe('the nodes of the master routing (#351)', () => {
expect([at(MASTER_BUS).x, at(MASTER_BUS).y]).toEqual([640, -80]);
});
it('link a new or duplicated asset where most others of its type go, else where all that plays goes', () => {
const f = edited();
const reverb = f.create('bus', 'Reverb');
const drums = f.create('bus', 'Drums');
const kick = f.sound('Kick');
const snare = f.sound('Snare');
const hat = f.sound('Hat');
const offMaster = (id: string) =>
f.run(new DisconnectCommand(ROUTING_ID, f.project.routing.edges.find((e) => e.from.node === id)!.id));
// Two sounds go into Drums and Reverb, one into the master alone: a new one goes with the two.
for (const id of [kick, snare]) {
offMaster(id);
f.link(id, drums);
f.run(new SetSendCommand(ROUTING_ID, f.link(id, reverb), { volume: -9, tap: 'post' }));
}
const tom = f.sound('Tom');
expect(f.linksOf(tom).sort()).toEqual([drums, reverb].sort());
const sendTo = (id: string, to: string) =>
f.project.routing.edges.find((e) => e.from.node === id && e.to.node === to)?.send;
expect(sendTo(tom, reverb)).toEqual({ volume: -9, tap: 'post' });
const copy = new DuplicateAssetCommand(hat);
f.run(copy);
expect(f.linksOf(copy.copyId).sort()).toEqual([drums, reverb].sort());
expect(f.linksOf(hat)).toEqual([MASTER_BUS]);
// The first song goes as most that plays; the one song there is then decides for the next.
const theme = f.create('song', 'Theme');
expect(f.linksOf(theme).sort()).toEqual([drums, reverb].sort());
f.run(
new DisconnectCommand(
ROUTING_ID,
f.project.routing.edges.find((e) => e.from.node === theme && e.to.node === drums)!.id,
),
);
expect(f.linksOf(f.create('song', 'Outro'))).toEqual([reverb]);
expect(f.linksOf(f.create('pattern', 'Riff')).sort()).toEqual([drums, reverb].sort());
// A bus goes to the master as before.
expect(f.linksOf(f.create('bus', 'Delay'))).toEqual([MASTER_BUS]);
// Undone, a new asset takes its links along.
const links = f.project.routing.edges.length;
f.stack.undo();
expect(f.project.routing.edges.length).toBe(links - 1);
});
it('come in by type as a project from before the routing is opened', () => {
const f = makeProject();
for (const command of [
+3 -1
View File
@@ -67,11 +67,13 @@ function makeSong(tracks = 4) {
}
describe('the song asset (#334)', () => {
it('starts with one track, nothing on it, at 120 BPM in 4/4 on a grid of a bar', () => {
it('starts with one track, nothing on it, at 120 BPM in 4/4 on a grid of 1/16', () => {
const f = makeSong(1);
expect(f.song().tracks.map((t) => t.name)).toEqual(['Track 1']);
expect(f.song().items).toEqual([]);
expect(schemaForAsset(f.project, f.song()).map((d) => d.key)).toEqual(['tempo', 'sign', 'grid', 'fx']);
expect(songGrid(f.song().props)).toBe(120);
f.stack.execute(new SetAssetPropertyCommand(f.song().id, 'grid', 'bar'));
expect(songGrid(f.song().props)).toBe(BAR);
f.stack.execute(new SetAssetPropertyCommand(f.song().id, 'grid', '1/8T'));
expect(songGrid(f.song().props)).toBe(160);