Skip to content

SWI 0x21 — SoundWhatever1 (MusicPlayerStart / MPlayStart)

  • Entry: 0x00001434 (THUMB; SWI table stores 0x00001435)
  • 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

  1. Verify MusicPlayerInfo identity (+0x34 == 0x68736d53); no-op if not open.
  2. 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.
  3. Initialize tempo/volume fields: tempo-related values 0x96 (150) at +0x1C and +0x20, 0x100 at +0x1E, and clear the fade fields at +0x22/+0x24.
  4. For each track i up to min(songTrackCount, openTrackCount): run the track init helper (0x23E6), set the track status byte to 0xC0 (active/keyed), and set the track's command pointer from song header +0x08 + i*4.
  5. For any remaining opened tracks beyond the song's count: init them and set status 0 (idle).
  6. 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.