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: }