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