annotate include/Midi.h @ 301:e4392164b458 prerelease

RENAMED BeagleRT to Bela AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA, scripts probably not working
author Giulio Moro <giuliomoro@yahoo.it>
date Fri, 27 May 2016 14:34:41 +0100
parents 6ca9b3f557bf
children a9905703219d
rev   line source
giuliomoro@181 1 /*
giuliomoro@181 2 * Midi.h
giuliomoro@181 3 *
giuliomoro@181 4 * Created on: 15 Jan 2016
giuliomoro@181 5 * Author: giulio
giuliomoro@181 6 */
giuliomoro@181 7
giuliomoro@181 8 #ifndef MIDI_H_
giuliomoro@181 9 #define MIDI_H_
giuliomoro@181 10
giuliomoro@301 11 #include <Bela.h>
giuliomoro@181 12 #include <vector>
giuliomoro@181 13
giuliomoro@181 14 typedef unsigned char midi_byte_t;
giuliomoro@181 15
giuliomoro@197 16
giuliomoro@197 17 typedef enum midiMessageType{
giuliomoro@197 18 kmmNoteOff = 0,
giuliomoro@197 19 kmmNoteOn,
giuliomoro@197 20 kmmPolyphonicKeyPressure,
giuliomoro@197 21 kmmControlChange,
giuliomoro@197 22 kmmProgramChange,
giuliomoro@197 23 kmmChannelPressure,
giuliomoro@197 24 kmmPitchBend,
giuliomoro@197 25 kmmNone,
giuliomoro@197 26 kmmAny,
giuliomoro@197 27 } MidiMessageType;
giuliomoro@197 28 #define midiMessageStatusBytesLength 7+2 //2 being kmmNone and kmmAny
giuliomoro@197 29
giuliomoro@197 30 extern midi_byte_t midiMessageStatusBytes[midiMessageStatusBytesLength];
giuliomoro@197 31 extern unsigned int midiMessageNumDataBytes[midiMessageStatusBytesLength];
giuliomoro@197 32
giuliomoro@197 33 class MidiChannelMessage{
giuliomoro@197 34 public:
giuliomoro@197 35 MidiChannelMessage();
giuliomoro@197 36 MidiChannelMessage(MidiMessageType type);
giuliomoro@197 37 virtual ~MidiChannelMessage();
giuliomoro@197 38 MidiMessageType getType();
giuliomoro@197 39 int getChannel();
giuliomoro@197 40 unsigned int getNumDataBytes(){
giuliomoro@197 41 return midiMessageNumDataBytes[(unsigned int)_type];
giuliomoro@197 42 }
giuliomoro@197 43 void setDataByte(unsigned int dataByteIndex, midi_byte_t input){
giuliomoro@197 44 _dataBytes[dataByteIndex] = input;
giuliomoro@197 45 }
giuliomoro@197 46 void setType(MidiMessageType type){
giuliomoro@197 47 _type = type;
giuliomoro@197 48 _statusByte = midiMessageStatusBytes[_type];
giuliomoro@197 49 }
giuliomoro@197 50 void setChannel(midi_byte_t channel){
giuliomoro@197 51 _channel = channel;
giuliomoro@197 52 }
giuliomoro@197 53 midi_byte_t getDataByte(unsigned int index){
giuliomoro@197 54 return _dataBytes[index];
giuliomoro@197 55 }
giuliomoro@197 56 void clear(){
giuliomoro@197 57 for(int n = 0; n<maxDataBytes; n++){
giuliomoro@197 58 _dataBytes[n] = 0;
giuliomoro@197 59 }
giuliomoro@197 60 _type = kmmNone;
giuliomoro@197 61 _statusByte = 0;
giuliomoro@197 62 }
giuliomoro@197 63 void prettyPrint(){
giuliomoro@197 64 rt_printf("MessageType: %x, ", this->getType());
giuliomoro@197 65 rt_printf("channel: %u, ", this->getChannel());
giuliomoro@216 66 for(unsigned int n = 0; n < this->getNumDataBytes(); n++){
giuliomoro@197 67 rt_printf("data%d: %d, ", n + 1, this->getDataByte(n));
giuliomoro@197 68 }
giuliomoro@197 69 rt_printf("\n");
giuliomoro@197 70 }
giuliomoro@197 71
giuliomoro@197 72 private:
giuliomoro@197 73 const static int maxDataBytes = 2;
giuliomoro@197 74 protected:
giuliomoro@197 75 midi_byte_t _statusByte;
giuliomoro@197 76 midi_byte_t _dataBytes[maxDataBytes]; // where 2 is the maximum number of data bytes for a channel message
giuliomoro@197 77 MidiMessageType _type;
giuliomoro@197 78 midi_byte_t _channel;
giuliomoro@197 79 };
giuliomoro@197 80 /*
giuliomoro@197 81 class MidiControlChangeMessage : public MidiChannelMessage{
giuliomoro@197 82 int number;
giuliomoro@197 83 int value;
giuliomoro@197 84 public:
giuliomoro@197 85 int getNumber();
giuliomoro@197 86 int getNumDataBytes();
giuliomoro@197 87 int setDataByte(midi_byte_t input, unsigned int dataByteIndex);
giuliomoro@197 88 int getValue();
giuliomoro@197 89 int set(midi_byte_t* input);
giuliomoro@197 90 };
giuliomoro@197 91
giuliomoro@197 92 class MidiNoteMessage : public MidiChannelMessage{
giuliomoro@197 93 int note;
giuliomoro@197 94 int velocity;
giuliomoro@197 95 public:
giuliomoro@197 96 int getNote();
giuliomoro@197 97 int getVelocity();
giuliomoro@197 98 int getNumDataBytes();
giuliomoro@197 99 int setDataByte(midi_byte_t input, unsigned int dataByteIndex);
giuliomoro@197 100 };
giuliomoro@197 101
giuliomoro@197 102 class MidiProgramChangeMessage : public MidiChannelMessage{
giuliomoro@197 103 midi_byte_t program;
giuliomoro@197 104 public:
giuliomoro@197 105 int getNumDataBytes();
giuliomoro@197 106 int setDataByte(midi_byte_t input, unsigned int dataByteIndex);
giuliomoro@197 107 midi_byte_t getProgram();
giuliomoro@197 108 };
giuliomoro@197 109 */
giuliomoro@197 110
giuliomoro@197 111 class MidiParser{
giuliomoro@197 112 private:
giuliomoro@197 113 std::vector<MidiChannelMessage> messages;
giuliomoro@197 114 unsigned int writePointer;
giuliomoro@197 115 unsigned int readPointer;
giuliomoro@197 116 unsigned int elapsedDataBytes;
giuliomoro@197 117 bool waitingForStatus;
giuliomoro@226 118 void (*messageReadyCallback)(MidiChannelMessage,void*);
giuliomoro@224 119 bool callbackEnabled;
giuliomoro@226 120 void* callbackArg;
giuliomoro@197 121 public:
giuliomoro@197 122 MidiParser(){
giuliomoro@197 123 waitingForStatus = true;
giuliomoro@197 124 elapsedDataBytes= 0;
giuliomoro@197 125 messages.resize(100); // 100 is the number of messages that can be buffered
giuliomoro@197 126 writePointer = 0;
giuliomoro@197 127 readPointer = 0;
giuliomoro@224 128 callbackEnabled = false;
giuliomoro@224 129 messageReadyCallback = NULL;
giuliomoro@226 130 callbackArg = NULL;
giuliomoro@197 131 }
giuliomoro@197 132
giuliomoro@197 133 /**
giuliomoro@197 134 * Parses some midi messages.
giuliomoro@197 135 *
giuliomoro@197 136 * @param input the array to read from
giuliomoro@197 137 * @param length the maximum number of values available at the array
giuliomoro@197 138 *
giuliomoro@197 139 * @return the number of bytes parsed
giuliomoro@197 140 */
giuliomoro@197 141 int parse(midi_byte_t* input, unsigned int length);
giuliomoro@224 142
giuliomoro@225 143 /**
giuliomoro@225 144 * Sets the callback to call when a new MidiChannelMessage is available
giuliomoro@225 145 * from the input port.
giuliomoro@225 146 *
giuliomoro@226 147 * The callback will be called with two arguments:
giuliomoro@226 148 * callback(MidiChannelMessage newMessage, void* arg)
giuliomoro@226 149 *
giuliomoro@226 150 * In order to deactivate the callback, call this method with NULL as the
giuliomoro@226 151 * first argument.
giuliomoro@225 152 * While the callback is enabled, calling numAvailableMessages() and
giuliomoro@225 153 * getNextChannelMessage() is still possible, but it will probably always
giuliomoro@225 154 * return 0 as the callback is called as soon as a new message is available.
giuliomoro@225 155 *
giuliomoro@226 156 * @param newCallback the callback function.
giuliomoro@226 157 * @param arg the second argument to be passed to the callback function.
giuliomoro@225 158 *
giuliomoro@225 159 */
giuliomoro@226 160 void setCallback(void (*newCallback)(MidiChannelMessage, void*), void* arg=NULL){
giuliomoro@226 161 callbackArg = arg;
giuliomoro@224 162 messageReadyCallback = newCallback;
giuliomoro@224 163 if(newCallback != NULL){
giuliomoro@224 164 callbackEnabled = true;
giuliomoro@224 165 } else {
giuliomoro@224 166 callbackEnabled = false;
giuliomoro@224 167 }
giuliomoro@197 168 };
giuliomoro@224 169
giuliomoro@225 170 /**
giuliomoro@225 171 * Checks whether there is a callback currently set to be called
giuliomoro@225 172 * every time a new input MidiChannelMessage is available from the
giuliomoro@225 173 * input port.
giuliomoro@225 174 */
giuliomoro@224 175 bool isCallbackEnabled(){
giuliomoro@224 176 return callbackEnabled;
giuliomoro@224 177 };
giuliomoro@224 178
giuliomoro@225 179 /**
giuliomoro@225 180 * Returns the number of unread MidiChannelMessage available from the
giuliomoro@225 181 * input port.
giuliomoro@225 182 *
giuliomoro@225 183 */
giuliomoro@225 184
giuliomoro@197 185 int numAvailableMessages(){
giuliomoro@197 186 int num = (writePointer - readPointer + messages.size() ) % messages.size();
giuliomoro@197 187 return num;
giuliomoro@197 188 }
giuliomoro@225 189
giuliomoro@197 190 /**
giuliomoro@197 191 * Get the oldest channel message in the buffer.
giuliomoro@197 192 *
giuliomoro@199 193 * If this method is called when numAvailableMessages()==0, then
giuliomoro@199 194 * a message with all fields set to zero is returned.
giuliomoro@225 195 *
giuliomoro@197 196 * @param type the type of the message to retrieve
giuliomoro@225 197 *
giuliomoro@197 198 * @return a copy of the oldest message of the give type in the buffer
giuliomoro@197 199 */
giuliomoro@197 200 MidiChannelMessage getNextChannelMessage(/*MidiMessageType type*/){
giuliomoro@197 201 MidiChannelMessage message;
giuliomoro@197 202 message = messages[readPointer];
giuliomoro@197 203 if(message.getType() == kmmNone){
giuliomoro@197 204 message.clear();
giuliomoro@197 205 }
giuliomoro@197 206 messages[readPointer].setType(kmmNone); // do not use it again
giuliomoro@197 207 readPointer++;
giuliomoro@197 208 if(readPointer == messages.size()){
giuliomoro@197 209 readPointer = 0;
giuliomoro@197 210 }
giuliomoro@197 211 return message;
giuliomoro@197 212 };
giuliomoro@197 213
giuliomoro@197 214 // MidiChannelMessage getNextChannelMessage(){
giuliomoro@197 215 // getNextChannelMessage(kmmAny);
giuliomoro@197 216 // }
giuliomoro@197 217 // MidiControlChangeMessage* getNextControlChangeMessage(){
giuliomoro@197 218 // return (MidiControlChangeMessage*)getNextChannelMessage(kmmControlChange);
giuliomoro@197 219 // };
giuliomoro@197 220 // MidiProgramChangeMessage* getNextProgramChangeMessage(){
giuliomoro@197 221 // return (MidiProgramChangeMessage*)getNextChannelMessage(kmmProgramChange);
giuliomoro@197 222 // };
giuliomoro@197 223 // MidiNoteMessage* getNextNoteOnMessage(){
giuliomoro@197 224 // return (MidiNoteMessage*)getNextChannelMessage(kmmNoteOn);
giuliomoro@197 225 // };
giuliomoro@197 226 };
giuliomoro@197 227
giuliomoro@197 228
giuliomoro@181 229 class Midi {
giuliomoro@181 230 public:
giuliomoro@181 231 Midi();
giuliomoro@197 232
giuliomoro@197 233 /**
giuliomoro@197 234 * Enable the input MidiParser.
giuliomoro@197 235 *
giuliomoro@199 236 * If the parser is enabled, getInput() will return an error code.
giuliomoro@197 237 * Midi messages should instead be retrieved via, e.g.: getMidiParser()->getNextChannelMessage();
giuliomoro@197 238 *
giuliomoro@197 239 * @param enable true to enable the input MidiParser, false to disable it.
giuliomoro@197 240 */
giuliomoro@197 241 void enableParser(bool enable);
giuliomoro@197 242
giuliomoro@197 243 /**
giuliomoro@197 244 * Get access to the input parser in use, if any.
giuliomoro@197 245 *
giuliomoro@197 246 * @return a pointer to the instance of MidiParser, if currently enabled, zero otherwise.
giuliomoro@197 247 */
giuliomoro@197 248 MidiParser* getParser();
giuliomoro@197 249
giuliomoro@225 250 /**
giuliomoro@225 251 * Sets the callback to call when a new MidiChannelMessage is available
giuliomoro@225 252 * from the input port.
giuliomoro@225 253 *
giuliomoro@225 254 * Internally, it calls enableParser() and the MidiParser::setCallback();
giuliomoro@225 255 *
giuliomoro@226 256 * @param newCallback the callback function.
giuliomoro@226 257 * @param arg the second argument to be passed to the callback function.
giuliomoro@225 258 */
giuliomoro@226 259 void setParserCallback(void (*callback)(MidiChannelMessage, void*), void* arg=NULL){
giuliomoro@224 260 // if callback is not NULL, also enable the parser
giuliomoro@224 261 enableParser(callback != NULL); //this needs to be first, as it deletes the parser(if exists)
giuliomoro@226 262 getParser()->setCallback(callback, arg);
giuliomoro@224 263 }
giuliomoro@224 264
giuliomoro@181 265 /**
giuliomoro@181 266 * Open the specified input Midi port and start reading from it.
giuliomoro@181 267 * @param port Midi port to open
giuliomoro@181 268 * @return 1 on success, -1 on failure
giuliomoro@181 269 */
giuliomoro@181 270 int readFrom(int port);
giuliomoro@181 271 /**
giuliomoro@181 272 * Open the specified output Midi port and prepares to write to it.
giuliomoro@181 273 * @param port Midi port to open
giuliomoro@181 274 * @return 1 on success, -1 on failure
giuliomoro@181 275 */
giuliomoro@181 276 int writeTo(int port);
giuliomoro@181 277
giuliomoro@181 278 /**
giuliomoro@191 279 * Get received midi bytes, one at a time.
giuliomoro@181 280 * @return -1 if no new byte is available, -2 on error,
giuliomoro@181 281 * the oldest not yet retrieved midi byte otherwise
giuliomoro@181 282 */
giuliomoro@181 283 int getInput();
giuliomoro@181 284
giuliomoro@181 285 /**
giuliomoro@181 286 * Writes a Midi byte to the output port
giuliomoro@181 287 * @param byte the Midi byte to write
giuliomoro@181 288 * @return 1 on success, -1 on error
giuliomoro@181 289 */
giuliomoro@181 290 int writeOutput(midi_byte_t byte);
giuliomoro@181 291
giuliomoro@181 292 /**
giuliomoro@181 293 * Writes Midi bytes to the output port
giuliomoro@181 294 * @param bytes an array of bytes to be written
giuliomoro@181 295 * @param length number of bytes to write
giuliomoro@181 296 * @return 1 on success, -1 on error
giuliomoro@181 297 */
giuliomoro@191 298 int writeOutput(midi_byte_t* bytes, unsigned int length);
giuliomoro@197 299 /**
giuliomoro@197 300 * Gives access to the midi parser, if it has been activated.
giuliomoro@197 301 *
giuliomoro@197 302 * @return a pointer to the midi parser if active, zero otherwise
giuliomoro@197 303 */
giuliomoro@197 304 MidiParser* getMidiParser();
giuliomoro@181 305 virtual ~Midi();
giuliomoro@181 306 static void midiInputLoop();
giuliomoro@191 307 static void midiOutputLoop();
giuliomoro@181 308 static bool staticConstructed;
giuliomoro@181 309 static void staticConstructor();
giuliomoro@181 310 private:
giuliomoro@199 311 int _getInput();
giuliomoro@181 312 void readInputLoop();
giuliomoro@191 313 void writeOutputLoop();
giuliomoro@181 314 int outputPort;
giuliomoro@181 315 int inputPort;
giuliomoro@181 316 std::vector<midi_byte_t> inputBytes;
giuliomoro@181 317 unsigned int inputBytesWritePointer;
giuliomoro@181 318 unsigned int inputBytesReadPointer;
giuliomoro@181 319 std::vector<midi_byte_t> outputBytes;
giuliomoro@191 320 unsigned int outputBytesWritePointer;
giuliomoro@191 321 unsigned int outputBytesReadPointer;
giuliomoro@197 322 MidiParser* inputParser;
giuliomoro@197 323 bool parserEnabled;
giuliomoro@191 324 static std::vector<Midi*> objAddrs[2];
giuliomoro@181 325 static AuxiliaryTask midiInputTask;
giuliomoro@181 326 static AuxiliaryTask midiOutputTask;
giuliomoro@181 327 };
giuliomoro@181 328
giuliomoro@181 329
giuliomoro@181 330 #endif /* MIDI_H_ */