started work on midi code
parent
28bf017e37
commit
86d88290a0
|
@ -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:
|
|
@ -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:
|
|
@ -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]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -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: */
|
Loading…
Reference in New Issue