A song could only be heard in its tab. Now a game plays it through
Play song and ends it through Stop song, with its tracks as they are
set. A playing pattern or song also no longer undoes the pause of the
toolbar.
- Play song plays from the start of the song and then round the loop
of its ruler, so an intro is heard once. Without loop it plays once
to its end. Inputs are song, volume, fade in, loop (on by default)
and detached (off by default). It gives out playback.
- Stop song stops one song, every song for none, or one playback by
its number, over its fade out. Stop sound with no sound named stops
songs too. Stop pattern with no pattern named stops only patterns.
- Songs play side by side, as patterns do. They are owned like a
sound, so leaving the scene ends one unless it is detached. Pause
game and the time scale leave the music alone.
- Each playing is heard through a master of its own, silent until its
first note. The fades move it, and a song's tracks sit inside it on
buses of their own. They go once the playing and its voices have.
- Notes and clips are struck the same way in the editor and the game
(strikeNote, playClip). What a sequence needs comes from one place
(core/music/needs).
Findings:
- Reading the audio clock resumed a suspended context. A playing
pattern read it every 25 ms and so undid the toolbar's pause. The
library now leaves a context alone while the toolbar holds it.
- A pattern played once to its end asked the list of playings about
its voices, and that list asked the pattern again. Once its last
voice was gone this ran until the stack overflowed. The scheduler of
a playing now asks only after voices.
- e2e 64 reads the playings through __gm.sound.playbacks() now.
Tests:
- song-play.test.ts (new): 8 tests, node catalog +8 cases
- sound-library.test.ts: 66 tests, 4 new
- e2e 64 (melektaus-atx): 23 of 23 checks passed
- e2e 65 (melektaus-atx): ALL PASSED, 22 checks (+4)
- Gate (melektaus-atx): CHECK EXIT 0, 251 files, 3903 tests
- Counter-checks: the old way of asking after voices, a clock read
that wakes a held context, and a start after a fade out began each
fail 1 test
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A pattern could only be heard in its tab. Songs come with #334, and
only then can #336 play them in a game. Until then a game plays a
single pattern, looped or once, through two new nodes.
- Play pattern plays the whole pattern through its instrument at its
own tempo. The loop on the ruler is only for editing. Inputs are
pattern, volume, loop (on by default) and detached. It gives out
playback, 0 where there is no instrument or no note.
- Stop pattern stops one pattern, every pattern for none, or one
playback by its number. Let ring lets notes with an Envelope fall
away in their release.
- A playing is numbered and owned like a voice. Destroying the object,
Stop sound with nothing named and the end of the run stop it. Stop
sound with a voice takes a playback too.
- Each playing runs on a scheduler of its own (core/music/playbacks).
It waits for its files first, and a stop that came earlier wins.
- The scheduler has an end for a sequence that does not loop. It stops
waking there and is done once its last notes are.
- The worker clock moved to viewport/wake.ts, so SoundLibrary can use
it without importing music.ts.
Tests:
- pattern-play.test.ts (new): 8 tests, node catalog +7 cases
- e2e 64 (melektaus-atx): ALL PASSED, 23 checks (+3)
- Gate (melektaus-atx): CHECK EXIT 0, 248 files, 3854 tests
- Counter-checks: no end in the scheduler, and no owner for the
playing, each fail 1 test
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>