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__) */