view Source/Main.cpp @ 56:b4a2d2ae43cf tip

merge
author Andrew McPherson <andrewm@eecs.qmul.ac.uk>
date Fri, 23 Nov 2018 15:48:14 +0000
parents 114427cb39f0
children
line wrap: on
line source
/*
  TouchKeys: multi-touch musical keyboard control software
  Copyright (c) 2013 Andrew McPherson

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
  =====================================================================
 
  Main.cpp: main startup routines, connecting to Juce library
*/

#include "MainApplicationController.h"
#include "../JuceLibraryCode/JuceHeader.h"

#ifndef TOUCHKEYS_NO_GUI
#include "GUI/MainWindow.h"
#include "GUI/GraphicsDisplayWindow.h"
#include "GUI/PreferencesWindow.h"
#include "GUI/PreferencesComponent.h"
#include "Display/OpenGLJuceCanvas.h"

//==============================================================================
class TouchKeysApplication  : public JUCEApplication
{
public:
    //==============================================================================
    TouchKeysApplication() {}

    const String getApplicationName()       { return ProjectInfo::projectName; }
    const String getApplicationVersion()    { return ProjectInfo::versionString; }
    bool moreThanOneInstanceAllowed()       { return true; }

    //==============================================================================
    void initialise (const String& commandLine) {
        // This method is where you should put your application's initialisation code..

        mainWindow_ = new MainWindow(controller_);
        keyboardDisplayWindow_ = new GraphicsDisplayWindow("TouchKeys Display", controller_.keyboardDisplay());
        preferencesWindow_ = new PreferencesWindow(controller_);
        
        controller_.setKeyboardDisplayWindow(keyboardDisplayWindow_);
        controller_.setPreferencesWindow(preferencesWindow_);
        controller_.initialise();
    }

    void shutdown() {
        // Add your application's shutdown code here..
        if(controller_.touchkeyDeviceIsRunning())
            controller_.stopTouchkeyDevice();
        
        mainWindow_ = nullptr; // (deletes our window)
        
        controller_.setKeyboardDisplayWindow(0);    // Delete display window and disconnect from controller
        controller_.setPreferencesWindow(0);
        keyboardDisplayWindow_ = nullptr;
        preferencesWindow_ = nullptr;
    }

    //==============================================================================
    void systemRequestedQuit() {
        // This is called when the app is being asked to quit: you can ignore this
        // request and let the app carry on running, or call quit() to allow the app to close.
        quit();
    }

    void anotherInstanceStarted (const String& commandLine) {
        // When another instance of the app is launched while this one is running,
        // this method is invoked, and the commandLine parameter tells you what
        // the other instance's command-line arguments were.
    }

private:
    ScopedPointer<MainWindow> mainWindow_;
    ScopedPointer<GraphicsDisplayWindow> keyboardDisplayWindow_;
    ScopedPointer<PreferencesWindow> preferencesWindow_;
    MainApplicationController controller_;
};

//==============================================================================
// This macro generates the main() routine that launches the app.
START_JUCE_APPLICATION (TouchKeysApplication)

#else // TOUCHKEYS_NO_GUI

#include <getopt.h>
#include <libgen.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>

bool programShouldStop_ = false;

static struct option long_options[] = {
	{"help", no_argument, NULL, 'h'},
	{"list", no_argument, NULL, 'l'},
	{"touchkeys", required_argument, NULL, 't'},
    {"midi-input", required_argument, NULL, 'i'},
    {"midi-output", required_argument, NULL, 'o'},
    {"virtual-midi-output", no_argument, NULL, 'V'},
    {"osc-input-port", required_argument, NULL, 'P'},
	{0,0,0,0}
};

void sigint_handler(int s){
    programShouldStop_ = true;
}

void usage(const char * processName)	// Print usage information and exit
{
	cerr << "Usage: " << processName << " [-h] [-l] [-t touchkeys] [-i MIDI-in] [-o MIDI-out]\n";
	cerr << "  -h:   Print this menu\n";
	cerr << "  -l:   List available TouchKeys and MIDI devices\n";
	cerr << "  -t:   Specify TouchKeys device path and autostart\n";
    cerr << "  -i:   Specify MIDI input device\n";
    cerr << "  -o:   Specify MIDI output device\n";
    cerr << "  -V:   Open virtual MIDI output\n";
    cerr << "  -P:   Specify OSC input port (default: " << kDefaultOscReceivePort << ")\n";
}

void list_devices(MainApplicationController& controller)
{
    std::vector<std::string> touchkeysDevices(controller.availableTouchkeyDevices());
    std::vector<std::pair<int, std::string> > midiInputDevices(controller.availableMIDIInputDevices());
    std::vector<std::pair<int, std::string> > midiOutputDevices(controller.availableMIDIOutputDevices());
    
    cerr << "TouchKeys devices: \n";
    if(touchkeysDevices.empty())
        cerr << "  [none found]\n";
    else {
        for(std::vector<std::string>::iterator it = touchkeysDevices.begin(); it != touchkeysDevices.end(); ++it) {
            cerr << "  /dev/" << *it << "\n";
        }
    }

    cerr << "\nMIDI input devices: \n";
    if(midiInputDevices.empty())
        cerr << "  [none found]\n";
    else {
        for(std::vector<std::pair<int, std::string> >::iterator it = midiInputDevices.begin();
            it != midiInputDevices.end();
            ++it) {
            cerr << "  " << it->first << ": " << it->second << "\n";
        }
    }
    
    cerr << "\nMIDI output devices: \n";
    if(midiOutputDevices.empty())
        cerr << "  [none found]\n";
    else {
        for(std::vector<std::pair<int, std::string> >::iterator it = midiOutputDevices.begin();
            it != midiOutputDevices.end();
            ++it) {
            cerr << "  " << it->first << ": " << it->second << "\n";
        }
    }
}

int main (int argc, char* argv[])
{
    MainApplicationController controller;
    
    int ch, option_index;
    int midiInputNum = 0, midiOutputNum = 0;
    bool useVirtualMidiOutput = false;
    bool shouldStart = true;
    bool autostartTouchkeys = false;
    bool autoopenMidiOut = false, autoopenMidiIn = false;
    int oscInputPort = kDefaultOscReceivePort;
    string touchkeysDevicePath;
    
	while((ch = getopt_long(argc, argv, "hli:o:t:VP:", long_options, &option_index)) != -1)
	{
        if(ch == 'l') { // List devices
            list_devices(controller);
            shouldStart = false;
            break;
        }
        else if(ch == 't') { // TouchKeys device
            touchkeysDevicePath = optarg;
            autostartTouchkeys = true;
        }
        else if(ch == 'i') { // MIDI input device
            midiInputNum = atoi(optarg);
            autoopenMidiIn = true;
        }
        else if(ch == 'o') { // MIDI output device
            midiOutputNum = atoi(optarg);
            autoopenMidiOut = true;
        }
        else if(ch == 'V') { // Virtual MIDI output
            useVirtualMidiOutput = true;
            autoopenMidiOut = true;
        }
        else if(ch == 'P') { // OSC port
            oscInputPort = atoi(optarg);
        }
        else {
            usage(basename(argv[0]));
            shouldStart = false;
            break;
		}
	}
    
    
    if(shouldStart) {
        // Main initialization: open TouchKeys and MIDI devices
        controller.initialise();
        
        // Always enable OSC input without GUI, since it is how we control
        // the system
        controller.oscReceiveSetPort(oscInputPort);
        controller.oscReceiveSetEnabled(true);
        
        try {
            // Open MIDI devices
            if(autoopenMidiIn) {
                cout << "Opening MIDI input device " << midiInputNum << endl;
                controller.enableMIDIInputPort(midiInputNum, true);
            }

            // TODO: enable multiple keyboard segments
            if(autoopenMidiOut) {
                if(useVirtualMidiOutput) {
#ifndef JUCE_WINDOWS
                    cout << "Opening virtual MIDI output\n";
                    controller.enableMIDIOutputVirtualPort(0, "TouchKeys");
#endif
                }
                else {
                    cout << "Opening MIDI output device " << midiOutputNum << endl;
                    controller.enableMIDIOutputPort(0, midiOutputNum);
                }
            }
            
            // Start the TouchKeys
            if(autostartTouchkeys) {
                cout << "Starting the TouchKeys on " << touchkeysDevicePath << " ... ";
                if(!controller.touchkeyDeviceStartupSequence(touchkeysDevicePath.c_str())) {
                    cout << "failed: " << controller.touchkeyDeviceErrorMessage() << endl;
                    throw new exception;
                }
                else
                    cout << "succeeded!\n";
            }
            
            // Set up interrupt catching so we can stop with Ctrl-C
            struct sigaction sigIntHandler;
            
            sigIntHandler.sa_handler = sigint_handler;
            sigemptyset(&sigIntHandler.sa_mask);
            sigIntHandler.sa_flags = 0;
            sigaction(SIGINT, &sigIntHandler, NULL);

            // Wait until interrupt signal is received
            while(!programShouldStop_) {
                Thread::sleep(50);
            }
        }
        catch(...) {
            
        }
        
        // Stop TouchKeys if still running
        if(controller.touchkeyDeviceIsRunning())
            controller.stopTouchkeyDevice();
    }
    
    // Clean up any MessageManager instance that JUCE creates
    DeletedAtShutdown::deleteAll();
    MessageManager::deleteInstance();
    return 0;
}

#endif // TOUCHKEYS_NO_GUI