annotate include/Midi.h @ 226:af1e662400fc mergingClockSync

Added argument to callback
author Giulio Moro <giuliomoro@yahoo.it>
date Sun, 13 Mar 2016 03:31:19 +0000
parents 444f6028d6b1
children 6ca9b3f557bf
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@181 11 #include <BeagleRT.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 if(num > 0){
giuliomoro@197 188 int a = a +1;
giuliomoro@224 189 a = readPointer;
giuliomoro@197 190 }
giuliomoro@197 191 return num;
giuliomoro@197 192 }
giuliomoro@225 193
giuliomoro@197 194 /**
giuliomoro@197 195 * Get the oldest channel message in the buffer.
giuliomoro@197 196 *
giuliomoro@199 197 * If this method is called when numAvailableMessages()==0, then
giuliomoro@199 198 * a message with all fields set to zero is returned.
giuliomoro@225 199 *
giuliomoro@197 200 * @param type the type of the message to retrieve
giuliomoro@225 201 *
giuliomoro@197 202 * @return a copy of the oldest message of the give type in the buffer
giuliomoro@197 203 */
giuliomoro@197 204 MidiChannelMessage getNextChannelMessage(/*MidiMessageType type*/){
giuliomoro@197 205 MidiChannelMessage message;
giuliomoro@197 206 message = messages[readPointer];
giuliomoro@197 207 if(message.getType() == kmmNone){
giuliomoro@197 208 message.clear();
giuliomoro@197 209 }
giuliomoro@197 210 messages[readPointer].setType(kmmNone); // do not use it again
giuliomoro@197 211 readPointer++;
giuliomoro@197 212 if(readPointer == messages.size()){
giuliomoro@197 213 readPointer = 0;
giuliomoro@197 214 }
giuliomoro@197 215 return message;
giuliomoro@197 216 };
giuliomoro@197 217
giuliomoro@197 218 // MidiChannelMessage getNextChannelMessage(){
giuliomoro@197 219 // getNextChannelMessage(kmmAny);
giuliomoro@197 220 // }
giuliomoro@197 221 // MidiControlChangeMessage* getNextControlChangeMessage(){
giuliomoro@197 222 // return (MidiControlChangeMessage*)getNextChannelMessage(kmmControlChange);
giuliomoro@197 223 // };
giuliomoro@197 224 // MidiProgramChangeMessage* getNextProgramChangeMessage(){
giuliomoro@197 225 // return (MidiProgramChangeMessage*)getNextChannelMessage(kmmProgramChange);
giuliomoro@197 226 // };
giuliomoro@197 227 // MidiNoteMessage* getNextNoteOnMessage(){
giuliomoro@197 228 // return (MidiNoteMessage*)getNextChannelMessage(kmmNoteOn);
giuliomoro@197 229 // };
giuliomoro@197 230 };
giuliomoro@197 231
giuliomoro@197 232
giuliomoro@181 233 class Midi {
giuliomoro@181 234 public:
giuliomoro@181 235 Midi();
giuliomoro@197 236
giuliomoro@197 237 /**
giuliomoro@197 238 * Enable the input MidiParser.
giuliomoro@197 239 *
giuliomoro@199 240 * If the parser is enabled, getInput() will return an error code.
giuliomoro@197 241 * Midi messages should instead be retrieved via, e.g.: getMidiParser()->getNextChannelMessage();
giuliomoro@197 242 *
giuliomoro@197 243 * @param enable true to enable the input MidiParser, false to disable it.
giuliomoro@197 244 */
giuliomoro@197 245 void enableParser(bool enable);
giuliomoro@197 246
giuliomoro@197 247 /**
giuliomoro@197 248 * Get access to the input parser in use, if any.
giuliomoro@197 249 *
giuliomoro@197 250 * @return a pointer to the instance of MidiParser, if currently enabled, zero otherwise.
giuliomoro@197 251 */
giuliomoro@197 252 MidiParser* getParser();
giuliomoro@197 253
giuliomoro@225 254 /**
giuliomoro@225 255 * Sets the callback to call when a new MidiChannelMessage is available
giuliomoro@225 256 * from the input port.
giuliomoro@225 257 *
giuliomoro@225 258 * Internally, it calls enableParser() and the MidiParser::setCallback();
giuliomoro@225 259 *
giuliomoro@226 260 * @param newCallback the callback function.
giuliomoro@226 261 * @param arg the second argument to be passed to the callback function.
giuliomoro@225 262 */
giuliomoro@226 263 void setParserCallback(void (*callback)(MidiChannelMessage, void*), void* arg=NULL){
giuliomoro@224 264 // if callback is not NULL, also enable the parser
giuliomoro@224 265 enableParser(callback != NULL); //this needs to be first, as it deletes the parser(if exists)
giuliomoro@226 266 getParser()->setCallback(callback, arg);
giuliomoro@224 267 }
giuliomoro@224 268
giuliomoro@181 269 /**
giuliomoro@181 270 * Open the specified input Midi port and start reading from it.
giuliomoro@181 271 * @param port Midi port to open
giuliomoro@181 272 * @return 1 on success, -1 on failure
giuliomoro@181 273 */
giuliomoro@181 274 int readFrom(int port);
giuliomoro@181 275 /**
giuliomoro@181 276 * Open the specified output Midi port and prepares to write to it.
giuliomoro@181 277 * @param port Midi port to open
giuliomoro@181 278 * @return 1 on success, -1 on failure
giuliomoro@181 279 */
giuliomoro@181 280 int writeTo(int port);
giuliomoro@181 281
giuliomoro@181 282 /**
giuliomoro@191 283 * Get received midi bytes, one at a time.
giuliomoro@181 284 * @return -1 if no new byte is available, -2 on error,
giuliomoro@181 285 * the oldest not yet retrieved midi byte otherwise
giuliomoro@181 286 */
giuliomoro@181 287 int getInput();
giuliomoro@181 288
giuliomoro@181 289 /**
giuliomoro@181 290 * Writes a Midi byte to the output port
giuliomoro@181 291 * @param byte the Midi byte to write
giuliomoro@181 292 * @return 1 on success, -1 on error
giuliomoro@181 293 */
giuliomoro@181 294 int writeOutput(midi_byte_t byte);
giuliomoro@181 295
giuliomoro@181 296 /**
giuliomoro@181 297 * Writes Midi bytes to the output port
giuliomoro@181 298 * @param bytes an array of bytes to be written
giuliomoro@181 299 * @param length number of bytes to write
giuliomoro@181 300 * @return 1 on success, -1 on error
giuliomoro@181 301 */
giuliomoro@191 302 int writeOutput(midi_byte_t* bytes, unsigned int length);
giuliomoro@197 303 /**
giuliomoro@197 304 * Gives access to the midi parser, if it has been activated.
giuliomoro@197 305 *
giuliomoro@197 306 * @return a pointer to the midi parser if active, zero otherwise
giuliomoro@197 307 */
giuliomoro@197 308 MidiParser* getMidiParser();
giuliomoro@181 309 virtual ~Midi();
giuliomoro@181 310 static void midiInputLoop();
giuliomoro@191 311 static void midiOutputLoop();
giuliomoro@181 312 static bool staticConstructed;
giuliomoro@181 313 static void staticConstructor();
giuliomoro@181 314 private:
giuliomoro@199 315 int _getInput();
giuliomoro@181 316 void readInputLoop();
giuliomoro@191 317 void writeOutputLoop();
giuliomoro@181 318 int outputPort;
giuliomoro@181 319 int inputPort;
giuliomoro@181 320 std::vector<midi_byte_t> inputBytes;
giuliomoro@181 321 unsigned int inputBytesWritePointer;
giuliomoro@181 322 unsigned int inputBytesReadPointer;
giuliomoro@181 323 std::vector<midi_byte_t> outputBytes;
giuliomoro@191 324 unsigned int outputBytesWritePointer;
giuliomoro@191 325 unsigned int outputBytesReadPointer;
giuliomoro@197 326 MidiParser* inputParser;
giuliomoro@197 327 bool parserEnabled;
giuliomoro@191 328 static std::vector<Midi*> objAddrs[2];
giuliomoro@181 329 static AuxiliaryTask midiInputTask;
giuliomoro@181 330 static AuxiliaryTask midiOutputTask;
giuliomoro@181 331 };
giuliomoro@181 332
giuliomoro@181 333
giuliomoro@181 334 #endif /* MIDI_H_ */