The agent has no ears. It could start music and sounds, but not tell
whether anything reached the speakers: a song without an instrument, a
bus at volume 0 or a browser that holds the audio clock all looked the
same from outside.
- get_runtime has a section audio. Under levels it gives the peak and
RMS in dB of the master, each bus of the mix, each pattern, song or
composition playing and the tracks of a song. Below -90 dB it says
silent.
- The levels come from a tap of their own after the level and pan of
each bus, an AnalyserNode per side as for the meters of the Song tab.
It looks back about 0.7 s, so the gap between two notes is not
silence. A pause holds the values, which fits play with until.
- Under voices it names what sounds now: a sound by its asset, a note
of an instrument with its note name, each with its bus and object.
Next to them planned, playing, waiting (bytes not here yet) and
failed.
- Under clock it gives the state of the audio clock, with a hint when
it stands still while the game runs. The state is told as it was
before a pause, else the pause would hide that case.
- The buses are tapped only while the agent is switched on.
- The note now travels with a voice from the Start of a pattern or song
to the SoundLibrary, so a voice can be named by it.
- tools.json and the relay's instructions tell the agent to check under
audio that music and sounds are really heard.
Found on the user's project: started right after F5, before a click in
the page, the browser kept the audio clock suspended for the whole run.
Nothing was heard and the notes stayed planned. That is what clock now
shows.
Tests:
- Unit: sound-library (taps, levels, voices, clock), agent-play
(audioView). Pattern and song tests expect the note in their timing.
- 9 counter-checks, 8 red. Not dropping a tap with its bus stays green,
as the bus is cut off and gone anyway.
- e2e 71 (melektaus-atx): 28/28. New 71h4: a sound on the master and
one on a bus at volume 0, both voices named, the master loud, the bus
silent, the values held in the pause.
- Gate (melektaus-atx): CHECK EXIT 0, 327 files, 5037 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>