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: MainApplicationController.h: contains the overall glue that holds
andrewm@0: together the various parts of the TouchKeys code. It works together
andrewm@0: with the user interface to let the user configure the hardware and
andrewm@0: manage the mappings, but it is kept separate from any particular user
andrewm@0: interface configuration.
andrewm@0: */
andrewm@0:
andrewm@0: #ifndef __TouchKeys__MainApplicationController__
andrewm@0: #define __TouchKeys__MainApplicationController__
andrewm@0:
andrewm@11: #undef TOUCHKEY_ENTROPY_GENERATOR_ENABLE
andrewm@11:
andrewm@0: #include
andrewm@0: #include
andrewm@20: #include "TouchKeys/Osc.h"
andrewm@0: #include "TouchKeys/MidiInputController.h"
andrewm@0: #include "TouchKeys/MidiKeyboardSegment.h"
andrewm@0: #include "TouchKeys/MidiOutputController.h"
andrewm@0: #include "TouchKeys/TouchkeyDevice.h"
andrewm@9: #include "TouchKeys/TouchkeyOscEmulator.h"
andrewm@0: #include "Mappings/Vibrato/TouchkeyVibratoMappingFactory.h"
andrewm@0: #include "Mappings/PitchBend/TouchkeyPitchBendMappingFactory.h"
andrewm@0: #include "Mappings/Control/TouchkeyControlMappingFactory.h"
andrewm@0: #include "Mappings/ReleaseAngle/TouchkeyReleaseAngleMappingFactory.h"
andrewm@0: #include "Mappings/OnsetAngle/TouchkeyOnsetAngleMappingFactory.h"
andrewm@0: #include "Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMappingFactory.h"
andrewm@0: #include "Mappings/KeyDivision/TouchkeyKeyDivisionMappingFactory.h"
andrewm@0: #include "Mappings/MappingFactorySplitter.h"
andrewm@0: #include "TouchKeys/LogPlayback.h"
andrewm@20: #include "../JuceLibraryCode/JuceHeader.h"
andrewm@0:
andrewm@11: #ifdef TOUCHKEY_ENTROPY_GENERATOR_ENABLE
andrewm@11: #include "TouchKeys/TouchkeyEntropyGenerator.h"
andrewm@11: #endif
andrewm@11:
andrewm@17: #ifndef TOUCHKEYS_NO_GUI
andrewm@17: #include "GUI/GraphicsDisplayWindow.h"
andrewm@46: #include "GUI/PreferencesWindow.h"
andrewm@17: class KeyboardTesterDisplay;
andrewm@17: #endif
andrewm@17:
andrewm@0: const char kDefaultOscTransmitHost[] = "127.0.0.1";
andrewm@0: const char kDefaultOscTransmitPort[] = "8000";
andrewm@6: const int kDefaultOscReceivePort = 8001;
andrewm@0:
andrewm@49: class MainApplicationOSCController;
andrewm@17:
andrewm@0: class MainApplicationController : public OscHandler {
andrewm@49: friend class MainApplicationOSCController;
andrewm@49:
andrewm@0: public:
andrewm@0: // *** Constructor ***
andrewm@0: MainApplicationController();
andrewm@0:
andrewm@0: // *** Destructor ***
andrewm@0: ~MainApplicationController();
andrewm@0:
andrewm@41: // *** Startup actions ***
andrewm@41: void initialise();
andrewm@41:
andrewm@0: // *** TouchKeys device methods ***
andrewm@0:
andrewm@0: // Return the path prefix of the TouchKeys device
andrewm@0: std::string touchkeyDevicePrefix();
andrewm@0:
andrewm@0: // Return a list of paths to all available touchkey devices
andrewm@0: std::vector availableTouchkeyDevices();
andrewm@0:
andrewm@0: // Run the main startup sequence: open device, check its presence,
andrewm@0: // start data collection, all in one method. Returns true if successful.
andrewm@0: // Will set the error message string if not
andrewm@0: bool touchkeyDeviceStartupSequence(const char * path);
andrewm@41: void touchkeyDeviceClearErrorMessage();
andrewm@41:
andrewm@41: // Check whether a given touchkey device exists
andrewm@41: bool touchkeyDeviceExists(const char * path);
andrewm@0:
andrewm@0: // Select a particular touchkey device
andrewm@41: bool openTouchkeyDevice(const char * path);
andrewm@41:
andrewm@11: void closeTouchkeyDevice();
andrewm@0:
andrewm@0: // Check for device present
andrewm@0: bool touchkeyDeviceCheckForPresence(int waitMilliseconds = 250, int tries = 10);
andrewm@0:
andrewm@0: // Start/stop the TouchKeys data collection
andrewm@41: bool startTouchkeyDevice();
andrewm@41: void stopTouchkeyDevice();
andrewm@0:
andrewm@0: // Status queries on TouchKeys
andrewm@0: // Returns true if device has been opened
andrewm@41: bool touchkeyDeviceIsOpen();
andrewm@41:
andrewm@0: // Return true if device is collecting data
andrewm@11: bool touchkeyDeviceIsRunning();
andrewm@11:
andrewm@0: // Returns true if an error has occurred
andrewm@41: bool touchkeyDeviceErrorOccurred();
andrewm@41:
andrewm@0: // Return the error message if one occurred
andrewm@41: std::string touchkeyDeviceErrorMessage();
andrewm@41:
andrewm@0: // How many octaves on the current device
andrewm@41: int touchkeyDeviceNumberOfOctaves();
andrewm@41:
andrewm@0: // Return the lowest MIDI note
andrewm@41: int touchkeyDeviceLowestMidiNote();
andrewm@41:
andrewm@0: // Set the lowest MIDI note for the TouchKeys
andrewm@41: void touchkeyDeviceSetLowestMidiNote(int note);
andrewm@41:
andrewm@0: // Attempt to autodetect the correct TouchKey octave from MIDI data
andrewm@0: void touchkeyDeviceAutodetectLowestMidiNote();
andrewm@0: void touchkeyDeviceStopAutodetecting();
andrewm@0: bool touchkeyDeviceIsAutodetecting();
andrewm@0:
andrewm@0: // *** MIDI device methods ***
andrewm@0:
andrewm@0: // Return a list of IDs and paths to all available MIDI devices
andrewm@0: std::vector > availableMIDIInputDevices() {
andrewm@0: return midiInputController_.availableMidiDevices();
andrewm@0: }
andrewm@0:
andrewm@0: std::vector > availableMIDIOutputDevices() {
andrewm@0: return midiOutputController_.availableMidiDevices();
andrewm@0: }
andrewm@0:
andrewm@0: // Return the number of keyboard segments
andrewm@0: int midiSegmentsCount() {
andrewm@0: return midiInputController_.numSegments();
andrewm@0: }
andrewm@0: // Return the pointer to a specific segment
andrewm@0: MidiKeyboardSegment* midiSegment(int index) {
andrewm@0: return midiInputController_.segment(index);
andrewm@0: }
andrewm@0: // Return a unique signature of segment configuration which
andrewm@0: // tells any listeners whether an update has happened
andrewm@0: int midiSegmentUniqueIdentifier() {
andrewm@0: return midiInputController_.segmentUniqueIdentifier();
andrewm@0: }
andrewm@0: // Add a new segment, returning the result. Segments are
andrewm@0: // stored
andrewm@0: MidiKeyboardSegment* midiSegmentAdd();
andrewm@0: // Remove a segment
andrewm@13: void midiSegmentRemove(MidiKeyboardSegment *segment);
andrewm@0:
andrewm@0: // Select MIDI input/output devices
andrewm@41: void enableMIDIInputPort(int portNumber, bool isPrimary);
andrewm@41: void enableAllMIDIInputPorts(int primaryPortNumber);
andrewm@41: void disableMIDIInputPort(int portNumber);
andrewm@41: void disablePrimaryMIDIInputPort();
andrewm@41: void disableAllMIDIInputPorts(bool auxiliaryOnly);
andrewm@41: void enableMIDIOutputPort(int identifier, int deviceNumber);
andrewm@20: #ifndef JUCE_WINDOWS
andrewm@41: void enableMIDIOutputVirtualPort(int identifier, const char *name);
andrewm@20: #endif
andrewm@41: void disableMIDIOutputPort(int identifier);
andrewm@41: void disableAllMIDIOutputPorts();
andrewm@0:
andrewm@0: // Get selected MIDI input/output devices by ID
andrewm@31: int selectedMIDIPrimaryInputPort() {
andrewm@31: return midiInputController_.primaryActivePort();
andrewm@31: }
andrewm@31: std::vector selectedMIDIAuxInputPorts() {
andrewm@31: return midiInputController_.auxiliaryActivePorts();
andrewm@0: }
andrewm@0: int selectedMIDIOutputPort(int identifier) {
andrewm@0: return midiOutputController_.enabledPort(identifier);
andrewm@0: }
andrewm@0:
andrewm@0: void midiTouchkeysStandaloneModeEnable();
andrewm@0: void midiTouchkeysStandaloneModeDisable();
andrewm@0: bool midiTouchkeysStandaloneModeIsEnabled() { return touchkeyStandaloneModeEnabled_; }
andrewm@0:
andrewm@28: // *** Update sync methods ***
andrewm@28: // The controller maintains a variable that tells when the devices should be updated
andrewm@28: // by the control window component. Whenever it changes value, the devices should be rescanned.
andrewm@28:
andrewm@28: int devicesShouldUpdate() { return deviceUpdateCounter_; }
andrewm@28: void tellDevicesToUpdate() { deviceUpdateCounter_++; }
andrewm@28:
andrewm@0: // *** OSC device methods ***
andrewm@0:
andrewm@41: bool oscTransmitEnabled();
andrewm@41: void oscTransmitSetEnabled(bool enable);
andrewm@41: bool oscTransmitRawDataEnabled();
andrewm@41: void oscTransmitSetRawDataEnabled(bool enable);
andrewm@41: std::vector oscTransmitAddresses();
andrewm@41: int oscTransmitAddAddress(const char * host, const char * port, int proto = LO_UDP);
andrewm@41: void oscTransmitRemoveAddress(int index);
andrewm@41: void oscTransmitClearAddresses();
andrewm@0:
andrewm@6: // OSC Input (receiver) methods
andrewm@6: // Enable or disable on the OSC receive, and report is status
andrewm@41: bool oscReceiveEnabled();
andrewm@41:
andrewm@6: // Enable method returns true on success (false only if it was
andrewm@6: // unable to set the port)
andrewm@41: bool oscReceiveSetEnabled(bool enable);
andrewm@6:
andrewm@6: // Whether the OSC server is running (false means couldn't open port)
andrewm@41: bool oscReceiveRunning();
andrewm@41:
andrewm@6: // Get the current OSC receive port
andrewm@41: int oscReceivePort();
andrewm@41:
andrewm@6: // Set the current OSC receive port (returns true on success)
andrewm@41: bool oscReceiveSetPort(int port);
andrewm@6:
andrewm@0: // *** Display methods ***
andrewm@0:
andrewm@0: KeyboardDisplay& keyboardDisplay() { return keyboardDisplay_; }
andrewm@0: #ifndef TOUCHKEYS_NO_GUI
andrewm@0: void setKeyboardDisplayWindow(DocumentWindow *window) { keyboardDisplayWindow_ = window; }
andrewm@0: void showKeyboardDisplayWindow() {
andrewm@0: if(keyboardDisplayWindow_ != 0) {
andrewm@46: keyboardDisplayWindow_->addToDesktop(keyboardDisplayWindow_->getDesktopWindowStyleFlags()
andrewm@46: | ComponentPeer::windowHasCloseButton);
andrewm@0: keyboardDisplayWindow_->setVisible(true);
andrewm@0: keyboardDisplayWindow_->toFront(true);
andrewm@0: }
andrewm@0: }
andrewm@41: void setPreferencesWindow(PreferencesWindow *window) { preferencesWindow_ = window; }
andrewm@41: void showPreferencesWindow() {
andrewm@41: if(preferencesWindow_ != 0) {
andrewm@46: preferencesWindow_->addToDesktop(preferencesWindow_->getDesktopWindowStyleFlags()
andrewm@46: | ComponentPeer::windowHasCloseButton);
andrewm@41: preferencesWindow_->setVisible(true);
andrewm@41: preferencesWindow_->toFront(true);
andrewm@41: }
andrewm@41: }
andrewm@0: #endif
andrewm@0:
andrewm@0: // *** Logging methods ***
andrewm@0: // Logging methods which record TouchKeys and MIDI data to files for
andrewm@0: // later analysis/playback
andrewm@0:
andrewm@0: void startLogging();
andrewm@0: void stopLogging();
andrewm@0: bool isLogging() { return loggingActive_; }
andrewm@0: void setLoggingDirectory(const char *directory);
andrewm@0:
andrewm@53: // Playback methods for log files
andrewm@53:
andrewm@53: void playLogWithDialog();
andrewm@53: void stopPlayingLog();
andrewm@53: bool isPlayingLog() { return isPlayingLog_; }
andrewm@53:
andrewm@0: // *** OSC handler method (different from OSC device selection) ***
andrewm@0:
andrewm@0: bool oscHandlerMethod(const char *path, const char *types, int numValues, lo_arg **values, void *data);
andrewm@0:
andrewm@0: // *** Mapping methods ***
andrewm@49:
andrewm@0: // Whether experimental (not totally finished/tested) mappings are available
andrewm@0: bool experimentalMappingsEnabled() { return experimentalMappingsEnabled_; }
andrewm@0: void setExperimentalMappingsEnabled(bool enable) { experimentalMappingsEnabled_ = enable; }
andrewm@0:
andrewm@33: // *** Preset Save/Load ***
andrewm@33: // These methods save the current settings to file or load settings
andrewm@33: // from a file. They return true on success.
andrewm@33: bool savePresetToFile(const char *filename);
andrewm@33: bool loadPresetFromFile(const char *filename);
andrewm@55:
andrewm@33: #ifndef TOUCHKEYS_NO_GUI
andrewm@33: bool savePresetWithDialog();
andrewm@33: bool loadPresetWithDialog();
andrewm@33: #endif
andrewm@33:
andrewm@37: // Clears the current preset and restores default settings to zones/mappings
andrewm@37: void clearPreset();
andrewm@37:
andrewm@41: // *** Preferences ***
andrewm@41:
andrewm@41: // Whether to automatically start the TouchKeys on startup
andrewm@41: bool getPrefsAutoStartTouchKeys();
andrewm@41: void setPrefsAutoStartTouchKeys(bool autoStart);
andrewm@41:
andrewm@41: // Whether to automatically detect the TouchKeys octave when they start
andrewm@41: bool getPrefsAutodetectOctave();
andrewm@41: void setPrefsAutodetectOctave(bool autoDetect);
andrewm@41:
andrewm@41: // Which preset (if any) to load at startup
andrewm@41: void setPrefsStartupPresetNone();
andrewm@41: bool getPrefsStartupPresetNone();
andrewm@41:
andrewm@41: void setPrefsStartupPresetLastSaved();
andrewm@41: bool getPrefsStartupPresetLastSaved();
andrewm@41:
andrewm@41: void setPrefsStartupPresetVibratoPitchBend();
andrewm@41: bool getPrefsStartupPresetVibratoPitchBend();
andrewm@41:
andrewm@41: void setPrefsStartupPreset(String const& path);
andrewm@41: String getPrefsStartupPreset();
andrewm@41:
andrewm@41: // Reset all preferences
andrewm@41: void resetPreferences();
andrewm@41:
andrewm@41: // Load global preferences from file
andrewm@41: void loadApplicationPreferences();
andrewm@41:
andrewm@41: // Load a MIDI output device from preexisting application preferences
andrewm@41: void loadMIDIOutputFromApplicationPreferences(int zone);
andrewm@41:
andrewm@17: #ifdef ENABLE_TOUCHKEYS_SENSOR_TEST
andrewm@17: // *** TouchKeys sensor testing methods ***
andrewm@17: // Start testing the TouchKeys sensors
andrewm@17: bool touchkeySensorTestStart(const char *path, int firstKey);
andrewm@17:
andrewm@17: // Stop testing the TouchKeys sensors
andrewm@17: void touchkeySensorTestStop();
andrewm@17:
andrewm@17: // Is the sensor test running?
andrewm@17: bool touchkeySensorTestIsRunning();
andrewm@17:
andrewm@17: // Set the current key that is begin tested
andrewm@17: void touchkeySensorTestSetKey(int key);
andrewm@17:
andrewm@17: // Reset the testing state to all sensors off
andrewm@17: void touchkeySensorTestResetState();
andrewm@17: #endif
andrewm@17:
andrewm@53: #ifdef ENABLE_TOUCHKEYS_FIRMWARE_UPDATE
andrewm@53: // Put TouchKeys controller board into bootloader mode
andrewm@53: bool touchkeyJumpToBootloader(const char *path);
andrewm@53: #endif
andrewm@53:
andrewm@0: // *** Static utility methods ***
andrewm@0: static std::string midiNoteName(int noteNumber);
andrewm@0: static int midiNoteNumberForName(std::string const& name);
andrewm@0:
andrewm@0: private:
andrewm@33: bool savePresetHelper(File& outputFile);
andrewm@33: bool loadPresetHelper(File const& inputFile);
andrewm@33:
andrewm@41: // Application properties: for managing preferences
andrewm@41: ApplicationProperties applicationProperties_;
andrewm@41:
andrewm@0: // TouchKeys objects
andrewm@49: MainApplicationOSCController *mainOscController_;
andrewm@0: PianoKeyboard keyboardController_;
andrewm@0: MidiInputController midiInputController_;
andrewm@0: MidiOutputController midiOutputController_;
andrewm@0: OscTransmitter oscTransmitter_;
andrewm@6: OscReceiver oscReceiver_;
andrewm@9: TouchkeyDevice touchkeyController_;
andrewm@9: TouchkeyOscEmulator touchkeyEmulator_;
andrewm@53: LogPlayback *logPlayback_;
andrewm@11: #ifdef TOUCHKEY_ENTROPY_GENERATOR_ENABLE
andrewm@11: TouchkeyEntropyGenerator touchkeyEntropyGenerator_;
andrewm@11: bool entropyGeneratorSelected_;
andrewm@11: #endif
andrewm@0:
andrewm@0: bool touchkeyErrorOccurred_;
andrewm@0: std::string touchkeyErrorMessage_;
andrewm@0: bool touchkeyAutodetecting_;
andrewm@0: bool touchkeyStandaloneModeEnabled_;
andrewm@28: int deviceUpdateCounter_; // Unique number that increments every time devices should
andrewm@28: // be rescanned
andrewm@6:
andrewm@6: // OSC information
andrewm@6: bool oscReceiveEnabled_;
andrewm@6: int oscReceivePort_;
andrewm@6:
andrewm@0: // Mapping objects
andrewm@0: bool experimentalMappingsEnabled_;
andrewm@0:
andrewm@0: // Display objects
andrewm@0: KeyboardDisplay keyboardDisplay_;
andrewm@0: #ifndef TOUCHKEYS_NO_GUI
andrewm@0: DocumentWindow *keyboardDisplayWindow_;
andrewm@17: KeyboardTesterDisplay *keyboardTesterDisplay_;
andrewm@17: GraphicsDisplayWindow *keyboardTesterWindow_;
andrewm@41: PreferencesWindow *preferencesWindow_;
andrewm@0: #endif
andrewm@0:
andrewm@0: // Segment info
andrewm@0: int segmentCounter_;
andrewm@0:
andrewm@0: // Logging info
andrewm@53: bool loggingActive_, isPlayingLog_;
andrewm@0: std::string loggingDirectory_;
andrewm@0: };
andrewm@0:
andrewm@49:
andrewm@49: // Separate class for handling external OSC control messages since
andrewm@49: // one class cannot have two receivers. This one is for all external
andrewm@49: // OSC messages which OscHandler on MainApplicationController is for
andrewm@49: // internally-generated messages via the PianoKeyboard class.
andrewm@49:
andrewm@49: class MainApplicationOSCController : public OscHandler {
andrewm@49: public:
andrewm@49: MainApplicationOSCController(MainApplicationController& controller,
andrewm@49: OscMessageSource& source) :
andrewm@49: controller_(controller), source_(source) {
andrewm@49: setOscController(&source_);
andrewm@49: addOscListener("/control*");
andrewm@49: }
andrewm@49:
andrewm@49: // *** OSC handler method (different from OSC device selection) ***
andrewm@49:
andrewm@49: bool oscHandlerMethod(const char *path, const char *types, int numValues, lo_arg **values, void *data);
andrewm@49:
andrewm@49: private:
andrewm@49: // Reply to OSC messages with a status
andrewm@49: void oscControlTransmitResult(int result);
andrewm@49:
andrewm@49: MainApplicationController& controller_;
andrewm@49: OscMessageSource& source_;
andrewm@49: };
andrewm@49:
andrewm@0: #endif /* defined(__TouchKeys__MainApplicationController__) */