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(absl::StrFormat(
31 "Song data not found at address $%04X bank %d", address, bank));
41 std::vector<uint16_t> segment_addresses;
43 while (offset + 1 <
static_cast<size_t>(data_length)) {
44 uint16_t segment_ptr = song_data[offset] | (song_data[offset + 1] << 8);
47 if (segment_ptr < 256) {
48 if (segment_ptr > 0) {
51 if (offset + 3 <
static_cast<size_t>(data_length)) {
52 uint16_t loop_target =
53 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(
117 absl::StrFormat(
"Song pointer table not found at $%04X for bank %d",
118 table_address, bank));
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");
184 const uint8_t* track_data =
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);
264 event.command.params[i] = track_data[pos];
269 if (opcode == 0xEF) {
270 uint16_t sub_addr =
event.command.GetSubroutineAddress();
271 uint8_t repeat =
event.command.GetSubroutineRepeatCount();
276 if (sub_result.ok()) {
277 current_tick += *sub_result;
281 track.
events.push_back(event);
297 int remaining_ticks) {
298 if (repeat_count == 0)
304 if (!track_result.ok()) {
305 return track_result.status();
309 return static_cast<int>(track_result->duration_ticks) * repeat_count;
329 size_t rom_size = rom.
size();
330 uint32_t header_offset = (rom_size % 0x8000 == 0x200) ? 0x200 : 0;
332 uint32_t bank_offset = 0;
340 bank_offset = 0xC8000 + header_offset;
345 bank_offset = 0xD1EF5 + header_offset;
350 bank_offset = 0xD8000 + header_offset;
355 bank_offset = 0xD5380 + header_offset;
358 bank_offset = 0xC8000 + header_offset;
363 if (bank_offset >= rom_size) {
368 uint32_t rom_ptr = bank_offset;
369 const uint8_t* rom_data = rom.
data();
371 for (
int iterations = 0; iterations < 1000; ++iterations) {
372 if (rom_ptr + 4 >= rom_size)
375 uint16_t block_size = rom_data[rom_ptr] | (rom_data[rom_ptr + 1] << 8);
376 uint16_t block_addr = rom_data[rom_ptr + 2] | (rom_data[rom_ptr + 3] << 8);
379 if (block_size == 0 || block_size > 0x10000)
385 if (spc_address >= block_addr && spc_address < block_addr + block_size) {
386 return rom_ptr + (spc_address - block_addr);
389 rom_ptr += block_size;
401 uint8_t bank,
int* out_length) {
403 if (rom_offset == 0 || rom_offset >= rom.
size()) {
412 const auto remaining =
413 static_cast<size_t>(rom.
size()) -
static_cast<size_t>(rom_offset);
414 *out_length =
static_cast<int>(
415 (std::min)(
static_cast<size_t>(0x1000), remaining));
418 return rom.
data() + rom_offset;
427 std::vector<int16_t> pcm;
429 if (brr_data.size() < 9) {
433 int prev1 = 0, prev2 = 0;
435 for (
size_t block = 0; block < brr_data.size(); block += 9) {
436 if (block + 9 > brr_data.size())
439 uint8_t header = brr_data[block];
440 int range = (header >> 4) & 0x0F;
441 int filter = (header >> 2) & 0x03;
442 bool end = (header & 0x01) != 0;
443 bool loop = (header & 0x02) != 0;
445 for (
int i = 0; i < 8; ++i) {
446 uint8_t
byte = brr_data[block + 1 + i];
448 for (
int nibble = 0; nibble < 2; ++nibble) {
449 int sample = (nibble == 0) ? (
byte >> 4) : (
byte & 0x0F);
465 sample -= (prev2 *
kFilter3[2]) >> 4;
469 sample -= (prev2 *
kFilter3[3]) >> 4;
476 if (sample < -0x8000)
479 pcm.push_back(
static_cast<int16_t
>(sample));
487 if (loop && loop_start) {
500 std::vector<uint8_t> brr;
503 std::vector<int16_t> padded = pcm_data;
504 while (padded.size() % 16 != 0) {
508 int prev1 = 0, prev2 = 0;
510 for (
size_t i = 0; i < padded.size(); i += 16) {
514 int best_error = INT_MAX;
516 for (
int range = 0; range < 13; ++range) {
517 for (
int filter = 0; filter < 4; ++filter) {
519 int p1 = prev1, p2 = prev2;
521 for (
int j = 0; j < 16; ++j) {
522 int sample = padded[i + j];
532 predicted -= (p2 *
kFilter3[2]) >> 4;
536 predicted -= (p2 *
kFilter3[3]) >> 4;
540 int diff = sample - predicted;
541 int encoded = (diff >> range);
550 int reconstructed = (encoded << range) + predicted;
551 error += (sample - reconstructed) * (sample - reconstructed);
557 if (error < best_error) {
560 best_filter = filter;
566 uint8_t header = (best_range << 4) | (best_filter << 2);
567 if (i + 16 >= padded.size()) {
569 if (loop_start >= 0) {
574 brr.push_back(header);
576 for (
int j = 0; j < 8; ++j) {
577 int s1 = padded[i + j * 2];
578 int s2 = padded[i + j * 2 + 1];
581 int predicted1 = 0, predicted2 = 0;
582 switch (best_filter) {
588 predicted1 -= (prev2 *
kFilter3[2]) >> 4;
592 predicted1 -= (prev2 *
kFilter3[3]) >> 4;
596 int enc1 = ((s1 - predicted1) >> best_range);
604 (((enc1 >= 8) ? enc1 - 16 : enc1) << best_range) + predicted1;
606 prev1 = reconstructed1;
608 switch (best_filter) {
614 predicted2 -= (prev2 *
kFilter3[2]) >> 4;
618 predicted2 -= (prev2 *
kFilter3[3]) >> 4;
622 int enc2 = ((s2 - predicted2) >> best_range);
630 (((enc2 >= 8) ? enc2 - 16 : enc2) << best_range) + predicted2;
632 prev1 = reconstructed2;
634 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)