annotate include/Midi.h @ 224:97faaf985164 mergingClockSync

Added callback for Midi channel messages
author Giulio Moro <giuliomoro@yahoo.it>
date Tue, 08 Mar 2016 15:49:42 +0000
parents 869f5e703844
children 444f6028d6b1
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@224 118 void (*messageReadyCallback)(MidiChannelMessage);
giuliomoro@224 119 bool callbackEnabled;
giuliomoro@197 120 public:
giuliomoro@197 121 MidiParser(){
giuliomoro@197 122 waitingForStatus = true;
giuliomoro@197 123 elapsedDataBytes= 0;
giuliomoro@197 124 messages.resize(100); // 100 is the number of messages that can be buffered
giuliomoro@197 125 writePointer = 0;
giuliomoro@197 126 readPointer = 0;
giuliomoro@224 127 callbackEnabled = false;
giuliomoro@224 128 messageReadyCallback = NULL;
giuliomoro@197 129 }
giuliomoro@197 130
giuliomoro@197 131 /**
giuliomoro@197 132 * Parses some midi messages.
giuliomoro@197 133 *
giuliomoro@197 134 * @param input the array to read from
giuliomoro@197 135 * @param length the maximum number of values available at the array
giuliomoro@197 136 *
giuliomoro@197 137 * @return the number of bytes parsed
giuliomoro@197 138 */
giuliomoro@197 139 int parse(midi_byte_t* input, unsigned int length);
giuliomoro@224 140
giuliomoro@224 141 void setCallback(void (*newCallback)(MidiChannelMessage)){
giuliomoro@224 142 messageReadyCallback = newCallback;
giuliomoro@224 143 if(newCallback != NULL){
giuliomoro@224 144 callbackEnabled = true;
giuliomoro@224 145 } else {
giuliomoro@224 146 callbackEnabled = false;
giuliomoro@224 147 }
giuliomoro@197 148 };
giuliomoro@224 149
giuliomoro@224 150 bool isCallbackEnabled(){
giuliomoro@224 151 return callbackEnabled;
giuliomoro@224 152 };
giuliomoro@224 153
giuliomoro@197 154 int numAvailableMessages(){
giuliomoro@197 155 int num = (writePointer - readPointer + messages.size() ) % messages.size();
giuliomoro@197 156 if(num > 0){
giuliomoro@197 157 int a = a +1;
giuliomoro@224 158 a = readPointer;
giuliomoro@197 159 }
giuliomoro@197 160 return num;
giuliomoro@197 161 }
giuliomoro@197 162 /**
giuliomoro@197 163 * Get the oldest channel message in the buffer.
giuliomoro@197 164 *
giuliomoro@199 165 * If this method is called when numAvailableMessages()==0, then
giuliomoro@199 166 * a message with all fields set to zero is returned.
giuliomoro@197 167 * @param type the type of the message to retrieve
giuliomoro@197 168 * @return a copy of the oldest message of the give type in the buffer
giuliomoro@197 169 */
giuliomoro@197 170 MidiChannelMessage getNextChannelMessage(/*MidiMessageType type*/){
giuliomoro@197 171 MidiChannelMessage message;
giuliomoro@197 172 message = messages[readPointer];
giuliomoro@197 173 if(message.getType() == kmmNone){
giuliomoro@197 174 message.clear();
giuliomoro@197 175 }
giuliomoro@197 176 messages[readPointer].setType(kmmNone); // do not use it again
giuliomoro@197 177 readPointer++;
giuliomoro@197 178 if(readPointer == messages.size()){
giuliomoro@197 179 readPointer = 0;
giuliomoro@197 180 }
giuliomoro@197 181 return message;
giuliomoro@197 182 };
giuliomoro@197 183
giuliomoro@197 184 // MidiChannelMessage getNextChannelMessage(){
giuliomoro@197 185 // getNextChannelMessage(kmmAny);
giuliomoro@197 186 // }
giuliomoro@197 187 // MidiControlChangeMessage* getNextControlChangeMessage(){
giuliomoro@197 188 // return (MidiControlChangeMessage*)getNextChannelMessage(kmmControlChange);
giuliomoro@197 189 // };
giuliomoro@197 190 // MidiProgramChangeMessage* getNextProgramChangeMessage(){
giuliomoro@197 191 // return (MidiProgramChangeMessage*)getNextChannelMessage(kmmProgramChange);
giuliomoro@197 192 // };
giuliomoro@197 193 // MidiNoteMessage* getNextNoteOnMessage(){
giuliomoro@197 194 // return (MidiNoteMessage*)getNextChannelMessage(kmmNoteOn);
giuliomoro@197 195 // };
giuliomoro@197 196 };
giuliomoro@197 197
giuliomoro@197 198
giuliomoro@181 199 class Midi {
giuliomoro@181 200 public:
giuliomoro@181 201 Midi();
giuliomoro@197 202
giuliomoro@197 203 /**
giuliomoro@197 204 * Enable the input MidiParser.
giuliomoro@197 205 *
giuliomoro@199 206 * If the parser is enabled, getInput() will return an error code.
giuliomoro@197 207 * Midi messages should instead be retrieved via, e.g.: getMidiParser()->getNextChannelMessage();
giuliomoro@197 208 *
giuliomoro@197 209 * @param enable true to enable the input MidiParser, false to disable it.
giuliomoro@197 210 */
giuliomoro@197 211 void enableParser(bool enable);
giuliomoro@197 212
giuliomoro@197 213 /**
giuliomoro@197 214 * Get access to the input parser in use, if any.
giuliomoro@197 215 *
giuliomoro@197 216 * @return a pointer to the instance of MidiParser, if currently enabled, zero otherwise.
giuliomoro@197 217 */
giuliomoro@197 218 MidiParser* getParser();
giuliomoro@197 219
giuliomoro@224 220 void setParserCallback(void (*callback)(MidiChannelMessage)){
giuliomoro@224 221 // if callback is not NULL, also enable the parser
giuliomoro@224 222 enableParser(callback != NULL); //this needs to be first, as it deletes the parser(if exists)
giuliomoro@224 223 getParser()->setCallback(callback);
giuliomoro@224 224 }
giuliomoro@224 225
giuliomoro@181 226 /**
giuliomoro@181 227 * Open the specified input Midi port and start reading from it.
giuliomoro@181 228 * @param port Midi port to open
giuliomoro@181 229 * @return 1 on success, -1 on failure
giuliomoro@181 230 */
giuliomoro@181 231 int readFrom(int port);
giuliomoro@181 232 /**
giuliomoro@181 233 * Open the specified output Midi port and prepares to write to it.
giuliomoro@181 234 * @param port Midi port to open
giuliomoro@181 235 * @return 1 on success, -1 on failure
giuliomoro@181 236 */
giuliomoro@181 237 int writeTo(int port);
giuliomoro@181 238
giuliomoro@181 239 /**
giuliomoro@191 240 * Get received midi bytes, one at a time.
giuliomoro@181 241 * @return -1 if no new byte is available, -2 on error,
giuliomoro@181 242 * the oldest not yet retrieved midi byte otherwise
giuliomoro@181 243 */
giuliomoro@181 244 int getInput();
giuliomoro@181 245
giuliomoro@181 246 /**
giuliomoro@181 247 * Writes a Midi byte to the output port
giuliomoro@181 248 * @param byte the Midi byte to write
giuliomoro@181 249 * @return 1 on success, -1 on error
giuliomoro@181 250 */
giuliomoro@181 251 int writeOutput(midi_byte_t byte);
giuliomoro@181 252
giuliomoro@181 253 /**
giuliomoro@181 254 * Writes Midi bytes to the output port
giuliomoro@181 255 * @param bytes an array of bytes to be written
giuliomoro@181 256 * @param length number of bytes to write
giuliomoro@181 257 * @return 1 on success, -1 on error
giuliomoro@181 258 */
giuliomoro@191 259 int writeOutput(midi_byte_t* bytes, unsigned int length);
giuliomoro@197 260 /**
giuliomoro@197 261 * Gives access to the midi parser, if it has been activated.
giuliomoro@197 262 *
giuliomoro@197 263 * @return a pointer to the midi parser if active, zero otherwise
giuliomoro@197 264 */
giuliomoro@197 265 MidiParser* getMidiParser();
giuliomoro@181 266 virtual ~Midi();
giuliomoro@181 267 static void midiInputLoop();
giuliomoro@191 268 static void midiOutputLoop();
giuliomoro@181 269 static bool staticConstructed;
giuliomoro@181 270 static void staticConstructor();
giuliomoro@181 271 private:
giuliomoro@199 272 int _getInput();
giuliomoro@181 273 void readInputLoop();
giuliomoro@191 274 void writeOutputLoop();
giuliomoro@181 275 int outputPort;
giuliomoro@181 276 int inputPort;
giuliomoro@181 277 std::vector<midi_byte_t> inputBytes;
giuliomoro@181 278 unsigned int inputBytesWritePointer;
giuliomoro@181 279 unsigned int inputBytesReadPointer;
giuliomoro@181 280 std::vector<midi_byte_t> outputBytes;
giuliomoro@191 281 unsigned int outputBytesWritePointer;
giuliomoro@191 282 unsigned int outputBytesReadPointer;
giuliomoro@197 283 MidiParser* inputParser;
giuliomoro@197 284 bool parserEnabled;
giuliomoro@191 285 static std::vector<Midi*> objAddrs[2];
giuliomoro@181 286 static AuxiliaryTask midiInputTask;
giuliomoro@181 287 static AuxiliaryTask midiOutputTask;
giuliomoro@181 288 };
giuliomoro@181 289
giuliomoro@181 290
giuliomoro@181 291 #endif /* MIDI_H_ */