boo/lib/audiodev/MIDIDecoder.cpp

210 lines
5.8 KiB
C++
Raw Normal View History

2016-05-20 06:16:07 +00:00
#include "boo/audiodev/MIDIDecoder.hpp"
#include "MIDICommon.hpp"
#include <memory>
2016-05-21 03:22:00 +00:00
#include <algorithm>
2016-05-20 06:16:07 +00:00
namespace boo
{
static inline uint8_t clamp7(uint8_t val) {return std::max(0, std::min(127, int(val)));}
2016-05-20 22:57:34 +00:00
bool MIDIDecoder::_readContinuedValue(std::vector<uint8_t>::const_iterator& it,
std::vector<uint8_t>::const_iterator end,
uint32_t& valOut)
2016-05-20 06:16:07 +00:00
{
2016-05-20 22:57:34 +00:00
uint8_t a = *it++;
valOut = a & 0x7f;
2016-05-20 06:16:07 +00:00
if (a & 0x80)
{
2016-05-20 22:57:34 +00:00
if (it == end)
return false;
valOut <<= 7;
a = *it++;
valOut |= a & 0x7f;
2016-05-20 06:16:07 +00:00
if (a & 0x80)
{
2016-05-20 22:57:34 +00:00
if (it == end)
return false;
valOut <<= 7;
a = *it++;
valOut |= a & 0x7f;
2016-05-20 06:16:07 +00:00
}
}
2016-05-20 22:57:34 +00:00
return true;
2016-05-20 06:16:07 +00:00
}
2016-05-20 22:57:34 +00:00
std::vector<uint8_t>::const_iterator
MIDIDecoder::receiveBytes(std::vector<uint8_t>::const_iterator begin,
std::vector<uint8_t>::const_iterator end)
2016-05-20 06:16:07 +00:00
{
2016-05-20 22:57:34 +00:00
std::vector<uint8_t>::const_iterator it = begin;
while (it != end)
2016-05-20 06:16:07 +00:00
{
uint8_t a = *it++;
uint8_t b;
if (a & 0x80)
m_status = a;
else
it--;
2016-06-22 21:44:37 +00:00
if (m_status == 0xff)
2016-06-22 21:44:37 +00:00
{
/* Meta events (ignored for now) */
2016-06-22 21:44:37 +00:00
if (it == end)
return begin;
a = *it++;
uint32_t length;
_readContinuedValue(it, end, length);
it += length;
} else
2016-06-22 21:44:37 +00:00
{
uint8_t chan = m_status & 0xf;
switch (Status(m_status & 0xf0))
2016-06-22 21:44:37 +00:00
{
case Status::NoteOff:
2016-06-22 21:44:37 +00:00
{
if (it == end)
return begin;
a = *it++;
if (it == end)
2016-06-22 21:44:37 +00:00
return begin;
b = *it++;
m_out.noteOff(chan, clamp7(a), clamp7(b));
2016-06-22 21:44:37 +00:00
break;
}
case Status::NoteOn:
2016-06-22 21:44:37 +00:00
{
if (it == end)
return begin;
a = *it++;
if (it == end)
return begin;
b = *it++;
m_out.noteOn(chan, clamp7(a), clamp7(b));
2016-06-22 21:44:37 +00:00
break;
}
case Status::NotePressure:
2016-06-22 21:44:37 +00:00
{
if (it == end)
return begin;
a = *it++;
if (it == end)
return begin;
b = *it++;
m_out.notePressure(chan, clamp7(a), clamp7(b));
2016-06-22 21:44:37 +00:00
break;
}
case Status::ControlChange:
2016-06-22 21:44:37 +00:00
{
if (it == end)
return begin;
a = *it++;
if (it == end)
return begin;
b = *it++;
m_out.controlChange(chan, clamp7(a), clamp7(b));
2016-06-22 21:44:37 +00:00
break;
}
case Status::ProgramChange:
{
if (it == end)
return begin;
a = *it++;
m_out.programChange(chan, clamp7(a));
2016-06-22 21:44:37 +00:00
break;
}
case Status::ChannelPressure:
{
if (it == end)
return begin;
a = *it++;
m_out.channelPressure(chan, clamp7(a));
2016-06-22 21:44:37 +00:00
break;
}
case Status::PitchBend:
{
if (it == end)
return begin;
a = *it++;
if (it == end)
return begin;
b = *it++;
m_out.pitchBend(chan, clamp7(b) * 128 + clamp7(a));
2016-06-22 21:44:37 +00:00
break;
}
case Status::SysEx:
{
switch (Status(m_status & 0xff))
{
case Status::SysEx:
{
uint32_t len;
if (!_readContinuedValue(it, end, len) || end - it < len)
return begin;
m_out.sysex(&*it, len);
break;
}
case Status::TimecodeQuarterFrame:
{
if (it == end)
return begin;
a = *it++;
m_out.timeCodeQuarterFrame(a >> 4 & 0x7, a & 0xf);
break;
}
case Status::SongPositionPointer:
{
if (it == end)
return begin;
a = *it++;
if (it == end)
return begin;
b = *it++;
m_out.songPositionPointer(clamp7(b) * 128 + clamp7(a));
break;
}
case Status::SongSelect:
{
if (it == end)
return begin;
a = *it++;
m_out.songSelect(clamp7(a));
break;
}
case Status::TuneRequest:
m_out.tuneRequest();
break;
case Status::Start:
m_out.startSeq();
break;
case Status::Continue:
m_out.continueSeq();
break;
case Status::Stop:
m_out.stopSeq();
break;
case Status::Reset:
m_out.reset();
break;
case Status::SysExTerm:
case Status::TimingClock:
case Status::ActiveSensing:
default:
break;
}
2016-06-22 21:44:37 +00:00
break;
}
default:
2016-06-22 21:44:37 +00:00
break;
}
2016-05-20 06:16:07 +00:00
}
}
2016-05-20 22:57:34 +00:00
return it;
2016-05-20 06:16:07 +00:00
}
}