annotate core/Midi.cpp @ 198:62f6269f4b3e

Added support for MidiIn to heavy (with example patch and subpatches).
author Giulio Moro <giuliomoro@yahoo.it>
date Fri, 05 Feb 2016 06:17:35 +0000
parents 265a527f8be8
children b128e3ea84ff
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@197 137 while((input=getInput()) >= 0){
giuliomoro@197 138 midi_byte_t inputByte = (midi_byte_t)(input);
giuliomoro@197 139 // printf("__0x%x\n", input);
giuliomoro@197 140 inputParser->parse(&inputByte, 1);
giuliomoro@197 141 }
giuliomoro@197 142 // if(inputBytesReadPointer == inputBytesWritePointer){
giuliomoro@197 143 // this should never be the case, it should only happen when ret == 0
giuliomoro@197 144 // } else {
giuliomoro@197 145
giuliomoro@197 146 // unsigned int length = (inputBytesWritePointer - inputBytesReadPointer + inputBytes.size())
giuliomoro@197 147 // % inputBytes.size();
giuliomoro@197 148 // rt_printf("inputBytes: 0x%x 0x%x 0x%x", inputBytes[inputBytesReadPointer],
giuliomoro@197 149 // inputBytes[inputBytesReadPointer+1], inputBytes[inputBytesReadPointer+2]);
giuliomoro@197 150 // length = inputParser->parse(&inputBytes[inputBytesReadPointer], length);
giuliomoro@197 151 // inputBytesReadPointer += length; //if parserEnabled, the readPointer is incremented here,
giuliomoro@197 152 // //so calls to getInput() should be avoided
giuliomoro@197 153 // if(inputBytesReadPointer == inputBytes.size()){
giuliomoro@197 154 // inputBytesReadPointer = 0;
giuliomoro@197 155 // }
giuliomoro@197 156 // }
giuliomoro@197 157 }
giuliomoro@181 158 if(ret < maxBytesToRead){ //no more data to retrieve at the moment
giuliomoro@181 159 usleep(1000);
giuliomoro@197 160 } // otherwise there might be more data ready to be read (we were at the end of the buffer), so don't sleep
giuliomoro@181 161 }
giuliomoro@181 162 }
giuliomoro@181 163
giuliomoro@191 164 void Midi::writeOutputLoop(){
giuliomoro@191 165 while(!gShouldStop){
giuliomoro@191 166 usleep(1000);
giuliomoro@191 167 int length = outputBytesWritePointer - outputBytesReadPointer;
giuliomoro@191 168 if(length < 0){
giuliomoro@191 169 length = outputBytes.size() - outputBytesReadPointer;
giuliomoro@191 170 }
giuliomoro@191 171 if(length == 0){ //nothing to be written
giuliomoro@191 172 continue;
giuliomoro@191 173 }
giuliomoro@191 174 int ret;
giuliomoro@191 175 ret = write(outputPort, &outputBytes[outputBytesReadPointer], sizeof(midi_byte_t)*length);
giuliomoro@191 176 if(ret < 0){ //error occurred
giuliomoro@191 177 rt_printf("error occurred while writing: %d\n", errno);
giuliomoro@191 178 usleep(10000); //wait before retrying
giuliomoro@191 179 continue;
giuliomoro@191 180 }
giuliomoro@191 181 }
giuliomoro@191 182 }
giuliomoro@181 183 int Midi::readFrom(int port){
giuliomoro@191 184 objAddrs[kMidiInput].push_back(this);
giuliomoro@181 185 inputPort = open("/dev/midi1", O_RDONLY | O_NONBLOCK | O_NOCTTY);
giuliomoro@181 186 if(inputPort < 0){
giuliomoro@191 187 printf("Error occurred while opening midi input port %d: %d", port, inputPort);
giuliomoro@181 188 return -1;
giuliomoro@181 189 } else {
giuliomoro@191 190 printf("Reading from port %d\n", port);
giuliomoro@181 191 BeagleRT_scheduleAuxiliaryTask(midiInputTask);
giuliomoro@181 192 return 1;
giuliomoro@181 193 }
giuliomoro@181 194 }
giuliomoro@181 195
giuliomoro@191 196 int Midi::writeTo(int port){
giuliomoro@191 197 objAddrs[kMidiOutput].push_back(this);
giuliomoro@191 198 outputPort = open("/dev/midi1", O_WRONLY, 0);
giuliomoro@191 199 if(outputPort < 0){
giuliomoro@191 200 printf("Error occurred while opening midi output port %d: %d", port, outputPort);
giuliomoro@191 201 return -1;
giuliomoro@191 202 } else {
giuliomoro@191 203 printf("Writing to Midi port %d\n", port);
giuliomoro@191 204 BeagleRT_scheduleAuxiliaryTask(midiOutputTask);
giuliomoro@191 205 return 1;
giuliomoro@191 206 }
giuliomoro@191 207 }
giuliomoro@191 208
giuliomoro@191 209 int Midi::getInput(){
giuliomoro@197 210 // if(parserEnabled == true) {
giuliomoro@197 211 // return -3;
giuliomoro@197 212 // }
giuliomoro@181 213 if(inputPort < 0)
giuliomoro@181 214 return -2;
giuliomoro@181 215 if(inputBytesReadPointer == inputBytesWritePointer){
giuliomoro@181 216 return -1; // no bytes to read
giuliomoro@181 217 }
giuliomoro@181 218 midi_byte_t inputMessage = inputBytes[inputBytesReadPointer++];
giuliomoro@181 219 if(inputBytesReadPointer == inputBytes.size()){ // wrap pointer
giuliomoro@181 220 inputBytesReadPointer = 0;
giuliomoro@181 221 }
giuliomoro@181 222 return inputMessage;
giuliomoro@181 223 }
giuliomoro@191 224
giuliomoro@197 225 MidiParser* Midi::getParser(){
giuliomoro@197 226 if(parserEnabled == false){
giuliomoro@197 227 return 0;
giuliomoro@197 228 }
giuliomoro@197 229 return inputParser;
giuliomoro@197 230 };
giuliomoro@197 231
giuliomoro@191 232 int Midi::writeOutput(midi_byte_t byte){
giuliomoro@191 233 return writeOutput(&byte, 1);
giuliomoro@191 234 }
giuliomoro@191 235
giuliomoro@191 236 int Midi::writeOutput(midi_byte_t* bytes, unsigned int length){
giuliomoro@191 237 int ret = write(outputPort, bytes, length);
giuliomoro@191 238 if(ret < 0)
giuliomoro@191 239 return -1;
giuliomoro@191 240 else
giuliomoro@191 241 return 1;
giuliomoro@191 242 }
giuliomoro@197 243
giuliomoro@197 244 MidiChannelMessage::MidiChannelMessage(){};
giuliomoro@197 245 MidiChannelMessage::MidiChannelMessage(MidiMessageType type){
giuliomoro@197 246 setType(type);
giuliomoro@197 247 };
giuliomoro@197 248 MidiChannelMessage::~MidiChannelMessage(){};
giuliomoro@197 249 MidiMessageType MidiChannelMessage::getType(){
giuliomoro@197 250 return _type;
giuliomoro@197 251 };
giuliomoro@197 252 int MidiChannelMessage::getChannel(){
giuliomoro@197 253 return _channel;
giuliomoro@197 254 };
giuliomoro@197 255 //int MidiChannelMessage::set(midi_byte_t* input);
giuliomoro@197 256 //
giuliomoro@197 257 //int MidiControlChangeMessage ::getValue();
giuliomoro@197 258 //int MidiControlChangeMessage::set(midi_byte_t* input){
giuliomoro@197 259 // channel = input[0];
giuliomoro@197 260 // number = input[1];
giuliomoro@197 261 // value = input[2];
giuliomoro@197 262 // return 3;
giuliomoro@197 263 //}
giuliomoro@197 264
giuliomoro@197 265 //int MidiNoteMessage::getNote();
giuliomoro@197 266 //int MidiNoteMessage::getVelocity();
giuliomoro@197 267
giuliomoro@197 268 //midi_byte_t MidiProgramChangeMessage::getProgram();