diff options
-rw-r--r-- | src/midi_sequencer.hpp | 13 | ||||
-rw-r--r-- | src/midi_sequencer_impl.hpp | 92 |
2 files changed, 100 insertions, 5 deletions
diff --git a/src/midi_sequencer.hpp b/src/midi_sequencer.hpp index a8cbfac..54ceeea 100644 --- a/src/midi_sequencer.hpp +++ b/src/midi_sequencer.hpp @@ -315,11 +315,24 @@ public: Format_XMIDI }; + /** + * @brief Format of loop points implemented by CC events + */ + enum LoopFormat + { + Loop_Default, + Loop_RPGMaker = 1, + Loop_EMIDI, + Loop_HMI + }; + private: //! Music file format type. MIDI is default. FileFormat m_format; //! SMF format identifier. unsigned m_smfFormat; + //! Loop points format + LoopFormat m_loopFormat; //! Current position Position m_currentPosition; diff --git a/src/midi_sequencer_impl.hpp b/src/midi_sequencer_impl.hpp index 59da621..6d6b2d8 100644 --- a/src/midi_sequencer_impl.hpp +++ b/src/midi_sequencer_impl.hpp @@ -270,6 +270,7 @@ BW_MidiSequencer::BW_MidiSequencer() : m_interface(NULL), m_format(Format_MIDI), m_smfFormat(0), + m_loopFormat(Loop_Default), m_loopEnabled(false), m_fullSongTimeLength(0.0), m_postSongWaitDelay(1.0), @@ -399,6 +400,7 @@ void BW_MidiSequencer::buildSmfSetupReset(size_t trackCount) m_fullSongTimeLength = 0.0; m_loopStartTime = -1.0; m_loopEndTime = -1.0; + m_loopFormat = Loop_Default; m_trackDisable.clear(); m_trackSolo = ~(size_t)0; m_musTitle.clear(); @@ -1374,12 +1376,92 @@ BW_MidiSequencer::MidiEvent BW_MidiSequencer::parseEvent(const uint8_t **pptr, c if(evType == MidiEvent::T_CTRLCHANGE) { //111'th loopStart controller (RPG Maker and others) - if((m_format == Format_MIDI) && (evt.data[0] == 111)) + if(m_format == Format_MIDI) { - //Change event type to custom Loop Start event and clear data - evt.type = MidiEvent::T_SPECIAL; - evt.subtype = MidiEvent::ST_LOOPSTART; - evt.data.clear(); + switch(evt.data[0]) + { + case 110: + if(m_loopFormat == Loop_Default) + { + //Change event type to custom Loop Start event and clear data + evt.type = MidiEvent::T_SPECIAL; + evt.subtype = MidiEvent::ST_LOOPSTART; + evt.data.clear(); + m_loopFormat = Loop_HMI; + } + else if(m_loopFormat == Loop_HMI) + { + // Repeating of 110'th point is BAD practice, treat as EMIDI + m_loopFormat = Loop_EMIDI; + } + break; + + case 111: + if(m_loopFormat == Loop_HMI) + { + //Change event type to custom Loop End event and clear data + evt.type = MidiEvent::T_SPECIAL; + evt.subtype = MidiEvent::ST_LOOPEND; + evt.data.clear(); + } + else if(m_loopFormat != Loop_EMIDI) + { + // Change event type to custom Loop Start event and clear data + evt.type = MidiEvent::T_SPECIAL; + evt.subtype = MidiEvent::ST_LOOPSTART; + evt.data.clear(); + } + break; + + case 113: + if(m_loopFormat == Loop_EMIDI) + { + //EMIDI does using of CC113 with same purpose as CC7 + evt.data[0] = 7; + } + break; +#if 0 //WIP + case 116: + if(m_loopFormat == Loop_EMIDI) + { + evt.type = MidiEvent::T_SPECIAL; + evt.subtype = MidiEvent::ST_LOOPSTACK_BEGIN; + evt.data[0] = evt.data[1]; + evt.data.pop_back(); + + if(m_interface->onDebugMessage) + { + m_interface->onDebugMessage( + m_interface->onDebugMessage_userData, + "Stack EMIDI Loop Start at %d to %d level with %d loops", + m_loop.stackLevel, + m_loop.stackLevel + 1, + evt.data[0] + ); + } + } + break; + + case 117: // Next/Break Loop Controller + if(m_loopFormat == Loop_EMIDI) + { + evt.type = MidiEvent::T_SPECIAL; + evt.subtype = MidiEvent::ST_LOOPSTACK_END; + evt.data.clear(); + + if(m_interface->onDebugMessage) + { + m_interface->onDebugMessage( + m_interface->onDebugMessage_userData, + "Stack EMIDI Loop End at %d to %d level", + m_loop.stackLevel, + m_loop.stackLevel - 1 + ); + } + } + break; +#endif + } } if(m_format == Format_XMIDI) |