Describe the voice limit and when previews stop (#356)

- Instruments: at most 12 ways through the pitch worklet at once, a
  preset plays nothing, and closing the tab stops what it plays.
- Sounds: the leak of ended voices on the bus, with the measured
  numbers before and after. Closing the tab and starting the game
  stop what the Sound and Sound FX tabs play.
- Songs and Patterns: game start and closing the tab stop playback.
- Development: 1893 checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
adminandClaude Opus 5.5 committed 2026-10-08 17:57:37 +02:00
1 parent ccc9542870
commit 10e056d0cc
5 files changed
+29 -10

No files matched your search

+1 -1
@@ -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 # 1890 editor checks, screenshots in /tmp/gm-e2e-*.png
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1893 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
+10 -3
@@ -88,6 +88,11 @@ voice 0.
- **Pitch.** A Sample that follows the note is shifted by the phase vocoder of #317, so a note far
from the root sounds rough, as there. A note at its root is the sound itself, played without the
worklet. On a Chip a Pitch moves its frequency itself, exactly and at no cost.
- **At most 12 ways on the pitch worklet** play at once, in the whole editor or game. One more cuts
the oldest in 10 ms, a note already let go before one still held. Each runs a phase vocoder:
measured in Chrome on the Windows runner, 12 take half of the audio thread and 24 all of it. Past
that every sound dropped out until enough of them had ended, as a quick run up the keys of
sampled one-shots did.
- **Sound FX node and a Mix.** The arriving sound is set in wherever the FX's Input was. A Mix in
the FX therefore plays the sound twice, one source per way, as in the sound FX itself.
@@ -215,14 +220,16 @@ The header says which notes the keys play (*Keys C3 to E5*), and a line under th
while the keys have the focus. A held key does not repeat; letting it go, or the keys losing the
focus, ends the note. A key let go stays **half lit** while its note is still heard: a one-shot
playing out, a loop left, an echo. Striking it again plays a new note beside it, as a sampler does,
so a drum can be hit quickly. **Stop**, or `Esc` on the keys, ends everything the tab started. Every parameter of the
so a drum can be hit quickly. **Stop**, or `Esc` on the keys, ends everything the tab started, and
so does closing the tab or pressing Play for the game. Every parameter of the
instrument has a number field in the header, starting at its default: what the keys play with,
heard at once on what is playing. Those values are the tab's own and never written into the asset.
### Presets, Randomize and Mutate
Three buttons in the header make 8-bit sounds the way sfxr does (#329). Each is one undo step and
plays the note last played at once (C4 before any), for up to 2 s.
Three buttons in the header make 8-bit sounds the way sfxr does (#329). Each is one undo step.
Randomize and Mutate play the note last played at once (C4 before any), for up to 2 s. A preset
plays nothing: try it on the keys. With Audition on it is heard like any other change.
- **Preset** opens a menu in two parts. Either kind puts a new graph in place of the
instrument's; groups and notes on the canvas stay.
+2 -2
@@ -138,8 +138,8 @@ next window on, without starting over: a note drawn ahead of the playhead in thi
behind it in the next. A new loop or tempo counts from what is planned.
Playing goes on while another tab is open, so an instrument can be changed while its pattern plays.
It stops when another pattern is shown in the tab, when the pattern is gone and when a project is
opened.
It stops when another pattern is shown in the tab, when its tab is closed (a key of the roll too),
when the pattern is gone, when Play starts the game and when a project is opened.
Measured (2026-10-06, e2e 64 on the CI's Windows machine): bar 1 of a pattern at 120 BPM, its notes
at ticks 720, 960, 1440 and 1680 were planned exactly 0, 0.25, 0.75 and 1 s apart on the audio
+2 -1
@@ -181,7 +181,8 @@ next window on, without starting over; a track's volume, pan, mute and solo at o
The editor plays one piece at a time: playing a pattern stops the song, and playing the song stops
a pattern. Playing goes on while another tab is open; it stops when another song is shown in the
tab, when the song is gone and when a project is opened.
tab, when its tab is closed, when the song is gone, when Play starts the game and when a project is
opened.
Measured (2026-10-06, e2e 65 on the CI's Windows machine): a sound clip on the first track and a
pattern at bar 3 on the third, at 120 BPM, were planned 4 s apart, the pattern's notes 1 s apart,
+14 -3
@@ -64,7 +64,8 @@ waveform, a Sample's loop points, a Pitch.
falling for the fade out; its tooltip names it. The ramps are drawn in the wave, each in its
curve.
- **Play** (or Space) plays the stretch once, at the asset's volume, with a playhead. It ends
whatever pattern or song the music tabs were playing, as they end each other.
whatever pattern or song the music tabs were playing, as they end each other. Closing the tab
and starting the game end it.
- The **wheel** zooms about the pointer, the **middle button** pans, as in the music tabs. Zoomed
in far enough, the samples themselves are drawn as a line.
- A stereo file shows **one** wave, the loudest of its channels; it plays in stereo.
@@ -459,7 +460,16 @@ change ends. The end is timed on the clock of the sound, so a paused run holds a
- **Cost**: a Delay is a handful of Web Audio's own nodes per voice, no worklet. In e2e 34 headless
Chrome on the CI's Windows machine rendered 64 stereo voices with a ping-pong Delay for 2 s in
about 0.3 s, so about **400 of them play at once** (2026-10-06). There is no limit on how many
voices play, also now that they live longer.
voices play, also now that they live longer. Only the ways on the pitch worklet are held to 12,
see [Instruments](Instruments#how-a-note-is-made).
- **What has ended is let go.** A voice without echoes leaves its bus as soon as its sound and what
its stages hold back are through, one with echoes once they have faded. A way or stage on the
worklet closes its port when it ends or is stopped. Before that a port that was listened to was
never collected, and through it neither was its voice: every node of it stayed on its bus and
was worked on in every block. Measured (2026-10-08, a copy of a project, a song of 4 tracks
played for 12 s and stopped, Chrome on stein2): 740 nodes were left behind each time, 4469 after
six times, and the load of the audio thread at rest grew from 1 % to 6 %. Since then 7 are left,
the master and one bus, however often it is played.
### Filter
@@ -670,7 +680,8 @@ stays.
**Listening in the tab.** The header picks one of the project's sounds and plays it through the
graph as it stands — the same library as a running game, so it sounds the way the game will.
`Stop` there ends only what the tab started. Play is offered only while the graph compiles.
`Stop` there ends only what the tab started, as closing the tab and starting the game do. Play is
offered only while the graph compiles.
Every parameter has a number field in the header, starting at its default: what Play hands in.
Moving a field while the tab plays is heard at once on that sound. Those values are the tab's own
and never written into the asset.