f@5
|
1 /*
|
f@5
|
2
|
f@5
|
3 Copyright (C) 2016 Queen Mary University of London
|
f@5
|
4 Author: Fiore Martin
|
f@5
|
5
|
f@5
|
6 This file is part of Collidoscope.
|
f@5
|
7
|
f@5
|
8 Collidoscope is free software: you can redistribute it and/or modify
|
f@5
|
9 it under the terms of the GNU General Public License as published by
|
f@5
|
10 the Free Software Foundation, either version 3 of the License, or
|
f@5
|
11 (at your option) any later version.
|
f@5
|
12
|
f@5
|
13 This program is distributed in the hope that it will be useful,
|
f@5
|
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
f@5
|
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
f@5
|
16 GNU General Public License for more details.
|
f@5
|
17
|
f@5
|
18 You should have received a copy of the GNU General Public License
|
f@5
|
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
f@5
|
20 */
|
f@5
|
21
|
f@0
|
22 #include "MIDI.h"
|
f@0
|
23 #include "Config.h"
|
f@0
|
24
|
f@0
|
25
|
f@0
|
26 collidoscope::MIDI::MIDI()
|
f@0
|
27 {
|
f@0
|
28 }
|
f@0
|
29
|
f@0
|
30
|
f@0
|
31 collidoscope::MIDI::~MIDI()
|
f@0
|
32 {
|
f@0
|
33 // FIXME check cause destructor of RTInput might throw
|
f@0
|
34 for ( auto & input : mInputs )
|
f@0
|
35 input->closePort();
|
f@0
|
36 }
|
f@0
|
37
|
f@0
|
38 void collidoscope::MIDI::RtMidiInCallback( double deltatime, std::vector<unsigned char> *message, void *userData )
|
f@0
|
39 {
|
f@0
|
40 collidoscope::MIDI* midi = ((collidoscope::MIDI*)userData);
|
f@0
|
41 std::lock_guard< std::mutex > lock( midi->mMutex );
|
f@0
|
42
|
f@0
|
43 MIDIMessage msg = midi->parseRtMidiMessage( message );
|
f@0
|
44
|
f@0
|
45 switch ( msg.getVoice() ){
|
f@0
|
46 case MIDIMessage::Voice::ePitchBend:
|
f@0
|
47 midi->mPitchBendMessages[msg.getChannel()] = msg;
|
f@0
|
48 break;
|
f@0
|
49
|
f@0
|
50 case MIDIMessage::Voice::eControlChange:
|
f@0
|
51 if ( msg.getChannel() == 7 ) // FIXME no harcoded
|
f@0
|
52 midi->mFilterMessages[msg.getChannel()] = msg;
|
f@0
|
53 else
|
f@0
|
54 midi->mMIDIMessages.push_back( msg );
|
f@0
|
55 break;
|
f@0
|
56
|
f@0
|
57 default:
|
f@0
|
58 midi->mMIDIMessages.push_back( msg );
|
f@0
|
59 break;
|
f@0
|
60 }
|
f@0
|
61 }
|
f@0
|
62
|
f@0
|
63 void collidoscope::MIDI::setup( const Config& config )
|
f@0
|
64 {
|
f@0
|
65 unsigned int numPorts = 0;
|
f@0
|
66
|
f@0
|
67 try {
|
f@0
|
68 RtMidiIn in;
|
f@0
|
69 numPorts = in.getPortCount();
|
f@0
|
70 }
|
f@0
|
71 catch ( RtMidiError &error ) {
|
f@0
|
72 throw MIDIException( error.getMessage() );
|
f@0
|
73 }
|
f@0
|
74
|
f@0
|
75 if ( numPorts == 0 ){
|
f@0
|
76 throw MIDIException(" no MIDI input found ");
|
f@0
|
77 }
|
f@0
|
78
|
f@0
|
79 for ( unsigned int portNum = 0; portNum < numPorts; portNum++ ) {
|
f@0
|
80 try {
|
f@0
|
81 std::unique_ptr< RtMidiIn > input ( new RtMidiIn() );
|
f@0
|
82 input->openPort( portNum, "Collidoscope Input" );
|
f@0
|
83 input->setCallback( &RtMidiInCallback, this );
|
f@0
|
84 mInputs.push_back( std::move(input) );
|
f@0
|
85
|
f@0
|
86 }
|
f@0
|
87 catch ( RtMidiError &error ) {
|
f@0
|
88 throw MIDIException( error.getMessage() );
|
f@0
|
89 }
|
f@0
|
90 }
|
f@0
|
91 }
|
f@0
|
92
|
f@0
|
93
|
f@0
|
94 void collidoscope::MIDI::checkMessages( std::vector<MIDIMessage> & midiMessages )
|
f@0
|
95 {
|
f@0
|
96 std::lock_guard<std::mutex> lock( mMutex );
|
f@0
|
97 midiMessages.swap( mMIDIMessages );
|
f@0
|
98
|
f@0
|
99 for ( int i = 0; i < NUM_WAVES; i++ ){
|
f@0
|
100 if ( mPitchBendMessages[i].mVoice != MIDIMessage::Voice::eIgnore ){
|
f@0
|
101 midiMessages.push_back( mPitchBendMessages[i] );
|
f@0
|
102 mPitchBendMessages[i].mVoice = MIDIMessage::Voice::eIgnore;
|
f@0
|
103 }
|
f@0
|
104
|
f@0
|
105 if ( mFilterMessages[i].mVoice != MIDIMessage::Voice::eIgnore ){
|
f@0
|
106 midiMessages.push_back( mFilterMessages[i] );
|
f@0
|
107 mFilterMessages[i].mVoice = MIDIMessage::Voice::eIgnore;
|
f@0
|
108 }
|
f@0
|
109 }
|
f@0
|
110 }
|
f@0
|
111
|
f@0
|
112 // only call this function when the size of mRtMidiMessage != 0
|
f@0
|
113 collidoscope::MIDIMessage collidoscope::MIDI::parseRtMidiMessage( std::vector<unsigned char> *rtMidiMessage )
|
f@0
|
114 {
|
f@0
|
115 collidoscope::MIDIMessage msg;
|
f@0
|
116
|
f@0
|
117 size_t numBytes = rtMidiMessage->size();
|
f@0
|
118
|
f@0
|
119 // voice is the 4 most significant bits
|
f@0
|
120 unsigned char voice = (*rtMidiMessage)[0] >> 4;
|
f@0
|
121
|
f@0
|
122 switch ( voice ){
|
f@0
|
123 case 0x9 :
|
f@0
|
124 msg.mVoice = MIDIMessage::Voice::eNoteOn;
|
f@0
|
125 break;
|
f@0
|
126
|
f@0
|
127 case 0x8:
|
f@0
|
128 msg.mVoice = MIDIMessage::Voice::eNoteOff;
|
f@0
|
129 break;
|
f@0
|
130
|
f@0
|
131 case 0xB:
|
f@0
|
132 msg.mVoice = MIDIMessage::Voice::eControlChange;
|
f@0
|
133 break;
|
f@0
|
134
|
f@0
|
135 case 0xE:
|
f@0
|
136 msg.mVoice = MIDIMessage::Voice::ePitchBend;
|
f@0
|
137 break;
|
f@0
|
138
|
f@0
|
139 default:
|
f@0
|
140 msg.mVoice = MIDIMessage::Voice::eIgnore;
|
f@0
|
141 return msg;
|
f@0
|
142 }
|
f@0
|
143
|
f@0
|
144 // channel is 4 less significant bits
|
f@0
|
145 unsigned char channel = (*rtMidiMessage)[0] & 0x0f;
|
f@0
|
146 msg.mChannel = channel;
|
f@0
|
147
|
f@0
|
148 //data byte 1
|
f@0
|
149 msg.mData1 = (*rtMidiMessage)[1];
|
f@0
|
150
|
f@0
|
151 // data byte 2 if it exists
|
f@0
|
152 msg.mData2 = (numBytes == 3 ? (*rtMidiMessage)[2] : 0);
|
f@0
|
153
|
f@0
|
154 return msg;
|
f@2
|
155 }
|