Bela
Real-time, ultra-low-latency audio and sensor processing system for BeagleBone Black
Loading...
Searching...
No Matches
Midi.h
1#pragma once
2#include <Bela.h>
3#include <vector>
4#include <string>
5#ifdef XENOMAI_SKIN_native
6#include <native/pipe.h>
7#endif
8
9typedef unsigned char midi_byte_t;
10
11typedef enum midiMessageType{
12 kmmNoteOff = 0,
13 kmmNoteOn,
14 kmmPolyphonicKeyPressure,
15 kmmControlChange,
16 kmmProgramChange,
17 kmmChannelPressure,
18 kmmPitchBend,
19 kmmSystem,
20 kmmNone,
21 kmmAny,
22} MidiMessageType;
23#define midiMessageStatusBytesLength 8+2 //2 being kmmNone and kmmAny
24
25extern midi_byte_t midiMessageStatusBytes[midiMessageStatusBytesLength];
26extern unsigned int midiMessageNumDataBytes[midiMessageStatusBytesLength];
27
28class MidiChannelMessage{
29public:
30 MidiChannelMessage();
31 MidiChannelMessage(MidiMessageType type);
32 midi_byte_t getStatusByte() const {
33 return _statusByte;
34 }
35 virtual ~MidiChannelMessage();
36 MidiMessageType getType() const;
37 int getChannel() const;
38 const char* getTypeText() const {
39 return getTypeText(getType());
40 }
41 static const char* getTypeText(MidiMessageType type){
42 switch (type) {
43 case kmmNoteOff:
44 return "note off";
45 case kmmNoteOn:
46 return "note on";
47 case kmmPolyphonicKeyPressure:
48 return "polyphonic aftertouch";
49 case kmmControlChange:
50 return "control change";
51 case kmmProgramChange:
52 return "program change";
53 case kmmChannelPressure:
54 return "channel aftertouch";
55 case kmmPitchBend:
56 return "pitch bend";
57 case kmmSystem:
58 return "system";
59 case kmmAny:
60 return "any";
61 case kmmNone:
62 default:
63 return "none";
64 }
65 }
66
67 unsigned int getNumDataBytes() const {
68 return midiMessageNumDataBytes[(unsigned int)_type];
69 }
70 void setDataByte(unsigned int dataByteIndex, midi_byte_t input){
71 _dataBytes[dataByteIndex] = input;
72 }
73 void setType(MidiMessageType type){
74 _type = type;
75 _statusByte = midiMessageStatusBytes[_type];
76 }
77 void setChannel(midi_byte_t channel){
78 _channel = channel;
79 }
80 midi_byte_t getDataByte(unsigned int index) const {
81 return _dataBytes[index];
82 }
83 void clear(){
84 for(int n = 0; n<maxDataBytes; n++){
85 _dataBytes[n] = 0;
86 }
87 _type = kmmNone;
88 _statusByte = 0;
89 }
90 void prettyPrint() const {
91 rt_printf("type: %s, ", this->getTypeText());
92 rt_printf("channel: %u, ", this->getChannel());
93 for(unsigned int n = 0; n < this->getNumDataBytes(); n++){
94 rt_printf("data%d: %d, ", n + 1, this->getDataByte(n));
95 }
96 rt_printf("\n");
97 }
98private:
99 const static int maxDataBytes = 2;
100protected:
101 midi_byte_t _statusByte;
102 midi_byte_t _dataBytes[maxDataBytes]; // where 2 is the maximum number of data bytes for a channel message
103 MidiMessageType _type;
104 midi_byte_t _channel;
105};
106/*
107class MidiControlChangeMessage : public MidiChannelMessage{
108 int number;
109 int value;
110public:
111 int getNumber();
112 int getNumDataBytes();
113 int setDataByte(midi_byte_t input, unsigned int dataByteIndex);
114 int getValue();
115 int set(midi_byte_t* input);
116};
117
118class MidiNoteMessage : public MidiChannelMessage{
119 int note;
120 int velocity;
121public:
122 int getNote();
123 int getVelocity();
124 int getNumDataBytes();
125 int setDataByte(midi_byte_t input, unsigned int dataByteIndex);
126};
127
128class MidiProgramChangeMessage : public MidiChannelMessage{
129 midi_byte_t program;
130public:
131 int getNumDataBytes();
132 int setDataByte(midi_byte_t input, unsigned int dataByteIndex);
133 midi_byte_t getProgram();
134};
135*/
136
137class MidiParser{
138private:
139 std::vector<MidiChannelMessage> messages;
140 unsigned int writePointer;
141 unsigned int readPointer;
142 unsigned int elapsedDataBytes;
143 bool waitingForStatus;
144 bool receivingSysex;
145 void (*messageReadyCallback)(MidiChannelMessage,void*);
146 void* callbackArg;
147 void (*sysexCallback)(midi_byte_t,void*);
148 void* sysexCallbackArg;
149public:
150 MidiParser(){
151 waitingForStatus = true;
152 receivingSysex = false;
153 elapsedDataBytes= 0;
154 messages.resize(100); // 100 is the number of messages that can be buffered
155 writePointer = 0;
156 readPointer = 0;
157 messageReadyCallback = nullptr;
158 callbackArg = nullptr;
159 sysexCallback = nullptr;
160 sysexCallbackArg = nullptr;
161 }
162
171 int parse(midi_byte_t* input, unsigned int length);
172
190 void setCallback(void (*newCallback)(MidiChannelMessage, void*), void* arg=NULL){
191 callbackArg = arg;
192 messageReadyCallback = newCallback;
193 };
194
201 return messageReadyCallback != nullptr;
202 };
203
220 void setSysexCallback(void (*newCallback)(midi_byte_t, void*), void* arg=nullptr){
221 sysexCallbackArg = arg;
222 sysexCallback = newCallback;
223 };
224
231 return sysexCallback != nullptr;
232 };
233
240 int num = (writePointer - readPointer + messages.size() ) % messages.size();
241 return num;
242 }
243
253 MidiChannelMessage message;
254 message = messages[readPointer];
255 if(message.getType() == kmmNone){
256 message.clear();
257 }
258 messages[readPointer].setType(kmmNone); // do not use it again
259 readPointer++;
260 if(readPointer == messages.size()){
261 readPointer = 0;
262 }
263 return message;
264 };
265
266// MidiChannelMessage getNextChannelMessage(){
267// getNextChannelMessage(kmmAny);
268// }
269// MidiControlChangeMessage* getNextControlChangeMessage(){
270// return (MidiControlChangeMessage*)getNextChannelMessage(kmmControlChange);
271// };
272// MidiProgramChangeMessage* getNextProgramChangeMessage(){
273// return (MidiProgramChangeMessage*)getNextChannelMessage(kmmProgramChange);
274// };
275// MidiNoteMessage* getNextNoteOnMessage(){
276// return (MidiNoteMessage*)getNextChannelMessage(kmmNoteOn);
277// };
278};
279
280
281typedef struct _snd_rawmidi snd_rawmidi_t;
282class Midi {
283public:
284 Midi();
285 void setup();
286 void cleanup();
295 void enableParser(bool enable);
296
303
313 void setParserCallback(void (*callback)(MidiChannelMessage, void*), void* arg=NULL){
314 // if callback is not NULL, also enable the parser
315 enableParser(callback != NULL); //this needs to be first, as it deletes the parser(if exists)
316 getParser()->setCallback(callback, arg);
317 }
318
324 int readFrom(const char* port);
325
331 int writeTo(const char* port);
332
338 int getInput();
339
345 int writeOutput(midi_byte_t byte);
346
353 int writeOutput(midi_byte_t* bytes, unsigned int length);
354
355
356 static midi_byte_t makeStatusByte(midi_byte_t statusCode, midi_byte_t dataByte);
357 int writeMessage(midi_byte_t statusCode, midi_byte_t channel, midi_byte_t dataByte);
358 int writeMessage(midi_byte_t statusCode, midi_byte_t channel, midi_byte_t dataByte1, midi_byte_t dataByte2);
359 int writeMessage(const MidiChannelMessage& msg);
360 int writeNoteOff(midi_byte_t channel, midi_byte_t pitch, midi_byte_t velocity);
361 int writeNoteOn(midi_byte_t channel, midi_byte_t pitch, midi_byte_t velocity);
362 int writePolyphonicKeyPressure(midi_byte_t channel, midi_byte_t pitch, midi_byte_t pressure);
363 int writeControlChange(midi_byte_t channel, midi_byte_t controller, midi_byte_t value);
364 int writeProgramChange(midi_byte_t channel, midi_byte_t program);
365 int writeChannelPressure(midi_byte_t channel, midi_byte_t pressure);
366 int writePitchBend(midi_byte_t channel, uint16_t bend);
367
374 virtual ~Midi();
375
376 bool isInputEnabled();
377
378 bool isOutputEnabled();
379
384 static void createAllPorts(std::vector<Midi*>& ports, bool useParser = false);
385
389 static void destroyPorts(std::vector<Midi*>& ports);
390private:
391 char defaultPort[9];
392 std::string inPort;
393 std::string outPort;
394 int _getInput();
395 int attemptRecoveryRead();
396 static void readInputLoop(void* obj);
397 int attemptRecoveryWrite();
398 static void writeOutputLoop(void* obj);
399 snd_rawmidi_t *alsaIn,*alsaOut;
400 std::vector<midi_byte_t> inputBytes;
401 unsigned int inputBytesWritePointer;
402 unsigned int inputBytesReadPointer;
403 std::vector<midi_byte_t> outputBytes;
404 MidiParser* inputParser;
405 bool parserEnabled;
406 bool inputEnabled;
407 bool outputEnabled;
408 AuxiliaryTask midiInputTask;
409 AuxiliaryTask midiOutputTask;
410 char* inId;
411 char* outId;
412 char* outPipeName;
413#ifdef XENOMAI_SKIN_native
414 RT_PIPE outPipe;
415#endif
416#ifdef XENOMAI_SKIN_posix
417 int sock;
418#endif
419};
Main Bela public API.
Definition Midi.h:28
Definition Midi.h:137
void setCallback(void(*newCallback)(MidiChannelMessage, void *), void *arg=NULL)
Definition Midi.h:190
bool isCallbackEnabled()
Definition Midi.h:200
void setSysexCallback(void(*newCallback)(midi_byte_t, void *), void *arg=nullptr)
Definition Midi.h:220
int numAvailableMessages()
Definition Midi.h:239
MidiChannelMessage getNextChannelMessage()
Definition Midi.h:252
bool isSysexCallbackEnabled()
Definition Midi.h:230
int parse(midi_byte_t *input, unsigned int length)
Definition Midi.cpp:39
static void createAllPorts(std::vector< Midi * > &ports, bool useParser=false)
Definition Midi.cpp:366
int getInput()
Definition Midi.cpp:462
MidiParser * getParser()
Definition Midi.cpp:469
static void destroyPorts(std::vector< Midi * > &ports)
void setParserCallback(void(*callback)(MidiChannelMessage, void *), void *arg=NULL)
Definition Midi.h:313
int writeTo(const char *port)
Definition Midi.cpp:322
void enableParser(bool enable)
Definition Midi.cpp:148
int writeOutput(midi_byte_t byte)
Definition Midi.cpp:476
int readFrom(const char *port)
Definition Midi.cpp:303
MidiParser * getMidiParser()
void * AuxiliaryTask
Definition Bela.h:561