started work on midi code

master
Rachel Fae Fox (foxiepaws) 2020-03-11 04:54:40 -04:00
parent 28bf017e37
commit 86d88290a0
5 changed files with 409 additions and 0 deletions

139
src/midi/SMF.h Normal file
View File

@ -0,0 +1,139 @@
/*
* Filename: SMF.h
*
* Description:
*
*
* Version:
* Created: Wed Mar 11 01:18:30 2020
* Revision: None
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
*
*/
#include "message.h"
namespace amalgam {
typedef std::basic_string<unsigned char> ByteString;
namespace midi {
static unsigned int vlv_length(unsigned char* bytes) {
int vlvLength = 1;
int i = 0;
while ((bytes[i] & 0x80) == 0x80) {
vlvLength++;
i++;
}
return vlvLength;
}
static unsigned int vlv_to_int(unsigned char* bytes) {
unsigned char* vlvBytes;
unsigned int real = 0;
int vlvLength = vlv_length(bytes);
vlvBytes = (unsigned char*) calloc(vlvLength, sizeof(unsigned char));
memcpy(vlvBytes,bytes, vlvLength);
int i = 0;
do {
vlvLength--;
real |= (vlvBytes[i] & 0x7f) << (7*vlvLength);
i++;
} while (vlvLength >= 0);
free(vlvBytes);
return real;
}
static unsigned int int_vlv_length(unsigned int i) {
int bytes = 0;
int temp = i;
while (temp > 127) {
bytes++;
temp >>= 7;
}
return bytes;
}
static void int_to_vlv(unsigned int i, ByteString ba) {
unsigned int bytes = int_vlv_length(i);
unsigned int temp = i;
for (int i = bytes; i >= 0; i--) {
int cv = temp & 0x7f;
temp >>= 7;
if (i < bytes)
cv |= 0x80;
ba.insert(ba.begin(),cv);
}
}
class Event {
protected:
unsigned int delta;
ByteString bytes;
};
class MidiEvent : Event {
Message midi;
ByteString toBytes() {
if (bytes.length() == 0) {
bytes += int_to_vlv(delta, bytes, length);
bytes += midi.raw;
}
return bytes
}
};
class SysexEvent : MidiEvent {
};
class MetaEvent : Event {
enum class MetaType : int { SequenceNumber = 0x00, Text, Copyright,
TrackName, InstrumentName, Lyric, Marker, Cue,
ChannelPrefix = 0x20, End = 0x2F, Tempo = 0x51,
SMPTEOffset = 0x54, SequencerSpecificEvent = 0x7f,
TimeSigniture = 0x58, KeySigniture = 0x59 };
MetaType mt;
unsigned int length;
ByteString bytes;
}
class Track {
uint32_t bytelength;
unsigned char* bytes;
std::list<Event> events;
ByteString toBytes() {
if (bytes.length() == 0) {
uint32_t length = 0;
for (auto e = events.begin(); e != events.end(); ++e) {
ByteString ebytes = e->toBytes();
length += ebytes.length();
bytes += ebytes;
}
ByteString len;
unsigned char* l = (unsigned char* &length);
len += l[3];
len += l[2];
len += l[1];
len += l[0];
bytes = "MTrk" + len + bytes;
}
return bytes;
}
Track(){}
Track(unsigned char* b) {
bytes = b;
fromBytes();
}
Track(std::list<event> e) {
events = e;
toBytes();
}
}
class SMF {
}
}
}
// Local Variables:
// mode: c++
// flycheck-clang-language-standard: "c++11"
// End:

22
src/midi/SMFReader.h Normal file
View File

@ -0,0 +1,22 @@
/*
* Filename: SMFReader.h
*
* Description:
*
*
* Version:
* Created: Wed Mar 11 01:17:15 2020
* Revision: None
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
*
*/
// Local Variables:
// mode: c++
// flycheck-clang-language-standard: "c++11"
// End:

146
src/midi/message.h Normal file
View File

@ -0,0 +1,146 @@
/*
* 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]);
}
};
}
}
}

52
src/utils/Message.h Normal file
View File

@ -0,0 +1,52 @@
/*
* Filename: Message.h
*
* Description:
*
*
* Version:
* Created: Tue Mar 10 23:06:17 2020
* Revision: None
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
*
*/
#include <cstdint>
#include "midi/message.h"
namespace amalgam {
namespace Utils {
template <class T>
T clamp(T num, T max, T min) {
num = (num < min) ? min : num;
return (num > max) ? max : num;
}
// this MType must contain some of the same
enum class MType : int { NoteOff = 0x80, NoteOn = 0x90, PKP = 0xA0,
CC = 0xB0, PC = 0xC0, Aftertouch = 0xD0,
PitchBend = 0xE0, System =0xF0 };
class Message {
MType m;
uint8_t midinote;
double bender; //
double bendamount;
double velocity; // velocity is a 0-1 value;
double pressure; // pressure is a 0-1 value;
void* data; // for extended message types.
float freq() { return (powf(2.0,(((float)midinote-69.0)/12.0)) * 440.0) + (bendamount * bender); }
Midi::Message* toMidiMessage() {
if (m >= MType::System)
throw "Not able to convert to a std midi message";
unsigned int bend = 0x2000 + clamp((int)floor(bender * 0x2000), (int)-8191, (int)8191);
unsigned int v = clamp((int) (velocity * 127), 0, 127);
unsigned int p = clamp((int) (pressure * 127), 0, 127);
return new Midi::VoiceMessage();
}
};
}
}

50
src/utils/node.h Normal file
View File

@ -0,0 +1,50 @@
/*
* Filename: node.h
*
* Description:
*
*
* Version:
* Created: Tue Mar 10 18:45:45 2020
* Revision: None
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
*
*/
#include <array>
namespace amalgam {
typedef std::pair<double,double> Stereo;
typedef double Mono;
class Node {
protected:
unsigned int sr;
Stereo out;
public:
virtual void process();
Mono getMono() { return out.first + out.second; }
Stereo getStereo() { return out; }
Mono sampleMono() { process(); return out.first + out.second; }
Stereo sampleStereo() { process(); return out; }
};
class IEngine : Node {
protected:
double _freq;
bool _gate;
public:
// getters
double freq() { return _freq; }
bool gate() { return _gate; }
// setters
void freq(double v) { _freq = v;};
void gate(bool v) { _gate = v;};
};
class Instrument : Node {
std::array<IEngine*,32> engines;
unsigned int poly = 1;
};
}
/* Local Variables: */
/* mode: c++ */
/* End: */