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));
67 static_cast<uint32_t
>(track_blobs.back().data.size());
71 const uint32_t track_data_size = next_track_offset - track_data_base;
72 const uint32_t total_size =
73 header_size + segment_count * 16 + track_data_size;
74 result.
data.reserve(total_size);
76 auto write_pointer = [&](uint16_t value,
bool record) {
77 result.
data.push_back(value & 0xFF);
78 result.
data.push_back((value >> 8) & 0xFF);
79 if (record && value != 0) {
81 static_cast<uint16_t
>(result.
data.size() - 2));
86 uint16_t segment_offset = segment_table_base + base_address;
87 for (
size_t i = 0; i < segment_count; ++i) {
88 write_pointer(segment_offset,
true);
89 segment_offset =
static_cast<uint16_t
>(segment_offset + 16);
94 result.
data.push_back(0xFF);
95 result.
data.push_back(0x00);
96 uint16_t loop_target =
static_cast<uint16_t
>(
97 segment_table_base + base_address + song.
loop_point * 16);
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 =
108 (ptrs[ch] == 0) ? 0 :
static_cast<uint16_t
>(ptrs[ch] + base_address);
109 write_pointer(pointer_value, ptrs[ch] != 0);
114 for (
const auto& blob : track_blobs) {
115 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) {