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: Main.cpp: main startup routines, connecting to Juce library andrewm@0: */ andrewm@0: andrewm@20: #include "MainApplicationController.h" andrewm@0: #include "../JuceLibraryCode/JuceHeader.h" andrewm@0: andrewm@0: #ifndef TOUCHKEYS_NO_GUI andrewm@0: #include "GUI/MainWindow.h" andrewm@0: #include "GUI/GraphicsDisplayWindow.h" andrewm@41: #include "GUI/PreferencesWindow.h" andrewm@41: #include "GUI/PreferencesComponent.h" andrewm@0: #include "Display/OpenGLJuceCanvas.h" andrewm@0: andrewm@0: //============================================================================== andrewm@0: class TouchKeysApplication : public JUCEApplication andrewm@0: { andrewm@0: public: andrewm@0: //============================================================================== andrewm@0: TouchKeysApplication() {} andrewm@0: andrewm@0: const String getApplicationName() { return ProjectInfo::projectName; } andrewm@0: const String getApplicationVersion() { return ProjectInfo::versionString; } andrewm@0: bool moreThanOneInstanceAllowed() { return true; } andrewm@0: andrewm@0: //============================================================================== andrewm@0: void initialise (const String& commandLine) { andrewm@0: // This method is where you should put your application's initialisation code.. andrewm@0: andrewm@0: mainWindow_ = new MainWindow(controller_); andrewm@17: keyboardDisplayWindow_ = new GraphicsDisplayWindow("TouchKeys Display", controller_.keyboardDisplay()); andrewm@41: preferencesWindow_ = new PreferencesWindow(controller_); andrewm@0: andrewm@0: controller_.setKeyboardDisplayWindow(keyboardDisplayWindow_); andrewm@41: controller_.setPreferencesWindow(preferencesWindow_); andrewm@41: controller_.initialise(); andrewm@0: } andrewm@0: andrewm@0: void shutdown() { andrewm@0: // Add your application's shutdown code here.. andrewm@28: if(controller_.touchkeyDeviceIsRunning()) andrewm@28: controller_.stopTouchkeyDevice(); andrewm@28: andrewm@0: mainWindow_ = nullptr; // (deletes our window) andrewm@0: andrewm@0: controller_.setKeyboardDisplayWindow(0); // Delete display window and disconnect from controller andrewm@41: controller_.setPreferencesWindow(0); andrewm@0: keyboardDisplayWindow_ = nullptr; andrewm@41: preferencesWindow_ = nullptr; andrewm@0: } andrewm@0: andrewm@0: //============================================================================== andrewm@0: void systemRequestedQuit() { andrewm@0: // This is called when the app is being asked to quit: you can ignore this andrewm@0: // request and let the app carry on running, or call quit() to allow the app to close. andrewm@0: quit(); andrewm@0: } andrewm@0: andrewm@0: void anotherInstanceStarted (const String& commandLine) { andrewm@0: // When another instance of the app is launched while this one is running, andrewm@0: // this method is invoked, and the commandLine parameter tells you what andrewm@0: // the other instance's command-line arguments were. andrewm@0: } andrewm@0: andrewm@0: private: andrewm@0: ScopedPointer mainWindow_; andrewm@0: ScopedPointer keyboardDisplayWindow_; andrewm@41: ScopedPointer preferencesWindow_; andrewm@0: MainApplicationController controller_; andrewm@0: }; andrewm@0: andrewm@0: //============================================================================== andrewm@0: // This macro generates the main() routine that launches the app. andrewm@0: START_JUCE_APPLICATION (TouchKeysApplication) andrewm@0: andrewm@0: #else // TOUCHKEYS_NO_GUI andrewm@0: andrewm@0: #include andrewm@0: #include andrewm@0: #include andrewm@0: #include andrewm@0: #include andrewm@0: andrewm@0: bool programShouldStop_ = false; andrewm@0: andrewm@0: static struct option long_options[] = { andrewm@0: {"help", no_argument, NULL, 'h'}, andrewm@0: {"list", no_argument, NULL, 'l'}, andrewm@0: {"touchkeys", required_argument, NULL, 't'}, andrewm@0: {"midi-input", required_argument, NULL, 'i'}, andrewm@0: {"midi-output", required_argument, NULL, 'o'}, andrewm@50: {"virtual-midi-output", no_argument, NULL, 'V'}, andrewm@50: {"osc-input-port", required_argument, NULL, 'P'}, andrewm@0: {0,0,0,0} andrewm@0: }; andrewm@0: andrewm@0: void sigint_handler(int s){ andrewm@0: programShouldStop_ = true; andrewm@0: } andrewm@0: andrewm@0: void usage(const char * processName) // Print usage information and exit andrewm@0: { andrewm@0: cerr << "Usage: " << processName << " [-h] [-l] [-t touchkeys] [-i MIDI-in] [-o MIDI-out]\n"; andrewm@0: cerr << " -h: Print this menu\n"; andrewm@0: cerr << " -l: List available TouchKeys and MIDI devices\n"; andrewm@50: cerr << " -t: Specify TouchKeys device path and autostart\n"; andrewm@0: cerr << " -i: Specify MIDI input device\n"; andrewm@0: cerr << " -o: Specify MIDI output device\n"; andrewm@50: cerr << " -V: Open virtual MIDI output\n"; andrewm@50: cerr << " -P: Specify OSC input port (default: " << kDefaultOscReceivePort << ")\n"; andrewm@0: } andrewm@0: andrewm@0: void list_devices(MainApplicationController& controller) andrewm@0: { andrewm@0: std::vector touchkeysDevices(controller.availableTouchkeyDevices()); andrewm@0: std::vector > midiInputDevices(controller.availableMIDIInputDevices()); andrewm@0: std::vector > midiOutputDevices(controller.availableMIDIOutputDevices()); andrewm@0: andrewm@0: cerr << "TouchKeys devices: \n"; andrewm@0: if(touchkeysDevices.empty()) andrewm@0: cerr << " [none found]\n"; andrewm@0: else { andrewm@0: for(std::vector::iterator it = touchkeysDevices.begin(); it != touchkeysDevices.end(); ++it) { andrewm@0: cerr << " /dev/" << *it << "\n"; andrewm@0: } andrewm@0: } andrewm@0: andrewm@0: cerr << "\nMIDI input devices: \n"; andrewm@0: if(midiInputDevices.empty()) andrewm@0: cerr << " [none found]\n"; andrewm@0: else { andrewm@0: for(std::vector >::iterator it = midiInputDevices.begin(); andrewm@0: it != midiInputDevices.end(); andrewm@0: ++it) { andrewm@0: cerr << " " << it->first << ": " << it->second << "\n"; andrewm@0: } andrewm@0: } andrewm@0: andrewm@0: cerr << "\nMIDI output devices: \n"; andrewm@0: if(midiOutputDevices.empty()) andrewm@0: cerr << " [none found]\n"; andrewm@0: else { andrewm@0: for(std::vector >::iterator it = midiOutputDevices.begin(); andrewm@0: it != midiOutputDevices.end(); andrewm@0: ++it) { andrewm@0: cerr << " " << it->first << ": " << it->second << "\n"; andrewm@0: } andrewm@0: } andrewm@0: } andrewm@0: andrewm@0: int main (int argc, char* argv[]) andrewm@0: { andrewm@0: MainApplicationController controller; andrewm@50: andrewm@0: int ch, option_index; andrewm@0: int midiInputNum = 0, midiOutputNum = 0; andrewm@0: bool useVirtualMidiOutput = false; andrewm@0: bool shouldStart = true; andrewm@50: bool autostartTouchkeys = false; andrewm@50: bool autoopenMidiOut = false, autoopenMidiIn = false; andrewm@50: int oscInputPort = kDefaultOscReceivePort; andrewm@0: string touchkeysDevicePath; andrewm@0: andrewm@50: while((ch = getopt_long(argc, argv, "hli:o:t:VP:", long_options, &option_index)) != -1) andrewm@0: { andrewm@0: if(ch == 'l') { // List devices andrewm@0: list_devices(controller); andrewm@0: shouldStart = false; andrewm@0: break; andrewm@0: } andrewm@0: else if(ch == 't') { // TouchKeys device andrewm@0: touchkeysDevicePath = optarg; andrewm@50: autostartTouchkeys = true; andrewm@0: } andrewm@0: else if(ch == 'i') { // MIDI input device andrewm@0: midiInputNum = atoi(optarg); andrewm@50: autoopenMidiIn = true; andrewm@0: } andrewm@0: else if(ch == 'o') { // MIDI output device andrewm@0: midiOutputNum = atoi(optarg); andrewm@50: autoopenMidiOut = true; andrewm@0: } andrewm@50: else if(ch == 'V') { // Virtual MIDI output andrewm@0: useVirtualMidiOutput = true; andrewm@50: autoopenMidiOut = true; andrewm@50: } andrewm@50: else if(ch == 'P') { // OSC port andrewm@50: oscInputPort = atoi(optarg); andrewm@0: } andrewm@0: else { andrewm@0: usage(basename(argv[0])); andrewm@0: shouldStart = false; andrewm@0: break; andrewm@0: } andrewm@0: } andrewm@0: andrewm@50: andrewm@0: if(shouldStart) { andrewm@0: // Main initialization: open TouchKeys and MIDI devices andrewm@50: controller.initialise(); andrewm@50: andrewm@50: // Always enable OSC input without GUI, since it is how we control andrewm@50: // the system andrewm@50: controller.oscReceiveSetPort(oscInputPort); andrewm@50: controller.oscReceiveSetEnabled(true); andrewm@50: andrewm@0: try { andrewm@50: // Open MIDI devices andrewm@50: if(autoopenMidiIn) { andrewm@50: cout << "Opening MIDI input device " << midiInputNum << endl; andrewm@50: controller.enableMIDIInputPort(midiInputNum, true); andrewm@50: } andrewm@50: andrewm@50: // TODO: enable multiple keyboard segments andrewm@50: if(autoopenMidiOut) { andrewm@50: if(useVirtualMidiOutput) { andrewm@50: #ifndef JUCE_WINDOWS andrewm@50: cout << "Opening virtual MIDI output\n"; andrewm@50: controller.enableMIDIOutputVirtualPort(0, "TouchKeys"); andrewm@50: #endif andrewm@0: } andrewm@0: else { andrewm@50: cout << "Opening MIDI output device " << midiOutputNum << endl; andrewm@50: controller.enableMIDIOutputPort(0, midiOutputNum); andrewm@0: } andrewm@0: } andrewm@0: andrewm@0: // Start the TouchKeys andrewm@50: if(autostartTouchkeys) { andrewm@50: cout << "Starting the TouchKeys on " << touchkeysDevicePath << " ... "; andrewm@50: if(!controller.touchkeyDeviceStartupSequence(touchkeysDevicePath.c_str())) { andrewm@50: cout << "failed: " << controller.touchkeyDeviceErrorMessage() << endl; andrewm@50: throw new exception; andrewm@50: } andrewm@50: else andrewm@50: cout << "succeeded!\n"; andrewm@0: } andrewm@0: andrewm@0: // Set up interrupt catching so we can stop with Ctrl-C andrewm@50: struct sigaction sigIntHandler; andrewm@0: andrewm@0: sigIntHandler.sa_handler = sigint_handler; andrewm@0: sigemptyset(&sigIntHandler.sa_mask); andrewm@0: sigIntHandler.sa_flags = 0; andrewm@0: sigaction(SIGINT, &sigIntHandler, NULL); andrewm@0: andrewm@50: // Wait until interrupt signal is received andrewm@0: while(!programShouldStop_) { andrewm@0: Thread::sleep(50); andrewm@50: } andrewm@0: } andrewm@0: catch(...) { andrewm@0: andrewm@0: } andrewm@50: andrewm@50: // Stop TouchKeys if still running andrewm@50: if(controller.touchkeyDeviceIsRunning()) andrewm@50: controller.stopTouchkeyDevice(); andrewm@0: } andrewm@0: andrewm@0: // Clean up any MessageManager instance that JUCE creates andrewm@0: DeletedAtShutdown::deleteAll(); andrewm@0: MessageManager::deleteInstance(); andrewm@0: return 0; andrewm@0: } andrewm@0: andrewm@0: #endif // TOUCHKEYS_NO_GUI