annotate core/Midi.cpp @ 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 97faaf985164
rev   line source
giuliomoro@181 1 /*
giuliomoro@181 2 * Midi.cpp
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 #include "Midi.h"
giuliomoro@181 9 #include <fcntl.h>
giuliomoro@181 10 #include <errno.h>
giuliomoro@181 11
giuliomoro@191 12 #define kMidiInput 0
giuliomoro@191 13 #define kMidiOutput 1
giuliomoro@191 14
giuliomoro@197 15
giuliomoro@197 16 midi_byte_t midiMessageStatusBytes[midiMessageStatusBytesLength]=
giuliomoro@197 17 {
giuliomoro@197 18 0x80,
giuliomoro@197 19 0x90,
giuliomoro@197 20 0xA0,
giuliomoro@197 21 0xB0,
giuliomoro@197 22 0xC0,
giuliomoro@197 23 0xD0,
giuliomoro@197 24 0xE0,
giuliomoro@197 25 0
giuliomoro@197 26 };
giuliomoro@197 27
giuliomoro@197 28 unsigned int midiMessageNumDataBytes[midiMessageStatusBytesLength]={2, 2, 2, 2, 1, 1, 2, 0};
giuliomoro@197 29
giuliomoro@181 30 bool Midi::staticConstructed;
giuliomoro@181 31 AuxiliaryTask Midi::midiInputTask;
giuliomoro@181 32 AuxiliaryTask Midi::midiOutputTask;
giuliomoro@191 33 std::vector<Midi *> Midi::objAddrs[2];
giuliomoro@181 34
giuliomoro@197 35 int MidiParser::parse(midi_byte_t* input, unsigned int length){
giuliomoro@197 36 unsigned int consumedBytes = 0;
giuliomoro@197 37 for(unsigned int n = 0; n < length; n++){
giuliomoro@197 38 consumedBytes++;
giuliomoro@197 39 if(waitingForStatus == true){
giuliomoro@197 40 int statusByte = input[n];
giuliomoro@197 41 MidiMessageType newType = kmmNone;
giuliomoro@197 42 if (statusByte >= 0x80){//it actually is a status byte
giuliomoro@197 43 for(int n = 0; n < midiMessageStatusBytesLength; n++){ //find the statusByte in the array
giuliomoro@197 44 if(midiMessageStatusBytes[n] == (statusByte&0xf0)){
giuliomoro@197 45 newType = (MidiMessageType)n;
giuliomoro@197 46 break;
giuliomoro@197 47 }
giuliomoro@197 48 }
giuliomoro@197 49 elapsedDataBytes = 0;
giuliomoro@197 50 waitingForStatus = false;
giuliomoro@197 51 messages[writePointer].setType(newType);
giuliomoro@197 52 messages[writePointer].setChannel((midi_byte_t)(statusByte&0xf));
giuliomoro@197 53 consumedBytes++;
giuliomoro@197 54 } else { // either something went wrong or it's a system message
giuliomoro@197 55 continue;
giuliomoro@197 56 }
giuliomoro@197 57 } else {
giuliomoro@197 58 messages[writePointer].setDataByte(elapsedDataBytes, input[n]);
giuliomoro@197 59 elapsedDataBytes++;
giuliomoro@197 60 if(elapsedDataBytes == messages[writePointer].getNumDataBytes()){
giuliomoro@197 61 waitingForStatus = true;
giuliomoro@197 62 writePointer++;
giuliomoro@197 63 if(writePointer == messages.size()){
giuliomoro@197 64 writePointer = 0;
giuliomoro@197 65 }
giuliomoro@197 66 }
giuliomoro@197 67 }
giuliomoro@197 68 }
giuliomoro@197 69 return consumedBytes;
giuliomoro@197 70 };
giuliomoro@197 71
giuliomoro@197 72
giuliomoro@181 73 Midi::Midi(){
giuliomoro@181 74 outputPort = -1;
giuliomoro@181 75 inputPort = -1;
giuliomoro@197 76 inputParser = 0;
giuliomoro@181 77 size_t inputBytesInitialSize = 1000;
giuliomoro@181 78 inputBytes.resize(inputBytesInitialSize);
giuliomoro@191 79 outputBytes.resize(inputBytesInitialSize);
giuliomoro@181 80 inputBytesWritePointer = 0;
giuliomoro@181 81 inputBytesReadPointer = inputBytes.size() - 1;
giuliomoro@181 82 if(!staticConstructed){
giuliomoro@181 83 staticConstructor();
giuliomoro@181 84 }
giuliomoro@181 85 }
giuliomoro@181 86
giuliomoro@181 87 void Midi::staticConstructor(){
giuliomoro@181 88 staticConstructed = true;
giuliomoro@181 89 midiInputTask = BeagleRT_createAuxiliaryTask(Midi::midiInputLoop, 50, "MidiInput");
giuliomoro@191 90 midiOutputTask = BeagleRT_createAuxiliaryTask(Midi::midiOutputLoop, 50, "MidiOutupt");
giuliomoro@181 91 }
giuliomoro@181 92
giuliomoro@181 93 Midi::~Midi(){}
giuliomoro@197 94
giuliomoro@197 95 void Midi::enableParser(bool enable){
giuliomoro@197 96 if(enable == true){
giuliomoro@197 97 delete inputParser;
giuliomoro@197 98 inputParser = new MidiParser();
giuliomoro@197 99 parserEnabled = true;
giuliomoro@197 100 } else {
giuliomoro@197 101 delete inputParser;
giuliomoro@197 102 parserEnabled = false;
giuliomoro@197 103 }
giuliomoro@197 104 }
giuliomoro@197 105
giuliomoro@191 106 void Midi::midiInputLoop(){
giuliomoro@191 107 printf("Midi input loop %d\n", objAddrs[kMidiInput].size());
giuliomoro@191 108 for(unsigned int n = 0; n < objAddrs[kMidiInput].size(); n++){
giuliomoro@191 109 objAddrs[kMidiInput][n] -> readInputLoop();
giuliomoro@191 110 }
giuliomoro@191 111 }
giuliomoro@181 112
giuliomoro@191 113 void Midi::midiOutputLoop(){
giuliomoro@191 114 printf("Midi output loop %d\n", objAddrs[kMidiOutput].size());
giuliomoro@191 115 for(unsigned int n = 0; n < objAddrs[kMidiOutput].size(); n++){
giuliomoro@191 116 objAddrs[kMidiOutput][n] -> writeOutputLoop();
giuliomoro@181 117 }
giuliomoro@181 118 }
giuliomoro@181 119
giuliomoro@181 120 void Midi::readInputLoop(){
giuliomoro@181 121 while(!gShouldStop){
giuliomoro@181 122 int maxBytesToRead = inputBytes.size() - inputBytesWritePointer;
giuliomoro@181 123 int ret = read(inputPort, &inputBytes[inputBytesWritePointer], sizeof(midi_byte_t)*maxBytesToRead);
giuliomoro@181 124 if(ret < 0){
giuliomoro@181 125 if(errno != EAGAIN){ // read() would return EAGAIN when no data are available to read just now
giuliomoro@181 126 rt_printf("Error while reading midi %d\n", errno);
giuliomoro@181 127 }
giuliomoro@181 128 usleep(1000);
giuliomoro@181 129 continue;
giuliomoro@181 130 }
giuliomoro@181 131 inputBytesWritePointer += ret;
giuliomoro@181 132 if(inputBytesWritePointer == inputBytes.size()){ //wrap pointer around
giuliomoro@181 133 inputBytesWritePointer = 0;
giuliomoro@181 134 }
giuliomoro@197 135 if(parserEnabled == true && ret > 0){ // if the parser is enabled and there is new data, send the data to it
giuliomoro@197 136 int input;
giuliomoro@199 137 while((input=_getInput()) >= 0){
giuliomoro@197 138 midi_byte_t inputByte = (midi_byte_t)(input);
giuliomoro@197 139 inputParser->parse(&inputByte, 1);
giuliomoro@197 140 }
giuliomoro@197 141 }
giuliomoro@181 142 if(ret < maxBytesToRead){ //no more data to retrieve at the moment
giuliomoro@181 143 usleep(1000);
giuliomoro@197 144 } // otherwise there might be more data ready to be read (we were at the end of the buffer), so don't sleep
giuliomoro@181 145 }
giuliomoro@181 146 }
giuliomoro@181 147
giuliomoro@191 148 void Midi::writeOutputLoop(){
giuliomoro@191 149 while(!gShouldStop){
giuliomoro@191 150 usleep(1000);
giuliomoro@191 151 int length = outputBytesWritePointer - outputBytesReadPointer;
giuliomoro@191 152 if(length < 0){
giuliomoro@191 153 length = outputBytes.size() - outputBytesReadPointer;
giuliomoro@191 154 }
giuliomoro@191 155 if(length == 0){ //nothing to be written
giuliomoro@191 156 continue;
giuliomoro@191 157 }
giuliomoro@191 158 int ret;
giuliomoro@191 159 ret = write(outputPort, &outputBytes[outputBytesReadPointer], sizeof(midi_byte_t)*length);
giuliomoro@191 160 if(ret < 0){ //error occurred
giuliomoro@191 161 rt_printf("error occurred while writing: %d\n", errno);
giuliomoro@191 162 usleep(10000); //wait before retrying
giuliomoro@191 163 continue;
giuliomoro@191 164 }
giuliomoro@191 165 }
giuliomoro@191 166 }
giuliomoro@181 167 int Midi::readFrom(int port){
giuliomoro@191 168 objAddrs[kMidiInput].push_back(this);
giuliomoro@181 169 inputPort = open("/dev/midi1", O_RDONLY | O_NONBLOCK | O_NOCTTY);
giuliomoro@181 170 if(inputPort < 0){
giuliomoro@191 171 printf("Error occurred while opening midi input port %d: %d", port, inputPort);
giuliomoro@181 172 return -1;
giuliomoro@181 173 } else {
giuliomoro@191 174 printf("Reading from port %d\n", port);
giuliomoro@181 175 BeagleRT_scheduleAuxiliaryTask(midiInputTask);
giuliomoro@181 176 return 1;
giuliomoro@181 177 }
giuliomoro@181 178 }
giuliomoro@181 179
giuliomoro@191 180 int Midi::writeTo(int port){
giuliomoro@191 181 objAddrs[kMidiOutput].push_back(this);
giuliomoro@191 182 outputPort = open("/dev/midi1", O_WRONLY, 0);
giuliomoro@191 183 if(outputPort < 0){
giuliomoro@191 184 printf("Error occurred while opening midi output port %d: %d", port, outputPort);
giuliomoro@191 185 return -1;
giuliomoro@191 186 } else {
giuliomoro@191 187 printf("Writing to Midi port %d\n", port);
giuliomoro@191 188 BeagleRT_scheduleAuxiliaryTask(midiOutputTask);
giuliomoro@191 189 return 1;
giuliomoro@191 190 }
giuliomoro@191 191 }
giuliomoro@191 192
giuliomoro@199 193 int Midi::_getInput(){
giuliomoro@181 194 if(inputPort < 0)
giuliomoro@181 195 return -2;
giuliomoro@181 196 if(inputBytesReadPointer == inputBytesWritePointer){
giuliomoro@181 197 return -1; // no bytes to read
giuliomoro@181 198 }
giuliomoro@181 199 midi_byte_t inputMessage = inputBytes[inputBytesReadPointer++];
giuliomoro@181 200 if(inputBytesReadPointer == inputBytes.size()){ // wrap pointer
giuliomoro@181 201 inputBytesReadPointer = 0;
giuliomoro@181 202 }
giuliomoro@181 203 return inputMessage;
giuliomoro@181 204 }
giuliomoro@191 205
giuliomoro@199 206 int Midi::getInput(){
giuliomoro@199 207 if(parserEnabled == true) {
giuliomoro@199 208 return -3;
giuliomoro@199 209 }
giuliomoro@199 210 return _getInput();
giuliomoro@199 211 }
giuliomoro@199 212
giuliomoro@197 213 MidiParser* Midi::getParser(){
giuliomoro@197 214 if(parserEnabled == false){
giuliomoro@197 215 return 0;
giuliomoro@197 216 }
giuliomoro@197 217 return inputParser;
giuliomoro@197 218 };
giuliomoro@197 219
giuliomoro@191 220 int Midi::writeOutput(midi_byte_t byte){
giuliomoro@191 221 return writeOutput(&byte, 1);
giuliomoro@191 222 }
giuliomoro@191 223
giuliomoro@191 224 int Midi::writeOutput(midi_byte_t* bytes, unsigned int length){
giuliomoro@191 225 int ret = write(outputPort, bytes, length);
giuliomoro@191 226 if(ret < 0)
giuliomoro@191 227 return -1;
giuliomoro@191 228 else
giuliomoro@191 229 return 1;
giuliomoro@191 230 }
giuliomoro@197 231
giuliomoro@197 232 MidiChannelMessage::MidiChannelMessage(){};
giuliomoro@197 233 MidiChannelMessage::MidiChannelMessage(MidiMessageType type){
giuliomoro@197 234 setType(type);
giuliomoro@197 235 };
giuliomoro@197 236 MidiChannelMessage::~MidiChannelMessage(){};
giuliomoro@197 237 MidiMessageType MidiChannelMessage::getType(){
giuliomoro@197 238 return _type;
giuliomoro@197 239 };
giuliomoro@197 240 int MidiChannelMessage::getChannel(){
giuliomoro@197 241 return _channel;
giuliomoro@197 242 };
giuliomoro@197 243 //int MidiChannelMessage::set(midi_byte_t* input);
giuliomoro@197 244 //
giuliomoro@197 245 //int MidiControlChangeMessage ::getValue();
giuliomoro@197 246 //int MidiControlChangeMessage::set(midi_byte_t* input){
giuliomoro@197 247 // channel = input[0];
giuliomoro@197 248 // number = input[1];
giuliomoro@197 249 // value = input[2];
giuliomoro@197 250 // return 3;
giuliomoro@197 251 //}
giuliomoro@197 252
giuliomoro@197 253 //int MidiNoteMessage::getNote();
giuliomoro@197 254 //int MidiNoteMessage::getVelocity();
giuliomoro@197 255
giuliomoro@197 256 //midi_byte_t MidiProgramChangeMessage::getProgram();