annotate include/Midi.h @ 199:b128e3ea84ff

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