andrewm@0: /* andrewm@0: TouchKeys: multi-touch musical keyboard control software andrewm@0: Copyright (c) 2013 Andrew McPherson andrewm@0: andrewm@0: This program is free software: you can redistribute it and/or modify andrewm@0: it under the terms of the GNU General Public License as published by andrewm@0: the Free Software Foundation, either version 3 of the License, or andrewm@0: (at your option) any later version. andrewm@0: andrewm@0: This program is distributed in the hope that it will be useful, andrewm@0: but WITHOUT ANY WARRANTY; without even the implied warranty of andrewm@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the andrewm@0: GNU General Public License for more details. andrewm@0: andrewm@0: You should have received a copy of the GNU General Public License andrewm@0: along with this program. If not, see . andrewm@0: andrewm@0: ===================================================================== andrewm@0: andrewm@0: MidiOutputController.cpp: handles outgoing MIDI messages and manages output andrewm@0: ports; uses Juce MIDI library functions. andrewm@0: */ andrewm@0: andrewm@0: #include "MidiOutputController.h" andrewm@0: andrewm@39: #undef DEBUG_MIDI_OUTPUT_CONTROLLER andrewm@7: #undef MIDI_OUTPUT_CONTROLLER_DEBUG_RAW andrewm@0: andrewm@0: // Constructor andrewm@0: MidiOutputController::MidiOutputController() andrewm@0: { andrewm@0: } andrewm@0: andrewm@0: // Iterate through the available MIDI devices. Return a vector containing andrewm@0: // indices and names for each device. The index will later be passed back andrewm@0: // to indicate which device to open. andrewm@0: andrewm@0: vector > MidiOutputController::availableMidiDevices() { andrewm@0: vector > deviceList; andrewm@0: andrewm@0: try { andrewm@0: StringArray deviceStrings = MidiOutput::getDevices(); andrewm@0: andrewm@0: for(int i = 0; i < deviceStrings.size(); i++) { andrewm@0: pair p(i, string(deviceStrings[i].toUTF8())); andrewm@0: deviceList.push_back(p); andrewm@0: } andrewm@0: } andrewm@0: catch(...) { andrewm@0: deviceList.clear(); andrewm@0: } andrewm@0: andrewm@0: return deviceList; andrewm@0: } andrewm@0: andrewm@0: // Open a new MIDI output port, given an index related to the list from andrewm@0: // availableMidiDevices(). Returns true on success. andrewm@0: andrewm@0: bool MidiOutputController::enablePort(int identifier, int deviceNumber) { andrewm@0: if(deviceNumber < 0) andrewm@0: return false; andrewm@0: andrewm@0: // Check if there is a port for this identifier, and disable it if so andrewm@0: if(activePorts_.count(identifier) > 0) andrewm@0: disablePort(identifier); andrewm@0: andrewm@0: MidiOutput *device = MidiOutput::openDevice(deviceNumber); andrewm@0: andrewm@0: if(device == 0) { andrewm@0: cout << "Failed to enable MIDI output port " << deviceNumber << ")\n"; andrewm@0: return false; andrewm@0: } andrewm@0: andrewm@39: #ifdef DEBUG_MIDI_OUTPUT_CONTROLLER andrewm@39: cout << "Enabling MIDI output port " << deviceNumber << " for ID " << identifier << "\n"; andrewm@39: #endif andrewm@0: andrewm@0: // Save the device in the set of ports andrewm@0: MidiOutputControllerRecord record; andrewm@0: record.portNumber = deviceNumber; andrewm@0: record.output = device; andrewm@0: andrewm@13: activePorts_[identifier] = record; andrewm@0: andrewm@0: return true; andrewm@0: } andrewm@0: andrewm@20: #ifndef JUCE_WINDOWS andrewm@0: bool MidiOutputController::enableVirtualPort(int identifier, const char *name) { andrewm@13: // Check if there is a port for this identifier, and disable it if so andrewm@13: if(activePorts_.count(identifier) > 0) andrewm@13: disablePort(identifier); andrewm@13: andrewm@0: // Try to create a new port andrewm@13: MidiOutput* device = MidiOutput::createNewDevice(name); andrewm@13: if(device == 0) { andrewm@13: cout << "Failed to enable MIDI virtual output port " << name << ")\n"; andrewm@0: return false; andrewm@13: } andrewm@0: andrewm@13: MidiOutputControllerRecord record; andrewm@13: record.portNumber = kMidiVirtualOutputPortNumber; andrewm@13: record.output = device; andrewm@13: andrewm@13: activePorts_[identifier] = record; andrewm@0: andrewm@39: #ifdef DEBUG_MIDI_OUTPUT_CONTROLLER andrewm@39: cout << "Enabling virtual output port " << name << endl; andrewm@39: #endif andrewm@39: andrewm@0: return true; andrewm@0: } andrewm@20: #endif andrewm@0: andrewm@0: void MidiOutputController::disablePort(int identifier) { andrewm@0: if(activePorts_.count(identifier) <= 0) andrewm@0: return; andrewm@0: andrewm@0: MidiOutput *device = activePorts_[identifier].output; andrewm@0: andrewm@0: if(device == 0) andrewm@0: return; andrewm@0: andrewm@39: #ifdef DEBUG_MIDI_OUTPUT_CONTROLLER andrewm@39: cout << "Disabling MIDI output " << activePorts_[identifier].portNumber << " for ID " << identifier << "\n"; andrewm@39: #endif andrewm@0: delete device; andrewm@0: andrewm@0: activePorts_.erase(identifier); andrewm@0: } andrewm@0: andrewm@0: void MidiOutputController::disableAllPorts() { andrewm@0: std::map::iterator it; andrewm@0: andrewm@39: #ifdef DEBUG_MIDI_OUTPUT_CONTROLLER andrewm@39: cout << "Disabling all MIDI output ports\n"; andrewm@39: #endif andrewm@39: andrewm@0: it = activePorts_.begin(); andrewm@0: andrewm@0: while(it != activePorts_.end()) { andrewm@0: if(it->second.output == 0) andrewm@0: continue; andrewm@0: delete it->second.output; // free MidiInputCallback andrewm@0: it++; andrewm@0: } andrewm@0: andrewm@0: activePorts_.clear(); andrewm@0: } andrewm@0: andrewm@0: int MidiOutputController::enabledPort(int identifier) { andrewm@0: if(activePorts_.count(identifier) <= 0) andrewm@0: return -1; andrewm@0: return activePorts_[identifier].portNumber; andrewm@0: } andrewm@0: andrewm@0: std::vector > MidiOutputController::enabledPorts() { andrewm@0: std::vector > ports; andrewm@0: std::map::iterator it; andrewm@0: andrewm@0: for(it = activePorts_.begin(); it != activePorts_.end(); ++it) { andrewm@0: ports.push_back(std::pair(it->first, it->second.portNumber)); andrewm@0: } andrewm@0: andrewm@0: return ports; andrewm@0: } andrewm@0: andrewm@41: // Get the name of a particular MIDI input port andrewm@41: String MidiOutputController::deviceName(int portNumber) { andrewm@41: StringArray const& deviceStrings = MidiOutput::getDevices(); andrewm@41: if(portNumber < 0 || portNumber >= deviceStrings.size()) andrewm@41: return ""; andrewm@41: return deviceStrings[portNumber]; andrewm@41: } andrewm@41: andrewm@41: // Find the index of a device with a given name; return -1 if not found andrewm@41: int MidiOutputController::indexOfDeviceNamed(String const& name) { andrewm@41: StringArray const& deviceStrings = MidiOutput::getDevices(); andrewm@41: andrewm@41: for(int i = 0; i < deviceStrings.size(); i++) { andrewm@41: if(name == deviceStrings[i]) andrewm@41: return i; andrewm@41: } andrewm@41: andrewm@41: return -1; andrewm@41: } andrewm@41: andrewm@0: // Send a MIDI Note On message andrewm@0: void MidiOutputController::sendNoteOn(int port, unsigned char channel, unsigned char note, unsigned char velocity) { andrewm@0: sendMessage(port, andrewm@0: MidiMessage((int)((channel & 0x0F) | kMidiMessageNoteOn), andrewm@0: (int)(note & 0x7F), andrewm@0: (int)(velocity & 0x7F))); andrewm@0: } andrewm@0: andrewm@0: // Send a MIDI Note Off message andrewm@0: void MidiOutputController::sendNoteOff(int port, unsigned char channel, unsigned char note, unsigned char velocity) { andrewm@0: sendMessage(port, andrewm@0: MidiMessage((int)((channel & 0x0F) | kMidiMessageNoteOff), andrewm@0: (int)(note & 0x7F), andrewm@0: (int)(velocity & 0x7F))); andrewm@0: } andrewm@0: andrewm@0: // Send a MIDI Control Change message andrewm@0: void MidiOutputController::sendControlChange(int port, unsigned char channel, unsigned char control, unsigned char value) { andrewm@0: sendMessage(port, andrewm@0: MidiMessage((int)((channel & 0x0F) | kMidiMessageControlChange), andrewm@0: (int)(control & 0x7F), andrewm@0: (int)(value & 0x7F))); andrewm@0: } andrewm@0: andrewm@0: // Send a MIDI Program Change message andrewm@0: void MidiOutputController::sendProgramChange(int port, unsigned char channel, unsigned char value) { andrewm@0: sendMessage(port, andrewm@0: MidiMessage((int)((channel & 0x0F) | kMidiMessageProgramChange), andrewm@0: (int)(value & 0x7F))); andrewm@0: } andrewm@0: andrewm@0: // Send a Channel Aftertouch message andrewm@0: void MidiOutputController::sendAftertouchChannel(int port, unsigned char channel, unsigned char value) { andrewm@0: sendMessage(port, andrewm@0: MidiMessage((int)((channel & 0x0F) | kMidiMessageAftertouchChannel), andrewm@0: (int)(value & 0x7F))); andrewm@0: } andrewm@0: andrewm@0: // Send a Polyphonic Aftertouch message andrewm@0: void MidiOutputController::sendAftertouchPoly(int port, unsigned char channel, unsigned char note, unsigned char value) { andrewm@0: sendMessage(port, andrewm@0: MidiMessage((int)((channel & 0x0F) | kMidiMessageAftertouchPoly), andrewm@0: (int)(note & 0x7F), andrewm@0: (int)(value & 0x7F))); andrewm@0: } andrewm@0: andrewm@0: // Send a Pitch Wheel message andrewm@0: void MidiOutputController::sendPitchWheel(int port, unsigned char channel, unsigned int value) { andrewm@0: sendMessage(port, andrewm@0: MidiMessage((int)((channel & 0x0F) | kMidiMessagePitchWheel), andrewm@0: (int)(value & 0x7F), andrewm@0: (int)((value >> 7) & 0x7F))); andrewm@0: } andrewm@0: andrewm@0: // Send a MIDI system reset message andrewm@0: void MidiOutputController::sendReset(int port) { andrewm@0: sendMessage(port, MidiMessage(kMidiMessageReset)); andrewm@0: } andrewm@0: andrewm@0: // Send a generic MIDI message (pre-formatted data) andrewm@0: void MidiOutputController::sendMessage(int port, const MidiMessage& message) { andrewm@0: #ifdef MIDI_OUTPUT_CONTROLLER_DEBUG_RAW andrewm@0: int dataSize = message.getRawDataSize(); andrewm@0: const unsigned char *data = message.getRawData(); andrewm@0: andrewm@0: cout << "MIDI Output " << port << ": "; andrewm@0: for(int debugPrint = 0; debugPrint < dataSize; debugPrint++) andrewm@0: printf("%x ", data[debugPrint]); andrewm@0: cout << endl; andrewm@0: #endif /* MIDI_OUTPUT_CONTROLLER_DEBUG_RAW */ andrewm@0: andrewm@0: if(activePorts_.count(port) == 0) { andrewm@0: #ifdef MIDI_OUTPUT_CONTROLLER_DEBUG_RAW andrewm@0: cout << "MIDI Output: no port on " << port << endl; andrewm@0: #endif andrewm@0: return; andrewm@0: } andrewm@0: andrewm@0: activePorts_[port].output->sendMessageNow(message); andrewm@0: }