docs: Enhance tracker.cc and tracker.h with detailed function and struct documentation

- Added comprehensive Doxygen-style comments for key functions in tracker.cc, including AllocSpcBlock, GetSpcAddr, and LoadSpcCommand, to improve code readability and maintainability.
- Documented the purpose and parameters of various structs in tracker.h, such as SongSpcBlock, SongRange, and SpcCommand, providing clarity on their roles in the music data handling process.
- Improved overall documentation quality to assist developers in understanding the music tracking system's architecture and functionality.
This commit is contained in:
scawful
2025-10-09 20:50:03 -04:00
parent c33a9c9635
commit 0ba767d6fe
2 changed files with 189 additions and 54 deletions

View File

@@ -31,6 +31,14 @@ void AddSpcReloc(music::SongSpcBlock *sbl, short addr) {
} // namespace
namespace music {
/**
* @brief Allocates a new SongSpcBlock for holding generated SPC data.
* These blocks are the building blocks for the final binary output that will be
* written to the ROM and eventually loaded into the APU.
* @param len The size of the data buffer to allocate for this block.
* @param bank The target sound bank for this block.
* @return A pointer to the newly allocated SongSpcBlock.
*/
SongSpcBlock *Tracker::AllocSpcBlock(int len, int bank) {
SongSpcBlock *sbl;
if (!len) {
@@ -54,6 +62,16 @@ SongSpcBlock *Tracker::AllocSpcBlock(int len, int bank) {
return sbl;
}
/**
* @brief Gets a direct pointer to music data within the ROM.
* This function is critical for parsing. It correctly resolves a virtual SPC
* address and bank into a physical offset within the loaded ROM file, handling
* the game's specific sound bank mapping.
* @param rom The ROM object.
* @param addr The 16-bit virtual address of the data.
* @param bank The sound bank where the data resides.
* @return A pointer to the data within the ROM buffer, or nullptr if not found.
*/
unsigned char *Tracker::GetSpcAddr(Rom &rom, unsigned short addr, short bank) {
unsigned char *rom_ptr;
unsigned short a;
@@ -88,6 +106,12 @@ again:
}
}
/**
* @brief Allocates a new SpcCommand from a pre-allocated pool.
* This uses a classic free-list implementation for efficient memory management
* without repeated malloc/free calls.
* @return The index of the newly allocated command.
*/
short Tracker::AllocSpcCommand() {
int i = m_free;
int j;
@@ -112,6 +136,15 @@ short Tracker::AllocSpcCommand() {
return i;
}
/**
* @brief Calculates the total time (duration) of a block of SpcCommands.
* This is essential for synchronization and editor display. It works backwards
* from the end of a command list, calculating and caching the duration.
* @param rom The ROM object.
* @param num The starting command index.
* @param prevtime The duration of the subsequent block.
* @return The total duration in ticks.
*/
short Tracker::GetBlockTime(Rom &rom, short num, short prevtime) {
SpcCommand *spc_command = current_spc_command_;
SpcCommand *spc_command2;
@@ -204,6 +237,16 @@ short Tracker::GetBlockTime(Rom &rom, short num, short prevtime) {
return spc_command[num].tim + prevtime * spc_command[num].tim2;
}
/**
* @brief Loads a block of music data from a given ROM address.
* This is the main parser. It reads the raw byte stream from the ROM and
* converts it into a doubly-linked list of SpcCommand structs.
* @param rom The ROM object.
* @param addr The starting address in the ROM.
* @param bank The sound bank.
* @param t A time limit for parsing, to handle potentially infinite loops.
* @return The index of the first command in the newly loaded block.
*/
short Tracker::LoadSpcCommand(Rom &rom, unsigned short addr, short bank,
int t) {
int b = 0;
@@ -378,6 +421,13 @@ short Tracker::LoadSpcCommand(Rom &rom, unsigned short addr, short bank,
return h;
}
/**
* @brief High-level function to load all song data from the ROM.
* (Currently commented out, but this would be the main entry point for parsing.)
* It would iterate through the main song table in the ROM, and for each song,
* recursively load all its parts and commands using LoadSpcCommand. It would
* also load instrument and sample data.
*/
void Tracker::LoadSongs(Rom &rom) {
// unsigned char *b;
// unsigned char *c;
@@ -648,6 +698,16 @@ void Tracker::LoadSongs(Rom &rom) {
// w_modf = 0;
}
/**
* @brief Saves a block of edited SpcCommands back into a binary format.
* This is the serializer, the inverse of LoadSpcCommand. It walks the linked
* list of commands and writes the corresponding bytes into a new SongSpcBlock.
* @param rom The ROM object.
* @param num The index of the first command to save.
* @param songtime The total duration of the song, used for padding.
* @param endtr Flag indicating if this is the end of a track.
* @return The new virtual address of the saved block.
*/
short Tracker::SaveSpcCommand(Rom &rom, short num, short songtime,
short endtr) {
SpcCommand *spc_command = current_spc_command_;
@@ -769,6 +829,18 @@ short Tracker::SaveSpcCommand(Rom &rom, short num, short songtime,
return 0;
}
/**
* @brief Writes a prepared data block into the ROM file.
* This is a utility for SaveSongs, formatting the data with a header
* containing the length and target SPC address.
* @param rom The ROM object.
* @param buf The data to write.
* @param len The length of the data.
* @param addr The ROM address to write to.
* @param spc The target SPC address for this data.
* @param limit The upper bound for writing in the ROM.
* @return The next available ROM address after writing.
*/
int Tracker::WriteSpcData(Rom &rom, void *buf, int len, int addr, int spc,
int limit) {
unsigned char *rom_data = rom.mutable_data();
@@ -797,6 +869,14 @@ int Tracker::WriteSpcData(Rom &rom, void *buf, int len, int addr, int spc,
return addr + len + 4;
}
/**
* @brief High-level function to save all modified song data back to the ROM.
* (Currently commented out, but this would orchestrate the entire save process.)
* This function would be responsible for taking all the edited, in-memory
* SongSpcBlocks, arranging them into a final binary layout, patching all the
* relocated pointers, and writing the result back into the ROM file using
* WriteSpcData.
*/
void Tracker::SaveSongs(Rom &rom) {
// int i;
// int j;
@@ -1245,6 +1325,12 @@ void Tracker::SaveSongs(Rom &rom) {
// free(ssblt);
}
/**
* @brief Opens an editor window for a specific track.
* (Legacy UI-related function)
* @param rom The ROM object.
* @param i The index of the first command of the track to edit.
*/
void Tracker::EditTrack(Rom &rom, short i) {
int j, k, l;
SongRange *sr = song_range_;
@@ -1295,6 +1381,12 @@ void Tracker::EditTrack(Rom &rom, short i) {
// CRITICAL_SECTION cs_song;
// =============================================================================
/**
* @brief Creates a new, empty song range (SongRange) and opens it for editing.
* (Legacy UI-related function)
* @param rom The ROM object.
* @param bank The target bank for the new song.
*/
void Tracker::NewSR(Rom &rom, int bank) {
SpcCommand *spc_command;
SongRange *sr;

View File

@@ -13,18 +13,21 @@ namespace zelda3 {
* @namespace yaze::zelda3::music
* @brief Contains classes and functions for handling music data in Zelda 3.
*
* Based off of the HyruleMagic tracker code.
* Based off of the Hyrule Magic tracker code, this system is designed to parse
* the game's complex, pointer-based music format into an editable in-memory
* representation and then serialize it back into a binary format that the
* SNES Audio Processing Unit (APU) can understand.
*/
namespace music {
// bank 19, 1A, 1B
// iirc 1A is OW, 1B is dungeon
// 19 is general spc stuff like samples, ects
// Length of each SPC700 command opcode (0xE0-0xFF). Used for parsing.
constexpr char op_len[32] = {1, 1, 2, 3, 0, 1, 2, 1, 2, 1, 1, 3, 0, 1, 2, 3,
1, 3, 3, 0, 1, 3, 0, 3, 3, 3, 1, 2, 0, 0, 0, 0};
// Default ROM offsets for specific sound banks.
static int sbank_ofs[] = {0xc8000, 0, 0xd8000, 0};
// Filter coefficients for BRR sample decoding.
constexpr char fil1[4] = {0, 15, 61, 115};
constexpr char fil2[4] = {0, 4, 5, 6};
constexpr char fil3[4] = {0, 0, 15, 13};
@@ -34,57 +37,83 @@ constexpr int kDungeonMusicBank = 0x0D8000;
using text_buf_ty = char[512];
/**
* @struct SongSpcBlock
* @brief Represents a block of binary data destined for the APU (SPC700) RAM.
* This is the intermediate format used before writing data back to the ROM.
*/
struct SongSpcBlock {
unsigned short start;
unsigned short len;
unsigned short relnum;
unsigned short relsz;
unsigned short *relocs;
unsigned short bank;
unsigned short addr;
unsigned char *buf;
int flag;
unsigned short start; // The starting address of this block in the virtual SPC memory space.
unsigned short len; // Length of the data buffer.
unsigned short relnum; // Number of relocation entries.
unsigned short relsz; // Allocated size of the relocation table.
unsigned short *relocs; // Table of offsets within 'buf' that are pointers and need to be relocated.
unsigned short bank; // The target sound bank.
unsigned short addr; // The final, relocated address of this block.
unsigned char *buf; // The raw binary data for this block.
int flag; // Flags for managing the block's state.
};
/**
* @struct SongRange
* @brief A metadata structure to keep track of parsed sections of the song data.
* Used to avoid re-parsing the same data from the ROM multiple times.
*/
struct SongRange {
unsigned short start;
unsigned short end;
unsigned short start; // Start address of this range in the ROM.
unsigned short end; // End address of this range in the ROM.
short first;
short inst;
short bank;
short first; // Index of the first SpcCommand in this range.
short inst; // Instance count, for tracking usage.
short bank; // The ROM bank this range was loaded from.
unsigned char endtime;
unsigned char endtime; // Default time/duration for this block.
unsigned char filler;
int editor;
int editor; // Window handle for an associated editor, if any.
};
/**
* @struct SongPart
* @brief Represents one of the 8 channels (tracks) in a song.
*/
struct SongPart {
uint8_t flag;
uint8_t inst;
short tbl[8];
unsigned short addr;
uint8_t flag; // State flags for parsing and saving.
uint8_t inst; // Instance count.
short tbl[8]; // Pointers to the first SpcCommand for each of the 8 channels.
unsigned short addr; // The address of this part's data in the ROM.
};
/**
* @struct Song
* @brief Represents a complete song, which is a collection of SongParts.
*/
struct Song {
unsigned char flag;
unsigned char inst;
SongPart **tbl;
short numparts;
short lopst;
unsigned short addr;
bool in_use; // true
unsigned char flag; // State flags.
unsigned char inst; // Instance count.
SongPart **tbl; // Table of pointers to the song's parts.
short numparts; // Number of parts in the song.
short lopst; // Loop start point.
unsigned short addr; // Address of the song's main data table in the ROM.
bool in_use; // Flag indicating if the song is currently loaded.
};
/**
* @struct ZeldaWave
* @brief Represents a decoded instrument sample (a waveform).
*/
struct ZeldaWave {
int lopst;
int end;
short lflag;
short copy;
short *buf;
int lopst; // Loop start point within the sample data.
int end; // End of the sample data.
short lflag; // Loop flag.
short copy; // Index of another wave this is a copy of, to save memory.
short *buf; // The buffer containing the decoded PCM sample data.
};
/**
* @struct SampleEdit
* @brief A state structure for a GUI sample editor.
*/
struct SampleEdit {
unsigned short flag;
unsigned short init;
@@ -108,15 +137,23 @@ struct SampleEdit {
ZeldaWave *zw;
};
/**
* @struct ZeldaInstrument
* @brief Defines an instrument for a song, mapping to a sample and ADSR settings.
*/
struct ZeldaInstrument {
unsigned char samp;
unsigned char ad;
unsigned char sr;
unsigned char gain;
unsigned char multhi;
unsigned char multlo;
unsigned char samp; // Index of the sample (ZeldaWave) to use.
unsigned char ad; // Attack & Decay rates.
unsigned char sr; // Sustain Rate.
unsigned char gain; // Sustain Level & Gain.
unsigned char multhi; // Pitch multiplier (high byte).
unsigned char multlo; // Pitch multiplier (low byte).
};
/**
* @struct ZeldaSfxInstrument
* @brief Defines an instrument for a sound effect.
*/
struct ZeldaSfxInstrument {
unsigned char voll;
unsigned char volr;
@@ -128,23 +165,29 @@ struct ZeldaSfxInstrument {
unsigned char multhi;
};
/**
* @struct SpcCommand
* @brief The core data structure representing a single command in a music track.
* A song track is a doubly-linked list of these commands.
*/
struct SpcCommand {
unsigned short addr;
short next;
short prev;
unsigned char flag;
unsigned char cmd;
unsigned char p1;
unsigned char p2;
unsigned char p3;
unsigned char b1;
unsigned char b2;
unsigned char tim2;
unsigned short tim;
unsigned short addr; // The ROM address this command was loaded from.
short next; // Index of the next command in the list.
short prev; // Index of the previous command in the list.
unsigned char flag; // Bitfield for command properties (e.g., has duration).
unsigned char cmd; // The actual command/opcode.
unsigned char p1; // Parameter 1.
unsigned char p2; // Parameter 2.
unsigned char p3; // Parameter 3.
unsigned char b1; // Note duration or first byte of a multi-byte duration.
unsigned char b2; // Second byte of a multi-byte duration.
unsigned char tim2; // Calculated time/duration component.
unsigned short tim; // Calculated time/duration component.
};
class Tracker {
public:
SongSpcBlock *AllocSpcBlock(int len, int bank);
unsigned char *GetSpcAddr(Rom &rom, unsigned short addr, short bank);