diff options
-rw-r--r-- | include/adlmidi.h | 18 | ||||
-rw-r--r-- | src/adlmidi.cpp | 19 | ||||
-rw-r--r-- | src/midi_sequencer.hpp | 22 | ||||
-rw-r--r-- | src/midi_sequencer_impl.hpp | 36 |
4 files changed, 90 insertions, 5 deletions
diff --git a/include/adlmidi.h b/include/adlmidi.h index f19bca0..77fbe74 100644 --- a/include/adlmidi.h +++ b/include/adlmidi.h @@ -664,6 +664,24 @@ enum ADLMIDI_TrackOptions */ extern int adl_setTrackOptions(struct ADL_MIDIPlayer *device, size_t trackNumber, unsigned trackOptions); +/** + * @brief Handler of callback trigger events + * @param userData Pointer to user data (usually, context of something) + * @param trigger Value of the event which triggered this callback. + * @param track Identifier of the track which triggered this callback. + */ +typedef void (*ADL_TriggerHandler)(void *userData, unsigned trigger, size_t track); + +/** + * @brief Defines a handler for callback trigger events + * @param device Instance of the library + * @param handler Handler to invoke from the sequencer when triggered, or NULL. + * @param userData Instance of the library + * @return 0 on success, <0 when any error has occurred + */ +extern int adl_setTriggerHandler(struct ADL_MIDIPlayer *device, ADL_TriggerHandler handler, void *userData); + + /* ======== Meta-Tags ======== */ diff --git a/src/adlmidi.cpp b/src/adlmidi.cpp index 37e0c21..d839399 100644 --- a/src/adlmidi.cpp +++ b/src/adlmidi.cpp @@ -1413,6 +1413,25 @@ ADLMIDI_EXPORT int adl_setTrackOptions(struct ADL_MIDIPlayer *device, size_t tra #endif } +ADLMIDI_EXPORT int adl_setTriggerHandler(struct ADL_MIDIPlayer *device, ADL_TriggerHandler handler, void *userData) +{ +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER + if(!device) + return -1; + MidiPlayer *play = GET_MIDI_PLAYER(device); + if(!play) + return -1; + MidiSequencer &seq = play->m_sequencer; + seq.setTriggerHandler(handler, userData); + return 0; +#else + ADL_UNUSED(device); + ADL_UNUSED(handler); + ADL_UNUSED(userData); + return -1; +#endif +} + ADLMIDI_EXPORT void adl_panic(struct ADL_MIDIPlayer *device) { if(!device) diff --git a/src/midi_sequencer.hpp b/src/midi_sequencer.hpp index 8cb8c6e..2c75da4 100644 --- a/src/midi_sequencer.hpp +++ b/src/midi_sequencer.hpp @@ -131,6 +131,8 @@ class BW_MidiSequencer ST_LOOPSTACK_END = 0xE5,//size == 0 <CUSTOM> //! [Non-Standard] Loop End point with support of multi-loops ST_LOOPSTACK_BREAK = 0xE6,//size == 0 <CUSTOM> + //! [Non-Standard] Callback Trigger + ST_CALLBACK_TRIGGER = 0xE7,//size == 1 <CUSTOM> }; //! Main type of event uint8_t type; @@ -453,6 +455,19 @@ private: //! Index of solo track, or max for disabled size_t m_trackSolo; + /** + * @brief Handler of callback trigger events + * @param userData Pointer to user data (usually, context of something) + * @param trigger Value of the event which triggered this callback. + * @param track Identifier of the track which triggered this callback. + */ + typedef void (*TriggerHandler)(void *userData, unsigned trigger, size_t track); + + //! Handler of callback trigger events + TriggerHandler m_triggerHandler; + //! User data of callback trigger events + void *m_triggerUserData; + //! File parsing errors string (adding into m_errorString on aborting of the process) std::string m_parsingErrorsString; //! Common error string @@ -495,6 +510,13 @@ public: void setSoloTrack(size_t track); /** + * @brief Defines a handler for callback trigger events + * @param handler Handler to invoke from the sequencer when triggered, or NULL. + * @param userData Instance of the library + */ + void setTriggerHandler(TriggerHandler handler, void *userData); + + /** * @brief Get the list of CMF instruments (CMF only) * @return Array of raw CMF instruments entries */ diff --git a/src/midi_sequencer_impl.hpp b/src/midi_sequencer_impl.hpp index 2749e26..bd0a226 100644 --- a/src/midi_sequencer_impl.hpp +++ b/src/midi_sequencer_impl.hpp @@ -277,7 +277,9 @@ BW_MidiSequencer::BW_MidiSequencer() : m_loopEndTime(-1.0), m_tempoMultiplier(1.0), m_atEnd(false), - m_trackSolo(~(size_t)0) + m_trackSolo(~(size_t)0), + m_triggerHandler(NULL), + m_triggerUserData(NULL) { m_loop.reset(); m_loop.invalidLoop = false; @@ -335,6 +337,12 @@ void BW_MidiSequencer::setSoloTrack(size_t track) m_trackSolo = track; } +void BW_MidiSequencer::setTriggerHandler(TriggerHandler handler, void *userData) +{ + m_triggerHandler = handler; + m_triggerUserData = userData; +} + const std::vector<BW_MidiSequencer::CmfInstrument> BW_MidiSequencer::getRawCmfInstruments() { return m_cmfInstruments; @@ -1345,8 +1353,9 @@ BW_MidiSequencer::MidiEvent BW_MidiSequencer::parseEvent(const uint8_t **pptr, c if(m_format == Format_XMIDI) { - if(evt.data[0] == 116) + switch(evt.data[0]) { + case 116: // For Loop Controller evt.type = MidiEvent::T_SPECIAL; evt.subtype = MidiEvent::ST_LOOPSTACK_BEGIN; evt.data[0] = evt.data[1]; @@ -1362,10 +1371,9 @@ BW_MidiSequencer::MidiEvent BW_MidiSequencer::parseEvent(const uint8_t **pptr, c evt.data[0] ); } - } + break; - if(evt.data[0] == 117) - { + case 117: // Next/Break Loop Controller evt.type = MidiEvent::T_SPECIAL; evt.subtype = evt.data[1] < 64 ? MidiEvent::ST_LOOPSTACK_BREAK : @@ -1382,6 +1390,13 @@ BW_MidiSequencer::MidiEvent BW_MidiSequencer::parseEvent(const uint8_t **pptr, c m_loop.stackLevel - 1 ); } + break; + + case 119: // Callback Trigger + evt.type = MidiEvent::T_SPECIAL; + evt.subtype = MidiEvent::ST_CALLBACK_TRIGGER; + evt.data.assign(1, evt.data[1]); + break; } } } @@ -1518,6 +1533,17 @@ void BW_MidiSequencer::handleEvent(size_t track, const BW_MidiSequencer::MidiEve } } + if(evtype == MidiEvent::ST_CALLBACK_TRIGGER) + { +#if 0 /* Print all callback triggers events */ + if(m_interface->onDebugMessage) + m_interface->onDebugMessage(m_interface->onDebugMessage_userData, "Callback Trigger: %02X", evt.data[0]); +#endif + if(m_triggerHandler) + m_triggerHandler(m_triggerUserData, data[0], track); + return; + } + if(evtype == MidiEvent::ST_RAWOPL) // Special non-spec ADLMIDI special for IMF playback: Direct poke to AdLib { if(m_interface->rt_rawOPL) |