SWI 0x24 — SoundWhatever4 (MusicPlayerFadeOut / MPlayFadeOut)¶
- Entry:
0x00001514(THUMB; SWI table stores0x00001515) - 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 MPlayFadeOut: starts a volume fade-out on a
MusicPlayerInfo. It seeds the fade state (starting fade level and per-step speed);
the actual per-frame volume decay and eventual track silencing are carried out by
the companion fade-processing routine (0x1534, invoked from the player's update
path).
Parameters¶
| Reg | In | Meaning |
|---|---|---|
| r0 | ptr | MusicPlayerInfo (identity 0x68736d53 at +0x34) |
| r1 | speed | fade step interval / speed value written to the fade counter |
Returns¶
No return value.
Clobbered registers¶
r1, r7.
Hardware audit (2026-07-08, canary r4–r12 + CPSR snapshot): caller-visible clobbers: r0 (player pointer) preserved, r1 = 0x100 (fade counter), r2/r3 preserved. 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.
Algorithm¶
- Verify MusicPlayerInfo identity (+0x34); no-op if not open. Bump it as a busy lock.
- Seed the fade state:
- fade interval/reload (+0x24) = r1,
- fade counter (+0x26) = r1,
- fade level (+0x28) =
0x100(full volume, the starting point of the decay). - Restore the identity word and return.
Companion per-frame fade (0x1534)¶
Each processing pass: when a fade is active, count down the fade counter (+0x26);
when it hits 0, reload it and subtract 0x10 from the fade level (+0x28). The
current level scales every track's output (written to each track's volume field,
level >> 2). When the level reaches 0, the fade routine stops all tracks (status
byte set to 0), ending the song.
Edge cases & known bugs¶
- No-op if the MusicPlayerInfo is not a valid opened player.
- A larger r1 slows the fade (more frames between each
0x10volume decrement);0x100 / 0x10 = 16decrement steps to reach silence.
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).
89 cycles (fade state seeding only; the actual fade runs in MPlayMain).
Open questions (need hardware verification)¶
- Whether r1 is frames-per-step or a direct rate; exact fade-level → track-volume
scaling (observed as
>> 2).
GBATEK cross-reference¶
Identifies GBATEK's reserved SWI 0x24 as the sequencer MPlayFadeOut, with the fade
level starting at 0x100 and decaying by 0x10 per step.