annotate Source/TouchKeys/MidiOutputController.cpp @ 56:b4a2d2ae43cf tip

merge
author Andrew McPherson <andrewm@eecs.qmul.ac.uk>
date Fri, 23 Nov 2018 15:48:14 +0000
parents 85577160a0d4
children
rev   line source
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 }