From 59142d270e2c1031a4885696ae1dac64c69457aa Mon Sep 17 00:00:00 2001 From: meleki Date: Fri, 9 Oct 2026 09:19:02 +0200 Subject: [PATCH] Describe the Master routing graph instead of Bus and Into (#351) The rows Bus and Into are gone. Sounds, instruments, patterns, songs and buses are routed in one graph per project now. - Sounds: the section Master routing replaces Buses and the master. - Songs, Patterns and Instruments point there instead of a Bus row. - Development counts 1909 checks. Co-Authored-By: Claude Opus 5.5 --- Development.md | 2 +- Instruments.md | 2 +- Patterns.md | 4 ++- Songs.md | 20 ++++++++------ Sounds.md | 73 +++++++++++++++++++++++++++++++++++--------------- 5 files changed, 69 insertions(+), 32 deletions(-) diff --git a/Development.md b/Development.md index 62339f4..5c6609b 100644 --- a/Development.md +++ b/Development.md @@ -19,7 +19,7 @@ php tests/php/accounts.test.php # the API's accoun php tests/php/snapshots.test.php # the snapshot store (#231), the same way php tests/php/releases.test.php # the release store (#266), the same way php tests/php/files.test.php # uploaded files in a folder per account (#344), the same way -node tools/seed-e2e.mjs && node tools/e2e.mjs # 1908 editor checks, screenshots in /tmp/gm-e2e-*.png +node tools/seed-e2e.mjs && node tools/e2e.mjs # 1909 editor checks, screenshots in /tmp/gm-e2e-*.png GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step ./e2e.sh start [GM_STEPS] # the same run detached, see below ./e2e.sh status # live progress, or the last run's result diff --git a/Instruments.md b/Instruments.md index c77f145..95c1829 100644 --- a/Instruments.md +++ b/Instruments.md @@ -302,7 +302,7 @@ low-pass. | `tempo` | BPM, what a [Delay synced to beats](Sounds#delay-and-the-tail-of-a-voice) in the instrument counts by. Default 120. | | `fx` | A [sound FX](Sounds#sound-fx) the note goes through on top of what the instrument does (#346), as through a *Sound FX* node at its Output. *From the asset* (the default) is the row **Sound FX** of the instrument, *None* none (#352). Its Pitch moves the note's sound itself, with no latency. | | `fx params` | Values for that FX's parameters, from a **Sound FX parameters** node. They stay apart from `params`: an FX parameter and an instrument parameter of the same name are two numbers. | -| `bus` | The [bus](Sounds#buses-and-the-master) the note is heard on. *From the asset* (the default) takes the row **Bus** of the instrument, which is also what its tab plays on (#325). | +| `bus` | The [bus](Sounds#buses-and-the-master) the note is heard on. *From the asset* (the default) goes along the links of the instrument in the [Master routing](Sounds#master-routing), as its tab plays (#351). | Its output `voice` is the number of the note, like `Play sound`'s: `Set sound FX parameters` moves its parameters while it plays (the bundle of an Instrument parameters node goes into its diff --git a/Patterns.md b/Patterns.md index 21a2038..158123e 100644 --- a/Patterns.md +++ b/Patterns.md @@ -17,7 +17,9 @@ The notes and the loop are the pattern's own data; everything else is a row in t | **Sign** | The time signature, from the same list as a [song's](Songs) (#364): 1/2, 2/2, 3/2, 1/4 to 6/4, or 5/8 to 9/8, 4/4 by default. It only says where the bars and beats of the ruler are; the notes are kept in ticks, so a pattern changed from 4/4 to 6/8 keeps every note where it was. | | **Tempo (BPM)** | 20 to 400, quarter notes a minute, for hearing the pattern in its tab. A song plays it at its own tempo. | | **Sound FX** | A [sound FX](Sounds#the-sound-fx-of-an-asset) all its notes go through together, as one chain (#352): `Play pattern`, the tab, and a pattern item of a song that picks none. | -| **Bus** | The [bus](Sounds#buses-and-the-master) a `Play pattern` and the tab play it on, *Master* while none is picked (#325). In a song the song's bus counts. | + +Where a `Play pattern` and the tab are heard is said by the links of its node in the +[Master routing](Sounds#master-routing) (#351). In a song the song's links count. A note is a start and a length in ticks (480 to the quarter note, see [Playing in time](Instruments#playing-in-time)), a note number (60 is C4) and a velocity from 0 to 1. diff --git a/Songs.md b/Songs.md index d6f9cfc..dbe9e3b 100644 --- a/Songs.md +++ b/Songs.md @@ -16,8 +16,10 @@ inspector. | **Tempo (BPM)** | 20 to 400, quarter notes a minute. The song plays every pattern at this tempo; the tempo set on a pattern is only for its own tab. | | **Sign** | The time signature of the ruler (#363): 1/2, 2/2, 3/2, 1/4 to 6/4, or 5/8 to 9/8, 4/4 by default. Items are kept in ticks, so a change only moves the bar lines. | | **Grid** | What items snap to: **Bar** (the default), or one of the grids of a pattern, 1/1 to 1/32 and the triplets. The tab's header has the same choice. | -| **Sound FX** | A [sound FX](Sounds#the-sound-fx-of-an-asset) the whole song goes through, after its tracks and the routing, before its bus (#352). `Play song` and the tab play through it. | -| **Bus** | The [bus](Sounds#buses-and-the-master) a `Play song` and the tab play it on, *Master* while none is picked (#325). | +| **Sound FX** | A [sound FX](Sounds#the-sound-fx-of-an-asset) the whole song goes through, after its tracks and the routing, before its links in the Master routing (#352). `Play song` and the tab play through it. | + +Where a `Play song` and the tab are heard is said by the links of the song's node in the +[Master routing](Sounds#master-routing) (#351). The *Output* of the song's own routing goes there. One tempo and one meter hold for the whole song. A change of tempo within a song would come with automation (#337). @@ -133,7 +135,7 @@ below them. **Routing** in the header shows the song as a graph instead of the timeline (#350): a node for every track, named after it, and one node **Output**. The output is what the song sounds like; from -there it goes on to the [bus](Sounds#buses-and-the-master) of the song. It is the same graph editor +there it goes on along the links of the song in the [Master routing](Sounds#master-routing). It is the same graph editor as for a sound FX, with zoom, undo, groups and comments. The magnet next to **Routing** snaps the nodes to the grid while it is lit. It is off at first and greyed out on the timeline, just as **Grid** is greyed out in the routing. **Timeline** goes back. @@ -204,7 +206,7 @@ above the heads shows the whole song (#359). -48 to +6 dBFS. Green, yellow from -6 dB, red past 0 dB. A line marks the loudest peak, it holds for 1.5 s and then falls. - **Where they measure:** a track after its sound FX, volume and pan, before its links. Out after - the song's own sound FX, before the bus of the song and the master. Both measure before the + the song's own sound FX, before the links of the song and the master. Both measure before the [limiter at the output](Sounds#buses-and-the-master), so they show what the mix would be without it. - **Clip lamp:** once a sample was past 0 dBFS, the far end of the meter stays red, through Stop @@ -272,8 +274,9 @@ sounds and their clips, the *Pattern* row its patterns, every sound FX pick its asset is deleted in the same undo step. A copied item keeps it in the clipboard, so a paste after the delete brings it back. *Duplicate* on the song copies everything it keeps to itself. - A click on its name in the inspector lights up its song in the Assets panel. -- In the Sound tab of an embedded sound the rows *Loop* and *Bus* are left out: in a song an item - repeats its sound as long as it is, and the track decides where it goes. +- In the Sound tab of an embedded sound the row *Loop* is left out: in a song an item repeats its + sound as long as it is. Where it goes the track decides, so it has no node in the + [Master routing](Sounds#master-routing). - **Make project asset** (the item's menu) turns an embedded asset into an ordinary one; a name the project has already gets a number. **Embed a copy** goes the other way: the item plays a copy of its project asset that only the song has, to bend without touching the rest. @@ -289,7 +292,8 @@ song) and an item for it, one undo step, and opens it in the Pattern tab. else of the first one after it; on a track without one it has none yet. - It starts with the tempo and the sign of the song. From then on they are its own, as with a project pattern (#363): a change of the song's sign leaves its length alone, so its item is not - cut or stretched. Its inspector leaves out only *Bus*, which the song decides. + cut or stretched. Its inspector leaves out nothing. Where it goes the song decides, so it has no + node in the [Master routing](Sounds#master-routing). - A project pattern embedded as a copy, or one pasted from another song, keeps its tempo and sign. ### A sound FX of its own @@ -358,7 +362,7 @@ Bitcrusher crushes the chord, and it costs one chain however many notes sound. per clip, then goes on through its track's. - **Which FX:** an item's FX and the song's are those of the [assets](Sounds#the-sound-fx-of-an-asset) (the pattern, the sound, the song) unless the item or the `Play song` picks another one or *None* - (#352). In the tab the song's FX sits on a bus of the tab between the output and the song's bus. + (#352). In the tab the song's FX sits on a bus of the tab between the output and the song's links. - A sound FX that is gone or does not compile passes everything on as it is. - Track and item FX play at the defaults of their parameters. Those of a `Play pattern` / `Play song` take `fx params`, and `Set sound FX parameters` moves them by the `playback`. diff --git a/Sounds.md b/Sounds.md index 4465922..6755911 100644 --- a/Sounds.md +++ b/Sounds.md @@ -31,7 +31,6 @@ signature, so nothing a request claims can decide what is written. | **Volume** | How loud this sound is by itself, 0-1. | | **Loop** | Whether it is music: it repeats until something stops it. | | **Sound FX** | The [sound FX](#sound-fx) it goes through wherever it plays, none while none is picked (#352). See [The sound FX of an asset](#the-sound-fx-of-an-asset). | -| **Bus** | The [bus](#buses-and-the-master) it is heard on, *Master* while none is picked (#325). | The preview plays through the very same library a running game uses — same decode, same device — so what the inspector plays is what the graph will play. @@ -241,13 +240,15 @@ Every sound ends in the **master** (#325). Between a sound and the master there turns all of it up or down together, and its sound FX works on the sum: one compressor, one echo for everything on it. -**A bus is an asset** (`+` → *Audio* → *Bus*). Its inspector has three rows: +**A bus is an asset** (`+` → *Audio* → *Bus*). Its inspector has two rows: | Row | Meaning | | --- | --- | | **Volume** | How loud everything on it is, 0-1. | | **Sound FX** | A [sound FX](#sound-fx) all of it goes through as one chain, before the volume. Its [parameters](#parameters) start at their defaults. | -| **Into** | The bus it goes on into, *Master* while none is picked. A bus can go into another one: *Drums* into *Music*, *Music* into the master. | + +Where a bus goes on, and where a sound, an instrument, a pattern or a song is heard, is said in +one place: the [Master routing](#master-routing). **The master** is no asset. Its *Volume* and *Sound FX* are in **Project settings** under *Master*, so every project has exactly one. A new project has only the master; buses are made as @@ -261,20 +262,51 @@ so everything is heard 5 ms later. Playing a song or pattern, the playhead and a count that in. It needs the FX worklet. Until that is loaded, a moment after the first sound, the master goes straight out. -**No loops.** *Into* never offers the bus itself, nor a bus that already goes into it. Should a -project still hold a loop (written by hand, say), the buses on it go into the master instead. +### Master routing + +**Menu → Master routing** opens a tab with one graph per project (#351). It works like the +[routing of a song](Songs#routing), one level up: + +- **A node per asset.** Every sound, instrument, pattern, song and bus of the project has one, + named after it, and there is one **Master**. The nodes come and go with the assets: a new asset + gets its node in a column for its type, linked to the master, and a deleted one takes its node + and its links along. They cannot be added or deleted by hand. What a song keeps to itself + (an embedded sound or pattern) has no node: its song routes it. +- **Links are sends.** A drag from the out of a node into the in of a bus or of the master links + them. A node may have several links, the same sound then goes everywhere it is linked at once: + a step sound into *SFX* and, quieter, into a *Reverb* bus. Only a bus and the master take links + in. +- **Volume and Mode of a link** are in the inspector when it is picked: its level from -60 to + +12 dB, 0 by default. A link out of a bus or a song also has a **Mode**, as on a track: after the + volume (the default), after the sound FX but before the volume, or before the sound FX. A link + out of a sound, an instrument or a pattern always takes it after the volume and the sound FX. +- **No loops.** A link that would lead round to where it started is refused. +- **A node without a link is never heard.** It says *Goes nowhere*, and the header counts how many + do. A deleted bus leaves what went only into it on the master, so deleting a bus silences + nothing. +- **A click on a node** shows its asset in the inspector, as the asset panel would; on the master, + its volume and sound FX, the same as in Project settings. **A double click** opens the asset's + tab. `Fit` and the magnet in the header work as in every graph tab. + +A project from before there was a routing has every asset linked to the master, which is how it +always sounded. **Which bus a sound is heard on.** -- Sounds, instruments, patterns and songs have a row **Bus**. Empty means the master. So a step - sound is *SFX* everywhere it is played, and no node has to say so. +- Where its node in the routing is linked. So a step sound is *SFX* everywhere it is played, and + no node has to say so. - `Play sound`, `Play note`, `Play pattern` and `Play song` have an input `bus`. Left at - *From the asset* it takes the bus the asset names. *Master* or a bus picked there overrules it. -- What lies **inside** a song or a pattern is heard the way the song or pattern is: the bus of a - sound placed on a track, or of the instrument of a pattern, does not count there. The order is - the song's own (see [Songs](Songs#sound-fx-on-tracks-items-and-whole-songs)), then the bus of the - song, then the buses it goes into, then the master. -- A bus that was deleted leaves what named it on the master. + *From the asset* it goes along the links of the asset. *Master* or a bus picked there overrules + it: then it goes into that bus alone. +- What lies **inside** a song or a pattern is heard the way the song or pattern is: the links of a + sound placed on a track, or of the instrument of a pattern, do not count there. The order is + the song's own (see [Songs](Songs#sound-fx-on-tracks-items-and-whole-songs)), then the links of + the song, then the buses they go into, then the master. + +**What it costs.** An asset with one link at 0 dB goes straight into its bus, as with no routing +at all. Only one with more than one link, or another level, gets a bus of its own that all its +voices go through, with the sends on it. Each send is held back as far as the latest way of the +asset, so a bus with a Pitch on it does not make one way come later than the other. **In the game.** `Set bus volume` changes a bus while the game runs, `Bus volume` reads it. The volume set holds for the rest of the run, the next scene included, over the volume of the asset. @@ -285,11 +317,11 @@ sound FX of the bus picked in its `bus` input instead, the master among them. **Pausing** with `Pause game` does nothing to the buses: sounds play on. A game that wants quiet in its pause menu sets a bus volume itself, for instance *SFX* to 0 while *Music* plays on. -**In the editor** the tabs play as the game does: the Sound tab through the sound FX and the bus of -the sound, the Instrument tab through those of the instrument, the Pattern and Song tab through -those of the pattern or song, all of it on through the master. So a compressor on the master is -heard while editing, too. The Sound FX tab plays the sound it tries out on that sound's bus, -through the FX in the tab instead of the sound's own. +**In the editor** the tabs play as the game does: the Sound tab through the sound FX and along the +links of the sound, the Instrument tab through those of the instrument, the Pattern and Song tab +through those of the pattern or song, all of it on through the master. So a compressor on the +master is heard while editing, too. The Sound FX tab plays the sound it tries out along that +sound's links, through the FX in the tab instead of the sound's own. **A Pitch on a bus or on the master** is allowed. It is late by one frame like every [Pitch on a bus](#a-pitch-on-a-bus), and notes of a song are started that much earlier. @@ -303,15 +335,14 @@ Input and the Output once each; their pins carry sound and fit nothing but each ### The sound FX of an asset -Sounds, instruments, patterns and songs have a row **Sound FX**, right above *Bus* (#352). Empty -is none. What it does depends on the asset: +Sounds, instruments, patterns and songs have a row **Sound FX** (#352). Empty is none. What it does depends on the asset: | Asset | Goes through its Sound FX | | --- | --- | | **Sound** | every voice of it: `Play sound`, an item of a [song](Songs#items), the Sound tab. | | **Instrument** | every note, after what the [instrument](Instruments) graph does, as through a *Sound FX* node at its Output: `Play note`, every note of a pattern or song, the keys of its tab and of the Pattern tab. | | **Pattern** | all its notes **together**, as one chain: `Play pattern`, the Pattern tab, a pattern item of a song. | -| **Song** | the whole song, after its tracks and the [routing](Songs#routing), before its bus: `Play song`, the Song tab. | +| **Song** | the whole song, after its tracks and the [routing](Songs#routing), before its links in the [Master routing](#master-routing): `Play song`, the Song tab. | `Play sound`, `Play note`, `Play pattern` and `Play song` have an input `fx`, and an item of a song a row *Sound FX*, with the same choice: **From the asset** (empty, the default) takes the row of the