3.0 KiB
3.0 KiB
Music System Architecture
Status: Draft
Last Updated: 2025-11-21
Related Code: src/zelda3/music/, src/app/editor/music/
This document outlines the architecture of the Music System in YAZE, covering both the editor and the underlying engine.
Overview
The Music System is designed to edit the soundtrack of A Link to the Past, which runs on the SNES N-SPC audio engine. The system consists of:
- Tracker Backend (
src/zelda3/music/): Parses binary ROM data into editable structures. - Music Editor (
src/app/editor/music/): Provides a UI for playback and modification. - Emulator Integration: Uses the internal
Spc700emulation for live preview.
Core Components
1. The Tracker (tracker.h, tracker.cc)
Derived from the legacy "Hyrule Magic" C codebase, this class handles the low-level complexity of the N-SPC format.
- Data Structures:
SpcCommand: A doubly-linked list node representing a single music event (note, rest, command).Song: A collection ofSongParts (tracks), typically 8 channels.SongRange: Metadata mapping a ROM address range to parsed commands.ZeldaInstrument: ADSR and sample definitions.
- Parsing:
LoadSongs: Iterates through the game's pointer tables (Banks 0x1A, 0x1B) to load all music.LoadSpcCommand: Recursive descent parser for the byte-code stream.
- Serialization:
SaveSongs: Re-packs the linked lists into binary blocks.AllocSpcBlock: Manages memory for the binary output.
2. Music Editor (music_editor.cc)
The frontend GUI built with ImGui.
- Playback:
PlaySong(int id): Writes to game RAM ($7E012C) to trigger the in-game song request mechanism via the emulator.
- Visualization:
DrawPianoRoll: Renders note data (currently a placeholder).DrawToolset: Transport controls (Play/Stop/Rewind).
3. SPC700 Audio Engine
The SNES audio subsystem (APU) runs independently of the main CPU.
- Communication: The CPU uploads music data to the APU RAM (ARAM) via a handshake protocol on ports
$2140-$2143. - Banks:
- Overworld: Bank
$1A - Underworld: Bank
$1B - Credits: Bank
$1A(offset)
- Overworld: Bank
Data Flow
- Loading:
MusicEditor::Initialize->Tracker::LoadSongs-> Parses ROM -> Populatesstd::vector<Song>. - Editing: User modifies
SpcCommandlinked lists (Not yet fully implemented in UI). - Preview: User clicks "Play". Editor writes ID to emulated RAM. Emulator NMI handler sees ID, uploads data to SPC700.
- Saving:
Tracker::SaveSongs-> Serializes commands -> Writes to ROM buffer -> Fixes pointers.
Limitations
- Vanilla-Centric: The
Trackercurrently assumes vanilla bank sizes and offsets. - Legacy Code: The parsing logic is essentially a C port and uses raw pointers/malloc heavily.
- No Expansion: Does not support the "Expanded Music" hack (relocated pointers) or "NewSPC" engine.