yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
spc_parser.h
Go to the documentation of this file.
1#ifndef YAZE_ZELDA3_MUSIC_SPC_PARSER_H
2#define YAZE_ZELDA3_MUSIC_SPC_PARSER_H
3
4#include <cstdint>
5#include <vector>
6
7#include "absl/status/statusor.h"
8#include "rom/rom.h"
10
11namespace yaze {
12namespace zelda3 {
13namespace music {
14
15// ROM offsets for sound bank block headers (from usdasm disassembly)
16// Each bank has a block header: [size:2][aram_addr:2][data:size]
17//
18// Banks 0, 1, 3 are contiguous starting at $19:8000 (PC 0xC8000)
19// Bank 2 (dungeon) is separate at $1B:8000 (PC 0xD8000)
20//
21// Song table blocks (loading to ARAM $D000):
22// - Overworld: $1A:9EF5 (PC 0xD1EF5)
23// - Dungeon: $1B:8000 (PC 0xD8000)
24// - Credits: $1A:D380 (PC 0xD5380)
25constexpr uint32_t kSoundBankOffsets[] = {
26 0xC8000, // Bank 0 (common) - start of contiguous region
27 0xD1EF5, // Bank 1 (overworld) - song table block
28 0xD8000, // Bank 2 (dungeon) - separate region
29 0xD5380 // Bank 3 (credits) - song table block
30};
31
43class SpcParser {
44 public:
48 struct ParseContext {
49 Rom* rom = nullptr;
50 uint8_t current_bank = 0;
51 uint32_t bank_offset = 0;
52
53 // Parsing state
54 std::vector<uint16_t> visited_addresses; // Prevent infinite loops
55 int max_parse_depth = 100;
57 };
58
59 // =========================================================================
60 // Song Parsing
61 // =========================================================================
62
70 static absl::StatusOr<MusicSong> ParseSong(Rom& rom, uint16_t address,
71 uint8_t bank);
72
81 static absl::StatusOr<std::vector<uint16_t>> ReadSongPointerTable(
82 Rom& rom, uint16_t table_address, uint8_t bank, int max_entries = 40);
83
92 static absl::StatusOr<MusicTrack> ParseTrack(Rom& rom, uint16_t address,
93 uint8_t bank,
94 int max_ticks = 50000);
95
96 // =========================================================================
97 // Address Resolution
98 // =========================================================================
99
107 static uint32_t SpcAddressToRomOffset(Rom& rom, uint16_t spc_address,
108 uint8_t bank);
109
118 static const uint8_t* GetSpcData(Rom& rom, uint16_t spc_address,
119 uint8_t bank, int* out_length = nullptr);
120
121 // =========================================================================
122 // Command Utilities
123 // =========================================================================
124
130 static int GetCommandParamCount(uint8_t opcode) {
131 if (opcode < 0xE0) return 0;
132 return kCommandParamCount[opcode - 0xE0];
133 }
134
138 static bool IsNotePitch(uint8_t byte) {
139 return byte >= kNoteMinPitch && byte <= kNoteRest;
140 }
141
145 static bool IsDuration(uint8_t byte) {
146 return byte < 0x80;
147 }
148
152 static bool IsCommand(uint8_t byte) {
153 return byte >= 0xE0;
154 }
155
156 private:
157 // Internal parsing with context
158 static absl::StatusOr<MusicTrack> ParseTrackInternal(ParseContext& ctx,
159 uint16_t address,
160 int max_ticks);
161
162 // Parse subroutine call
163 static absl::StatusOr<int> ParseSubroutine(ParseContext& ctx,
164 uint16_t address,
165 int repeat_count,
166 int remaining_ticks);
167};
168
176 public:
181 std::vector<uint8_t> data;
182 std::vector<uint16_t> relocations; // Offsets that need address fixup
183 uint16_t base_address = 0;
184 };
185
186 // =========================================================================
187 // Song Serialization
188 // =========================================================================
189
196 static absl::StatusOr<SerializeResult> SerializeSong(const MusicSong& song,
197 uint16_t base_address);
198
204 static std::vector<uint8_t> SerializeTrack(const MusicTrack& track);
205
211 static int CalculateRequiredSpace(const MusicSong& song);
212
213 // =========================================================================
214 // Event Serialization
215 // =========================================================================
216
223 static std::vector<uint8_t> SerializeNote(const Note& note,
224 uint8_t* current_duration);
225
231 static std::vector<uint8_t> SerializeCommand(const MusicCommand& command);
232
238 static void ApplyBaseAddress(SerializeResult* result,
239 uint16_t new_base_address);
240};
241
247class BrrCodec {
248 public:
255 static std::vector<int16_t> Decode(const std::vector<uint8_t>& brr_data,
256 int* loop_start = nullptr);
257
264 static std::vector<uint8_t> Encode(const std::vector<int16_t>& pcm_data,
265 int loop_start = -1);
266
267 private:
268 // Filter coefficients for BRR decoding
269 static constexpr int kFilter1[4] = {0, 15, 61, 115};
270 static constexpr int kFilter2[4] = {0, 4, 5, 6};
271 static constexpr int kFilter3[4] = {0, 0, 15, 13};
272};
273
274} // namespace music
275} // namespace zelda3
276} // namespace yaze
277
278#endif // YAZE_ZELDA3_MUSIC_SPC_PARSER_H
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:24
BRR sample encoder/decoder.
Definition spc_parser.h:247
static constexpr int kFilter2[4]
Definition spc_parser.h:270
static std::vector< int16_t > Decode(const std::vector< uint8_t > &brr_data, int *loop_start=nullptr)
Decode BRR data to PCM samples.
static std::vector< uint8_t > Encode(const std::vector< int16_t > &pcm_data, int loop_start=-1)
Encode PCM samples to BRR format.
static constexpr int kFilter3[4]
Definition spc_parser.h:271
static constexpr int kFilter1[4]
Definition spc_parser.h:269
Parser for N-SPC music data from ROM.
Definition spc_parser.h:43
static bool IsDuration(uint8_t byte)
Check if a byte is a duration value (< 128).
Definition spc_parser.h:145
static bool IsCommand(uint8_t byte)
Check if a byte is a command opcode.
Definition spc_parser.h:152
static absl::StatusOr< MusicSong > ParseSong(Rom &rom, uint16_t address, uint8_t bank)
Parse a complete song from ROM.
Definition spc_parser.cc:16
static bool IsNotePitch(uint8_t byte)
Check if a byte is a note pitch.
Definition spc_parser.h:138
static absl::StatusOr< std::vector< uint16_t > > ReadSongPointerTable(Rom &rom, uint16_t table_address, uint8_t bank, int max_entries=40)
Read the song pointer table for a given SPC bank.
static const uint8_t * GetSpcData(Rom &rom, uint16_t spc_address, uint8_t bank, int *out_length=nullptr)
Get a pointer to ROM data at an SPC address.
static absl::StatusOr< MusicTrack > ParseTrackInternal(ParseContext &ctx, uint16_t address, int max_ticks)
static absl::StatusOr< int > ParseSubroutine(ParseContext &ctx, uint16_t address, int repeat_count, int remaining_ticks)
static absl::StatusOr< MusicTrack > ParseTrack(Rom &rom, uint16_t address, uint8_t bank, int max_ticks=50000)
Parse a single track from ROM.
static int GetCommandParamCount(uint8_t opcode)
Get the parameter count for an N-SPC command.
Definition spc_parser.h:130
static uint32_t SpcAddressToRomOffset(Rom &rom, uint16_t spc_address, uint8_t bank)
Convert an SPC address to a ROM offset.
Serializer for N-SPC music data to ROM format.
Definition spc_parser.h:175
static int CalculateRequiredSpace(const MusicSong &song)
Calculate the space required for a song.
static std::vector< uint8_t > SerializeNote(const Note &note, uint8_t *current_duration)
Serialize a note event.
static std::vector< uint8_t > SerializeCommand(const MusicCommand &command)
Serialize a command event.
static absl::StatusOr< SerializeResult > SerializeSong(const MusicSong &song, uint16_t base_address)
Serialize a complete song to binary format.
static void ApplyBaseAddress(SerializeResult *result, uint16_t new_base_address)
Adjust all serialized pointers to a new base address.
static std::vector< uint8_t > SerializeTrack(const MusicTrack &track)
Serialize a single track to binary format.
constexpr uint8_t kNoteRest
Definition song_data.h:58
constexpr uint8_t kNoteMinPitch
Definition song_data.h:55
constexpr int kCommandParamCount[32]
Definition song_data.h:19
constexpr uint32_t kSoundBankOffsets[]
Definition spc_parser.h:25
Represents an N-SPC command (opcodes 0xE0-0xFF).
Definition song_data.h:222
A complete song composed of segments.
Definition song_data.h:334
One of 8 channels in a music segment.
Definition song_data.h:291
Represents a single musical note.
Definition song_data.h:192
Context for parsing operations.
Definition spc_parser.h:48
std::vector< uint16_t > visited_addresses
Definition spc_parser.h:54
Result of serialization with relocation info.
Definition spc_parser.h:180