f@5: /* f@5: f@5: Copyright (C) 2016 Queen Mary University of London f@5: Author: Fiore Martin f@5: f@5: This file is part of Collidoscope. f@5: f@5: Collidoscope is free software: you can redistribute it and/or modify f@5: it under the terms of the GNU General Public License as published by f@5: the Free Software Foundation, either version 3 of the License, or f@5: (at your option) any later version. f@5: f@5: This program is distributed in the hope that it will be useful, f@5: but WITHOUT ANY WARRANTY; without even the implied warranty of f@5: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the f@5: GNU General Public License for more details. f@5: f@5: You should have received a copy of the GNU General Public License f@5: along with this program. If not, see . f@5: */ f@5: f@0: #include "MIDI.h" f@0: #include "Config.h" f@0: f@0: f@0: collidoscope::MIDI::MIDI() f@0: { f@0: } f@0: f@0: f@0: collidoscope::MIDI::~MIDI() f@0: { f@0: // FIXME check cause destructor of RTInput might throw f@0: for ( auto & input : mInputs ) f@0: input->closePort(); f@0: } f@0: f@0: void collidoscope::MIDI::RtMidiInCallback( double deltatime, std::vector *message, void *userData ) f@0: { f@0: collidoscope::MIDI* midi = ((collidoscope::MIDI*)userData); f@0: std::lock_guard< std::mutex > lock( midi->mMutex ); f@0: f@0: MIDIMessage msg = midi->parseRtMidiMessage( message ); f@0: f@0: switch ( msg.getVoice() ){ f@0: case MIDIMessage::Voice::ePitchBend: f@0: midi->mPitchBendMessages[msg.getChannel()] = msg; f@0: break; f@0: f@0: case MIDIMessage::Voice::eControlChange: f@0: if ( msg.getChannel() == 7 ) // FIXME no harcoded f@0: midi->mFilterMessages[msg.getChannel()] = msg; f@0: else f@0: midi->mMIDIMessages.push_back( msg ); f@0: break; f@0: f@0: default: f@0: midi->mMIDIMessages.push_back( msg ); f@0: break; f@0: } f@0: } f@0: f@0: void collidoscope::MIDI::setup( const Config& config ) f@0: { f@0: unsigned int numPorts = 0; f@0: f@0: try { f@0: RtMidiIn in; f@0: numPorts = in.getPortCount(); f@0: } f@0: catch ( RtMidiError &error ) { f@0: throw MIDIException( error.getMessage() ); f@0: } f@0: f@0: if ( numPorts == 0 ){ f@0: throw MIDIException(" no MIDI input found "); f@0: } f@0: f@0: for ( unsigned int portNum = 0; portNum < numPorts; portNum++ ) { f@0: try { f@0: std::unique_ptr< RtMidiIn > input ( new RtMidiIn() ); f@0: input->openPort( portNum, "Collidoscope Input" ); f@0: input->setCallback( &RtMidiInCallback, this ); f@0: mInputs.push_back( std::move(input) ); f@0: f@0: } f@0: catch ( RtMidiError &error ) { f@0: throw MIDIException( error.getMessage() ); f@0: } f@0: } f@0: } f@0: f@0: f@0: void collidoscope::MIDI::checkMessages( std::vector & midiMessages ) f@0: { f@0: std::lock_guard lock( mMutex ); f@0: midiMessages.swap( mMIDIMessages ); f@0: f@0: for ( int i = 0; i < NUM_WAVES; i++ ){ f@0: if ( mPitchBendMessages[i].mVoice != MIDIMessage::Voice::eIgnore ){ f@0: midiMessages.push_back( mPitchBendMessages[i] ); f@0: mPitchBendMessages[i].mVoice = MIDIMessage::Voice::eIgnore; f@0: } f@0: f@0: if ( mFilterMessages[i].mVoice != MIDIMessage::Voice::eIgnore ){ f@0: midiMessages.push_back( mFilterMessages[i] ); f@0: mFilterMessages[i].mVoice = MIDIMessage::Voice::eIgnore; f@0: } f@0: } f@0: } f@0: f@0: // only call this function when the size of mRtMidiMessage != 0 f@0: collidoscope::MIDIMessage collidoscope::MIDI::parseRtMidiMessage( std::vector *rtMidiMessage ) f@0: { f@0: collidoscope::MIDIMessage msg; f@0: f@0: size_t numBytes = rtMidiMessage->size(); f@0: f@0: // voice is the 4 most significant bits f@0: unsigned char voice = (*rtMidiMessage)[0] >> 4; f@0: f@0: switch ( voice ){ f@0: case 0x9 : f@0: msg.mVoice = MIDIMessage::Voice::eNoteOn; f@0: break; f@0: f@0: case 0x8: f@0: msg.mVoice = MIDIMessage::Voice::eNoteOff; f@0: break; f@0: f@0: case 0xB: f@0: msg.mVoice = MIDIMessage::Voice::eControlChange; f@0: break; f@0: f@0: case 0xE: f@0: msg.mVoice = MIDIMessage::Voice::ePitchBend; f@0: break; f@0: f@0: default: f@0: msg.mVoice = MIDIMessage::Voice::eIgnore; f@0: return msg; f@0: } f@0: f@0: // channel is 4 less significant bits f@0: unsigned char channel = (*rtMidiMessage)[0] & 0x0f; f@0: msg.mChannel = channel; f@0: f@0: //data byte 1 f@0: msg.mData1 = (*rtMidiMessage)[1]; f@0: f@0: // data byte 2 if it exists f@0: msg.mData2 = (numBytes == 3 ? (*rtMidiMessage)[2] : 0); f@0: f@0: return msg; f@2: }