Bela
Real-time, ultra-low-latency audio and sensor processing system for BeagleBone Black
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator 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 #include <string>
15 #ifdef XENOMAI_SKIN_native
16 #include <native/pipe.h>
17 #endif
18 
19 typedef unsigned char midi_byte_t;
20 
21 typedef enum midiMessageType{
22  kmmNoteOff = 0,
23  kmmNoteOn,
24  kmmPolyphonicKeyPressure,
25  kmmControlChange,
26  kmmProgramChange,
27  kmmChannelPressure,
28  kmmPitchBend,
29  kmmSystem,
30  kmmNone,
31  kmmAny,
32 } MidiMessageType;
33 #define midiMessageStatusBytesLength 8+2 //2 being kmmNone and kmmAny
34 
35 extern midi_byte_t midiMessageStatusBytes[midiMessageStatusBytesLength];
36 extern unsigned int midiMessageNumDataBytes[midiMessageStatusBytesLength];
37 
39 public:
41  MidiChannelMessage(MidiMessageType type);
42  midi_byte_t getStatusByte() const {
43  return _statusByte;
44  }
45  virtual ~MidiChannelMessage();
46  MidiMessageType getType() const;
47  int getChannel() const;
48  const char* getTypeText() const {
49  return getTypeText(getType());
50  }
51  static const char* getTypeText(MidiMessageType type){
52  switch (type) {
53  case kmmNoteOff:
54  return "note off";
55  case kmmNoteOn:
56  return "note on";
57  case kmmPolyphonicKeyPressure:
58  return "polyphonic aftertouch";
59  case kmmControlChange:
60  return "control change";
61  case kmmProgramChange:
62  return "program change";
63  case kmmChannelPressure:
64  return "channel aftertouch";
65  case kmmPitchBend:
66  return "pitch bend";
67  case kmmSystem:
68  return "system";
69  case kmmAny:
70  return "any";
71  case kmmNone:
72  default:
73  return "none";
74  }
75  }
76 
77  unsigned int getNumDataBytes() const {
78  return midiMessageNumDataBytes[(unsigned int)_type];
79  }
80  void setDataByte(unsigned int dataByteIndex, midi_byte_t input){
81  _dataBytes[dataByteIndex] = input;
82  }
83  void setType(MidiMessageType type){
84  _type = type;
85  _statusByte = midiMessageStatusBytes[_type];
86  }
87  void setChannel(midi_byte_t channel){
88  _channel = channel;
89  }
90  midi_byte_t getDataByte(unsigned int index) const {
91  return _dataBytes[index];
92  }
93  void clear(){
94  for(int n = 0; n<maxDataBytes; n++){
95  _dataBytes[n] = 0;
96  }
97  _type = kmmNone;
98  _statusByte = 0;
99  }
100  void prettyPrint() const {
101  rt_printf("type: %s, ", this->getTypeText());
102  rt_printf("channel: %u, ", this->getChannel());
103  for(unsigned int n = 0; n < this->getNumDataBytes(); n++){
104  rt_printf("data%d: %d, ", n + 1, this->getDataByte(n));
105  }
106  rt_printf("\n");
107  }
108 private:
109  const static int maxDataBytes = 2;
110 protected:
111  midi_byte_t _statusByte;
112  midi_byte_t _dataBytes[maxDataBytes]; // where 2 is the maximum number of data bytes for a channel message
113  MidiMessageType _type;
114  midi_byte_t _channel;
115 };
116 /*
117 class MidiControlChangeMessage : public MidiChannelMessage{
118  int number;
119  int value;
120 public:
121  int getNumber();
122  int getNumDataBytes();
123  int setDataByte(midi_byte_t input, unsigned int dataByteIndex);
124  int getValue();
125  int set(midi_byte_t* input);
126 };
127 
128 class MidiNoteMessage : public MidiChannelMessage{
129  int note;
130  int velocity;
131 public:
132  int getNote();
133  int getVelocity();
134  int getNumDataBytes();
135  int setDataByte(midi_byte_t input, unsigned int dataByteIndex);
136 };
137 
138 class MidiProgramChangeMessage : public MidiChannelMessage{
139  midi_byte_t program;
140 public:
141  int getNumDataBytes();
142  int setDataByte(midi_byte_t input, unsigned int dataByteIndex);
143  midi_byte_t getProgram();
144 };
145 */
146 
148 private:
149  std::vector<MidiChannelMessage> messages;
150  unsigned int writePointer;
151  unsigned int readPointer;
152  unsigned int elapsedDataBytes;
153  bool waitingForStatus;
154  bool receivingSysex;
155  void (*messageReadyCallback)(MidiChannelMessage,void*);
156  void* callbackArg;
157  void (*sysexCallback)(midi_byte_t,void*);
158  void* sysexCallbackArg;
159 public:
160  MidiParser(){
161  waitingForStatus = true;
162  receivingSysex = false;
163  elapsedDataBytes= 0;
164  messages.resize(100); // 100 is the number of messages that can be buffered
165  writePointer = 0;
166  readPointer = 0;
167  messageReadyCallback = nullptr;
168  callbackArg = nullptr;
169  sysexCallback = nullptr;
170  sysexCallbackArg = nullptr;
171  }
172 
181  int parse(midi_byte_t* input, unsigned int length);
182 
200  void setCallback(void (*newCallback)(MidiChannelMessage, void*), void* arg=NULL){
201  callbackArg = arg;
202  messageReadyCallback = newCallback;
203  };
204 
211  return messageReadyCallback != nullptr;
212  };
213 
230  void setSysexCallback(void (*newCallback)(midi_byte_t, void*), void* arg=nullptr){
231  sysexCallbackArg = arg;
232  sysexCallback = newCallback;
233  };
234 
241  return sysexCallback != nullptr;
242  };
243 
250  int num = (writePointer - readPointer + messages.size() ) % messages.size();
251  return num;
252  }
253 
263  MidiChannelMessage message;
264  message = messages[readPointer];
265  if(message.getType() == kmmNone){
266  message.clear();
267  }
268  messages[readPointer].setType(kmmNone); // do not use it again
269  readPointer++;
270  if(readPointer == messages.size()){
271  readPointer = 0;
272  }
273  return message;
274  };
275 
276 // MidiChannelMessage getNextChannelMessage(){
277 // getNextChannelMessage(kmmAny);
278 // }
279 // MidiControlChangeMessage* getNextControlChangeMessage(){
280 // return (MidiControlChangeMessage*)getNextChannelMessage(kmmControlChange);
281 // };
282 // MidiProgramChangeMessage* getNextProgramChangeMessage(){
283 // return (MidiProgramChangeMessage*)getNextChannelMessage(kmmProgramChange);
284 // };
285 // MidiNoteMessage* getNextNoteOnMessage(){
286 // return (MidiNoteMessage*)getNextChannelMessage(kmmNoteOn);
287 // };
288 };
289 
290 
291 class Midi {
292 public:
293  Midi();
294  void setup();
295  void cleanup();
304  void enableParser(bool enable);
305 
312 
322  void setParserCallback(void (*callback)(MidiChannelMessage, void*), void* arg=NULL){
323  // if callback is not NULL, also enable the parser
324  enableParser(callback != NULL); //this needs to be first, as it deletes the parser(if exists)
325  getParser()->setCallback(callback, arg);
326  }
327 
333  int readFrom(const char* port);
334 
340  int writeTo(const char* port);
341 
347  int getInput();
348 
354  int writeOutput(midi_byte_t byte);
355 
362  int writeOutput(midi_byte_t* bytes, unsigned int length);
363 
364 
365  static midi_byte_t makeStatusByte(midi_byte_t statusCode, midi_byte_t dataByte);
366  int writeMessage(midi_byte_t statusCode, midi_byte_t channel, midi_byte_t dataByte);
367  int writeMessage(midi_byte_t statusCode, midi_byte_t channel, midi_byte_t dataByte1, midi_byte_t dataByte2);
368  int writeMessage(const MidiChannelMessage& msg);
369  int writeNoteOff(midi_byte_t channel, midi_byte_t pitch, midi_byte_t velocity);
370  int writeNoteOn(midi_byte_t channel, midi_byte_t pitch, midi_byte_t velocity);
371  int writePolyphonicKeyPressure(midi_byte_t channel, midi_byte_t pitch, midi_byte_t pressure);
372  int writeControlChange(midi_byte_t channel, midi_byte_t controller, midi_byte_t value);
373  int writeProgramChange(midi_byte_t channel, midi_byte_t program);
374  int writeChannelPressure(midi_byte_t channel, midi_byte_t pressure);
375  int writePitchBend(midi_byte_t channel, uint16_t bend);
376 
383  virtual ~Midi();
384 
385  bool isInputEnabled();
386 
387  bool isOutputEnabled();
388 
393  static void createAllPorts(std::vector<Midi*>& ports, bool useParser = false);
394 
398  static void destroyPorts(std::vector<Midi*>& ports);
399 private:
400  char defaultPort[9];
401  std::string inPort;
402  std::string outPort;
403  int _getInput();
404  int attemptRecoveryRead();
405  static void readInputLoop(void* obj);
406  int attemptRecoveryWrite();
407  static void writeOutputLoop(void* obj);
408  snd_rawmidi_t *alsaIn,*alsaOut;
409  std::vector<midi_byte_t> inputBytes;
410  unsigned int inputBytesWritePointer;
411  unsigned int inputBytesReadPointer;
412  std::vector<midi_byte_t> outputBytes;
413  MidiParser* inputParser;
414  bool parserEnabled;
415  bool inputEnabled;
416  bool outputEnabled;
417  AuxiliaryTask midiInputTask;
418  AuxiliaryTask midiOutputTask;
419  char* inId;
420  char* outId;
421  char* outPipeName;
422 #ifdef XENOMAI_SKIN_native
423  RT_PIPE outPipe;
424 #endif
425 #ifdef XENOMAI_SKIN_posix
426  int sock;
427 #endif
428 };
429 
430 
431 #endif /* MIDI_H_ */
static void createAllPorts(std::vector< Midi * > &ports, bool useParser=false)
Definition: Midi.cpp:365
MidiParser * getMidiParser()
Definition: Midi.h:147
int numAvailableMessages()
Definition: Midi.h:249
void setSysexCallback(void(*newCallback)(midi_byte_t, void *), void *arg=nullptr)
Definition: Midi.h:230
void enableParser(bool enable)
Definition: Midi.cpp:147
bool isCallbackEnabled()
Definition: Midi.h:210
MidiParser * getParser()
Definition: Midi.cpp:468
Definition: Midi.h:38
int writeTo(const char *port)
Definition: Midi.cpp:321
Definition: Midi.h:291
int parse(midi_byte_t *input, unsigned int length)
Definition: Midi.cpp:38
int writeOutput(midi_byte_t byte)
Definition: Midi.cpp:475
bool isSysexCallbackEnabled()
Definition: Midi.h:240
MidiChannelMessage getNextChannelMessage()
Definition: Midi.h:262
void setParserCallback(void(*callback)(MidiChannelMessage, void *), void *arg=NULL)
Definition: Midi.h:322
static void destroyPorts(std::vector< Midi * > &ports)
int readFrom(const char *port)
Definition: Midi.cpp:302
int getInput()
Definition: Midi.cpp:461
Main Bela public API.
void * AuxiliaryTask
Definition: Bela.h:492
void setCallback(void(*newCallback)(MidiChannelMessage, void *), void *arg=NULL)
Definition: Midi.h:200