Bela
Real-time, ultra-low-latency audio and sensor processing system for BeagleBone Black
 All Classes Files Functions Variables Typedefs Macros Groups
Midi.h
1 /*
2  * Midi.h
3  *
4  * Created on: 15 Jan 2016
5  * Author: giulio
6  */
7 
8 #ifndef MIDI_H_
9 #define MIDI_H_
10 
11 #include <Bela.h>
12 #include <vector>
13 #include <alsa/asoundlib.h>
14 #ifdef XENOMAI_SKIN_native
15 #include <native/pipe.h>
16 #endif
17 
18 typedef unsigned char midi_byte_t;
19 
20 typedef enum midiMessageType{
21  kmmNoteOff = 0,
22  kmmNoteOn,
23  kmmPolyphonicKeyPressure,
24  kmmControlChange,
25  kmmProgramChange,
26  kmmChannelPressure,
27  kmmPitchBend,
28  kmmSystem,
29  kmmNone,
30  kmmAny,
31 } MidiMessageType;
32 #define midiMessageStatusBytesLength 8+2 //2 being kmmNone and kmmAny
33 
34 extern midi_byte_t midiMessageStatusBytes[midiMessageStatusBytesLength];
35 extern unsigned int midiMessageNumDataBytes[midiMessageStatusBytesLength];
36 
38 public:
40  MidiChannelMessage(MidiMessageType type);
41  midi_byte_t getStatusByte(){
42  return _statusByte;
43  }
44  virtual ~MidiChannelMessage();
45  MidiMessageType getType();
46  int getChannel();
47  const char* getTypeText(){
48  return getTypeText(getType());
49  }
50  static const char* getTypeText(MidiMessageType type){
51  switch (type) {
52  case kmmNoteOff:
53  return "note off";
54  case kmmNoteOn:
55  return "note on";
56  case kmmPolyphonicKeyPressure:
57  return "polyphonic aftertouch";
58  case kmmControlChange:
59  return "control change";
60  case kmmProgramChange:
61  return "program change";
62  case kmmChannelPressure:
63  return "channel aftertouch";
64  case kmmPitchBend:
65  return "pitch bend";
66  case kmmSystem:
67  return "system";
68  case kmmAny:
69  return "any";
70  case kmmNone:
71  default:
72  return "none";
73  }
74  }
75 
76  unsigned int getNumDataBytes(){
77  return midiMessageNumDataBytes[(unsigned int)_type];
78  }
79  void setDataByte(unsigned int dataByteIndex, midi_byte_t input){
80  _dataBytes[dataByteIndex] = input;
81  }
82  void setType(MidiMessageType type){
83  _type = type;
84  _statusByte = midiMessageStatusBytes[_type];
85  }
86  void setChannel(midi_byte_t channel){
87  _channel = channel;
88  }
89  midi_byte_t getDataByte(unsigned int index){
90  return _dataBytes[index];
91  }
92  void clear(){
93  for(int n = 0; n<maxDataBytes; n++){
94  _dataBytes[n] = 0;
95  }
96  _type = kmmNone;
97  _statusByte = 0;
98  }
99  void prettyPrint(){
100  rt_printf("type: %s, ", this->getTypeText());
101  rt_printf("channel: %u, ", this->getChannel());
102  for(unsigned int n = 0; n < this->getNumDataBytes(); n++){
103  rt_printf("data%d: %d, ", n + 1, this->getDataByte(n));
104  }
105  rt_printf("\n");
106  }
107 private:
108  const static int maxDataBytes = 2;
109 protected:
110  midi_byte_t _statusByte;
111  midi_byte_t _dataBytes[maxDataBytes]; // where 2 is the maximum number of data bytes for a channel message
112  MidiMessageType _type;
113  midi_byte_t _channel;
114 };
115 /*
116 class MidiControlChangeMessage : public MidiChannelMessage{
117  int number;
118  int value;
119 public:
120  int getNumber();
121  int getNumDataBytes();
122  int setDataByte(midi_byte_t input, unsigned int dataByteIndex);
123  int getValue();
124  int set(midi_byte_t* input);
125 };
126 
127 class MidiNoteMessage : public MidiChannelMessage{
128  int note;
129  int velocity;
130 public:
131  int getNote();
132  int getVelocity();
133  int getNumDataBytes();
134  int setDataByte(midi_byte_t input, unsigned int dataByteIndex);
135 };
136 
137 class MidiProgramChangeMessage : public MidiChannelMessage{
138  midi_byte_t program;
139 public:
140  int getNumDataBytes();
141  int setDataByte(midi_byte_t input, unsigned int dataByteIndex);
142  midi_byte_t getProgram();
143 };
144 */
145 
147 private:
148  std::vector<MidiChannelMessage> messages;
149  unsigned int writePointer;
150  unsigned int readPointer;
151  unsigned int elapsedDataBytes;
152  bool waitingForStatus;
153  bool receivingSysex;
154  void (*messageReadyCallback)(MidiChannelMessage,void*);
155  bool callbackEnabled;
156  void* callbackArg;
157 public:
158  MidiParser(){
159  waitingForStatus = true;
160  receivingSysex = false;
161  elapsedDataBytes= 0;
162  messages.resize(100); // 100 is the number of messages that can be buffered
163  writePointer = 0;
164  readPointer = 0;
165  callbackEnabled = false;
166  messageReadyCallback = NULL;
167  callbackArg = NULL;
168  }
169 
178  int parse(midi_byte_t* input, unsigned int length);
179 
197  void setCallback(void (*newCallback)(MidiChannelMessage, void*), void* arg=NULL){
198  callbackArg = arg;
199  messageReadyCallback = newCallback;
200  if(newCallback != NULL){
201  callbackEnabled = true;
202  } else {
203  callbackEnabled = false;
204  }
205  };
206 
213  return callbackEnabled;
214  };
215 
223  int num = (writePointer - readPointer + messages.size() ) % messages.size();
224  return num;
225  }
226 
236  MidiChannelMessage message;
237  message = messages[readPointer];
238  if(message.getType() == kmmNone){
239  message.clear();
240  }
241  messages[readPointer].setType(kmmNone); // do not use it again
242  readPointer++;
243  if(readPointer == messages.size()){
244  readPointer = 0;
245  }
246  return message;
247  };
248 
249 // MidiChannelMessage getNextChannelMessage(){
250 // getNextChannelMessage(kmmAny);
251 // }
252 // MidiControlChangeMessage* getNextControlChangeMessage(){
253 // return (MidiControlChangeMessage*)getNextChannelMessage(kmmControlChange);
254 // };
255 // MidiProgramChangeMessage* getNextProgramChangeMessage(){
256 // return (MidiProgramChangeMessage*)getNextChannelMessage(kmmProgramChange);
257 // };
258 // MidiNoteMessage* getNextNoteOnMessage(){
259 // return (MidiNoteMessage*)getNextChannelMessage(kmmNoteOn);
260 // };
261 };
262 
263 
264 class Midi {
265 public:
266  Midi();
267 
276  void enableParser(bool enable);
277 
284 
294  void setParserCallback(void (*callback)(MidiChannelMessage, void*), void* arg=NULL){
295  // if callback is not NULL, also enable the parser
296  enableParser(callback != NULL); //this needs to be first, as it deletes the parser(if exists)
297  getParser()->setCallback(callback, arg);
298  }
299 
305  int readFrom(const char* port);
306 
312  int writeTo(const char* port);
313 
319  int getInput();
320 
326  int writeOutput(midi_byte_t byte);
327 
334  int writeOutput(midi_byte_t* bytes, unsigned int length);
335 
336 
337  static midi_byte_t makeStatusByte(midi_byte_t statusCode, midi_byte_t dataByte);
338  int writeMessage(midi_byte_t statusCode, midi_byte_t channel, midi_byte_t dataByte);
339  int writeMessage(midi_byte_t statusCode, midi_byte_t channel, midi_byte_t dataByte1, midi_byte_t dataByte2);
340  int writeNoteOff(midi_byte_t channel, midi_byte_t pitch, midi_byte_t velocity);
341  int writeNoteOn(midi_byte_t channel, midi_byte_t pitch, midi_byte_t velocity);
342  int writePolyphonicKeyPressure(midi_byte_t channel, midi_byte_t pitch, midi_byte_t pressure);
343  int writeControlChange(midi_byte_t channel, midi_byte_t controller, midi_byte_t value);
344  int writeProgramChange(midi_byte_t channel, midi_byte_t program);
345  int writeChannelPressure(midi_byte_t channel, midi_byte_t pressure);
346  int writePitchBend(midi_byte_t channel, uint16_t bend);
347 
354  virtual ~Midi();
355 
356  bool isInputEnabled();
357 
358  bool isOutputEnabled();
359 
364  static void createAllPorts(std::vector<Midi*>& ports, bool useParser = false);
365 
369  static void destroyPorts(std::vector<Midi*>& ports);
370 private:
371  char defaultPort[9];
372  int _getInput();
373  static void readInputLoop(void* obj) ;
374  static void writeOutputLoop(void* obj);
375  snd_rawmidi_t *alsaIn,*alsaOut;
376  std::vector<midi_byte_t> inputBytes;
377  unsigned int inputBytesWritePointer;
378  unsigned int inputBytesReadPointer;
379  std::vector<midi_byte_t> outputBytes;
380  MidiParser* inputParser;
381  bool parserEnabled;
382  bool inputEnabled;
383  bool outputEnabled;
384  AuxiliaryTask midiInputTask;
385  AuxiliaryTask midiOutputTask;
386  char* inId;
387  char* outId;
388  char* outPipeName;
389 #ifdef XENOMAI_SKIN_native
390  RT_PIPE outPipe;
391 #endif
392 #ifdef XENOMAI_SKIN_posix
393  int sock;
394 #endif
395 };
396 
397 
398 #endif /* MIDI_H_ */
MidiParser * getMidiParser()
Definition: Midi.h:146
int numAvailableMessages()
Definition: Midi.h:222
MidiParser * getParser()
void enableParser(bool enable)
static void createAllPorts(std::vector< Midi * > &ports, bool useParser=false)
bool isCallbackEnabled()
Definition: Midi.h:212
Definition: Midi.h:37
int writeTo(const char *port)
Definition: Midi.h:264
int parse(midi_byte_t *input, unsigned int length)
int writeOutput(midi_byte_t byte)
MidiChannelMessage getNextChannelMessage()
Definition: Midi.h:235
void setParserCallback(void(*callback)(MidiChannelMessage, void *), void *arg=NULL)
Definition: Midi.h:294
static void destroyPorts(std::vector< Midi * > &ports)
int readFrom(const char *port)
int getInput()
Main Bela public API.
void * AuxiliaryTask
Definition: Bela.h:445
void setCallback(void(*newCallback)(MidiChannelMessage, void *), void *arg=NULL)
Definition: Midi.h:197