amalgam/src/midi/message.h

147 lines
5.1 KiB
C++

/*
* 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 <cmath>
#include <cstdint>
#include <cstring>
#include <cstdlib>
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<uint8_t>(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<uint8_t>(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<uint16_t>(databytes[0]) << 7) | static_cast<uint16_t>(databytes[1]);
}
};
}
}
}