aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWohlstand <admin@wohlnet.ru>2019-12-02 20:47:10 +0300
committerWohlstand <admin@wohlnet.ru>2019-12-02 20:47:10 +0300
commitc83fff6de633403c6c216bd1abf83e6915aa9913 (patch)
treea6902e82bcf3c3383ffeac9ac841063f5ced8f07
parent45190534246f6c5186aa1708187d5010363db03d (diff)
parent84af1cde8d624100b4396173688743368db64b58 (diff)
downloadlibADLMIDI-c83fff6de633403c6c216bd1abf83e6915aa9913.tar.gz
libADLMIDI-c83fff6de633403c6c216bd1abf83e6915aa9913.tar.bz2
libADLMIDI-c83fff6de633403c6c216bd1abf83e6915aa9913.zip
Merge branch 'master' into wip-new-embedded-banks
-rw-r--r--src/adlmidi.cpp30
-rw-r--r--src/midi_sequencer.h14
-rw-r--r--src/midi_sequencer.hpp8
-rw-r--r--src/midi_sequencer_impl.hpp88
-rw-r--r--utils/midiplay/adlmidiplay.cpp30
5 files changed, 159 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)
diff --git a/utils/midiplay/adlmidiplay.cpp b/utils/midiplay/adlmidiplay.cpp
index 30e21ba..bbf1dbf 100644
--- a/utils/midiplay/adlmidiplay.cpp
+++ b/utils/midiplay/adlmidiplay.cpp
@@ -35,6 +35,36 @@
#include <signal.h>
#include <stdint.h>
+#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
+
#if defined(__WATCOMC__)
#include <stdio.h> // snprintf is here!
#define flushout(stream)