10 const MusicSong& song, uint16_t base_address) {
15 return absl::InvalidArgumentError(
"Song has no segments");
18 const size_t segment_count = song.
segments.size();
19 const uint16_t header_size =
20 static_cast<uint16_t
>(segment_count * 2 + 2 + (song.
HasLoop() ? 2 : 0));
21 const uint16_t segment_table_base = header_size;
22 const uint16_t track_data_base =
23 static_cast<uint16_t
>(segment_table_base + segment_count * 16);
27 std::vector<uint8_t> data;
30 std::vector<std::array<uint16_t, 8>> segment_track_ptrs(segment_count);
31 std::vector<TrackBlob> track_blobs;
32 track_blobs.reserve(segment_count * 2);
34 uint32_t next_track_offset = track_data_base;
36 for (
size_t seg_index = 0; seg_index < segment_count; ++seg_index) {
37 const auto& segment = song.
segments[seg_index];
38 auto& ptrs = segment_track_ptrs[seg_index];
41 for (
int ch = 0; ch < 8; ++ch) {
42 const auto& track = segment.tracks[ch];
43 if (track.is_empty || track.events.empty()) {
49 if (track_bytes.empty()) {
54 if (next_track_offset + track_bytes.size() > 0x10000) {
55 return absl::ResourceExhaustedError(
56 "Serialized track exceeds SPC address space");
59 ptrs[ch] =
static_cast<uint16_t
>(next_track_offset);
62 blob.offset = ptrs[ch];
63 blob.data = std::move(track_bytes);
64 track_blobs.push_back(std::move(blob));
66 next_track_offset +=
static_cast<uint32_t
>(track_blobs.back().data.size());
70 const uint32_t track_data_size = next_track_offset - track_data_base;
71 const uint32_t total_size =
72 header_size + segment_count * 16 + track_data_size;
73 result.
data.reserve(total_size);
75 auto write_pointer = [&](uint16_t value,
bool record) {
76 result.
data.push_back(value & 0xFF);
77 result.
data.push_back((value >> 8) & 0xFF);
78 if (record && value != 0) {
80 static_cast<uint16_t
>(result.
data.size() - 2));
85 uint16_t segment_offset = segment_table_base + base_address;
86 for (
size_t i = 0; i < segment_count; ++i) {
87 write_pointer(segment_offset,
true);
88 segment_offset =
static_cast<uint16_t
>(segment_offset + 16);
93 result.
data.push_back(0xFF);
94 result.
data.push_back(0x00);
95 uint16_t loop_target =
96 static_cast<uint16_t
>(segment_table_base + base_address +
98 write_pointer(loop_target,
true);
100 result.
data.push_back(0x00);
101 result.
data.push_back(0x00);
105 for (
const auto& ptrs : segment_track_ptrs) {
106 for (
int ch = 0; ch < 8; ++ch) {
107 uint16_t pointer_value =
109 :
static_cast<uint16_t
>(ptrs[ch] + base_address);
110 write_pointer(pointer_value, ptrs[ch] != 0);
115 for (
const auto& blob : track_blobs) {
116 result.
data.insert(result.
data.end(), blob.data.begin(), blob.data.end());
160 std::vector<uint8_t> data;
161 uint8_t current_duration = 0;
163 for (
const auto& event : track.
events) {
164 switch (event.type) {
166 auto note_bytes =
SerializeNote(event.note, ¤t_duration);
167 data.insert(data.end(), note_bytes.begin(), note_bytes.end());
173 data.insert(data.end(), cmd_bytes.begin(), cmd_bytes.end());
187 if (data.empty() || data.back() !=
kTrackEnd) {