| 137 | } |
| 138 | |
| 139 | LIBREMIDI_INLINE |
| 140 | void writer::write(std::ostream& out) const |
| 141 | { |
| 142 | // MIDI File Header |
| 143 | out.write("MThd", 4); |
| 144 | util::write_be<uint32_t>(out, 6); |
| 145 | util::write_be<uint16_t>(out, (tracks.size() == 1) ? 0 : 1); |
| 146 | util::write_be<uint16_t>(out, static_cast<uint16_t>(tracks.size())); |
| 147 | util::write_be<uint16_t>(out, ticksPerQuarterNote); |
| 148 | |
| 149 | std::vector<uint8_t> track_raw_data; |
| 150 | for (const auto& event_list : tracks) |
| 151 | { |
| 152 | track_raw_data.clear(); |
| 153 | // Rough estimation of the memory to allocate |
| 154 | track_raw_data.reserve(event_list.size() * 3); |
| 155 | |
| 156 | for (const auto& event : event_list) |
| 157 | { |
| 158 | const auto& msg = event.m; |
| 159 | if (msg.empty()) |
| 160 | continue; |
| 161 | |
| 162 | // Suppress end-of-track meta messages (one will be added |
| 163 | // automatically after all track data has been written). |
| 164 | if (msg.get_meta_event_type() == meta_event_type::END_OF_TRACK) |
| 165 | continue; |
| 166 | |
| 167 | util::write_variable_length(static_cast<uint32_t>(event.tick), track_raw_data); |
| 168 | |
| 169 | if ((msg.get_message_type() == message_type::SYSTEM_EXCLUSIVE) |
| 170 | || (event.m.get_message_type() == message_type::EOX)) |
| 171 | { |
| 172 | // 0xf0 == Complete sysex message (0xf0 is part of the raw MIDI). |
| 173 | // 0xf7 == Raw byte message (0xf7 not part of the raw MIDI). |
| 174 | // Print the first byte of the message (0xf0 or 0xf7), then |
| 175 | // print a VLV length for the rest of the bytes in the message. |
| 176 | // In other words, when creating a 0xf0 or 0xf7 MIDI message, |
| 177 | // do not insert the VLV byte length yourself, as this code will |
| 178 | // do it for you automatically. |
| 179 | track_raw_data.emplace_back(msg.bytes[0]); // 0xf0 or 0xf7; |
| 180 | |
| 181 | util::write_variable_length(static_cast<uint32_t>(msg.size()) - 1, track_raw_data); |
| 182 | |
| 183 | track_raw_data.insert( |
| 184 | track_raw_data.end(), msg.bytes.data() + 1, msg.bytes.data() + msg.bytes.size()); |
| 185 | } |
| 186 | else |
| 187 | { |
| 188 | // Non-sysex type of message, so just output the bytes of the message: |
| 189 | track_raw_data.insert( |
| 190 | track_raw_data.end(), msg.bytes.data(), msg.bytes.data() + msg.bytes.size()); |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | auto size = track_raw_data.size(); |
| 195 | const auto eot = meta_events::end_of_track(); |
| 196 |
no test coverage detected