andrewm@0
|
1 /*
|
andrewm@0
|
2 TouchKeys: multi-touch musical keyboard control software
|
andrewm@0
|
3 Copyright (c) 2013 Andrew McPherson
|
andrewm@0
|
4
|
andrewm@0
|
5 This program is free software: you can redistribute it and/or modify
|
andrewm@0
|
6 it under the terms of the GNU General Public License as published by
|
andrewm@0
|
7 the Free Software Foundation, either version 3 of the License, or
|
andrewm@0
|
8 (at your option) any later version.
|
andrewm@0
|
9
|
andrewm@0
|
10 This program is distributed in the hope that it will be useful,
|
andrewm@0
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
andrewm@0
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
andrewm@0
|
13 GNU General Public License for more details.
|
andrewm@0
|
14
|
andrewm@0
|
15 You should have received a copy of the GNU General Public License
|
andrewm@0
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
andrewm@0
|
17
|
andrewm@0
|
18 =====================================================================
|
andrewm@0
|
19
|
andrewm@0
|
20 MidiOutputController.cpp: handles outgoing MIDI messages and manages output
|
andrewm@0
|
21 ports; uses Juce MIDI library functions.
|
andrewm@0
|
22 */
|
andrewm@0
|
23
|
andrewm@0
|
24 #include "MidiOutputController.h"
|
andrewm@0
|
25
|
andrewm@39
|
26 #undef DEBUG_MIDI_OUTPUT_CONTROLLER
|
andrewm@7
|
27 #undef MIDI_OUTPUT_CONTROLLER_DEBUG_RAW
|
andrewm@0
|
28
|
andrewm@0
|
29 // Constructor
|
andrewm@0
|
30 MidiOutputController::MidiOutputController()
|
andrewm@0
|
31 {
|
andrewm@0
|
32 }
|
andrewm@0
|
33
|
andrewm@0
|
34 // Iterate through the available MIDI devices. Return a vector containing
|
andrewm@0
|
35 // indices and names for each device. The index will later be passed back
|
andrewm@0
|
36 // to indicate which device to open.
|
andrewm@0
|
37
|
andrewm@0
|
38 vector<pair<int, string> > MidiOutputController::availableMidiDevices() {
|
andrewm@0
|
39 vector<pair<int, string> > deviceList;
|
andrewm@0
|
40
|
andrewm@0
|
41 try {
|
andrewm@0
|
42 StringArray deviceStrings = MidiOutput::getDevices();
|
andrewm@0
|
43
|
andrewm@0
|
44 for(int i = 0; i < deviceStrings.size(); i++) {
|
andrewm@0
|
45 pair<int, string> p(i, string(deviceStrings[i].toUTF8()));
|
andrewm@0
|
46 deviceList.push_back(p);
|
andrewm@0
|
47 }
|
andrewm@0
|
48 }
|
andrewm@0
|
49 catch(...) {
|
andrewm@0
|
50 deviceList.clear();
|
andrewm@0
|
51 }
|
andrewm@0
|
52
|
andrewm@0
|
53 return deviceList;
|
andrewm@0
|
54 }
|
andrewm@0
|
55
|
andrewm@0
|
56 // Open a new MIDI output port, given an index related to the list from
|
andrewm@0
|
57 // availableMidiDevices(). Returns true on success.
|
andrewm@0
|
58
|
andrewm@0
|
59 bool MidiOutputController::enablePort(int identifier, int deviceNumber) {
|
andrewm@0
|
60 if(deviceNumber < 0)
|
andrewm@0
|
61 return false;
|
andrewm@0
|
62
|
andrewm@0
|
63 // Check if there is a port for this identifier, and disable it if so
|
andrewm@0
|
64 if(activePorts_.count(identifier) > 0)
|
andrewm@0
|
65 disablePort(identifier);
|
andrewm@0
|
66
|
andrewm@0
|
67 MidiOutput *device = MidiOutput::openDevice(deviceNumber);
|
andrewm@0
|
68
|
andrewm@0
|
69 if(device == 0) {
|
andrewm@0
|
70 cout << "Failed to enable MIDI output port " << deviceNumber << ")\n";
|
andrewm@0
|
71 return false;
|
andrewm@0
|
72 }
|
andrewm@0
|
73
|
andrewm@39
|
74 #ifdef DEBUG_MIDI_OUTPUT_CONTROLLER
|
andrewm@39
|
75 cout << "Enabling MIDI output port " << deviceNumber << " for ID " << identifier << "\n";
|
andrewm@39
|
76 #endif
|
andrewm@0
|
77
|
andrewm@0
|
78 // Save the device in the set of ports
|
andrewm@0
|
79 MidiOutputControllerRecord record;
|
andrewm@0
|
80 record.portNumber = deviceNumber;
|
andrewm@0
|
81 record.output = device;
|
andrewm@0
|
82
|
andrewm@13
|
83 activePorts_[identifier] = record;
|
andrewm@0
|
84
|
andrewm@0
|
85 return true;
|
andrewm@0
|
86 }
|
andrewm@0
|
87
|
andrewm@20
|
88 #ifndef JUCE_WINDOWS
|
andrewm@0
|
89 bool MidiOutputController::enableVirtualPort(int identifier, const char *name) {
|
andrewm@13
|
90 // Check if there is a port for this identifier, and disable it if so
|
andrewm@13
|
91 if(activePorts_.count(identifier) > 0)
|
andrewm@13
|
92 disablePort(identifier);
|
andrewm@13
|
93
|
andrewm@0
|
94 // Try to create a new port
|
andrewm@13
|
95 MidiOutput* device = MidiOutput::createNewDevice(name);
|
andrewm@13
|
96 if(device == 0) {
|
andrewm@13
|
97 cout << "Failed to enable MIDI virtual output port " << name << ")\n";
|
andrewm@0
|
98 return false;
|
andrewm@13
|
99 }
|
andrewm@0
|
100
|
andrewm@13
|
101 MidiOutputControllerRecord record;
|
andrewm@13
|
102 record.portNumber = kMidiVirtualOutputPortNumber;
|
andrewm@13
|
103 record.output = device;
|
andrewm@13
|
104
|
andrewm@13
|
105 activePorts_[identifier] = record;
|
andrewm@0
|
106
|
andrewm@39
|
107 #ifdef DEBUG_MIDI_OUTPUT_CONTROLLER
|
andrewm@39
|
108 cout << "Enabling virtual output port " << name << endl;
|
andrewm@39
|
109 #endif
|
andrewm@39
|
110
|
andrewm@0
|
111 return true;
|
andrewm@0
|
112 }
|
andrewm@20
|
113 #endif
|
andrewm@0
|
114
|
andrewm@0
|
115 void MidiOutputController::disablePort(int identifier) {
|
andrewm@0
|
116 if(activePorts_.count(identifier) <= 0)
|
andrewm@0
|
117 return;
|
andrewm@0
|
118
|
andrewm@0
|
119 MidiOutput *device = activePorts_[identifier].output;
|
andrewm@0
|
120
|
andrewm@0
|
121 if(device == 0)
|
andrewm@0
|
122 return;
|
andrewm@0
|
123
|
andrewm@39
|
124 #ifdef DEBUG_MIDI_OUTPUT_CONTROLLER
|
andrewm@39
|
125 cout << "Disabling MIDI output " << activePorts_[identifier].portNumber << " for ID " << identifier << "\n";
|
andrewm@39
|
126 #endif
|
andrewm@0
|
127 delete device;
|
andrewm@0
|
128
|
andrewm@0
|
129 activePorts_.erase(identifier);
|
andrewm@0
|
130 }
|
andrewm@0
|
131
|
andrewm@0
|
132 void MidiOutputController::disableAllPorts() {
|
andrewm@0
|
133 std::map<int, MidiOutputControllerRecord>::iterator it;
|
andrewm@0
|
134
|
andrewm@39
|
135 #ifdef DEBUG_MIDI_OUTPUT_CONTROLLER
|
andrewm@39
|
136 cout << "Disabling all MIDI output ports\n";
|
andrewm@39
|
137 #endif
|
andrewm@39
|
138
|
andrewm@0
|
139 it = activePorts_.begin();
|
andrewm@0
|
140
|
andrewm@0
|
141 while(it != activePorts_.end()) {
|
andrewm@0
|
142 if(it->second.output == 0)
|
andrewm@0
|
143 continue;
|
andrewm@0
|
144 delete it->second.output; // free MidiInputCallback
|
andrewm@0
|
145 it++;
|
andrewm@0
|
146 }
|
andrewm@0
|
147
|
andrewm@0
|
148 activePorts_.clear();
|
andrewm@0
|
149 }
|
andrewm@0
|
150
|
andrewm@0
|
151 int MidiOutputController::enabledPort(int identifier) {
|
andrewm@0
|
152 if(activePorts_.count(identifier) <= 0)
|
andrewm@0
|
153 return -1;
|
andrewm@0
|
154 return activePorts_[identifier].portNumber;
|
andrewm@0
|
155 }
|
andrewm@0
|
156
|
andrewm@0
|
157 std::vector<std::pair<int, int> > MidiOutputController::enabledPorts() {
|
andrewm@0
|
158 std::vector<std::pair<int, int> > ports;
|
andrewm@0
|
159 std::map<int, MidiOutputControllerRecord>::iterator it;
|
andrewm@0
|
160
|
andrewm@0
|
161 for(it = activePorts_.begin(); it != activePorts_.end(); ++it) {
|
andrewm@0
|
162 ports.push_back(std::pair<int,int>(it->first, it->second.portNumber));
|
andrewm@0
|
163 }
|
andrewm@0
|
164
|
andrewm@0
|
165 return ports;
|
andrewm@0
|
166 }
|
andrewm@0
|
167
|
andrewm@41
|
168 // Get the name of a particular MIDI input port
|
andrewm@41
|
169 String MidiOutputController::deviceName(int portNumber) {
|
andrewm@41
|
170 StringArray const& deviceStrings = MidiOutput::getDevices();
|
andrewm@41
|
171 if(portNumber < 0 || portNumber >= deviceStrings.size())
|
andrewm@41
|
172 return "";
|
andrewm@41
|
173 return deviceStrings[portNumber];
|
andrewm@41
|
174 }
|
andrewm@41
|
175
|
andrewm@41
|
176 // Find the index of a device with a given name; return -1 if not found
|
andrewm@41
|
177 int MidiOutputController::indexOfDeviceNamed(String const& name) {
|
andrewm@41
|
178 StringArray const& deviceStrings = MidiOutput::getDevices();
|
andrewm@41
|
179
|
andrewm@41
|
180 for(int i = 0; i < deviceStrings.size(); i++) {
|
andrewm@41
|
181 if(name == deviceStrings[i])
|
andrewm@41
|
182 return i;
|
andrewm@41
|
183 }
|
andrewm@41
|
184
|
andrewm@41
|
185 return -1;
|
andrewm@41
|
186 }
|
andrewm@41
|
187
|
andrewm@0
|
188 // Send a MIDI Note On message
|
andrewm@0
|
189 void MidiOutputController::sendNoteOn(int port, unsigned char channel, unsigned char note, unsigned char velocity) {
|
andrewm@0
|
190 sendMessage(port,
|
andrewm@0
|
191 MidiMessage((int)((channel & 0x0F) | kMidiMessageNoteOn),
|
andrewm@0
|
192 (int)(note & 0x7F),
|
andrewm@0
|
193 (int)(velocity & 0x7F)));
|
andrewm@0
|
194 }
|
andrewm@0
|
195
|
andrewm@0
|
196 // Send a MIDI Note Off message
|
andrewm@0
|
197 void MidiOutputController::sendNoteOff(int port, unsigned char channel, unsigned char note, unsigned char velocity) {
|
andrewm@0
|
198 sendMessage(port,
|
andrewm@0
|
199 MidiMessage((int)((channel & 0x0F) | kMidiMessageNoteOff),
|
andrewm@0
|
200 (int)(note & 0x7F),
|
andrewm@0
|
201 (int)(velocity & 0x7F)));
|
andrewm@0
|
202 }
|
andrewm@0
|
203
|
andrewm@0
|
204 // Send a MIDI Control Change message
|
andrewm@0
|
205 void MidiOutputController::sendControlChange(int port, unsigned char channel, unsigned char control, unsigned char value) {
|
andrewm@0
|
206 sendMessage(port,
|
andrewm@0
|
207 MidiMessage((int)((channel & 0x0F) | kMidiMessageControlChange),
|
andrewm@0
|
208 (int)(control & 0x7F),
|
andrewm@0
|
209 (int)(value & 0x7F)));
|
andrewm@0
|
210 }
|
andrewm@0
|
211
|
andrewm@0
|
212 // Send a MIDI Program Change message
|
andrewm@0
|
213 void MidiOutputController::sendProgramChange(int port, unsigned char channel, unsigned char value) {
|
andrewm@0
|
214 sendMessage(port,
|
andrewm@0
|
215 MidiMessage((int)((channel & 0x0F) | kMidiMessageProgramChange),
|
andrewm@0
|
216 (int)(value & 0x7F)));
|
andrewm@0
|
217 }
|
andrewm@0
|
218
|
andrewm@0
|
219 // Send a Channel Aftertouch message
|
andrewm@0
|
220 void MidiOutputController::sendAftertouchChannel(int port, unsigned char channel, unsigned char value) {
|
andrewm@0
|
221 sendMessage(port,
|
andrewm@0
|
222 MidiMessage((int)((channel & 0x0F) | kMidiMessageAftertouchChannel),
|
andrewm@0
|
223 (int)(value & 0x7F)));
|
andrewm@0
|
224 }
|
andrewm@0
|
225
|
andrewm@0
|
226 // Send a Polyphonic Aftertouch message
|
andrewm@0
|
227 void MidiOutputController::sendAftertouchPoly(int port, unsigned char channel, unsigned char note, unsigned char value) {
|
andrewm@0
|
228 sendMessage(port,
|
andrewm@0
|
229 MidiMessage((int)((channel & 0x0F) | kMidiMessageAftertouchPoly),
|
andrewm@0
|
230 (int)(note & 0x7F),
|
andrewm@0
|
231 (int)(value & 0x7F)));
|
andrewm@0
|
232 }
|
andrewm@0
|
233
|
andrewm@0
|
234 // Send a Pitch Wheel message
|
andrewm@0
|
235 void MidiOutputController::sendPitchWheel(int port, unsigned char channel, unsigned int value) {
|
andrewm@0
|
236 sendMessage(port,
|
andrewm@0
|
237 MidiMessage((int)((channel & 0x0F) | kMidiMessagePitchWheel),
|
andrewm@0
|
238 (int)(value & 0x7F),
|
andrewm@0
|
239 (int)((value >> 7) & 0x7F)));
|
andrewm@0
|
240 }
|
andrewm@0
|
241
|
andrewm@0
|
242 // Send a MIDI system reset message
|
andrewm@0
|
243 void MidiOutputController::sendReset(int port) {
|
andrewm@0
|
244 sendMessage(port, MidiMessage(kMidiMessageReset));
|
andrewm@0
|
245 }
|
andrewm@0
|
246
|
andrewm@0
|
247 // Send a generic MIDI message (pre-formatted data)
|
andrewm@0
|
248 void MidiOutputController::sendMessage(int port, const MidiMessage& message) {
|
andrewm@0
|
249 #ifdef MIDI_OUTPUT_CONTROLLER_DEBUG_RAW
|
andrewm@0
|
250 int dataSize = message.getRawDataSize();
|
andrewm@0
|
251 const unsigned char *data = message.getRawData();
|
andrewm@0
|
252
|
andrewm@0
|
253 cout << "MIDI Output " << port << ": ";
|
andrewm@0
|
254 for(int debugPrint = 0; debugPrint < dataSize; debugPrint++)
|
andrewm@0
|
255 printf("%x ", data[debugPrint]);
|
andrewm@0
|
256 cout << endl;
|
andrewm@0
|
257 #endif /* MIDI_OUTPUT_CONTROLLER_DEBUG_RAW */
|
andrewm@0
|
258
|
andrewm@0
|
259 if(activePorts_.count(port) == 0) {
|
andrewm@0
|
260 #ifdef MIDI_OUTPUT_CONTROLLER_DEBUG_RAW
|
andrewm@0
|
261 cout << "MIDI Output: no port on " << port << endl;
|
andrewm@0
|
262 #endif
|
andrewm@0
|
263 return;
|
andrewm@0
|
264 }
|
andrewm@0
|
265
|
andrewm@0
|
266 activePorts_[port].output->sendMessageNow(message);
|
andrewm@0
|
267 } |