147 lines
5.1 KiB
C++
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]);
|
|
}
|
|
};
|
|
|
|
}
|
|
}
|
|
}
|