/* * Filename: message.h * * Description: * * * Version: * Created: Tue Mar 10 19:41:33 2020 * Revision: None * Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws * */ /* struct { unsigned int status : 1; // always 1 unsigned int type : 3; unsigned int channel: 4; unsigned int d10 : 1; // padding, always 0 unsigned int data1 : 7; unsigned int d20 : 1; // padding, always 0 unsigned int data2 : 7; }; */ #include #include #include #include namespace amalgam { namespace Utils { namespace Midi { float freqFromMidinote(int note) { return powf(2.0,(((float)note-69.0)/12.0)) * 440.0; } class Message { protected: enum class MType : int { NoteOff = 0x80, NoteOn = 0x90, PKP = 0xA0, CC = 0xB0, PC = 0xC0, Aftertouch = 0xD0, PitchBend = 0xE0, System = 0xF0 }; public: uint8_t statusbyte; // raw status byte uint8_t status = 0; uint8_t channel = 0; uint8_t *databytes; unsigned int bytecount = 0; MType type; uint8_t midinote = 0; uint8_t velocity = 0; uint8_t program = 0; uint8_t pressure = 0; uint16_t bender = 0x2000; float freq() { return freqFromMidinote(midinote); } void do_solve() { switch (type) { case MType::NoteOff: midinote = databytes[0]; velocity = databytes[1]; break; case MType::NoteOn: midinote = databytes[0]; velocity = databytes[1]; // handle 0 = NoteOff if (velocity == 0) { type = MType::NoteOff; } break; case MType::PitchBend: bender = dataTo16bit(); break; case MType::PKP: midinote = databytes[0]; pressure = databytes[1]; break; case MType::Aftertouch: pressure = databytes[0]; break; case MType::PC: program = databytes[0]; break; case MType::CC: case MType::System: default: throw "Not Implemented"; } } // Constructors related to making midi messages from our internal ones. Message(MType m, uint8_t ch, uint16_t bend) { databytes = (uint8_t*) malloc(sizeof(uint8_t) * 2); bytecount = 2; type = m; status = static_cast(m); channel = ch; statusbyte = status | channel; databytes[0] = bend & 0x007F; databytes[1] = ((bend & 0x3f80) >> 7); bender = bend; } Message(MType m, uint8_t ch, uint8_t d1, uint8_t d2) { databytes = (uint8_t*) malloc(sizeof(uint8_t) * 2); bytecount = 2; type = m; status = static_cast(m); channel = ch; statusbyte = status | channel; databytes[0] = d1; databytes[1] = d2; do_solve(); } Message(char* bytes, int count) { bytecount = (count-1); statusbyte = bytes[0]; databytes = (uint8_t*) malloc(sizeof(uint8_t) * bytecount); memcpy(++bytes,databytes,bytecount); processStatusByte(); do_solve(); } void processStatusByte() { if ((statusbyte & 0x80) != 127) throw "Not StatusByte"; type = (MType) (statusbyte & 0xF0); if (type != MType::System) { status = statusbyte & 0xF0; channel = statusbyte & 0x0F; } else { status = statusbyte; } } uint16_t dataTo16bit() { // interpret our databytes as 1 *14bit* number. return (static_cast(databytes[0]) << 7) | static_cast(databytes[1]); } }; } } }