diff options
author | Wohlstand <admin@wohlnet.ru> | 2019-12-02 20:47:10 +0300 |
---|---|---|
committer | Wohlstand <admin@wohlnet.ru> | 2019-12-02 20:47:10 +0300 |
commit | c83fff6de633403c6c216bd1abf83e6915aa9913 (patch) | |
tree | a6902e82bcf3c3383ffeac9ac841063f5ced8f07 /src | |
parent | 45190534246f6c5186aa1708187d5010363db03d (diff) | |
parent | 84af1cde8d624100b4396173688743368db64b58 (diff) | |
download | libADLMIDI-c83fff6de633403c6c216bd1abf83e6915aa9913.tar.gz libADLMIDI-c83fff6de633403c6c216bd1abf83e6915aa9913.tar.bz2 libADLMIDI-c83fff6de633403c6c216bd1abf83e6915aa9913.zip |
Merge branch 'master' into wip-new-embedded-banks
Diffstat (limited to 'src')
-rw-r--r-- | src/adlmidi.cpp | 30 | ||||
-rw-r--r-- | src/midi_sequencer.h | 14 | ||||
-rw-r--r-- | src/midi_sequencer.hpp | 8 | ||||
-rw-r--r-- | src/midi_sequencer_impl.hpp | 88 |
4 files changed, 129 insertions, 11 deletions
diff --git a/src/adlmidi.cpp b/src/adlmidi.cpp index dee99d2..3274716 100644 --- a/src/adlmidi.cpp +++ b/src/adlmidi.cpp @@ -31,6 +31,36 @@ #include "midi_sequencer.hpp" #endif +#if defined(_MSC_VER) && _MSC_VER < 1900 + +#define snprintf c99_snprintf +#define vsnprintf c99_vsnprintf + +__inline int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) +{ + int count = -1; + + if (size != 0) + count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); + if (count == -1) + count = _vscprintf(format, ap); + + return count; +} + +__inline int c99_snprintf(char *outBuf, size_t size, const char *format, ...) +{ + int count; + va_list ap; + + va_start(ap, format); + count = c99_vsnprintf(outBuf, size, format, ap); + va_end(ap); + + return count; +} +#endif + /* Unify MIDI player casting and interface between ADLMIDI and OPNMIDI */ #define GET_MIDI_PLAYER(device) reinterpret_cast<MIDIplay *>((device)->adl_midiPlayer) typedef MIDIplay MidiPlayer; diff --git a/src/midi_sequencer.h b/src/midi_sequencer.h index a914451..3f4b750 100644 --- a/src/midi_sequencer.h +++ b/src/midi_sequencer.h @@ -52,6 +52,20 @@ typedef struct BW_MidiRtInterface /*! User data which will be passed through Debug Message hook */ void *onDebugMessage_userData; + /*! Loop Start event hook */ + typedef void (*LoopStartHook)(void *userdata); + /*! Loop start hook which catches passing of loop start point */ + LoopStartHook onloopStart; + /*! User data which will be passed through On-LoopStart hook */ + void *onloopStart_userData; + + /*! Loop Start event hook */ + typedef void (*LoopEndHook)(void *userdata); + /*! Loop start hook which catches passing of loop start point */ + LoopEndHook onloopEnd; + /*! User data which will be passed through On-LoopStart hook */ + void *onloopEnd_userData; + /*! MIDI Run Time event calls user data */ void *rtUserData; diff --git a/src/midi_sequencer.hpp b/src/midi_sequencer.hpp index 04ac866..1eb5873 100644 --- a/src/midi_sequencer.hpp +++ b/src/midi_sequencer.hpp @@ -343,6 +343,8 @@ private: //! Is looping enabled or not bool m_loopEnabled; + //! Don't process loop: trigger hooks only if they are set + bool m_loopHooksOnly; //! Full song length in seconds double m_fullSongTimeLength; @@ -577,6 +579,12 @@ public: void setLoopEnabled(bool enabled); /** + * @brief Switch loop hooks-only mode on/off + * @param enabled Don't loop: trigger hooks only without loop + */ + void setLoopHooksOnly(bool enabled); + + /** * @brief Get music title * @return music title string */ diff --git a/src/midi_sequencer_impl.hpp b/src/midi_sequencer_impl.hpp index 2af80ea..ef4a3de 100644 --- a/src/midi_sequencer_impl.hpp +++ b/src/midi_sequencer_impl.hpp @@ -48,6 +48,36 @@ typedef int32_t ssize_t; # endif #endif +#if defined(_MSC_VER) && _MSC_VER < 1900 + +#define snprintf c99_snprintf +#define vsnprintf c99_vsnprintf + +__inline int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) +{ + int count = -1; + + if (size != 0) + count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); + if (count == -1) + count = _vscprintf(format, ap); + + return count; +} + +__inline int c99_snprintf(char *outBuf, size_t size, const char *format, ...) +{ + int count; + va_list ap; + + va_start(ap, format); + count = c99_vsnprintf(outBuf, size, format, ap); + va_end(ap); + + return count; +} +#endif + #ifndef BWMIDI_DISABLE_MUS_SUPPORT #include "cvt_mus2mid.hpp" #endif//MUS @@ -272,13 +302,14 @@ BW_MidiSequencer::BW_MidiSequencer() : m_smfFormat(0), m_loopFormat(Loop_Default), m_loopEnabled(false), + m_loopHooksOnly(false), m_fullSongTimeLength(0.0), m_postSongWaitDelay(1.0), m_loopStartTime(-1.0), m_loopEndTime(-1.0), m_tempoMultiplier(1.0), m_atEnd(false), - m_trackSolo(~(size_t)0), + m_trackSolo(~static_cast<size_t>(0)), m_triggerHandler(NULL), m_triggerUserData(NULL) { @@ -364,6 +395,11 @@ void BW_MidiSequencer::setLoopEnabled(bool enabled) m_loopEnabled = enabled; } +void BW_MidiSequencer::setLoopHooksOnly(bool enabled) +{ + m_loopHooksOnly = enabled; +} + const std::string &BW_MidiSequencer::getMusicTitle() { return m_musTitle; @@ -951,6 +987,7 @@ bool BW_MidiSequencer::processEvents(bool isSeek) unsigned caughLoopStart = 0; unsigned caughLoopStackStart = 0; unsigned caughLoopStackEnds = 0; + double caughLoopStackEndsTime = 0.0; unsigned caughLoopStackBreaks = 0; #ifdef DEBUG_TIME_CALCULATION @@ -983,12 +1020,18 @@ bool BW_MidiSequencer::processEvents(bool isSeek) if(m_loop.caughtStart) { + if(m_interface->onloopStart)//Loop Start hook + m_interface->onloopStart(m_interface->onloopStart_userData); + caughLoopStart++; m_loop.caughtStart = false; } if(m_loop.caughtStackStart) { + if(m_interface->onloopStart && (m_loopStartTime >= track.pos->time))//Loop Start hook + m_interface->onloopStart(m_interface->onloopStart_userData); + caughLoopStackStart++; m_loop.caughtStackStart = false; } @@ -1005,6 +1048,7 @@ bool BW_MidiSequencer::processEvents(bool isSeek) { m_loop.caughtStackEnd = false; caughLoopStackEnds++; + caughLoopStackEndsTime = track.pos->time; } doLoopJump = true; break;//Stop event handling on catching loopEnd event! @@ -1094,6 +1138,15 @@ bool BW_MidiSequencer::processEvents(bool isSeek) LoopStackEntry &s = m_loop.getCurStack(); if(s.infinity) { + if(m_interface->onloopEnd && (m_loopEndTime >= caughLoopStackEndsTime))//Loop End hook + { + m_interface->onloopEnd(m_interface->onloopEnd_userData); + if(m_loopHooksOnly)//Stop song on reaching loop end + { + m_atEnd = true; //Don't handle events anymore + m_currentPosition.wait += m_postSongWaitDelay;//One second delay until stop playing + } + } m_currentPosition = s.startPosition; m_loop.skipStackStart = true; return true; @@ -1127,10 +1180,14 @@ bool BW_MidiSequencer::processEvents(bool isSeek) if(shortest_no || m_loop.caughtEnd) { + if(m_interface->onloopEnd)//Loop End hook + m_interface->onloopEnd(m_interface->onloopEnd_userData); + //Loop if song end or loop end point has reached m_loop.caughtEnd = false; shortest = 0; - if(!m_loopEnabled) + + if(!m_loopEnabled || m_loopHooksOnly) { m_atEnd = true; //Don't handle events anymore m_currentPosition.wait += m_postSongWaitDelay;//One second delay until stop playing @@ -1208,12 +1265,14 @@ BW_MidiSequencer::MidiEvent BW_MidiSequencer::parseEvent(const uint8_t **pptr, c if(m_musCopyright.empty()) { m_musCopyright = std::string((const char *)evt.data.data(), evt.data.size()); + m_musCopyright.push_back('\0'); /* ending fix for UTF16 strings */ if(m_interface->onDebugMessage) m_interface->onDebugMessage(m_interface->onDebugMessage_userData, "Music copyright: %s", m_musCopyright.c_str()); } else if(m_interface->onDebugMessage) { std::string str((const char *)evt.data.data(), evt.data.size()); + str.push_back('\0'); /* ending fix for UTF16 strings */ m_interface->onDebugMessage(m_interface->onDebugMessage_userData, "Extra copyright event: %s", str.c_str()); } } @@ -1222,12 +1281,14 @@ BW_MidiSequencer::MidiEvent BW_MidiSequencer::parseEvent(const uint8_t **pptr, c if(m_musTitle.empty()) { m_musTitle = std::string((const char *)evt.data.data(), evt.data.size()); + m_musTitle.push_back('\0'); /* ending fix for UTF16 strings */ if(m_interface->onDebugMessage) m_interface->onDebugMessage(m_interface->onDebugMessage_userData, "Music title: %s", m_musTitle.c_str()); } else { std::string str((const char *)evt.data.data(), evt.data.size()); + str.push_back('\0'); /* ending fix for UTF16 strings */ m_musTrackTitles.push_back(str); if(m_interface->onDebugMessage) m_interface->onDebugMessage(m_interface->onDebugMessage_userData, "Track title: %s", str.c_str()); @@ -1238,6 +1299,7 @@ BW_MidiSequencer::MidiEvent BW_MidiSequencer::parseEvent(const uint8_t **pptr, c if(m_interface->onDebugMessage) { std::string str((const char *)evt.data.data(), evt.data.size()); + str.push_back('\0'); /* ending fix for UTF16 strings */ m_interface->onDebugMessage(m_interface->onDebugMessage_userData, "Instrument: %s", str.c_str()); } } @@ -1545,7 +1607,7 @@ void BW_MidiSequencer::handleEvent(size_t track, const BW_MidiSequencer::MidiEve } else { - if(m_trackSolo != ~(size_t)0 && track != m_trackSolo) + if(m_trackSolo != ~static_cast<size_t>(0) && track != m_trackSolo) return; if(m_trackDisable[track]) return; @@ -1576,8 +1638,8 @@ void BW_MidiSequencer::handleEvent(size_t track, const BW_MidiSequencer::MidiEve { // Special event FF uint8_t evtype = evt.subtype; - uint64_t length = (uint64_t)evt.data.size(); - const char *data(length ? (const char *)evt.data.data() : ""); + uint64_t length = static_cast<uint64_t>(evt.data.size()); + const char *data(length ? reinterpret_cast<const char *>(evt.data.data()) : ""); if(evtype == MidiEvent::ST_ENDTRACK)//End Of Track { @@ -1628,8 +1690,8 @@ void BW_MidiSequencer::handleEvent(size_t track, const BW_MidiSequencer::MidiEve m_loop.skipStackStart = false; return; } - LoopStackEntry &s = m_loop.stack[(m_loop.stackLevel + 1)]; - s.loops = (int)data[0]; + LoopStackEntry &s = m_loop.stack[static_cast<size_t>(m_loop.stackLevel + 1)]; + s.loops = static_cast<int>(data[0]); s.infinity = (data[0] == 0); m_loop.caughtStackStart = true; return; @@ -1942,14 +2004,14 @@ static bool detectIMF(const char *head, FileAndMemReader &fr) uint8_t raw[4]; size_t end = static_cast<size_t>(head[0]) + 256 * static_cast<size_t>(head[1]); - if(!end || (end & 3)) + if(end & 3) return false; size_t backup_pos = fr.tell(); int64_t sum1 = 0, sum2 = 0; - fr.seek(2, FileAndMemReader::SET); + fr.seek((end > 0 ? 2 : 0), FileAndMemReader::SET); - for(unsigned n = 0; n < 42; ++n) + for(size_t n = 0; n < 16383; ++n) { if(fr.read(raw, 1, 4) != 4) break; @@ -2108,7 +2170,11 @@ bool BW_MidiSequencer::parseIMF(FileAndMemReader &fr) event.absPosition = 0; event.data.resize(2); - fr.seek(2, FileAndMemReader::SET); + fr.seek((imfEnd > 0) ? 2 : 0, FileAndMemReader::SET); + + if(imfEnd == 0) // IMF Type 0 with unlimited file length + imfEnd = fr.fileSize(); + while(fr.tell() < imfEnd && !fr.eof()) { if(fr.read(imfRaw, 1, 4) != 4) |