From 86d88290a012eae98a9406d7a59a4726f4afb899 Mon Sep 17 00:00:00 2001 From: "Rachel Fae Fox (foxiepaws)" Date: Wed, 11 Mar 2020 04:54:40 -0400 Subject: [PATCH] started work on midi code --- src/midi/SMF.h | 139 ++++++++++++++++++++++++++++++++++++++++ src/midi/SMFReader.h | 22 +++++++ src/midi/message.h | 146 +++++++++++++++++++++++++++++++++++++++++++ src/utils/Message.h | 52 +++++++++++++++ src/utils/node.h | 50 +++++++++++++++ 5 files changed, 409 insertions(+) create mode 100644 src/midi/SMF.h create mode 100644 src/midi/SMFReader.h create mode 100644 src/midi/message.h create mode 100644 src/utils/Message.h create mode 100644 src/utils/node.h diff --git a/src/midi/SMF.h b/src/midi/SMF.h new file mode 100644 index 0000000..9f22651 --- /dev/null +++ b/src/midi/SMF.h @@ -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 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 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 e) { + events = e; + toBytes(); + } + + } + class SMF { + + + } + } +} + + + +// Local Variables: +// mode: c++ +// flycheck-clang-language-standard: "c++11" +// End: diff --git a/src/midi/SMFReader.h b/src/midi/SMFReader.h new file mode 100644 index 0000000..f153ad1 --- /dev/null +++ b/src/midi/SMFReader.h @@ -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: diff --git a/src/midi/message.h b/src/midi/message.h new file mode 100644 index 0000000..21270a2 --- /dev/null +++ b/src/midi/message.h @@ -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 +#include +#include +#include + + +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(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(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(databytes[0]) << 7) | static_cast(databytes[1]); + } + }; + + } + } +} diff --git a/src/utils/Message.h b/src/utils/Message.h new file mode 100644 index 0000000..04a5c7b --- /dev/null +++ b/src/utils/Message.h @@ -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 +#include "midi/message.h" +namespace amalgam { + namespace Utils { + template + 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(); + + } + }; + } +} diff --git a/src/utils/node.h b/src/utils/node.h new file mode 100644 index 0000000..da613c7 --- /dev/null +++ b/src/utils/node.h @@ -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 +namespace amalgam { + typedef std::pair 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 engines; + unsigned int poly = 1; + }; +} + +/* Local Variables: */ +/* mode: c++ */ +/* End: */