giuliomoro@181: /* giuliomoro@181: * Midi.cpp giuliomoro@181: * giuliomoro@181: * Created on: 15 Jan 2016 giuliomoro@181: * Author: giulio giuliomoro@181: */ giuliomoro@181: giuliomoro@181: #include "Midi.h" giuliomoro@181: #include giuliomoro@181: #include giuliomoro@181: giuliomoro@191: #define kMidiInput 0 giuliomoro@191: #define kMidiOutput 1 giuliomoro@191: giuliomoro@197: giuliomoro@197: midi_byte_t midiMessageStatusBytes[midiMessageStatusBytesLength]= giuliomoro@197: { giuliomoro@197: 0x80, giuliomoro@197: 0x90, giuliomoro@197: 0xA0, giuliomoro@197: 0xB0, giuliomoro@197: 0xC0, giuliomoro@197: 0xD0, giuliomoro@197: 0xE0, giuliomoro@197: 0 giuliomoro@197: }; giuliomoro@197: giuliomoro@197: unsigned int midiMessageNumDataBytes[midiMessageStatusBytesLength]={2, 2, 2, 2, 1, 1, 2, 0}; giuliomoro@197: giuliomoro@181: bool Midi::staticConstructed; giuliomoro@181: AuxiliaryTask Midi::midiInputTask; giuliomoro@181: AuxiliaryTask Midi::midiOutputTask; giuliomoro@191: std::vector Midi::objAddrs[2]; giuliomoro@181: giuliomoro@197: int MidiParser::parse(midi_byte_t* input, unsigned int length){ giuliomoro@197: unsigned int consumedBytes = 0; giuliomoro@197: for(unsigned int n = 0; n < length; n++){ giuliomoro@197: consumedBytes++; giuliomoro@197: if(waitingForStatus == true){ giuliomoro@197: int statusByte = input[n]; giuliomoro@197: MidiMessageType newType = kmmNone; giuliomoro@197: if (statusByte >= 0x80){//it actually is a status byte giuliomoro@197: for(int n = 0; n < midiMessageStatusBytesLength; n++){ //find the statusByte in the array giuliomoro@197: if(midiMessageStatusBytes[n] == (statusByte&0xf0)){ giuliomoro@197: newType = (MidiMessageType)n; giuliomoro@197: break; giuliomoro@197: } giuliomoro@197: } giuliomoro@197: elapsedDataBytes = 0; giuliomoro@197: waitingForStatus = false; giuliomoro@197: messages[writePointer].setType(newType); giuliomoro@197: messages[writePointer].setChannel((midi_byte_t)(statusByte&0xf)); giuliomoro@197: consumedBytes++; giuliomoro@197: } else { // either something went wrong or it's a system message giuliomoro@197: continue; giuliomoro@197: } giuliomoro@197: } else { giuliomoro@197: messages[writePointer].setDataByte(elapsedDataBytes, input[n]); giuliomoro@197: elapsedDataBytes++; giuliomoro@197: if(elapsedDataBytes == messages[writePointer].getNumDataBytes()){ giuliomoro@224: // done with the current message giuliomoro@224: // call the callback if available giuliomoro@224: if(isCallbackEnabled() == true){ giuliomoro@224: messageReadyCallback(getNextChannelMessage()); giuliomoro@224: } giuliomoro@197: waitingForStatus = true; giuliomoro@197: writePointer++; giuliomoro@197: if(writePointer == messages.size()){ giuliomoro@197: writePointer = 0; giuliomoro@197: } giuliomoro@197: } giuliomoro@197: } giuliomoro@197: } giuliomoro@224: giuliomoro@197: return consumedBytes; giuliomoro@197: }; giuliomoro@197: giuliomoro@197: giuliomoro@181: Midi::Midi(){ giuliomoro@181: outputPort = -1; giuliomoro@181: inputPort = -1; giuliomoro@197: inputParser = 0; giuliomoro@181: size_t inputBytesInitialSize = 1000; giuliomoro@181: inputBytes.resize(inputBytesInitialSize); giuliomoro@191: outputBytes.resize(inputBytesInitialSize); giuliomoro@181: inputBytesWritePointer = 0; giuliomoro@181: inputBytesReadPointer = inputBytes.size() - 1; giuliomoro@181: if(!staticConstructed){ giuliomoro@181: staticConstructor(); giuliomoro@181: } giuliomoro@181: } giuliomoro@181: giuliomoro@181: void Midi::staticConstructor(){ giuliomoro@181: staticConstructed = true; giuliomoro@181: midiInputTask = BeagleRT_createAuxiliaryTask(Midi::midiInputLoop, 50, "MidiInput"); giuliomoro@191: midiOutputTask = BeagleRT_createAuxiliaryTask(Midi::midiOutputLoop, 50, "MidiOutupt"); giuliomoro@181: } giuliomoro@181: giuliomoro@181: Midi::~Midi(){} giuliomoro@197: giuliomoro@197: void Midi::enableParser(bool enable){ giuliomoro@197: if(enable == true){ giuliomoro@197: delete inputParser; giuliomoro@197: inputParser = new MidiParser(); giuliomoro@197: parserEnabled = true; giuliomoro@197: } else { giuliomoro@197: delete inputParser; giuliomoro@197: parserEnabled = false; giuliomoro@197: } giuliomoro@197: } giuliomoro@197: giuliomoro@191: void Midi::midiInputLoop(){ giuliomoro@191: for(unsigned int n = 0; n < objAddrs[kMidiInput].size(); n++){ giuliomoro@191: objAddrs[kMidiInput][n] -> readInputLoop(); giuliomoro@191: } giuliomoro@191: } giuliomoro@181: giuliomoro@191: void Midi::midiOutputLoop(){ giuliomoro@191: for(unsigned int n = 0; n < objAddrs[kMidiOutput].size(); n++){ giuliomoro@191: objAddrs[kMidiOutput][n] -> writeOutputLoop(); giuliomoro@181: } giuliomoro@181: } giuliomoro@181: giuliomoro@181: void Midi::readInputLoop(){ giuliomoro@181: while(!gShouldStop){ giuliomoro@181: int maxBytesToRead = inputBytes.size() - inputBytesWritePointer; giuliomoro@181: int ret = read(inputPort, &inputBytes[inputBytesWritePointer], sizeof(midi_byte_t)*maxBytesToRead); giuliomoro@181: if(ret < 0){ giuliomoro@181: if(errno != EAGAIN){ // read() would return EAGAIN when no data are available to read just now giuliomoro@181: rt_printf("Error while reading midi %d\n", errno); giuliomoro@181: } giuliomoro@181: usleep(1000); giuliomoro@181: continue; giuliomoro@181: } giuliomoro@181: inputBytesWritePointer += ret; giuliomoro@181: if(inputBytesWritePointer == inputBytes.size()){ //wrap pointer around giuliomoro@181: inputBytesWritePointer = 0; giuliomoro@181: } giuliomoro@224: giuliomoro@197: if(parserEnabled == true && ret > 0){ // if the parser is enabled and there is new data, send the data to it giuliomoro@197: int input; giuliomoro@199: while((input=_getInput()) >= 0){ giuliomoro@197: midi_byte_t inputByte = (midi_byte_t)(input); giuliomoro@197: inputParser->parse(&inputByte, 1); giuliomoro@197: } giuliomoro@197: } giuliomoro@181: if(ret < maxBytesToRead){ //no more data to retrieve at the moment giuliomoro@181: usleep(1000); giuliomoro@197: } // otherwise there might be more data ready to be read (we were at the end of the buffer), so don't sleep giuliomoro@181: } giuliomoro@181: } giuliomoro@181: giuliomoro@191: void Midi::writeOutputLoop(){ giuliomoro@191: while(!gShouldStop){ giuliomoro@191: usleep(1000); giuliomoro@191: int length = outputBytesWritePointer - outputBytesReadPointer; giuliomoro@191: if(length < 0){ giuliomoro@191: length = outputBytes.size() - outputBytesReadPointer; giuliomoro@191: } giuliomoro@191: if(length == 0){ //nothing to be written giuliomoro@191: continue; giuliomoro@191: } giuliomoro@191: int ret; giuliomoro@191: ret = write(outputPort, &outputBytes[outputBytesReadPointer], sizeof(midi_byte_t)*length); giuliomoro@191: if(ret < 0){ //error occurred giuliomoro@191: rt_printf("error occurred while writing: %d\n", errno); giuliomoro@191: usleep(10000); //wait before retrying giuliomoro@191: continue; giuliomoro@191: } giuliomoro@191: } giuliomoro@191: } giuliomoro@181: int Midi::readFrom(int port){ giuliomoro@191: objAddrs[kMidiInput].push_back(this); giuliomoro@181: inputPort = open("/dev/midi1", O_RDONLY | O_NONBLOCK | O_NOCTTY); giuliomoro@181: if(inputPort < 0){ giuliomoro@191: printf("Error occurred while opening midi input port %d: %d", port, inputPort); giuliomoro@181: return -1; giuliomoro@181: } else { giuliomoro@191: printf("Reading from port %d\n", port); giuliomoro@181: BeagleRT_scheduleAuxiliaryTask(midiInputTask); giuliomoro@181: return 1; giuliomoro@181: } giuliomoro@181: } giuliomoro@181: giuliomoro@191: int Midi::writeTo(int port){ giuliomoro@191: objAddrs[kMidiOutput].push_back(this); giuliomoro@191: outputPort = open("/dev/midi1", O_WRONLY, 0); giuliomoro@191: if(outputPort < 0){ giuliomoro@191: printf("Error occurred while opening midi output port %d: %d", port, outputPort); giuliomoro@191: return -1; giuliomoro@191: } else { giuliomoro@191: printf("Writing to Midi port %d\n", port); giuliomoro@191: BeagleRT_scheduleAuxiliaryTask(midiOutputTask); giuliomoro@191: return 1; giuliomoro@191: } giuliomoro@191: } giuliomoro@191: giuliomoro@199: int Midi::_getInput(){ giuliomoro@181: if(inputPort < 0) giuliomoro@181: return -2; giuliomoro@181: if(inputBytesReadPointer == inputBytesWritePointer){ giuliomoro@181: return -1; // no bytes to read giuliomoro@181: } giuliomoro@181: midi_byte_t inputMessage = inputBytes[inputBytesReadPointer++]; giuliomoro@181: if(inputBytesReadPointer == inputBytes.size()){ // wrap pointer giuliomoro@181: inputBytesReadPointer = 0; giuliomoro@181: } giuliomoro@181: return inputMessage; giuliomoro@181: } giuliomoro@191: giuliomoro@199: int Midi::getInput(){ giuliomoro@199: if(parserEnabled == true) { giuliomoro@199: return -3; giuliomoro@199: } giuliomoro@199: return _getInput(); giuliomoro@199: } giuliomoro@199: giuliomoro@197: MidiParser* Midi::getParser(){ giuliomoro@197: if(parserEnabled == false){ giuliomoro@197: return 0; giuliomoro@197: } giuliomoro@197: return inputParser; giuliomoro@197: }; giuliomoro@197: giuliomoro@191: int Midi::writeOutput(midi_byte_t byte){ giuliomoro@191: return writeOutput(&byte, 1); giuliomoro@191: } giuliomoro@191: giuliomoro@191: int Midi::writeOutput(midi_byte_t* bytes, unsigned int length){ giuliomoro@191: int ret = write(outputPort, bytes, length); giuliomoro@191: if(ret < 0) giuliomoro@191: return -1; giuliomoro@191: else giuliomoro@191: return 1; giuliomoro@191: } giuliomoro@197: giuliomoro@197: MidiChannelMessage::MidiChannelMessage(){}; giuliomoro@197: MidiChannelMessage::MidiChannelMessage(MidiMessageType type){ giuliomoro@197: setType(type); giuliomoro@197: }; giuliomoro@197: MidiChannelMessage::~MidiChannelMessage(){}; giuliomoro@197: MidiMessageType MidiChannelMessage::getType(){ giuliomoro@197: return _type; giuliomoro@197: }; giuliomoro@197: int MidiChannelMessage::getChannel(){ giuliomoro@197: return _channel; giuliomoro@197: }; giuliomoro@197: //int MidiChannelMessage::set(midi_byte_t* input); giuliomoro@197: // giuliomoro@197: //int MidiControlChangeMessage ::getValue(); giuliomoro@197: //int MidiControlChangeMessage::set(midi_byte_t* input){ giuliomoro@197: // channel = input[0]; giuliomoro@197: // number = input[1]; giuliomoro@197: // value = input[2]; giuliomoro@197: // return 3; giuliomoro@197: //} giuliomoro@197: giuliomoro@197: //int MidiNoteMessage::getNote(); giuliomoro@197: //int MidiNoteMessage::getVelocity(); giuliomoro@197: giuliomoro@197: //midi_byte_t MidiProgramChangeMessage::getProgram();