Compositions: the composition's bus, video bus, sound kept in step

- Compositions has a new section "The composition's bus": every
  composition has a bus and a node in the master routing, audio items
  pick To composition, From asset, Master or a bus.
- The old limit "sound runs ahead after a hitch" gives way to the
  resync: more than 40 ms off, the sound starts again at the picture.
- Compositions also tells that the sprite of a video item reads
  "Driven (by composition)" in its Video clock row.
- Videos describes the row Video bus.
- Sounds lists compositions among the nodes of the master routing.
- Development counts 2077 checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
adminandClaude Opus 5.5 committed 2026-10-14 10:31:17 +02:00
1 parent 26df94ff36
commit 32fa30a983
4 files changed
+43 -19

No files matched your search

+33 -12
@@ -35,13 +35,28 @@ A **sound**, a **clip of a sound**, a **pattern** or a **song** dragged onto a t
`Play song` with Loop does. The **offset** is how far into it the item begins, in seconds; a trim
of the left edge moves it. Below 0 the item is silent until then.
- **A pattern or a song keeps its own tempo** inside the item. A Delay synced to beats counts by it.
- **The bus.** *From asset* (the default) sends it where the [Master routing](Sounds#master-routing)
sends its sound, pattern or song; *Master* or a bus sends it there instead. Each item is heard on
a bus of its own at its volume, through the sound FX of its pattern or song; a song's tracks are
buses of that item, so two items of one song do not share them.
- **The bus.** *To composition* (what a new item starts with) sends it into the
[composition's bus](#the-compositions-bus). *From asset* sends it where the
[Master routing](Sounds#master-routing) sends its sound, pattern or song; an item laid before
there was a composition's bus reads so. *Master* or a bus sends it there instead. Each item is
heard on a bus of its own at its volume, through the sound FX of its pattern or song; a song's
tracks are buses of that item, so two items of one song do not share them.
- **Animation clips do not belong to an audio item**: there is nothing on it they could move.
- **What is gone plays nothing.** The item stays, drawn red, named *(missing)*.
### The composition's bus
Every composition is a bus of the mix and has a **node in the [Master routing](Sounds#master-routing)**
(#418), named after it, so a cut is mixed as one: linked into a bus, its sound goes there; at its
volume, through that bus' sound FX. A new composition goes where most other compositions go, or to
the master where none is linked yet, never by where the sounds go.
- **Audio items** go into it where their Bus is *To composition*.
- **Videos of its items** go into it where their sprite's **Video bus** is empty: there it reads
*To composition*. *From asset* sends one along the links of its video, *Master* or a bus there
instead (see [Videos](Videos#following-an-animation)). That holds for a sprite below the item too.
- **In the tab** all of it is heard straight on the master, as in every tab; the bus counts in a game.
### Fades
An item with a sound, an audio item or an item whose sprite wears a video, can **fade in** at its
@@ -186,16 +201,18 @@ the clips as narrower bars above them. The header bar has **+ Track**, **Play**
**The picture** is a scene view whose objects are the items alive at the playhead. A click picks
an item or its child, dragging moves the real object. It takes nothing from the asset panel and
nothing from `Ctrl+V`: an object put there would have no item. Driven videos follow the playhead
and are heard while it plays, straight into the master as in every tab. In a game they go along
the links of their video in the [Master routing](Sounds#master-routing).
and are heard while it plays, straight into the master as in every tab. In a game they go into
the [composition's bus](#the-compositions-bus), or where their sprite's Video bus says.
**The hierarchy** lists the items alive at the playhead; re-parenting is off there, because items
stay at the top. **The inspector** of an item shows its object's rows and a block **TIMING**:
*Start*, *Length* and, for a video item, *Offset*, all in seconds, and **Fit to media**. An audio
item shows **SOUND ITEM** (*PATTERN*, *SONG*): what it plays, the same timing rows with *Offset*,
**Volume** in dB and **Bus** (*From asset*, *Master* or a bus). An item with a sound adds *Fade
in* and *Fade out* in seconds and a curve for each to its TIMING. A track
shows its name; a clip its animation and its start, with the length of one pass.
**Volume** in dB and **Bus** (*To composition*, *From asset*, *Master* or a bus). An item with a
sound adds *Fade in* and *Fade out* in seconds and a curve for each to its TIMING. The sprite of a
video item reads *Driven (by composition)* in its **Video clock** row, whatever it holds, and has
no *Video time* row: the composition sets that. Its *Video volume* stays, the fades scale it. A
track shows its name; a clip its animation and its start, with the length of one pass.
**Fit to media.** A new item's length follows its video: when an override gives its sprite another
video or clip, the length follows in the same undo step (`FitMediaCommand`). Dragging an edge or
@@ -235,9 +252,13 @@ it picks the placement, its items cannot be picked one by one there.
planned on the audio clock like the notes of a song, for the moment the clock reaches them, so
sound and picture keep together. While the clock stands (waiting for a video, the placement
switched off, the game paused), they are silent, and start again where it stands. `Stop
composition` and its end stop them. A time scale other than 1 moves the picture and not the
sound, and so does a frame longer than 0.1 s, which the game clock counts as 0.1 s: after one,
the sound is ahead of the picture until it starts again after the clock stood.
composition` and its end stop them.
- **Sound and picture are held together.** The sound runs on the audio clock, the picture on the
frames, and a frame counts 0.1 s at most: after a hitch the sound would be ahead. Every frame the
composition compares the two, and where they lie more than 40 ms apart, it starts the sound again
where the picture is (`CompositionSound.follow`), with the short fade a stop has. A note that
rings then starts anew. The tab does the same. At a time scale other than 1 that happens again and
again: the sound keeps to the picture, but in pieces.
- **The editor run plays none** (*Run in editor*): it writes into the saved project, and the items
would stay there. `Play composition` says so in the log there.
+1 -1
@@ -21,7 +21,7 @@ php tests/php/releases.test.php # the release stor
php tests/php/files.test.php # uploaded files in a folder per account (#344), the same way
php tests/php/videos.test.php # the video store, its queue and the worker (#402), with the
# real ffmpeg: the CI image and feuerwerk-video have it
node tools/seed-e2e.mjs && node tools/e2e.mjs # 2074 editor checks, screenshots in /tmp/gm-e2e-*.png
node tools/seed-e2e.mjs && node tools/e2e.mjs # 2077 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
+6 -5
@@ -335,8 +335,8 @@ master goes straight out.
**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, [video](Videos) with sound 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
- **A node per asset.** Every sound, instrument, pattern, song, [video](Videos) with sound,
[composition](Compositions#the-compositions-bus) 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, 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.
@@ -345,8 +345,9 @@ master goes straight out.
in *SFX* and *Reverb* and one on the master, the next one goes into *SFX* and *Reverb*. On a
tie the latest of them decides, so if there is only one song, the next one follows it. Where
nothing of its type is linked yet, it goes as most of all that plays, and where nothing is, to
the master. Videos and the music go by each other apart: a video where no other video is
linked goes to the master, not where the sounds go, and a song does not follow the videos.
the master. Videos, compositions and the music go by each other apart: a video where no other
video is linked goes to the master, not where the sounds go, and a song does not follow the
videos. The same holds for a composition.
A new bus is always linked to the master.
- **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:
@@ -355,7 +356,7 @@ master goes straight out.
- **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, a pattern or a video always takes it after the volume and the
out of a sound, an instrument, a pattern, a video or a composition 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
+3 -1
@@ -89,7 +89,8 @@ take pictures only.
sprite only out of view keeps it playing, heard in a game. A video nothing wears for 2 s is let
go and starts over the next time it is shown.
- **Play** starts every video over at its clip's start and lets it be heard at the video's
Volume, along its links in the [Master routing](Sounds#master-routing). A pause holds it, Esc
Volume, along its links in the [Master routing](Sounds#master-routing), or into the bus its
sprite's Video bus names. A pause holds it, Esc
makes it a quiet preview again. A [released game](Concepts) does the same.
- **A video with sound has a node in the Master routing**, like a sound: a new one goes where
most other videos go, or to the master where none is linked yet, never by where the sounds
@@ -111,6 +112,7 @@ rows show only while the Texture is a video or a clip of one.
| **Video clock** | **Free** (the default): the video plays by itself, as above. **Driven**: it shows the picture at its Video time |
| **Video time** | seconds into the clip, shown while the clock is Driven. A number like any other, so an animation keys it |
| **Video volume** | 0 to 1, how loud the video is heard through this sprite, on top of the video's own Volume. Shown while the clock is Driven. The fades of a [composition](Compositions#fades) item set it |
| **Video bus** | where the video is heard through this sprite in a game (#418): *From asset* (empty, the default) along the links of the video in the [Master routing](Sounds#master-routing), *Master*, or a bus. In a composition empty reads *To composition*, its [bus](Compositions#the-compositions-bus), and *From asset* is a choice of its own. A sprite with a bus of its own plays its video in a player of its own |
What the keys on Video time do: