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