6#include "absl/strings/str_format.h"
19 return absl::FailedPreconditionError(
"ROM is not loaded");
23 return absl::InvalidArgumentError(
"Invalid song address");
28 const uint8_t* song_data =
GetSpcData(rom, address, bank, &data_length);
30 return absl::NotFoundError(
31 absl::StrFormat(
"Song data not found at address $%04X bank %d",
42 std::vector<uint16_t> segment_addresses;
44 while (offset + 1 <
static_cast<size_t>(data_length)) {
45 uint16_t segment_ptr = song_data[offset] | (song_data[offset + 1] << 8);
48 if (segment_ptr < 256) {
49 if (segment_ptr > 0) {
52 if (offset + 3 <
static_cast<size_t>(data_length)) {
53 uint16_t loop_target = song_data[offset + 2] | (song_data[offset + 3] << 8);
55 for (
size_t i = 0; i < segment_addresses.size(); ++i) {
56 if (segment_addresses[i] == loop_target) {
66 segment_addresses.push_back(segment_ptr);
71 for (uint16_t seg_addr : segment_addresses) {
75 const uint8_t* seg_data =
GetSpcData(rom, seg_addr, bank,
nullptr);
78 song.
segments.push_back(std::move(segment));
83 for (
int ch = 0; ch < 8; ++ch) {
84 uint16_t track_addr = seg_data[ch * 2] | (seg_data[ch * 2 + 1] << 8);
86 if (track_addr == 0) {
87 segment.
tracks[ch].is_empty =
true;
91 auto track_result =
ParseTrack(rom, track_addr, bank);
92 if (track_result.ok()) {
93 segment.
tracks[ch] = std::move(*track_result);
96 segment.
tracks[ch].is_empty =
true;
100 song.
segments.push_back(std::move(segment));
107 Rom& rom, uint16_t table_address, uint8_t bank,
int max_entries) {
109 return absl::FailedPreconditionError(
"ROM is not loaded");
113 const uint8_t* table_data =
114 GetSpcData(rom, table_address, bank, &data_length);
116 return absl::NotFoundError(absl::StrFormat(
117 "Song pointer table not found at $%04X for bank %d", table_address,
121 if (data_length < 2) {
122 return absl::InvalidArgumentError(
123 "Song pointer table is too small to contain entries");
126 std::vector<uint16_t> pointers;
127 pointers.reserve(
static_cast<size_t>(max_entries));
133 int entries_read = 0;
134 for (
int offset = 0; offset + 1 < data_length && entries_read < max_entries;
136 uint16_t entry = table_data[offset] | (table_data[offset + 1] << 8);
137 pointers.push_back(entry);
145 uint8_t bank,
int max_ticks) {
160 return absl::FailedPreconditionError(
"ROM is not loaded");
172 return absl::InvalidArgumentError(
173 absl::StrFormat(
"Circular reference detected at $%04X", address));
179 return absl::ResourceExhaustedError(
"Maximum parse depth exceeded");
188 return absl::NotFoundError(
189 absl::StrFormat(
"Track data not found at $%04X", address));
196 uint16_t current_tick = 0;
197 uint8_t current_duration = 0;
198 uint8_t current_velocity = 0;
201 while (pos <
static_cast<size_t>(data_length) && current_tick < max_ticks) {
202 uint8_t
byte = track_data[pos];
212 current_duration = byte;
216 if (pos <
static_cast<size_t>(data_length)) {
217 uint8_t next = track_data[pos];
219 current_velocity = next;
230 event.tick = current_tick;
231 event.rom_offset = address +
static_cast<uint16_t
>(pos);
232 event.note.pitch = byte;
233 event.note.duration = current_duration;
234 event.note.velocity = current_velocity;
235 event.note.has_duration_prefix =
true;
237 track.
events.push_back(event);
241 current_tick += current_duration;
250 uint8_t opcode = byte;
255 event.tick = current_tick;
256 event.rom_offset = address +
static_cast<uint16_t
>(pos);
257 event.command.opcode = opcode;
262 for (
int i = 0; i < param_count && pos < static_cast<size_t>(data_length); ++i) {
263 event.command.params[i] = track_data[pos];
268 if (opcode == 0xEF) {
269 uint16_t sub_addr =
event.command.GetSubroutineAddress();
270 uint8_t repeat =
event.command.GetSubroutineRepeatCount();
274 max_ticks - current_tick);
275 if (sub_result.ok()) {
276 current_tick += *sub_result;
280 track.
events.push_back(event);
296 int remaining_ticks) {
297 if (repeat_count == 0)
return 0;
301 remaining_ticks / repeat_count);
302 if (!track_result.ok()) {
303 return track_result.status();
307 return static_cast<int>(track_result->duration_ticks) * repeat_count;
327 size_t rom_size = rom.
size();
328 uint32_t header_offset = (rom_size % 0x8000 == 0x200) ? 0x200 : 0;
330 uint32_t bank_offset = 0;
338 bank_offset = 0xC8000 + header_offset;
343 bank_offset = 0xD1EF5 + header_offset;
348 bank_offset = 0xD8000 + header_offset;
353 bank_offset = 0xD5380 + header_offset;
356 bank_offset = 0xC8000 + header_offset;
361 if (bank_offset >= rom_size) {
366 uint32_t rom_ptr = bank_offset;
367 const uint8_t* rom_data = rom.
data();
369 for (
int iterations = 0; iterations < 1000; ++iterations) {
370 if (rom_ptr + 4 >= rom_size)
break;
372 uint16_t block_size = rom_data[rom_ptr] | (rom_data[rom_ptr + 1] << 8);
373 uint16_t block_addr = rom_data[rom_ptr + 2] | (rom_data[rom_ptr + 3] << 8);
376 if (block_size == 0 || block_size > 0x10000)
break;
381 if (spc_address >= block_addr && spc_address < block_addr + block_size) {
382 return rom_ptr + (spc_address - block_addr);
385 rom_ptr += block_size;
397 uint8_t bank,
int* out_length) {
399 if (rom_offset == 0 || rom_offset >= rom.
size()) {
400 if (out_length) *out_length = 0;
407 *out_length = std::min(
static_cast<size_t>(0x1000),
408 rom.
size() - rom_offset);
411 return rom.
data() + rom_offset;
422 std::vector<int16_t> pcm;
424 if (brr_data.size() < 9) {
428 int prev1 = 0, prev2 = 0;
430 for (
size_t block = 0; block < brr_data.size(); block += 9) {
431 if (block + 9 > brr_data.size())
break;
433 uint8_t header = brr_data[block];
434 int range = (header >> 4) & 0x0F;
435 int filter = (header >> 2) & 0x03;
436 bool end = (header & 0x01) != 0;
437 bool loop = (header & 0x02) != 0;
439 for (
int i = 0; i < 8; ++i) {
440 uint8_t
byte = brr_data[block + 1 + i];
442 for (
int nibble = 0; nibble < 2; ++nibble) {
443 int sample = (nibble == 0) ? (
byte >> 4) : (
byte & 0x0F);
446 if (sample >= 8) sample -= 16;
458 sample -= (prev2 *
kFilter3[2]) >> 4;
462 sample -= (prev2 *
kFilter3[3]) >> 4;
467 if (sample > 0x7FFF) sample = 0x7FFF;
468 if (sample < -0x8000) sample = -0x8000;
470 pcm.push_back(
static_cast<int16_t
>(sample));
478 if (loop && loop_start) {
491 std::vector<uint8_t> brr;
494 std::vector<int16_t> padded = pcm_data;
495 while (padded.size() % 16 != 0) {
499 int prev1 = 0, prev2 = 0;
501 for (
size_t i = 0; i < padded.size(); i += 16) {
505 int best_error = INT_MAX;
507 for (
int range = 0; range < 13; ++range) {
508 for (
int filter = 0; filter < 4; ++filter) {
510 int p1 = prev1, p2 = prev2;
512 for (
int j = 0; j < 16; ++j) {
513 int sample = padded[i + j];
523 predicted -= (p2 *
kFilter3[2]) >> 4;
527 predicted -= (p2 *
kFilter3[3]) >> 4;
531 int diff = sample - predicted;
532 int encoded = (diff >> range);
535 if (encoded > 7) encoded = 7;
536 if (encoded < -8) encoded = -8;
539 int reconstructed = (encoded << range) + predicted;
540 error += (sample - reconstructed) * (sample - reconstructed);
546 if (error < best_error) {
549 best_filter = filter;
555 uint8_t header = (best_range << 4) | (best_filter << 2);
556 if (i + 16 >= padded.size()) {
558 if (loop_start >= 0) {
563 brr.push_back(header);
565 for (
int j = 0; j < 8; ++j) {
566 int s1 = padded[i + j * 2];
567 int s2 = padded[i + j * 2 + 1];
570 int predicted1 = 0, predicted2 = 0;
571 switch (best_filter) {
577 predicted1 -= (prev2 *
kFilter3[2]) >> 4;
581 predicted1 -= (prev2 *
kFilter3[3]) >> 4;
585 int enc1 = ((s1 - predicted1) >> best_range);
586 if (enc1 > 7) enc1 = 7;
587 if (enc1 < -8) enc1 = -8;
590 int reconstructed1 = (((enc1 >= 8) ? enc1 - 16 : enc1) << best_range) + predicted1;
592 prev1 = reconstructed1;
594 switch (best_filter) {
600 predicted2 -= (prev2 *
kFilter3[2]) >> 4;
604 predicted2 -= (prev2 *
kFilter3[3]) >> 4;
608 int enc2 = ((s2 - predicted2) >> best_range);
609 if (enc2 > 7) enc2 = 7;
610 if (enc2 < -8) enc2 = -8;
613 int reconstructed2 = (((enc2 >= 8) ? enc2 - 16 : enc2) << best_range) + predicted2;
615 prev1 = reconstructed2;
617 brr.push_back((enc1 << 4) | enc2);
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
static constexpr int kFilter2[4]
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]
static constexpr int kFilter1[4]
static bool IsDuration(uint8_t byte)
Check if a byte is a duration value (< 128).
static bool IsCommand(uint8_t byte)
Check if a byte is a command opcode.
static absl::StatusOr< MusicSong > ParseSong(Rom &rom, uint16_t address, uint8_t bank)
Parse a complete song from ROM.
static bool IsNotePitch(uint8_t byte)
Check if a byte is a note pitch.
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.
static uint32_t SpcAddressToRomOffset(Rom &rom, uint16_t spc_address, uint8_t bank)
Convert an SPC address to a ROM offset.
constexpr uint8_t kTrackEnd
constexpr uint8_t kNoteTie
constexpr uint32_t kSoundBankOffsets[]
A segment containing 8 parallel tracks.
std::array< MusicTrack, 8 > tracks
A complete song composed of segments.
std::vector< MusicSegment > segments
One of 8 channels in a music segment.
std::vector< TrackEvent > events
Context for parsing operations.
std::vector< uint16_t > visited_addresses
A single event in a music track (note, command, or control).
static TrackEvent MakeEnd(uint16_t tick)