SWI 0x21 — SoundWhatever1 (MusicPlayerStart / MPlayStart)¶
- Entry:
0x00001434(THUMB; SWI table stores0x00001435) - Status: verified (hardware-checked 2026-07-08: cycle counts and return registers measured on real GBA; struct layouts remain from static analysis)
Summary¶
Behaviorally the sequencer MPlayStart: begins playback of a song on a previously opened MusicPlayerInfo. It reads the song header, resets tempo/volume state, points each track at its command stream, keys the tracks on, and — if the song requests it — reconfigures the PCM driver via SoundDriverMode.
Parameters¶
| Reg | In | Meaning |
|---|---|---|
| r0 | ptr | MusicPlayerInfo (must be opened, identity 0x68736d53 at +0x34) |
| r1 | ptr | Song header |
Returns¶
No return value.
Clobbered registers¶
r0–r7.
Hardware audit (2026-07-08, canary r4–r12 + CPSR snapshot): caller-visible clobbers: r0 = 0x68736D53, r1 = 0, r3 = 0x170 leftover. r2, r4–r12, r13, and CPSR (flags and mode) came back bit-identical on every tested path. r11/r12 are explained by the SWI dispatcher (it pushes {r11, r12, lr} — see 10_irq_boot_and_iwram.md) and CPSR by the SPSR restore on return; r2 and r4–r10 must be preserved or restored by the routine itself — where a static note above claims r2 is destroyed, the hardware disagrees at the caller level. Raw data: results/clobber_audit_pass2.csv.
Song header fields used (inferred)¶
| Offset | Field |
|---|---|
| +0x00 | number of tracks in the song (byte) |
| +0x02 | control/priority byte → MusicPlayerInfo+0x09 |
| +0x03 | flags; a bit here requests a SoundDriverMode reconfigure |
| +0x04 | tone/voice-group (instrument) pointer → MusicPlayerInfo+0x30 |
| +0x08 + i*4 | per-track command-stream start pointer |
Algorithm¶
- Verify MusicPlayerInfo identity (+0x34 ==
0x68736d53); no-op if not open. - Reset player state: clear flags (+0x04), store song header pointer (+0x00 of info block region) and instrument pointer (+0x30), copy the control byte to +0x09.
- Initialize tempo/volume fields: tempo-related values
0x96(150) at +0x1C and +0x20,0x100at +0x1E, and clear the fade fields at +0x22/+0x24. - For each track
iup tomin(songTrackCount, openTrackCount): run the track init helper (0x23E6), set the track status byte to0xC0(active/keyed), and set the track's command pointer from song header+0x08 + i*4. - For any remaining opened tracks beyond the song's count: init them and set status
0(idle). - If the song header flag byte (+0x03) requests it, call SoundDriverMode (
0x179C) to apply the song's requested reverb/channels/volume/rate.
Edge cases & known bugs¶
- Songs with more tracks than the player was opened for are truncated to the opened track count.
- No-op if the MusicPlayerInfo is not a valid opened player.
Cycle count¶
Hardware-measured net CPU cycles (worker-ROM harness, TM0/TM1 cascade at F/1,
13-cycle baseline subtracted; identical across 3 runs — see
02_hardware_verification_checklist.md § Measurement setup).
393 cycles measured with a 4-track player and an arbitrary (garbage) song header — indicative only; real cost depends on the song's track count.
Open questions (need hardware verification)¶
- Exact song-header layout and the flag bit that triggers SoundDriverMode.
- Track status bit meanings (
0xC0).
GBATEK cross-reference¶
Identifies GBATEK's reserved SWI 0x21 as the sequencer MPlayStart.