diff options
author | Vitaly Novichkov <admin@wohlnet.ru> | 2019-12-04 22:14:32 +0300 |
---|---|---|
committer | Vitaly Novichkov <admin@wohlnet.ru> | 2019-12-04 22:14:32 +0300 |
commit | b92112685b1d1ba0ae376069bc42d61300a97fa1 (patch) | |
tree | c57a00d8fc8c275c3db23d7d4109161e1d9e6340 /src | |
parent | 9b41e9128035a84731ea21f465a328cdf7e6494b (diff) | |
parent | e7847d9ff4a71c0f5266d611b5c20988f0709f4f (diff) | |
download | libADLMIDI-b92112685b1d1ba0ae376069bc42d61300a97fa1.tar.gz libADLMIDI-b92112685b1d1ba0ae376069bc42d61300a97fa1.tar.bz2 libADLMIDI-b92112685b1d1ba0ae376069bc42d61300a97fa1.zip |
Merge branch 'wip-new-embedded-banks' of github.com:Wohlstand/libADLMIDI into wip-new-embedded-banks
Diffstat (limited to 'src')
-rw-r--r-- | src/midi_sequencer.h | 13 | ||||
-rw-r--r-- | src/midi_sequencer.hpp | 36 | ||||
-rw-r--r-- | src/midi_sequencer_impl.hpp | 58 |
3 files changed, 107 insertions, 0 deletions
diff --git a/src/midi_sequencer.h b/src/midi_sequencer.h index 3f4b750..4c6693f 100644 --- a/src/midi_sequencer.h +++ b/src/midi_sequencer.h @@ -45,6 +45,19 @@ typedef struct BW_MidiRtInterface /*! User data which will be passed through On-Event hook */ void *onEvent_userData; + /*! PCM render */ + typedef void (*PcmRender)(void *userdata, uint8_t *stream, size_t length); + /*! PCM render hook which catches passing of loop start point */ + PcmRender onPcmRender; + /*! User data which will be passed through On-PCM-render hook */ + void *onPcmRender_userData; + + //! Sample rate + uint32_t pcmSampleRate; + + //! Size of one sample in bytes + uint32_t pcmFrameSize; + /*! Library internal debug messages */ typedef void (*DebugMessageHook)(void *userdata, const char *fmt, ...); /*! Debug message hook */ diff --git a/src/midi_sequencer.hpp b/src/midi_sequencer.hpp index 1eb5873..6832492 100644 --- a/src/midi_sequencer.hpp +++ b/src/midi_sequencer.hpp @@ -511,6 +511,34 @@ private: //! Common error string std::string m_errorString; + struct SequencerTime + { + //! Time buffer + double timeRest; + //! Sample rate + uint32_t sampleRate; + //! Size of one frame in bytes + uint32_t frameSize; + //! Minimum possible delay, granuality + double minDelay; + //! Last delay + double delay; + + void init() + { + sampleRate = 44100; + frameSize = 2; + reset(); + } + + void reset() + { + timeRest = 0.0; + minDelay = 1.0 / static_cast<double>(sampleRate); + delay = 0.0; + } + } m_time; + public: BW_MidiSequencer(); virtual ~BW_MidiSequencer(); @@ -522,6 +550,14 @@ public: void setInterface(const BW_MidiRtInterface *intrf); /** + * @brief Runs ticking in a sync with audio streaming. Use this together with onPcmRender hook to easily play MIDI. + * @param stream pointer to the output PCM stream + * @param length length of the buffer in bytes + * @return Count of recorded data in bytes + */ + int playStream(uint8_t *stream, size_t length); + + /** * @brief Returns file format type of currently loaded file * @return File format type enumeration */ diff --git a/src/midi_sequencer_impl.hpp b/src/midi_sequencer_impl.hpp index 4dc3013..02a4156 100644 --- a/src/midi_sequencer_impl.hpp +++ b/src/midi_sequencer_impl.hpp @@ -315,6 +315,7 @@ BW_MidiSequencer::BW_MidiSequencer() : { m_loop.reset(); m_loop.invalidLoop = false; + m_time.init(); } BW_MidiSequencer::~BW_MidiSequencer() @@ -342,9 +343,56 @@ void BW_MidiSequencer::setInterface(const BW_MidiRtInterface *intrf) //System Exclusive hook is REQUIRED assert(intrf->rt_systemExclusive); + if(intrf->pcmSampleRate != 0 && intrf->pcmFrameSize != 0) + { + m_time.sampleRate = intrf->pcmSampleRate; + m_time.frameSize = intrf->pcmFrameSize; + m_time.reset(); + } + m_interface = intrf; } +int BW_MidiSequencer::playStream(uint8_t *stream, size_t length) +{ + int count = 0; + size_t samples = static_cast<size_t>(length / static_cast<size_t>(m_time.frameSize)); + size_t left = samples; + size_t periodSize = 0; + uint8_t *stream_pos = stream; + + assert(m_interface->onPcmRender); + + while(left > 0) + { + const double leftDelay = left / double(m_time.sampleRate); + const double maxDelay = m_time.timeRest < leftDelay ? m_time.timeRest : leftDelay; + if((positionAtEnd()) && (m_time.delay <= 0.0)) + break;//Stop to fetch samples at reaching the song end with disabled loop + + m_time.timeRest -= maxDelay; + periodSize = static_cast<size_t>(static_cast<double>(m_time.sampleRate) * maxDelay); + + if(stream) + { + size_t generateSize = periodSize > left ? static_cast<size_t>(left) : static_cast<size_t>(periodSize); + m_interface->onPcmRender(m_interface->onPcmRender_userData, stream_pos, generateSize * m_time.frameSize); + stream_pos += generateSize * m_time.frameSize; + count += generateSize; + left -= generateSize; + assert(left <= samples); + } + + if(m_time.timeRest <= 0.0) + { + m_time.delay = Tick(m_time.delay, m_time.minDelay); + m_time.timeRest += m_time.delay; + } + } + + return count * static_cast<int>(m_time.frameSize); +} + BW_MidiSequencer::FileFormat BW_MidiSequencer::getFormat() { return m_format; @@ -449,6 +497,7 @@ void BW_MidiSequencer::buildSmfSetupReset(size_t trackCount) m_loop.reset(); m_loop.invalidLoop = false; + m_time.reset(); m_currentPosition.began = false; m_currentPosition.absTimePosition = 0.0; @@ -1265,12 +1314,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()); } } @@ -1279,12 +1330,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()); @@ -1295,6 +1348,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()); } } @@ -1889,6 +1943,9 @@ double BW_MidiSequencer::seek(double seconds, const double granularity) if(m_currentPosition.wait < 0.0) m_currentPosition.wait = 0.0; + m_time.reset(); + m_time.delay = m_currentPosition.wait; + m_loopEnabled = loopFlagState; return m_currentPosition.wait; } @@ -1920,6 +1977,7 @@ void BW_MidiSequencer::rewind() m_loop.reset(); m_loop.caughtStart = true; + m_time.reset(); } void BW_MidiSequencer::setTempo(double tempo) |