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