diff --git a/src/supportpsx/midi-converter.h b/src/supportpsx/midi-converter.h index e70adbf1..6777311a 100644 --- a/src/supportpsx/midi-converter.h +++ b/src/supportpsx/midi-converter.h @@ -59,6 +59,7 @@ enum MidiMeta : uint8_t { MIDI_META_COPYRIGHT = 0x02, MIDI_META_TRACK_NAME = 0x03, MIDI_META_MARKER = 0x06, + MIDI_META_CUE_POINT = 0x07, MIDI_META_END_OF_TRACK = 0x2F, MIDI_META_TEMPO = 0x51, }; @@ -302,8 +303,8 @@ inline void MidiFile::parseTrack(PCSX::IO track) { uint8_t b2 = track->byte(); ev.tempo = (b0 << 16) | (b1 << 8) | b2; events.push_back(ev); - } else if (metaType == MIDI_META_MARKER || metaType == MIDI_META_TEXT || metaType == MIDI_META_TRACK_NAME || - metaType == MIDI_META_COPYRIGHT) { + } else if (metaType == MIDI_META_MARKER || metaType == MIDI_META_CUE_POINT || metaType == MIDI_META_TEXT || + metaType == MIDI_META_TRACK_NAME || metaType == MIDI_META_COPYRIGHT) { // Text-based meta events MidiEvent ev = {}; ev.absoluteTick = absTick; diff --git a/tools/midi2psm/midi2psm.cc b/tools/midi2psm/midi2psm.cc index 90f9e7aa..3ddd2055 100644 --- a/tools/midi2psm/midi2psm.cc +++ b/tools/midi2psm/midi2psm.cc @@ -18,6 +18,7 @@ ***************************************************************************/ #include +#include #include #include #include @@ -55,6 +56,7 @@ using PCSX::MidiConverter::MIDI_CC_VOLUME; using PCSX::MidiConverter::MIDI_DRUM_CHANNEL; using PCSX::MidiConverter::MIDI_META; using PCSX::MidiConverter::MIDI_META_COPYRIGHT; +using PCSX::MidiConverter::MIDI_META_CUE_POINT; using PCSX::MidiConverter::MIDI_META_MARKER; using PCSX::MidiConverter::MIDI_META_TRACK_NAME; using PCSX::MidiConverter::MIDI_META_TEMPO; @@ -92,6 +94,7 @@ enum PsmEventType : uint8_t { PSM_TEMPO_CHANGE = 0x0A, PSM_LOOP_POINT = 0x0B, PSM_END = 0x0C, + PSM_USER = 0x0D, PSM_LONG_WAIT = 0xFF, }; @@ -498,6 +501,26 @@ void ConvertContext::generate() { continue; } + // A cue point whose text is "tag:payload" becomes a USER event for the program playing the song. + if (mev.type == MIDI_META && mev.data1 == MIDI_META_CUE_POINT) { + std::string_view text = mev.textData; + auto colon = text.find(':'); + unsigned tag = 0; + uint32_t payload = 0; + if (colon != std::string_view::npos) { + auto end = text.data() + colon; + auto [p1, e1] = std::from_chars(text.data(), end, tag); + auto [p2, e2] = std::from_chars(end + 1, text.data() + text.size(), payload); + if (e1 == std::errc() && p1 == end && e2 == std::errc() && p2 == text.data() + text.size() && + tag <= 255) { + emitEvent(PSM_USER, tag, payload, mev.absoluteTick); + continue; + } + } + fmt::print(stderr, "Ignoring cue point \"{}\" at tick {}: expected tag:payload\n", text, mev.absoluteTick); + continue; + } + if (mev.type == MIDI_META) continue; if (mev.type == MIDI_PROGRAM_CHANGE) {