andrewm@0
|
1 /*
|
andrewm@0
|
2 TouchKeys: multi-touch musical keyboard control software
|
andrewm@0
|
3 Copyright (c) 2013 Andrew McPherson
|
andrewm@0
|
4
|
andrewm@0
|
5 This program is free software: you can redistribute it and/or modify
|
andrewm@0
|
6 it under the terms of the GNU General Public License as published by
|
andrewm@0
|
7 the Free Software Foundation, either version 3 of the License, or
|
andrewm@0
|
8 (at your option) any later version.
|
andrewm@0
|
9
|
andrewm@0
|
10 This program is distributed in the hope that it will be useful,
|
andrewm@0
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
andrewm@0
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
andrewm@0
|
13 GNU General Public License for more details.
|
andrewm@0
|
14
|
andrewm@0
|
15 You should have received a copy of the GNU General Public License
|
andrewm@0
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
andrewm@0
|
17
|
andrewm@0
|
18 =====================================================================
|
andrewm@0
|
19
|
andrewm@0
|
20 MainApplicationController.h: contains the overall glue that holds
|
andrewm@0
|
21 together the various parts of the TouchKeys code. It works together
|
andrewm@0
|
22 with the user interface to let the user configure the hardware and
|
andrewm@0
|
23 manage the mappings, but it is kept separate from any particular user
|
andrewm@0
|
24 interface configuration.
|
andrewm@0
|
25 */
|
andrewm@0
|
26
|
andrewm@0
|
27 #ifndef __TouchKeys__MainApplicationController__
|
andrewm@0
|
28 #define __TouchKeys__MainApplicationController__
|
andrewm@0
|
29
|
andrewm@11
|
30 #undef TOUCHKEY_ENTROPY_GENERATOR_ENABLE
|
andrewm@11
|
31
|
andrewm@0
|
32 #include <iostream>
|
andrewm@0
|
33 #include <vector>
|
andrewm@0
|
34 #include "../JuceLibraryCode/JuceHeader.h"
|
andrewm@0
|
35 #include "TouchKeys/MidiInputController.h"
|
andrewm@0
|
36 #include "TouchKeys/MidiKeyboardSegment.h"
|
andrewm@0
|
37 #include "TouchKeys/MidiOutputController.h"
|
andrewm@0
|
38 #include "TouchKeys/TouchkeyDevice.h"
|
andrewm@9
|
39 #include "TouchKeys/TouchkeyOscEmulator.h"
|
andrewm@0
|
40 #include "TouchKeys/Osc.h"
|
andrewm@0
|
41 #include "Mappings/Vibrato/TouchkeyVibratoMappingFactory.h"
|
andrewm@0
|
42 #include "Mappings/PitchBend/TouchkeyPitchBendMappingFactory.h"
|
andrewm@0
|
43 #include "Mappings/Control/TouchkeyControlMappingFactory.h"
|
andrewm@0
|
44 #include "Mappings/ReleaseAngle/TouchkeyReleaseAngleMappingFactory.h"
|
andrewm@0
|
45 #include "Mappings/OnsetAngle/TouchkeyOnsetAngleMappingFactory.h"
|
andrewm@0
|
46 #include "Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMappingFactory.h"
|
andrewm@0
|
47 #include "Mappings/KeyDivision/TouchkeyKeyDivisionMappingFactory.h"
|
andrewm@0
|
48 #include "Mappings/MappingFactorySplitter.h"
|
andrewm@0
|
49 #include "TouchKeys/LogPlayback.h"
|
andrewm@0
|
50
|
andrewm@11
|
51 #ifdef TOUCHKEY_ENTROPY_GENERATOR_ENABLE
|
andrewm@11
|
52 #include "TouchKeys/TouchkeyEntropyGenerator.h"
|
andrewm@11
|
53 #endif
|
andrewm@11
|
54
|
andrewm@0
|
55 const char kDefaultOscTransmitHost[] = "127.0.0.1";
|
andrewm@0
|
56 const char kDefaultOscTransmitPort[] = "8000";
|
andrewm@6
|
57 const int kDefaultOscReceivePort = 8001;
|
andrewm@0
|
58
|
andrewm@0
|
59 class InterfaceSelectorComponent;
|
andrewm@0
|
60
|
andrewm@0
|
61 class MainApplicationController : public OscHandler {
|
andrewm@0
|
62 public:
|
andrewm@0
|
63 // *** Constructor ***
|
andrewm@0
|
64 MainApplicationController();
|
andrewm@0
|
65
|
andrewm@0
|
66 // *** Destructor ***
|
andrewm@0
|
67 ~MainApplicationController();
|
andrewm@0
|
68
|
andrewm@0
|
69 // *** TouchKeys device methods ***
|
andrewm@0
|
70
|
andrewm@0
|
71 // Return the path prefix of the TouchKeys device
|
andrewm@0
|
72 std::string touchkeyDevicePrefix();
|
andrewm@0
|
73
|
andrewm@0
|
74 // Return a list of paths to all available touchkey devices
|
andrewm@0
|
75 std::vector<std::string> availableTouchkeyDevices();
|
andrewm@0
|
76
|
andrewm@0
|
77 // Run the main startup sequence: open device, check its presence,
|
andrewm@0
|
78 // start data collection, all in one method. Returns true if successful.
|
andrewm@0
|
79 // Will set the error message string if not
|
andrewm@0
|
80 bool touchkeyDeviceStartupSequence(const char * path);
|
andrewm@0
|
81 void touchkeyDeviceClearErrorMessage() {
|
andrewm@0
|
82 touchkeyErrorMessage_ = "";
|
andrewm@0
|
83 touchkeyErrorOccurred_ = false;
|
andrewm@0
|
84 }
|
andrewm@0
|
85
|
andrewm@0
|
86 // Select a particular touchkey device
|
andrewm@0
|
87 bool openTouchkeyDevice(const char * path) {
|
andrewm@0
|
88 return touchkeyController_.openDevice(path);
|
andrewm@0
|
89 }
|
andrewm@11
|
90 void closeTouchkeyDevice();
|
andrewm@0
|
91
|
andrewm@0
|
92 // Check for device present
|
andrewm@0
|
93 bool touchkeyDeviceCheckForPresence(int waitMilliseconds = 250, int tries = 10);
|
andrewm@0
|
94
|
andrewm@0
|
95 // Start/stop the TouchKeys data collection
|
andrewm@0
|
96 bool startTouchkeyDevice() {
|
andrewm@0
|
97 return touchkeyController_.startAutoGathering();
|
andrewm@0
|
98 }
|
andrewm@0
|
99 void stopTouchkeyDevice() {
|
andrewm@0
|
100 touchkeyController_.stopAutoGathering();
|
andrewm@0
|
101 }
|
andrewm@0
|
102
|
andrewm@0
|
103 // Status queries on TouchKeys
|
andrewm@0
|
104 // Returns true if device has been opened
|
andrewm@0
|
105 bool touchkeyDeviceIsOpen() {
|
andrewm@0
|
106 return touchkeyController_.isOpen();
|
andrewm@0
|
107 }
|
andrewm@0
|
108 // Return true if device is collecting data
|
andrewm@11
|
109 bool touchkeyDeviceIsRunning();
|
andrewm@11
|
110
|
andrewm@0
|
111 // Returns true if an error has occurred
|
andrewm@0
|
112 bool touchkeyDeviceErrorOccurred() {
|
andrewm@0
|
113 return touchkeyErrorOccurred_;
|
andrewm@0
|
114 }
|
andrewm@0
|
115 // Return the error message if one occurred
|
andrewm@0
|
116 std::string touchkeyDeviceErrorMessage() {
|
andrewm@0
|
117 return touchkeyErrorMessage_;
|
andrewm@0
|
118 }
|
andrewm@0
|
119 // How many octaves on the current device
|
andrewm@0
|
120 int touchkeyDeviceNumberOfOctaves() {
|
andrewm@0
|
121 return touchkeyController_.numberOfOctaves();
|
andrewm@0
|
122 }
|
andrewm@0
|
123 // Return the lowest MIDI note
|
andrewm@0
|
124 int touchkeyDeviceLowestMidiNote() {
|
andrewm@0
|
125 return touchkeyController_.lowestMidiNote();
|
andrewm@0
|
126 }
|
andrewm@0
|
127 // Set the lowest MIDI note for the TouchKeys
|
andrewm@0
|
128 void touchkeyDeviceSetLowestMidiNote(int note) {
|
andrewm@0
|
129 keyboardDisplay_.clearAllTouches();
|
andrewm@14
|
130 touchkeyEmulator_.setLowestMidiNote(note);
|
andrewm@0
|
131 touchkeyController_.setLowestMidiNote(note);
|
andrewm@0
|
132 }
|
andrewm@0
|
133 // Attempt to autodetect the correct TouchKey octave from MIDI data
|
andrewm@0
|
134 void touchkeyDeviceAutodetectLowestMidiNote();
|
andrewm@0
|
135 void touchkeyDeviceStopAutodetecting();
|
andrewm@0
|
136 bool touchkeyDeviceIsAutodetecting();
|
andrewm@0
|
137
|
andrewm@0
|
138 // *** MIDI device methods ***
|
andrewm@0
|
139
|
andrewm@0
|
140 // Return a list of IDs and paths to all available MIDI devices
|
andrewm@0
|
141 std::vector<std::pair<int, std::string> > availableMIDIInputDevices() {
|
andrewm@0
|
142 return midiInputController_.availableMidiDevices();
|
andrewm@0
|
143 }
|
andrewm@0
|
144
|
andrewm@0
|
145 std::vector<std::pair<int, std::string> > availableMIDIOutputDevices() {
|
andrewm@0
|
146 return midiOutputController_.availableMidiDevices();
|
andrewm@0
|
147 }
|
andrewm@0
|
148
|
andrewm@0
|
149 // Return the number of keyboard segments
|
andrewm@0
|
150 int midiSegmentsCount() {
|
andrewm@0
|
151 return midiInputController_.numSegments();
|
andrewm@0
|
152 }
|
andrewm@0
|
153 // Return the pointer to a specific segment
|
andrewm@0
|
154 MidiKeyboardSegment* midiSegment(int index) {
|
andrewm@0
|
155 return midiInputController_.segment(index);
|
andrewm@0
|
156 }
|
andrewm@0
|
157 // Return a unique signature of segment configuration which
|
andrewm@0
|
158 // tells any listeners whether an update has happened
|
andrewm@0
|
159 int midiSegmentUniqueIdentifier() {
|
andrewm@0
|
160 return midiInputController_.segmentUniqueIdentifier();
|
andrewm@0
|
161 }
|
andrewm@0
|
162 // Add a new segment, returning the result. Segments are
|
andrewm@0
|
163 // stored
|
andrewm@0
|
164 MidiKeyboardSegment* midiSegmentAdd();
|
andrewm@0
|
165 // Remove a segment
|
andrewm@13
|
166 void midiSegmentRemove(MidiKeyboardSegment *segment);
|
andrewm@0
|
167
|
andrewm@0
|
168 // Select MIDI input/output devices
|
andrewm@0
|
169 void enableMIDIInputPort(int portNumber) {
|
andrewm@0
|
170 midiInputController_.enablePort(portNumber);
|
andrewm@0
|
171 }
|
andrewm@0
|
172 void enableAllMIDIInputPorts() {
|
andrewm@0
|
173 midiInputController_.enableAllPorts();
|
andrewm@0
|
174 }
|
andrewm@0
|
175 void disableMIDIInputPort(int portNumber) {
|
andrewm@0
|
176 midiInputController_.disablePort(portNumber);
|
andrewm@0
|
177 }
|
andrewm@0
|
178 void disableAllMIDIInputPorts() {
|
andrewm@0
|
179 midiInputController_.disableAllPorts();
|
andrewm@0
|
180 }
|
andrewm@0
|
181 void enableMIDIOutputPort(int identifier, int deviceNumber) {
|
andrewm@0
|
182 midiOutputController_.enablePort(identifier, deviceNumber);
|
andrewm@0
|
183 }
|
andrewm@0
|
184 void enableMIDIOutputVirtualPort(int identifier, const char *name) {
|
andrewm@0
|
185 midiOutputController_.enableVirtualPort(identifier, name);
|
andrewm@0
|
186 }
|
andrewm@0
|
187 void disableMIDIOutputPort(int identifier) {
|
andrewm@0
|
188 midiOutputController_.disablePort(identifier);
|
andrewm@0
|
189 }
|
andrewm@0
|
190 void disableAllMIDIOutputPorts() {
|
andrewm@0
|
191 midiOutputController_.disableAllPorts();
|
andrewm@0
|
192 }
|
andrewm@0
|
193
|
andrewm@0
|
194 // Get selected MIDI input/output devices by ID
|
andrewm@0
|
195 std::vector<int> selectedMIDIInputPorts() {
|
andrewm@0
|
196 return midiInputController_.activePorts();
|
andrewm@0
|
197 }
|
andrewm@0
|
198 int selectedMIDIOutputPort(int identifier) {
|
andrewm@0
|
199 return midiOutputController_.enabledPort(identifier);
|
andrewm@0
|
200 }
|
andrewm@0
|
201
|
andrewm@0
|
202 void midiTouchkeysStandaloneModeEnable();
|
andrewm@0
|
203 void midiTouchkeysStandaloneModeDisable();
|
andrewm@0
|
204 bool midiTouchkeysStandaloneModeIsEnabled() { return touchkeyStandaloneModeEnabled_; }
|
andrewm@0
|
205
|
andrewm@0
|
206 // *** OSC device methods ***
|
andrewm@0
|
207
|
andrewm@0
|
208 bool oscTransmitEnabled() {
|
andrewm@0
|
209 return oscTransmitter_.enabled();
|
andrewm@0
|
210 }
|
andrewm@0
|
211 void oscTransmitSetEnabled(bool enable) {
|
andrewm@0
|
212 oscTransmitter_.setEnabled(enable);
|
andrewm@0
|
213 }
|
andrewm@0
|
214 bool oscTransmitRawDataEnabled() {
|
andrewm@0
|
215 return touchkeyController_.transmitRawDataEnabled();
|
andrewm@0
|
216 }
|
andrewm@0
|
217 void oscTransmitSetRawDataEnabled(bool enable) {
|
andrewm@0
|
218 touchkeyController_.setTransmitRawData(enable);
|
andrewm@0
|
219 }
|
andrewm@0
|
220 std::vector<lo_address> oscTransmitAddresses() {
|
andrewm@0
|
221 return oscTransmitter_.addresses();
|
andrewm@0
|
222 }
|
andrewm@0
|
223 int oscTransmitAddAddress(const char * host, const char * port, int proto = LO_UDP) {
|
andrewm@0
|
224 return oscTransmitter_.addAddress(host, port, proto);
|
andrewm@0
|
225 }
|
andrewm@0
|
226 void oscTransmitRemoveAddress(int index) {
|
andrewm@0
|
227 return oscTransmitter_.removeAddress(index);
|
andrewm@0
|
228 }
|
andrewm@0
|
229 void oscTransmitClearAddresses() {
|
andrewm@0
|
230 return oscTransmitter_.clearAddresses();
|
andrewm@0
|
231 }
|
andrewm@0
|
232
|
andrewm@6
|
233 // OSC Input (receiver) methods
|
andrewm@6
|
234 // Enable or disable on the OSC receive, and report is status
|
andrewm@6
|
235 bool oscReceiveEnabled() {
|
andrewm@6
|
236 return oscReceiveEnabled_;
|
andrewm@6
|
237 }
|
andrewm@6
|
238 // Enable method returns true on success (false only if it was
|
andrewm@6
|
239 // unable to set the port)
|
andrewm@6
|
240 bool oscReceiveSetEnabled(bool enable) {
|
andrewm@6
|
241 if(enable && !oscReceiveEnabled_) {
|
andrewm@6
|
242 oscReceiveEnabled_ = true;
|
andrewm@6
|
243 return oscReceiver_.setPort(oscReceivePort_);
|
andrewm@6
|
244 }
|
andrewm@6
|
245 else if(!enable && oscReceiveEnabled_) {
|
andrewm@6
|
246 oscReceiveEnabled_ = false;
|
andrewm@6
|
247 return oscReceiver_.setPort(0);
|
andrewm@6
|
248 }
|
andrewm@6
|
249 return true;
|
andrewm@6
|
250 }
|
andrewm@6
|
251
|
andrewm@6
|
252 // Whether the OSC server is running (false means couldn't open port)
|
andrewm@6
|
253 bool oscReceiveRunning() {
|
andrewm@6
|
254 return oscReceiver_.running();
|
andrewm@6
|
255 }
|
andrewm@6
|
256 // Get the current OSC receive port
|
andrewm@6
|
257 int oscReceivePort() {
|
andrewm@6
|
258 return oscReceivePort_;
|
andrewm@6
|
259 }
|
andrewm@6
|
260 // Set the current OSC receive port (returns true on success)
|
andrewm@6
|
261 bool oscReceiveSetPort(int port) {
|
andrewm@6
|
262 oscReceivePort_ = port;
|
andrewm@6
|
263 return oscReceiver_.setPort(port);
|
andrewm@6
|
264 }
|
andrewm@6
|
265
|
andrewm@6
|
266
|
andrewm@0
|
267 // *** Display methods ***
|
andrewm@0
|
268
|
andrewm@0
|
269 KeyboardDisplay& keyboardDisplay() { return keyboardDisplay_; }
|
andrewm@0
|
270 #ifndef TOUCHKEYS_NO_GUI
|
andrewm@0
|
271 void setKeyboardDisplayWindow(DocumentWindow *window) { keyboardDisplayWindow_ = window; }
|
andrewm@0
|
272 void showKeyboardDisplayWindow() {
|
andrewm@0
|
273 if(keyboardDisplayWindow_ != 0) {
|
andrewm@0
|
274 keyboardDisplayWindow_->setVisible(true);
|
andrewm@0
|
275 keyboardDisplayWindow_->toFront(true);
|
andrewm@0
|
276 }
|
andrewm@0
|
277 }
|
andrewm@0
|
278 #endif
|
andrewm@0
|
279
|
andrewm@0
|
280 // *** Logging methods ***
|
andrewm@0
|
281 // Logging methods which record TouchKeys and MIDI data to files for
|
andrewm@0
|
282 // later analysis/playback
|
andrewm@0
|
283
|
andrewm@0
|
284 void startLogging();
|
andrewm@0
|
285 void stopLogging();
|
andrewm@0
|
286 bool isLogging() { return loggingActive_; }
|
andrewm@0
|
287 void setLoggingDirectory(const char *directory);
|
andrewm@0
|
288
|
andrewm@0
|
289 // *** OSC handler method (different from OSC device selection) ***
|
andrewm@0
|
290
|
andrewm@0
|
291 bool oscHandlerMethod(const char *path, const char *types, int numValues, lo_arg **values, void *data);
|
andrewm@0
|
292
|
andrewm@0
|
293
|
andrewm@0
|
294 // *** Mapping methods ***
|
andrewm@0
|
295 // Return the number of mapping factory types available
|
andrewm@0
|
296 int numberOfMappingFactories();
|
andrewm@0
|
297
|
andrewm@0
|
298 // Return the name of a given mapping factory type
|
andrewm@0
|
299 String mappingFactoryNameForIndex(int index);
|
andrewm@0
|
300
|
andrewm@0
|
301 // Create a new mapping factory of the given type, attached to
|
andrewm@0
|
302 // the supplied segment
|
andrewm@0
|
303 MappingFactory* createMappingFactoryForIndex(int index, MidiKeyboardSegment& segment);
|
andrewm@0
|
304
|
andrewm@0
|
305 // Whether experimental (not totally finished/tested) mappings are available
|
andrewm@0
|
306 bool experimentalMappingsEnabled() { return experimentalMappingsEnabled_; }
|
andrewm@0
|
307 void setExperimentalMappingsEnabled(bool enable) { experimentalMappingsEnabled_ = enable; }
|
andrewm@0
|
308
|
andrewm@0
|
309 // Whether a given mapping is experimental
|
andrewm@0
|
310 bool mappingIsExperimental(int index);
|
andrewm@0
|
311
|
andrewm@0
|
312 // *** Static utility methods ***
|
andrewm@0
|
313 static std::string midiNoteName(int noteNumber);
|
andrewm@0
|
314 static int midiNoteNumberForName(std::string const& name);
|
andrewm@0
|
315
|
andrewm@0
|
316 private:
|
andrewm@0
|
317 // TouchKeys objects
|
andrewm@0
|
318 PianoKeyboard keyboardController_;
|
andrewm@0
|
319 MidiInputController midiInputController_;
|
andrewm@0
|
320 MidiOutputController midiOutputController_;
|
andrewm@0
|
321 OscTransmitter oscTransmitter_;
|
andrewm@6
|
322 OscReceiver oscReceiver_;
|
andrewm@9
|
323 TouchkeyDevice touchkeyController_;
|
andrewm@9
|
324 TouchkeyOscEmulator touchkeyEmulator_;
|
andrewm@11
|
325 #ifdef TOUCHKEY_ENTROPY_GENERATOR_ENABLE
|
andrewm@11
|
326 TouchkeyEntropyGenerator touchkeyEntropyGenerator_;
|
andrewm@11
|
327 bool entropyGeneratorSelected_;
|
andrewm@11
|
328 #endif
|
andrewm@0
|
329
|
andrewm@0
|
330 bool touchkeyErrorOccurred_;
|
andrewm@0
|
331 std::string touchkeyErrorMessage_;
|
andrewm@0
|
332 bool touchkeyAutodetecting_;
|
andrewm@0
|
333 bool touchkeyStandaloneModeEnabled_;
|
andrewm@6
|
334
|
andrewm@6
|
335 // OSC information
|
andrewm@6
|
336 bool oscReceiveEnabled_;
|
andrewm@6
|
337 int oscReceivePort_;
|
andrewm@6
|
338
|
andrewm@0
|
339 // Mapping objects
|
andrewm@0
|
340 bool experimentalMappingsEnabled_;
|
andrewm@0
|
341
|
andrewm@0
|
342 // Display objects
|
andrewm@0
|
343 KeyboardDisplay keyboardDisplay_;
|
andrewm@0
|
344 #ifndef TOUCHKEYS_NO_GUI
|
andrewm@0
|
345 DocumentWindow *keyboardDisplayWindow_;
|
andrewm@0
|
346 #endif
|
andrewm@0
|
347
|
andrewm@0
|
348 // Segment info
|
andrewm@0
|
349 int segmentCounter_;
|
andrewm@0
|
350
|
andrewm@0
|
351 // Logging info
|
andrewm@0
|
352 bool loggingActive_;
|
andrewm@0
|
353 std::string loggingDirectory_;
|
andrewm@0
|
354 };
|
andrewm@0
|
355
|
andrewm@0
|
356 #endif /* defined(__TouchKeys__MainApplicationController__) */
|