Functor-based MIDI command receiving

This commit is contained in:
Jack Andersen 2016-05-20 12:57:34 -10:00
parent 7756fcaf76
commit df61d6678b
7 changed files with 194 additions and 130 deletions

View File

@ -194,6 +194,7 @@ add_library(boo
lib/audiodev/MIDIEncoder.cpp lib/audiodev/MIDIEncoder.cpp
lib/audiodev/MIDIDecoder.cpp lib/audiodev/MIDIDecoder.cpp
lib/audiodev/MIDICommon.hpp lib/audiodev/MIDICommon.hpp
lib/audiodev/MIDICommon.cpp
include/boo/inputdev/IHIDListener.hpp include/boo/inputdev/IHIDListener.hpp
include/boo/IGraphicsContext.hpp include/boo/IGraphicsContext.hpp
include/boo/graphicsdev/IGraphicsDataFactory.hpp include/boo/graphicsdev/IGraphicsDataFactory.hpp

View File

@ -48,22 +48,22 @@ struct IAudioVoiceEngine
virtual std::vector<std::pair<std::string, std::string>> enumerateMIDIDevices() const=0; virtual std::vector<std::pair<std::string, std::string>> enumerateMIDIDevices() const=0;
/** Create ad-hoc MIDI in port and register with system */ /** Create ad-hoc MIDI in port and register with system */
virtual std::unique_ptr<IMIDIIn> newVirtualMIDIIn()=0; virtual std::unique_ptr<IMIDIIn> newVirtualMIDIIn(ReceiveFunctor&& receiver)=0;
/** Create ad-hoc MIDI out port and register with system */ /** Create ad-hoc MIDI out port and register with system */
virtual std::unique_ptr<IMIDIOut> newVirtualMIDIOut()=0; virtual std::unique_ptr<IMIDIOut> newVirtualMIDIOut()=0;
/** Create ad-hoc MIDI in/out port and register with system */ /** Create ad-hoc MIDI in/out port and register with system */
virtual std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut()=0; virtual std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut(ReceiveFunctor&& receiver)=0;
/** Open named MIDI in port, name format depends on OS */ /** Open named MIDI in port, name format depends on OS */
virtual std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name)=0; virtual std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name, ReceiveFunctor&& receiver)=0;
/** Open named MIDI out port, name format depends on OS */ /** Open named MIDI out port, name format depends on OS */
virtual std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name)=0; virtual std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name)=0;
/** Open named MIDI in/out port, name format depends on OS */ /** Open named MIDI in/out port, name format depends on OS */
virtual std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name)=0; virtual std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver)=0;
}; };
/** Construct host platform's voice engine */ /** Construct host platform's voice engine */

View File

@ -3,35 +3,53 @@
#include <string> #include <string>
#include <functional> #include <functional>
#include <vector>
#include <stdint.h>
namespace boo namespace boo
{ {
using ReceiveFunctor = std::function<void(std::vector<uint8_t>&&)>;
class IMIDIPort class IMIDIPort
{ {
bool m_virtual;
protected:
IMIDIPort(bool virt) : m_virtual(virt) {}
public: public:
virtual ~IMIDIPort() = default; virtual ~IMIDIPort();
virtual bool isVirtual() const=0; bool isVirtual() const {return m_virtual;}
virtual std::string description() const=0; virtual std::string description() const=0;
}; };
class IMIDIIn : public IMIDIPort class IMIDIIn : public IMIDIPort
{ {
protected:
ReceiveFunctor m_receiver;
IMIDIIn(bool virt, ReceiveFunctor&& receiver)
: IMIDIPort(virt), m_receiver(std::move(receiver)) {}
public: public:
virtual size_t receive(void* buf, size_t len) const=0; virtual ~IMIDIIn();
}; };
class IMIDIOut : public IMIDIPort class IMIDIOut : public IMIDIPort
{ {
protected:
IMIDIOut(bool virt) : IMIDIPort(virt) {}
public: public:
virtual ~IMIDIOut();
virtual size_t send(const void* buf, size_t len) const=0; virtual size_t send(const void* buf, size_t len) const=0;
}; };
class IMIDIInOut : public IMIDIPort class IMIDIInOut : public IMIDIPort
{ {
protected:
ReceiveFunctor m_receiver;
IMIDIInOut(bool virt, ReceiveFunctor&& receiver)
: IMIDIPort(virt), m_receiver(std::move(receiver)) {}
public: public:
virtual ~IMIDIInOut();
virtual size_t send(const void* buf, size_t len) const=0; virtual size_t send(const void* buf, size_t len) const=0;
virtual size_t receive(void* buf, size_t len) const=0;
}; };
} }

View File

@ -4,6 +4,7 @@
#include "boo/audiodev/IMIDIReader.hpp" #include "boo/audiodev/IMIDIReader.hpp"
#include "boo/audiodev/IMIDIPort.hpp" #include "boo/audiodev/IMIDIPort.hpp"
#include <functional> #include <functional>
#include <vector>
namespace boo namespace boo
{ {
@ -12,19 +13,14 @@ class MIDIDecoder
{ {
IMIDIReader& m_out; IMIDIReader& m_out;
uint8_t m_status = 0; uint8_t m_status = 0;
bool _readContinuedValue(std::vector<uint8_t>::const_iterator& it,
struct ReadController std::vector<uint8_t>::const_iterator end,
{ uint32_t& valOut);
IMIDIIn& m_in;
bool readByte(uint8_t& a);
bool read2Bytes(uint8_t& a, uint8_t& b);
bool readBuffer(void* buf, size_t len);
ReadController(IMIDIIn& in) : m_in(in) {}
} m_readControl;
uint32_t _readContinuedValue(uint8_t a);
public: public:
MIDIDecoder(IMIDIIn& in, IMIDIReader& out) : m_readControl(in), m_out(out) {} MIDIDecoder(IMIDIReader& out) : m_out(out) {}
bool receiveBytes(); std::vector<uint8_t>::const_iterator
receiveBytes(std::vector<uint8_t>::const_iterator begin,
std::vector<uint8_t>::const_iterator end);
}; };
} }

View File

@ -1,5 +1,6 @@
#include <memory> #include <memory>
#include <list> #include <list>
#include <thread>
#include "AudioVoiceEngine.hpp" #include "AudioVoiceEngine.hpp"
#include "logvisor/logvisor.hpp" #include "logvisor/logvisor.hpp"
@ -56,15 +57,15 @@ struct ALSAAudioVoiceEngine : BaseAudioVoiceEngine
return AudioChannelSet::Stereo; return AudioChannelSet::Stereo;
static const std::array<AudioChannelSet, 4> testSets = static const std::array<AudioChannelSet, 4> testSets =
{AudioChannelSet::Surround71, AudioChannelSet::Surround51, {{AudioChannelSet::Surround71, AudioChannelSet::Surround51,
AudioChannelSet::Quad, AudioChannelSet::Stereo}; AudioChannelSet::Quad, AudioChannelSet::Stereo}};
for (AudioChannelSet set : testSets) for (AudioChannelSet set : testSets)
{ {
for (snd_pcm_chmap_query_t** chmap = chmaps ; *chmap != nullptr ; ++chmap) for (snd_pcm_chmap_query_t** chmap = chmaps ; *chmap != nullptr ; ++chmap)
{ {
snd_pcm_chmap_t* chm = &(*chmap)->map; snd_pcm_chmap_t* chm = &(*chmap)->map;
uint64_t chBits = 0; uint64_t chBits = 0;
for (int c=0 ; c<chm->channels ; ++c) for (unsigned c=0 ; c<chm->channels ; ++c)
chBits |= 1 << chm->pos[c]; chBits |= 1 << chm->pos[c];
switch (set) switch (set)
@ -204,7 +205,7 @@ struct ALSAAudioVoiceEngine : BaseAudioVoiceEngine
{ {
snd_pcm_chmap_t* chm = &(*chmap)->map; snd_pcm_chmap_t* chm = &(*chmap)->map;
uint64_t chBits = 0; uint64_t chBits = 0;
for (int c=0 ; c<chm->channels ; ++c) for (unsigned c=0 ; c<chm->channels ; ++c)
chBits |= 1 << chm->pos[c]; chBits |= 1 << chm->pos[c];
bool good = false; bool good = false;
@ -246,7 +247,7 @@ struct ALSAAudioVoiceEngine : BaseAudioVoiceEngine
return; return;
} }
chmapOut.m_channelCount = chCount; chmapOut.m_channelCount = chCount;
for (int c=0 ; c<foundChmap->channels ; ++c) for (unsigned c=0 ; c<foundChmap->channels ; ++c)
chmapOut.m_channels[c] = AudioChannel(foundChmap->pos[c] - 3); chmapOut.m_channels[c] = AudioChannel(foundChmap->pos[c] - 3);
snd_pcm_set_chmap(m_pcm, foundChmap); snd_pcm_set_chmap(m_pcm, foundChmap);
snd_pcm_free_chmaps(chmaps); snd_pcm_free_chmaps(chmaps);
@ -364,15 +365,41 @@ struct ALSAAudioVoiceEngine : BaseAudioVoiceEngine
return ret; return ret;
} }
static void MIDIReceiveProc(snd_rawmidi_t* midi, const ReceiveFunctor& receiver, bool& running)
{
uint8_t buf[512];
while (running)
{
int rdBytes = snd_rawmidi_read(midi, buf, 512);
if (rdBytes < 0)
{
Log.report(logvisor::Error, "MIDI connection lost");
running = false;
break;
}
receiver(std::vector<uint8_t>(std::cbegin(buf), std::cbegin(buf) + rdBytes));
}
}
struct MIDIIn : public IMIDIIn struct MIDIIn : public IMIDIIn
{ {
bool m_midiRunning = true;
snd_rawmidi_t* m_midi; snd_rawmidi_t* m_midi;
bool m_virtual; std::thread m_midiThread;
MIDIIn(snd_rawmidi_t* midi, bool virt)
: m_midi(midi), m_virtual(virt) {} MIDIIn(snd_rawmidi_t* midi, bool virt, ReceiveFunctor&& receiver)
: IMIDIIn(virt, std::move(receiver)), m_midi(midi),
m_midiThread(std::bind(MIDIReceiveProc, m_midi, m_receiver, m_midiRunning)) {}
~MIDIIn()
{
m_midiRunning = false;
if (m_midiThread.joinable())
m_midiThread.join();
snd_rawmidi_close(m_midi);
}
~MIDIIn() {snd_rawmidi_close(m_midi);}
bool isVirtual() const {return m_virtual;}
std::string description() const std::string description() const
{ {
snd_rawmidi_info_t* info; snd_rawmidi_info_t* info;
@ -381,21 +408,16 @@ struct ALSAAudioVoiceEngine : BaseAudioVoiceEngine
std::string ret = snd_rawmidi_info_get_name(info); std::string ret = snd_rawmidi_info_get_name(info);
return ret; return ret;
} }
size_t receive(void* buf, size_t len) const
{
return std::max(0l, snd_rawmidi_read(m_midi, buf, len));
}
}; };
struct MIDIOut : public IMIDIOut struct MIDIOut : public IMIDIOut
{ {
snd_rawmidi_t* m_midi; snd_rawmidi_t* m_midi;
bool m_virtual;
MIDIOut(snd_rawmidi_t* midi, bool virt) MIDIOut(snd_rawmidi_t* midi, bool virt)
: m_midi(midi), m_virtual(virt) {} : IMIDIOut(virt), m_midi(midi) {}
~MIDIOut() {snd_rawmidi_close(m_midi);} ~MIDIOut() {snd_rawmidi_close(m_midi);}
bool isVirtual() const {return m_virtual;}
std::string description() const std::string description() const
{ {
snd_rawmidi_info_t* info; snd_rawmidi_info_t* info;
@ -404,26 +426,33 @@ struct ALSAAudioVoiceEngine : BaseAudioVoiceEngine
std::string ret = snd_rawmidi_info_get_name(info); std::string ret = snd_rawmidi_info_get_name(info);
return ret; return ret;
} }
size_t send(const void* buf, size_t len) const size_t send(const void* buf, size_t len) const
{ {
return std::max(0l, snd_rawmidi_write(m_midi, buf, len)); return size_t(std::max(0l, snd_rawmidi_write(m_midi, buf, len)));
} }
}; };
struct MIDIInOut : public IMIDIInOut struct MIDIInOut : public IMIDIInOut
{ {
bool m_midiRunning = true;
snd_rawmidi_t* m_midiIn; snd_rawmidi_t* m_midiIn;
snd_rawmidi_t* m_midiOut; snd_rawmidi_t* m_midiOut;
bool m_virtual; std::thread m_midiThread;
MIDIInOut(snd_rawmidi_t* midiIn, snd_rawmidi_t* midiOut, bool virt)
: m_midiIn(midiIn), m_midiOut(midiOut), m_virtual(virt) {} MIDIInOut(snd_rawmidi_t* midiIn, snd_rawmidi_t* midiOut, bool virt, ReceiveFunctor&& receiver)
: IMIDIInOut(virt, std::move(receiver)), m_midiIn(midiIn), m_midiOut(midiOut),
m_midiThread(std::bind(MIDIReceiveProc, m_midiIn, m_receiver, m_midiRunning)) {}
~MIDIInOut() ~MIDIInOut()
{ {
m_midiRunning = false;
if (m_midiThread.joinable())
m_midiThread.join();
snd_rawmidi_close(m_midiIn); snd_rawmidi_close(m_midiIn);
snd_rawmidi_close(m_midiOut); snd_rawmidi_close(m_midiOut);
} }
bool isVirtual() const {return m_virtual;}
std::string description() const std::string description() const
{ {
snd_rawmidi_info_t* info; snd_rawmidi_info_t* info;
@ -432,58 +461,55 @@ struct ALSAAudioVoiceEngine : BaseAudioVoiceEngine
std::string ret = snd_rawmidi_info_get_name(info); std::string ret = snd_rawmidi_info_get_name(info);
return ret; return ret;
} }
size_t receive(void* buf, size_t len) const
{
return std::max(0l, snd_rawmidi_read(m_midiOut, buf, len));
}
size_t send(const void* buf, size_t len) const size_t send(const void* buf, size_t len) const
{ {
return std::max(0l, snd_rawmidi_write(m_midiOut, buf, len)); return size_t(std::max(0l, snd_rawmidi_write(m_midiOut, buf, len)));
} }
}; };
std::unique_ptr<IMIDIIn> newVirtualMIDIIn() std::unique_ptr<IMIDIIn> newVirtualMIDIIn(ReceiveFunctor&& receiver)
{ {
int status; int status;
snd_rawmidi_t* midi; snd_rawmidi_t* midi;
status = snd_rawmidi_open(&midi, nullptr, "virtual", SND_RAWMIDI_NONBLOCK); status = snd_rawmidi_open(&midi, nullptr, "virtual", 0);
if (status) if (status)
return {}; return {};
return std::make_unique<MIDIIn>(midi, true); return std::make_unique<MIDIIn>(midi, true, std::move(receiver));
} }
std::unique_ptr<IMIDIOut> newVirtualMIDIOut() std::unique_ptr<IMIDIOut> newVirtualMIDIOut()
{ {
int status; int status;
snd_rawmidi_t* midi; snd_rawmidi_t* midi;
status = snd_rawmidi_open(nullptr, &midi, "virtual", SND_RAWMIDI_NONBLOCK); status = snd_rawmidi_open(nullptr, &midi, "virtual", 0);
if (status) if (status)
return {}; return {};
return std::make_unique<MIDIOut>(midi, true); return std::make_unique<MIDIOut>(midi, true);
} }
std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut() std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut(ReceiveFunctor&& receiver)
{ {
int status; int status;
snd_rawmidi_t* midiIn; snd_rawmidi_t* midiIn;
snd_rawmidi_t* midiOut; snd_rawmidi_t* midiOut;
status = snd_rawmidi_open(&midiIn, &midiOut, "virtual", SND_RAWMIDI_NONBLOCK); status = snd_rawmidi_open(&midiIn, &midiOut, "virtual", 0);
if (status) if (status)
return {}; return {};
return std::make_unique<MIDIInOut>(midiIn, midiOut, true); return std::make_unique<MIDIInOut>(midiIn, midiOut, true, std::move(receiver));
} }
std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name) std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name, ReceiveFunctor&& receiver)
{ {
int status; int status;
char path[128]; char path[128];
snprintf(path, 128, "hw:%s", name); snprintf(path, 128, "hw:%s", name);
snd_rawmidi_t* midi; snd_rawmidi_t* midi;
status = snd_rawmidi_open(&midi, nullptr, path, SND_RAWMIDI_NONBLOCK); status = snd_rawmidi_open(&midi, nullptr, path, 0);
if (status) if (status)
return {}; return {};
return std::make_unique<MIDIIn>(midi, true); return std::make_unique<MIDIIn>(midi, true, std::move(receiver));
} }
std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name) std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name)
@ -493,13 +519,13 @@ struct ALSAAudioVoiceEngine : BaseAudioVoiceEngine
snprintf(path, 128, "hw:%s", name); snprintf(path, 128, "hw:%s", name);
snd_rawmidi_t* midi; snd_rawmidi_t* midi;
status = snd_rawmidi_open(nullptr, &midi, path, SND_RAWMIDI_NONBLOCK); status = snd_rawmidi_open(nullptr, &midi, path, 0);
if (status) if (status)
return {}; return {};
return std::make_unique<MIDIOut>(midi, true); return std::make_unique<MIDIOut>(midi, true);
} }
std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name) std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver)
{ {
int status; int status;
char path[128]; char path[128];
@ -507,10 +533,10 @@ struct ALSAAudioVoiceEngine : BaseAudioVoiceEngine
snd_rawmidi_t* midiIn; snd_rawmidi_t* midiIn;
snd_rawmidi_t* midiOut; snd_rawmidi_t* midiOut;
status = snd_rawmidi_open(&midiIn, &midiOut, path, SND_RAWMIDI_NONBLOCK); status = snd_rawmidi_open(&midiIn, &midiOut, path, 0);
if (status) if (status)
return {}; return {};
return std::make_unique<MIDIInOut>(midiIn, midiOut, true); return std::make_unique<MIDIInOut>(midiIn, midiOut, true, std::move(receiver));
} }
}; };

View File

@ -0,0 +1,12 @@
#include "MIDICommon.hpp"
#include "boo/audiodev/IMIDIPort.hpp"
namespace boo
{
IMIDIPort::~IMIDIPort() {}
IMIDIIn::~IMIDIIn() {}
IMIDIOut::~IMIDIOut() {}
IMIDIInOut::~IMIDIInOut() {}
}

View File

@ -7,112 +7,118 @@ namespace boo
static inline uint8_t clamp7(uint8_t val) {return std::max(0, std::min(127, int(val)));} static inline uint8_t clamp7(uint8_t val) {return std::max(0, std::min(127, int(val)));}
bool MIDIDecoder::ReadController::readByte(uint8_t& a) bool MIDIDecoder::_readContinuedValue(std::vector<uint8_t>::const_iterator& it,
std::vector<uint8_t>::const_iterator end,
uint32_t& valOut)
{ {
return m_in.receive(&a, 1) != 0; uint8_t a = *it++;
} valOut = a & 0x7f;
bool MIDIDecoder::ReadController::read2Bytes(uint8_t& a, uint8_t& b)
{
uint8_t buf[2];
int len = m_in.receive(buf, 2);
a = buf[0];
b = buf[1];
return len > 1;
}
bool MIDIDecoder::ReadController::readBuffer(void* buf, size_t len)
{
return m_in.receive(buf, len) == len;
}
uint32_t MIDIDecoder::_readContinuedValue(uint8_t a)
{
uint32_t ret = a & 0x7f;
if (a & 0x80) if (a & 0x80)
{ {
ret <<= 7; if (it == end)
bool good = m_readControl.readByte(a); return false;
if (!good) valOut <<= 7;
return ret; a = *it++;
ret |= a & 0x7f; valOut |= a & 0x7f;
if (a & 0x80) if (a & 0x80)
{ {
ret <<= 7; if (it == end)
good = m_readControl.readByte(a); return false;
if (!good) valOut <<= 7;
return ret; a = *it++;
ret |= a & 0x7f; valOut |= a & 0x7f;
} }
} }
return ret; return true;
} }
bool MIDIDecoder::receiveBytes() std::vector<uint8_t>::const_iterator
MIDIDecoder::receiveBytes(std::vector<uint8_t>::const_iterator begin,
std::vector<uint8_t>::const_iterator end)
{ {
uint8_t a, b; std::vector<uint8_t>::const_iterator it = begin;
bool good = m_readControl.read2Bytes(a, b); if (it == end)
if (!good) return begin;
return false;
uint8_t a = *it++;
uint8_t b;
if (a & 0x80) if (a & 0x80)
m_status = a; m_status = a;
else
b = a;
uint8_t chan = m_status & 0xf; uint8_t chan = m_status & 0xf;
switch (Status(m_status & 0xf0)) switch (Status(m_status & 0xf0))
{ {
case Status::NoteOff: case Status::NoteOff:
{ {
good = m_readControl.read2Bytes(a, b); if (it == end)
if (!good) return begin;
return false; a = *it++;
if (it == end)
return begin;
b = *it++;
m_out.noteOff(chan, clamp7(a), clamp7(b)); m_out.noteOff(chan, clamp7(a), clamp7(b));
break; break;
} }
case Status::NoteOn: case Status::NoteOn:
{ {
good = m_readControl.read2Bytes(a, b); if (it == end)
if (!good) return begin;
return false; a = *it++;
if (it == end)
return begin;
b = *it++;
m_out.noteOn(chan, clamp7(a), clamp7(b)); m_out.noteOn(chan, clamp7(a), clamp7(b));
break; break;
} }
case Status::NotePressure: case Status::NotePressure:
{ {
good = m_readControl.read2Bytes(a, b); if (it == end)
if (!good) return begin;
return false; a = *it++;
if (it == end)
return begin;
b = *it++;
m_out.notePressure(chan, clamp7(a), clamp7(b)); m_out.notePressure(chan, clamp7(a), clamp7(b));
break; break;
} }
case Status::ControlChange: case Status::ControlChange:
{ {
good = m_readControl.read2Bytes(a, b); if (it == end)
if (!good) return begin;
return false; a = *it++;
if (it == end)
return begin;
b = *it++;
m_out.controlChange(chan, clamp7(a), clamp7(b)); m_out.controlChange(chan, clamp7(a), clamp7(b));
break; break;
} }
case Status::ProgramChange: case Status::ProgramChange:
{ {
m_out.programChange(chan, clamp7(b)); if (it == end)
return begin;
a = *it++;
m_out.programChange(chan, clamp7(a));
break; break;
} }
case Status::ChannelPressure: case Status::ChannelPressure:
{ {
m_out.channelPressure(chan, clamp7(b)); if (it == end)
return begin;
a = *it++;
m_out.channelPressure(chan, clamp7(a));
break; break;
} }
case Status::PitchBend: case Status::PitchBend:
{ {
good = m_readControl.read2Bytes(a, b); if (it == end)
if (!good) return begin;
return false; a = *it++;
if (it == end)
return begin;
b = *it++;
m_out.pitchBend(chan, clamp7(b) * 128 + clamp7(a)); m_out.pitchBend(chan, clamp7(b) * 128 + clamp7(a));
break; break;
} }
@ -122,32 +128,37 @@ bool MIDIDecoder::receiveBytes()
{ {
case Status::SysEx: case Status::SysEx:
{ {
uint32_t len = _readContinuedValue(a); uint32_t len;
std::unique_ptr<uint8_t[]> buf(new uint8_t[len]); if (!_readContinuedValue(it, end, len) || end - it < len)
if (!m_readControl.readBuffer(buf.get(), len)) return begin;
return false; m_out.sysex(&*it, len);
m_out.sysex(buf.get(), len);
break; break;
} }
case Status::TimecodeQuarterFrame: case Status::TimecodeQuarterFrame:
{ {
good = m_readControl.read2Bytes(a, b); if (it == end)
if (!good) return begin;
return false; a = *it++;
m_out.timeCodeQuarterFrame(a >> 4 & 0x7, a & 0xf); m_out.timeCodeQuarterFrame(a >> 4 & 0x7, a & 0xf);
break; break;
} }
case Status::SongPositionPointer: case Status::SongPositionPointer:
{ {
good = m_readControl.read2Bytes(a, b); if (it == end)
if (!good) return begin;
return false; a = *it++;
if (it == end)
return begin;
b = *it++;
m_out.songPositionPointer(clamp7(b) * 128 + clamp7(a)); m_out.songPositionPointer(clamp7(b) * 128 + clamp7(a));
break; break;
} }
case Status::SongSelect: case Status::SongSelect:
{ {
m_out.songSelect(clamp7(b)); if (it == end)
return begin;
a = *it++;
m_out.songSelect(clamp7(a));
break; break;
} }
case Status::TuneRequest: case Status::TuneRequest:
@ -175,7 +186,7 @@ bool MIDIDecoder::receiveBytes()
default: break; default: break;
} }
return true; return it;
} }
} }