Merge pull request #32 from lioncash/midi

MIDIEncoder: Make _sendMessage overload for the ContiguousContainer concept
This commit is contained in:
Phillip Stephens 2019-08-24 19:43:54 -07:00 committed by GitHub
commit 7c5a9ab4df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 80 additions and 52 deletions

View File

@ -1,5 +1,8 @@
#pragma once #pragma once
#include <cstdint>
#include <iterator>
#include "boo/audiodev/IMIDIReader.hpp" #include "boo/audiodev/IMIDIReader.hpp"
namespace boo { namespace boo {
@ -8,7 +11,14 @@ template <class Sender>
class MIDIEncoder : public IMIDIReader { class MIDIEncoder : public IMIDIReader {
Sender& m_sender; Sender& m_sender;
uint8_t m_status = 0; uint8_t m_status = 0;
void _sendMessage(const uint8_t* data, size_t len); void _sendMessage(const uint8_t* data, size_t len);
template <typename ContiguousContainer>
void _sendMessage(const ContiguousContainer& container) {
_sendMessage(std::data(container), std::size(container));
}
void _sendContinuedValue(uint32_t val); void _sendContinuedValue(uint32_t val);
public: public:

View File

@ -1,9 +1,17 @@
#include "boo/audiodev/MIDIEncoder.hpp" #include "boo/audiodev/MIDIEncoder.hpp"
#include <array>
#include "boo/audiodev/IMIDIPort.hpp" #include "boo/audiodev/IMIDIPort.hpp"
#include "lib/audiodev/MIDICommon.hpp" #include "lib/audiodev/MIDICommon.hpp"
namespace boo { namespace boo {
namespace {
template <typename... Args>
constexpr auto MakeCommand(Args&&... args) -> std::array<uint8_t, sizeof...(Args)> {
return {std::forward<Args>(args)...};
}
} // Anonymous namespace
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::_sendMessage(const uint8_t* data, size_t len) { void MIDIEncoder<Sender>::_sendMessage(const uint8_t* data, size_t len) {
@ -18,7 +26,7 @@ void MIDIEncoder<Sender>::_sendMessage(const uint8_t* data, size_t len) {
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::_sendContinuedValue(uint32_t val) { void MIDIEncoder<Sender>::_sendContinuedValue(uint32_t val) {
uint8_t send[3] = {}; std::array<uint8_t, 3> send{};
uint8_t* ptr = nullptr; uint8_t* ptr = nullptr;
if (val >= 0x4000) { if (val >= 0x4000) {
ptr = &send[0]; ptr = &send[0];
@ -28,154 +36,164 @@ void MIDIEncoder<Sender>::_sendContinuedValue(uint32_t val) {
} }
if (val >= 0x80) { if (val >= 0x80) {
if (!ptr) if (ptr == nullptr) {
ptr = &send[1]; ptr = &send[1];
}
send[1] = 0x80 | ((val / 0x80) & 0x7f); send[1] = 0x80 | ((val / 0x80) & 0x7f);
} }
if (!ptr) if (ptr == nullptr) {
ptr = &send[2]; ptr = &send[2];
}
send[2] = val & 0x7f; send[2] = val & 0x7f;
m_sender.send(ptr, 3 - (ptr - send)); const size_t sendLength = send.size() - (ptr - send.data());
m_sender.send(ptr, sendLength);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::noteOff(uint8_t chan, uint8_t key, uint8_t velocity) { void MIDIEncoder<Sender>::noteOff(uint8_t chan, uint8_t key, uint8_t velocity) {
uint8_t cmd[3] = {uint8_t(int(Status::NoteOff) | (chan & 0xf)), uint8_t(key & 0x7f), uint8_t(velocity & 0x7f)}; const auto cmd =
_sendMessage(cmd, 3); MakeCommand(uint8_t(int(Status::NoteOff) | (chan & 0xf)), uint8_t(key & 0x7f), uint8_t(velocity & 0x7f));
_sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::noteOn(uint8_t chan, uint8_t key, uint8_t velocity) { void MIDIEncoder<Sender>::noteOn(uint8_t chan, uint8_t key, uint8_t velocity) {
uint8_t cmd[3] = {uint8_t(int(Status::NoteOn) | (chan & 0xf)), uint8_t(key & 0x7f), uint8_t(velocity & 0x7f)}; const auto cmd =
_sendMessage(cmd, 3); MakeCommand(uint8_t(int(Status::NoteOn) | (chan & 0xf)), uint8_t(key & 0x7f), uint8_t(velocity & 0x7f));
_sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::notePressure(uint8_t chan, uint8_t key, uint8_t pressure) { void MIDIEncoder<Sender>::notePressure(uint8_t chan, uint8_t key, uint8_t pressure) {
uint8_t cmd[3] = {uint8_t(int(Status::NotePressure) | (chan & 0xf)), uint8_t(key & 0x7f), uint8_t(pressure & 0x7f)}; const auto cmd =
_sendMessage(cmd, 3); MakeCommand(uint8_t(int(Status::NotePressure) | (chan & 0xf)), uint8_t(key & 0x7f), uint8_t(pressure & 0x7f));
_sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::controlChange(uint8_t chan, uint8_t control, uint8_t value) { void MIDIEncoder<Sender>::controlChange(uint8_t chan, uint8_t control, uint8_t value) {
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t(control & 0x7f), uint8_t(value & 0x7f)}; const auto cmd =
_sendMessage(cmd, 3); MakeCommand(uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t(control & 0x7f), uint8_t(value & 0x7f));
_sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::programChange(uint8_t chan, uint8_t program) { void MIDIEncoder<Sender>::programChange(uint8_t chan, uint8_t program) {
uint8_t cmd[2] = {uint8_t(int(Status::ProgramChange) | (chan & 0xf)), uint8_t(program & 0x7f)}; const auto cmd = MakeCommand(uint8_t(int(Status::ProgramChange) | (chan & 0xf)), uint8_t(program & 0x7f));
_sendMessage(cmd, 2); _sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::channelPressure(uint8_t chan, uint8_t pressure) { void MIDIEncoder<Sender>::channelPressure(uint8_t chan, uint8_t pressure) {
uint8_t cmd[2] = {uint8_t(int(Status::ChannelPressure) | (chan & 0xf)), uint8_t(pressure & 0x7f)}; const auto cmd = MakeCommand(uint8_t(int(Status::ChannelPressure) | (chan & 0xf)), uint8_t(pressure & 0x7f));
_sendMessage(cmd, 2); _sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::pitchBend(uint8_t chan, int16_t pitch) { void MIDIEncoder<Sender>::pitchBend(uint8_t chan, int16_t pitch) {
uint8_t cmd[3] = {uint8_t(int(Status::PitchBend) | (chan & 0xf)), uint8_t((pitch % 128) & 0x7f), const auto cmd = MakeCommand(uint8_t(int(Status::PitchBend) | (chan & 0xf)), uint8_t((pitch % 128) & 0x7f),
uint8_t((pitch / 128) & 0x7f)}; uint8_t((pitch / 128) & 0x7f));
_sendMessage(cmd, 3); _sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::allSoundOff(uint8_t chan) { void MIDIEncoder<Sender>::allSoundOff(uint8_t chan) {
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), 120, 0}; const auto cmd = MakeCommand(uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t{120}, uint8_t{0});
_sendMessage(cmd, 3); _sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::resetAllControllers(uint8_t chan) { void MIDIEncoder<Sender>::resetAllControllers(uint8_t chan) {
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), 121, 0}; const auto cmd = MakeCommand(uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t{121}, uint8_t{0});
_sendMessage(cmd, 3); _sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::localControl(uint8_t chan, bool on) { void MIDIEncoder<Sender>::localControl(uint8_t chan, bool on) {
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), 122, uint8_t(on ? 127 : 0)}; const auto cmd = MakeCommand(uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t{122}, uint8_t(on ? 127 : 0));
_sendMessage(cmd, 3); _sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::allNotesOff(uint8_t chan) { void MIDIEncoder<Sender>::allNotesOff(uint8_t chan) {
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), 123, 0}; const auto cmd = MakeCommand(uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t{123}, uint8_t{0});
_sendMessage(cmd, 3); _sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::omniMode(uint8_t chan, bool on) { void MIDIEncoder<Sender>::omniMode(uint8_t chan, bool on) {
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t(on ? 125 : 124), 0}; const auto cmd = MakeCommand(uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t(on ? 125 : 124), uint8_t{0});
_sendMessage(cmd, 3); _sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::polyMode(uint8_t chan, bool on) { void MIDIEncoder<Sender>::polyMode(uint8_t chan, bool on) {
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t(on ? 127 : 126), 0}; const auto cmd = MakeCommand(uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t(on ? 127 : 126), uint8_t{0});
_sendMessage(cmd, 3); _sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::sysex(const void* data, size_t len) { void MIDIEncoder<Sender>::sysex(const void* data, size_t len) {
uint8_t cmd = uint8_t(Status::SysEx); constexpr auto sysexCmd = MakeCommand(uint8_t(Status::SysEx));
_sendMessage(&cmd, 1); _sendMessage(sysexCmd);
_sendContinuedValue(len); _sendContinuedValue(len);
m_sender.send(data, len); m_sender.send(data, len);
cmd = uint8_t(Status::SysExTerm);
_sendMessage(&cmd, 1); constexpr auto sysexTermCmd = MakeCommand(uint8_t(Status::SysExTerm));
_sendMessage(sysexTermCmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::timeCodeQuarterFrame(uint8_t message, uint8_t value) { void MIDIEncoder<Sender>::timeCodeQuarterFrame(uint8_t message, uint8_t value) {
uint8_t cmd[2] = {uint8_t(int(Status::TimecodeQuarterFrame)), uint8_t((message & 0x7 << 4) | (value & 0xf))}; const auto cmd =
_sendMessage(cmd, 2); MakeCommand(uint8_t(int(Status::TimecodeQuarterFrame)), uint8_t((message & 0x7 << 4) | (value & 0xf)));
_sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::songPositionPointer(uint16_t pointer) { void MIDIEncoder<Sender>::songPositionPointer(uint16_t pointer) {
uint8_t cmd[3] = {uint8_t(int(Status::SongPositionPointer)), uint8_t((pointer % 128) & 0x7f), const auto cmd = MakeCommand(uint8_t(int(Status::SongPositionPointer)), uint8_t((pointer % 128) & 0x7f),
uint8_t((pointer / 128) & 0x7f)}; uint8_t((pointer / 128) & 0x7f));
_sendMessage(cmd, 3); _sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::songSelect(uint8_t song) { void MIDIEncoder<Sender>::songSelect(uint8_t song) {
uint8_t cmd[2] = {uint8_t(int(Status::TimecodeQuarterFrame)), uint8_t(song & 0x7f)}; const auto cmd = MakeCommand(uint8_t(int(Status::TimecodeQuarterFrame)), uint8_t(song & 0x7f));
_sendMessage(cmd, 2); _sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::tuneRequest() { void MIDIEncoder<Sender>::tuneRequest() {
uint8_t cmd = uint8_t(Status::TuneRequest); constexpr auto cmd = MakeCommand(uint8_t(Status::TuneRequest));
_sendMessage(&cmd, 1); _sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::startSeq() { void MIDIEncoder<Sender>::startSeq() {
uint8_t cmd = uint8_t(Status::Start); constexpr auto cmd = MakeCommand(uint8_t(Status::Start));
_sendMessage(&cmd, 1); _sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::continueSeq() { void MIDIEncoder<Sender>::continueSeq() {
uint8_t cmd = uint8_t(Status::Continue); constexpr auto cmd = MakeCommand(uint8_t(Status::Continue));
_sendMessage(&cmd, 1); _sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::stopSeq() { void MIDIEncoder<Sender>::stopSeq() {
uint8_t cmd = uint8_t(Status::Stop); constexpr auto cmd = MakeCommand(uint8_t(Status::Stop));
_sendMessage(&cmd, 1); _sendMessage(cmd);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::reset() { void MIDIEncoder<Sender>::reset() {
uint8_t cmd = uint8_t(Status::Reset); constexpr auto cmd = MakeCommand(uint8_t(Status::Reset));
_sendMessage(&cmd, 1); _sendMessage(cmd);
} }
template class MIDIEncoder<IMIDIOut>; template class MIDIEncoder<IMIDIOut>;