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.cpp: 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 #include "MainApplicationController.h"
|
andrewm@17
|
28 #ifndef TOUCHKEYS_NO_GUI
|
andrewm@17
|
29 #include "Display/KeyboardTesterDisplay.h"
|
andrewm@17
|
30 #endif
|
andrewm@0
|
31 #include <cstdlib>
|
andrewm@0
|
32 #include <sstream>
|
andrewm@0
|
33
|
andrewm@0
|
34 // Strings for pitch classes (two forms for sharps), for static methods
|
andrewm@0
|
35 const char* kNoteNames[12] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};
|
andrewm@0
|
36 const char* kNoteNamesAlternate[12] = {"C", "Db", "D ", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"};
|
andrewm@0
|
37
|
andrewm@0
|
38 MainApplicationController::MainApplicationController()
|
andrewm@0
|
39 : midiInputController_(keyboardController_),
|
andrewm@9
|
40 oscReceiver_(0, "/touchkeys"),
|
andrewm@0
|
41 touchkeyController_(keyboardController_),
|
andrewm@9
|
42 touchkeyEmulator_(keyboardController_, oscReceiver_),
|
andrewm@53
|
43 logPlayback_(0),
|
andrewm@11
|
44 #ifdef TOUCHKEY_ENTROPY_GENERATOR_ENABLE
|
andrewm@11
|
45 touchkeyEntropyGenerator_(keyboardController_),
|
andrewm@11
|
46 entropyGeneratorSelected_(false),
|
andrewm@11
|
47 #endif
|
andrewm@0
|
48 touchkeyErrorOccurred_(false),
|
andrewm@0
|
49 touchkeyErrorMessage_(""),
|
andrewm@0
|
50 touchkeyAutodetecting_(false),
|
andrewm@0
|
51 touchkeyStandaloneModeEnabled_(false),
|
andrewm@28
|
52 deviceUpdateCounter_(0),
|
andrewm@7
|
53 oscReceiveEnabled_(false),
|
andrewm@6
|
54 oscReceivePort_(kDefaultOscReceivePort),
|
andrewm@0
|
55 experimentalMappingsEnabled_(false),
|
andrewm@0
|
56 #ifndef TOUCHKEYS_NO_GUI
|
andrewm@0
|
57 keyboardDisplayWindow_(0),
|
andrewm@17
|
58 keyboardTesterDisplay_(0),
|
andrewm@17
|
59 keyboardTesterWindow_(0),
|
andrewm@41
|
60 preferencesWindow_(0),
|
andrewm@0
|
61 #endif
|
andrewm@0
|
62 segmentCounter_(0),
|
andrewm@53
|
63 loggingActive_(false),
|
andrewm@53
|
64 isPlayingLog_(false)
|
andrewm@0
|
65 {
|
andrewm@0
|
66 // Set our OSC controller
|
andrewm@0
|
67 setOscController(&keyboardController_);
|
andrewm@0
|
68 oscTransmitter_.setEnabled(false);
|
andrewm@0
|
69 //oscTransmitter_.setDebugMessages(true);
|
andrewm@0
|
70
|
andrewm@0
|
71 // Initialize the links between objects
|
andrewm@0
|
72 keyboardController_.setOscTransmitter(&oscTransmitter_);
|
andrewm@0
|
73 keyboardController_.setMidiOutputController(&midiOutputController_);
|
andrewm@0
|
74 keyboardController_.setGUI(&keyboardDisplay_);
|
andrewm@0
|
75 midiInputController_.setMidiOutputController(&midiOutputController_);
|
andrewm@0
|
76
|
andrewm@0
|
77 // Set up default logging directory
|
andrewm@0
|
78 loggingDirectory_ = (File::getSpecialLocation(File::userHomeDirectory).getFullPathName() + "/Desktop").toUTF8();
|
andrewm@0
|
79
|
andrewm@41
|
80 // Configure application properties
|
andrewm@41
|
81 PropertiesFile::Options options;
|
andrewm@41
|
82 options.applicationName = "TouchKeys";
|
andrewm@41
|
83 options.folderName = "TouchKeys";
|
andrewm@41
|
84 options.filenameSuffix = ".properties";
|
andrewm@41
|
85 options.osxLibrarySubFolder = "Application Support";
|
andrewm@41
|
86 applicationProperties_.setStorageParameters(options);
|
andrewm@41
|
87
|
andrewm@0
|
88 // Defaults for display, until we get other information
|
andrewm@0
|
89 keyboardDisplay_.setKeyboardRange(36, 72);
|
andrewm@0
|
90
|
andrewm@0
|
91 // Add one keyboard segment at the beginning
|
andrewm@0
|
92 midiSegmentAdd();
|
andrewm@41
|
93
|
andrewm@41
|
94 // Load the current preferences
|
andrewm@41
|
95 loadApplicationPreferences();
|
andrewm@41
|
96
|
andrewm@41
|
97 // Set up an initial OSC transmit host/port if none has been loaded
|
andrewm@41
|
98 if(oscTransmitter_.addresses().size() == 0)
|
andrewm@41
|
99 oscTransmitter_.addAddress(kDefaultOscTransmitHost, kDefaultOscTransmitPort);
|
andrewm@49
|
100
|
andrewm@49
|
101 // Listen for control messages by OSC
|
andrewm@49
|
102 mainOscController_ = new MainApplicationOSCController(*this, oscReceiver_);
|
andrewm@0
|
103 }
|
andrewm@0
|
104
|
andrewm@0
|
105 MainApplicationController::~MainApplicationController() {
|
andrewm@17
|
106 #ifdef ENABLE_TOUCHKEYS_SENSOR_TEST
|
andrewm@17
|
107 if(touchkeySensorTestIsRunning())
|
andrewm@17
|
108 touchkeySensorTestStop();
|
andrewm@17
|
109 #endif
|
andrewm@53
|
110 if(logPlayback_ != 0)
|
andrewm@53
|
111 delete logPlayback_;
|
andrewm@42
|
112 removeAllOscListeners();
|
andrewm@51
|
113 midiInputController_.removeAllSegments(); // Remove segments now to avoid deletion-order problems
|
andrewm@49
|
114 delete mainOscController_;
|
andrewm@0
|
115 }
|
andrewm@0
|
116
|
andrewm@41
|
117 // Actions here run in the JUCE initialise() method once the application is loaded
|
andrewm@41
|
118 void MainApplicationController::initialise() {
|
andrewm@41
|
119 // Load a preset if enabled
|
andrewm@41
|
120 if(getPrefsStartupPresetLastSaved()) {
|
andrewm@41
|
121 if(applicationProperties_.getUserSettings()->containsKey("LastSavedPreset")) {
|
andrewm@41
|
122 String presetFile = applicationProperties_.getUserSettings()->getValue("LastSavedPreset");
|
andrewm@41
|
123 if(presetFile != "") {
|
andrewm@41
|
124 loadPresetFromFile(presetFile.toUTF8());
|
andrewm@41
|
125 }
|
andrewm@41
|
126 }
|
andrewm@41
|
127 }
|
andrewm@41
|
128 else if(getPrefsStartupPresetVibratoPitchBend()) {
|
andrewm@41
|
129 if(midiInputController_.numSegments() > 0) {
|
andrewm@41
|
130 MidiKeyboardSegment *segment = midiInputController_.segment(0);
|
andrewm@41
|
131
|
andrewm@41
|
132 MappingFactory *factory = new TouchkeyVibratoMappingFactory(keyboardController_, *segment);
|
andrewm@41
|
133 if(factory != 0)
|
andrewm@42
|
134 segment->addMappingFactory(factory, true);
|
andrewm@41
|
135 factory = new TouchkeyPitchBendMappingFactory(keyboardController_, *segment);
|
andrewm@41
|
136 if(factory != 0)
|
andrewm@42
|
137 segment->addMappingFactory(factory, true);
|
andrewm@41
|
138 }
|
andrewm@41
|
139 }
|
andrewm@41
|
140 else if(!getPrefsStartupPresetNone()) {
|
andrewm@41
|
141 String presetFile = getPrefsStartupPreset();
|
andrewm@41
|
142 if(presetFile != "") {
|
andrewm@41
|
143 loadPresetFromFile(presetFile.toUTF8());
|
andrewm@41
|
144 }
|
andrewm@41
|
145 }
|
andrewm@41
|
146
|
andrewm@41
|
147 // Automatically start the TouchKeys if the preferences are enabled
|
andrewm@41
|
148 if(getPrefsAutoStartTouchKeys() && applicationProperties_.getUserSettings()->containsKey("TouchKeysDevice")) {
|
andrewm@41
|
149 String tkDevicePath = applicationProperties_.getUserSettings()->getValue("TouchKeysDevice");
|
andrewm@41
|
150 if(touchkeyDeviceExists(tkDevicePath.toUTF8())) {
|
andrewm@41
|
151 // Exists: try to open and run
|
andrewm@41
|
152 touchkeyDeviceStartupSequence(tkDevicePath.toUTF8());
|
andrewm@41
|
153 }
|
andrewm@41
|
154 }
|
andrewm@41
|
155 }
|
andrewm@41
|
156
|
andrewm@0
|
157 bool MainApplicationController::touchkeyDeviceStartupSequence(const char * path) {
|
andrewm@11
|
158 #ifdef TOUCHKEY_ENTROPY_GENERATOR_ENABLE
|
andrewm@23
|
159 if(!strcmp(path, "/dev/Entropy Generator") || !strcmp(path, "\\\\.\\Entropy Generator")) {
|
andrewm@11
|
160 entropyGeneratorSelected_ = true;
|
andrewm@11
|
161 touchkeyEntropyGenerator_.start();
|
andrewm@11
|
162 }
|
andrewm@11
|
163 else {
|
andrewm@11
|
164 entropyGeneratorSelected_ = false;
|
andrewm@11
|
165 #endif
|
andrewm@11
|
166
|
andrewm@0
|
167 // Step 1: attempt to open device
|
andrewm@0
|
168 if(!openTouchkeyDevice(path)) {
|
andrewm@0
|
169 touchkeyErrorMessage_ = "Failed to open";
|
andrewm@0
|
170 touchkeyErrorOccurred_ = true;
|
andrewm@0
|
171 return false;
|
andrewm@0
|
172 }
|
andrewm@0
|
173
|
andrewm@0
|
174 // Step 2: see if a real TouchKeys device is present at the other end
|
andrewm@0
|
175 if(!touchkeyDeviceCheckForPresence()) {
|
andrewm@0
|
176 touchkeyErrorMessage_ = "Device not recognized";
|
andrewm@0
|
177 touchkeyErrorOccurred_ = true;
|
andrewm@0
|
178 return false;
|
andrewm@0
|
179 }
|
andrewm@0
|
180
|
andrewm@0
|
181 // Step 3: update the display
|
andrewm@0
|
182 keyboardDisplay_.setKeyboardRange(touchkeyController_.lowestKeyPresentMidiNote(), touchkeyController_.highestMidiNote());
|
andrewm@0
|
183 #ifndef TOUCHKEYS_NO_GUI
|
andrewm@0
|
184 if(keyboardDisplayWindow_ != 0) {
|
andrewm@0
|
185 keyboardDisplayWindow_->getConstrainer()->setFixedAspectRatio(keyboardDisplay_.keyboardAspectRatio());
|
andrewm@48
|
186
|
a@54
|
187 juce::Rectangle<int> bounds = keyboardDisplayWindow_->getBounds();
|
andrewm@48
|
188 if(bounds.getY() < 44)
|
andrewm@48
|
189 bounds.setY(44);
|
andrewm@48
|
190 keyboardDisplayWindow_->setBoundsConstrained(bounds);
|
andrewm@0
|
191 }
|
andrewm@0
|
192 #endif
|
andrewm@0
|
193
|
andrewm@0
|
194 // Step 4: start data collection from the device
|
andrewm@0
|
195 if(!startTouchkeyDevice()) {
|
andrewm@0
|
196 touchkeyErrorMessage_ = "Failed to start";
|
andrewm@0
|
197 touchkeyErrorOccurred_ = true;
|
andrewm@0
|
198 }
|
andrewm@0
|
199
|
andrewm@11
|
200 #ifdef TOUCHKEY_ENTROPY_GENERATOR_ENABLE
|
andrewm@11
|
201 }
|
andrewm@11
|
202 #endif
|
andrewm@11
|
203
|
andrewm@0
|
204 // Success!
|
andrewm@0
|
205 touchkeyErrorMessage_ = "";
|
andrewm@0
|
206 touchkeyErrorOccurred_ = false;
|
andrewm@41
|
207
|
andrewm@50
|
208 #ifndef TOUCHKEYS_NO_GUI
|
andrewm@41
|
209 showKeyboardDisplayWindow();
|
andrewm@50
|
210 #endif
|
andrewm@41
|
211
|
andrewm@41
|
212 // Automatically detect the lowest octave if set
|
andrewm@41
|
213 if(getPrefsAutodetectOctave())
|
andrewm@41
|
214 touchkeyDeviceAutodetectLowestMidiNote();
|
andrewm@41
|
215
|
andrewm@0
|
216 return true;
|
andrewm@0
|
217 }
|
andrewm@0
|
218
|
andrewm@0
|
219 std::string MainApplicationController::touchkeyDevicePrefix() {
|
andrewm@23
|
220 #ifdef _MSC_VER
|
andrewm@23
|
221 return "\\\\.\\";
|
andrewm@23
|
222 #else
|
andrewm@0
|
223 if(SystemStats::getOperatingSystemType() == SystemStats::Linux) {
|
andrewm@0
|
224 return "/dev/serial/by-id/";
|
andrewm@0
|
225 }
|
andrewm@0
|
226 else {
|
andrewm@0
|
227 return "/dev/";
|
andrewm@0
|
228 }
|
andrewm@23
|
229 #endif
|
andrewm@0
|
230 }
|
andrewm@0
|
231
|
andrewm@0
|
232 // Return a list of available TouchKey devices
|
andrewm@0
|
233 std::vector<std::string> MainApplicationController::availableTouchkeyDevices() {
|
andrewm@0
|
234 std::vector<std::string> devices;
|
andrewm@23
|
235
|
andrewm@27
|
236 #ifdef _MSC_VER
|
andrewm@27
|
237 for(int i = 1; i <= 128; i++) {
|
andrewm@27
|
238 String comPortName("COM");
|
andrewm@27
|
239 comPortName += i;
|
andrewm@27
|
240
|
andrewm@27
|
241 DWORD dwSize = 0;
|
andrewm@27
|
242 LPCOMMCONFIG lpCC = (LPCOMMCONFIG) new BYTE[1];
|
andrewm@27
|
243 BOOL ret = GetDefaultCommConfig(comPortName.toUTF8(), lpCC, &dwSize);
|
andrewm@27
|
244 delete [] lpCC;
|
andrewm@27
|
245
|
andrewm@27
|
246 if(ret)
|
andrewm@27
|
247 devices.push_back(comPortName.toStdString());
|
andrewm@27
|
248 else {
|
andrewm@27
|
249 if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
andrewm@27
|
250 //Logger::writeToLog(String::formatted("Found " + comPortName));
|
andrewm@27
|
251 lpCC = (LPCOMMCONFIG) new BYTE[dwSize];
|
andrewm@27
|
252 ret = GetDefaultCommConfig(comPortName.toUTF8(), lpCC, &dwSize);
|
andrewm@27
|
253 if(ret)
|
andrewm@27
|
254 devices.push_back(comPortName.toStdString());
|
andrewm@27
|
255 else {
|
andrewm@27
|
256 int error = GetLastError();
|
andrewm@27
|
257 //Logger::writeToLog(String("2Didn't find " + comPortName + "; error " + String(error)));
|
andrewm@27
|
258 }
|
andrewm@27
|
259 delete [] lpCC;
|
andrewm@27
|
260 }
|
andrewm@27
|
261 else {
|
andrewm@27
|
262 int error = GetLastError();
|
andrewm@27
|
263 //Logger::writeToLog(String("Didn't find " + comPortName + "; error " + String(error)));
|
andrewm@27
|
264 }
|
andrewm@27
|
265 }
|
andrewm@23
|
266 }
|
andrewm@23
|
267 #else
|
andrewm@0
|
268 if(SystemStats::getOperatingSystemType() == SystemStats::Linux) {
|
andrewm@0
|
269 DirectoryIterator devDirectory(File("/dev/serial/by-id"),false,"*");
|
andrewm@0
|
270
|
andrewm@0
|
271 while(devDirectory.next()) {
|
andrewm@0
|
272 devices.push_back(string(devDirectory.getFile().getFileName().toUTF8()));
|
andrewm@0
|
273 }
|
andrewm@0
|
274 }
|
andrewm@0
|
275 else {
|
andrewm@0
|
276 DirectoryIterator devDirectory(File("/dev"),false,"cu.usbmodem*");
|
andrewm@0
|
277
|
andrewm@0
|
278 while(devDirectory.next()) {
|
andrewm@0
|
279 devices.push_back(string(devDirectory.getFile().getFileName().toUTF8()));
|
andrewm@0
|
280 }
|
andrewm@0
|
281 }
|
andrewm@23
|
282 #endif
|
andrewm@0
|
283
|
andrewm@11
|
284 #ifdef TOUCHKEY_ENTROPY_GENERATOR_ENABLE
|
andrewm@11
|
285 devices.push_back("Entropy Generator");
|
andrewm@11
|
286 #endif
|
andrewm@11
|
287
|
andrewm@0
|
288 return devices;
|
andrewm@0
|
289 }
|
andrewm@0
|
290
|
andrewm@41
|
291 void MainApplicationController::touchkeyDeviceClearErrorMessage() {
|
andrewm@41
|
292 touchkeyErrorMessage_ = "";
|
andrewm@41
|
293 touchkeyErrorOccurred_ = false;
|
andrewm@41
|
294 }
|
andrewm@41
|
295
|
andrewm@41
|
296 // Check whether a given touchkey device exists
|
andrewm@41
|
297 bool MainApplicationController::touchkeyDeviceExists(const char * path) {
|
andrewm@41
|
298 String pathString(path);
|
andrewm@41
|
299 File tkDeviceFile(pathString);
|
andrewm@41
|
300 return tkDeviceFile.existsAsFile();
|
andrewm@41
|
301 }
|
andrewm@41
|
302
|
andrewm@41
|
303 // Select a particular touchkey device
|
andrewm@41
|
304 bool MainApplicationController::openTouchkeyDevice(const char * path) {
|
andrewm@41
|
305 bool success = touchkeyController_.openDevice(path);
|
andrewm@41
|
306
|
andrewm@41
|
307 if(success)
|
andrewm@41
|
308 applicationProperties_.getUserSettings()->setValue("TouchKeysDevice", String(path));
|
andrewm@41
|
309 return success;
|
andrewm@41
|
310 }
|
andrewm@41
|
311
|
andrewm@11
|
312 // Close the currently open TouchKeys device
|
andrewm@11
|
313 void MainApplicationController::closeTouchkeyDevice() {
|
andrewm@11
|
314 #ifdef TOUCHKEY_ENTROPY_GENERATOR_ENABLE
|
andrewm@11
|
315 if(entropyGeneratorSelected_)
|
andrewm@11
|
316 touchkeyEntropyGenerator_.stop();
|
andrewm@11
|
317 else
|
andrewm@11
|
318 touchkeyController_.closeDevice();
|
andrewm@11
|
319 #else
|
andrewm@11
|
320 touchkeyController_.closeDevice();
|
andrewm@11
|
321 #endif
|
andrewm@11
|
322 }
|
andrewm@11
|
323
|
andrewm@0
|
324 // Check whether a TouchKey device is present. Returns true if device found.
|
andrewm@0
|
325 bool MainApplicationController::touchkeyDeviceCheckForPresence(int waitMilliseconds, int tries) {
|
andrewm@0
|
326
|
andrewm@0
|
327 int count = 0;
|
andrewm@0
|
328 while(1) {
|
andrewm@0
|
329 if(touchkeyController_.checkIfDevicePresent(waitMilliseconds))
|
andrewm@0
|
330 break;
|
andrewm@0
|
331 if(++count >= tries) {
|
andrewm@0
|
332 return false;
|
andrewm@0
|
333 }
|
andrewm@0
|
334 }
|
andrewm@0
|
335
|
andrewm@0
|
336 return true;
|
andrewm@0
|
337 }
|
andrewm@0
|
338
|
andrewm@41
|
339 // Start/stop the TouchKeys data collection
|
andrewm@41
|
340 bool MainApplicationController::startTouchkeyDevice() {
|
andrewm@41
|
341 return touchkeyController_.startAutoGathering();
|
andrewm@41
|
342 }
|
andrewm@41
|
343
|
andrewm@41
|
344 void MainApplicationController::stopTouchkeyDevice() {
|
andrewm@41
|
345 touchkeyController_.stopAutoGathering();
|
andrewm@41
|
346 }
|
andrewm@41
|
347
|
andrewm@41
|
348 // Status queries on TouchKeys
|
andrewm@41
|
349 // Returns true if device has been opened
|
andrewm@41
|
350 bool MainApplicationController::touchkeyDeviceIsOpen() {
|
andrewm@41
|
351 return touchkeyController_.isOpen();
|
andrewm@41
|
352 }
|
andrewm@41
|
353
|
andrewm@11
|
354 // Return true if device is collecting data
|
andrewm@11
|
355 bool MainApplicationController::touchkeyDeviceIsRunning() {
|
andrewm@11
|
356 #ifdef TOUCHKEY_ENTROPY_GENERATOR_ENABLE
|
andrewm@11
|
357 if(entropyGeneratorSelected_)
|
andrewm@11
|
358 return touchkeyEntropyGenerator_.isRunning();
|
andrewm@11
|
359 else
|
andrewm@11
|
360 return touchkeyController_.isAutoGathering();
|
andrewm@11
|
361 #else
|
andrewm@11
|
362 return touchkeyController_.isAutoGathering();
|
andrewm@11
|
363 #endif
|
andrewm@11
|
364 }
|
andrewm@11
|
365
|
andrewm@41
|
366 // Returns true if an error has occurred
|
andrewm@41
|
367 bool MainApplicationController::touchkeyDeviceErrorOccurred() {
|
andrewm@41
|
368 return touchkeyErrorOccurred_;
|
andrewm@41
|
369 }
|
andrewm@41
|
370
|
andrewm@41
|
371 // Return the error message if one occurred
|
andrewm@41
|
372 std::string MainApplicationController::touchkeyDeviceErrorMessage() {
|
andrewm@41
|
373 return touchkeyErrorMessage_;
|
andrewm@41
|
374 }
|
andrewm@41
|
375
|
andrewm@41
|
376 // How many octaves on the current device
|
andrewm@41
|
377 int MainApplicationController::touchkeyDeviceNumberOfOctaves() {
|
andrewm@41
|
378 return touchkeyController_.numberOfOctaves();
|
andrewm@41
|
379 }
|
andrewm@41
|
380
|
andrewm@41
|
381 // Return the lowest MIDI note
|
andrewm@41
|
382 int MainApplicationController::touchkeyDeviceLowestMidiNote() {
|
andrewm@41
|
383 return touchkeyController_.lowestMidiNote();
|
andrewm@41
|
384 }
|
andrewm@41
|
385
|
andrewm@41
|
386 // Set the lowest MIDI note for the TouchKeys
|
andrewm@41
|
387 void MainApplicationController::touchkeyDeviceSetLowestMidiNote(int note) {
|
andrewm@41
|
388 keyboardDisplay_.clearAllTouches();
|
andrewm@41
|
389 touchkeyEmulator_.setLowestMidiNote(note);
|
andrewm@41
|
390 touchkeyController_.setLowestMidiNote(note);
|
andrewm@41
|
391
|
andrewm@41
|
392 applicationProperties_.getUserSettings()->setValue("TouchKeysLowestMIDINote", note);
|
andrewm@41
|
393 }
|
andrewm@41
|
394
|
andrewm@0
|
395 // Start an autodetection routine to match touch data to MIDI
|
andrewm@0
|
396 void MainApplicationController::touchkeyDeviceAutodetectLowestMidiNote() {
|
andrewm@0
|
397 if(touchkeyAutodetecting_)
|
andrewm@0
|
398 return;
|
andrewm@0
|
399
|
andrewm@0
|
400 touchkeyAutodetecting_ = true;
|
andrewm@0
|
401 addOscListener("/midi/noteon");
|
andrewm@0
|
402 }
|
andrewm@0
|
403
|
andrewm@0
|
404 // Abort an autodetection routine
|
andrewm@0
|
405 void MainApplicationController::touchkeyDeviceStopAutodetecting() {
|
andrewm@0
|
406 if(!touchkeyAutodetecting_)
|
andrewm@0
|
407 return;
|
andrewm@0
|
408
|
andrewm@0
|
409 removeOscListener("/midi/noteon");
|
andrewm@0
|
410 touchkeyAutodetecting_ = false;
|
andrewm@0
|
411 }
|
andrewm@0
|
412
|
andrewm@0
|
413 bool MainApplicationController::touchkeyDeviceIsAutodetecting() {
|
andrewm@0
|
414 return touchkeyAutodetecting_;
|
andrewm@0
|
415 }
|
andrewm@0
|
416
|
andrewm@0
|
417 // Start logging TouchKeys/MIDI data to a file. Filename is autogenerated
|
andrewm@0
|
418 // based on current time.
|
andrewm@0
|
419 void MainApplicationController::startLogging() {
|
andrewm@0
|
420 if(loggingActive_)
|
andrewm@0
|
421 stopLogging();
|
andrewm@0
|
422
|
andrewm@0
|
423 std::stringstream out;
|
andrewm@0
|
424 out << time(NULL);
|
andrewm@0
|
425 std::string fileId = out.str();
|
andrewm@0
|
426
|
andrewm@0
|
427
|
andrewm@0
|
428 string midiLogFileName = "midiLog_" + fileId + ".bin";
|
andrewm@0
|
429 string keyTouchLogFileName = "keyTouchLog_" + fileId + ".bin";
|
andrewm@0
|
430 string analogLogFileName = "keyAngleLog_" + fileId + ".bin";
|
andrewm@0
|
431
|
andrewm@0
|
432 // Create log files with these names
|
andrewm@0
|
433 midiInputController_.createLogFile(midiLogFileName, loggingDirectory_);
|
andrewm@0
|
434 touchkeyController_.createLogFiles(keyTouchLogFileName, analogLogFileName, loggingDirectory_);
|
andrewm@0
|
435
|
andrewm@0
|
436 // Enable logging from each controller
|
andrewm@0
|
437 midiInputController_.startLogging();
|
andrewm@0
|
438 touchkeyController_.startLogging();
|
andrewm@0
|
439
|
andrewm@0
|
440 loggingActive_ = true;
|
andrewm@0
|
441 }
|
andrewm@0
|
442
|
andrewm@0
|
443 // Stop a currently running log.
|
andrewm@0
|
444 void MainApplicationController::stopLogging() {
|
andrewm@0
|
445 if(!loggingActive_)
|
andrewm@0
|
446 return;
|
andrewm@0
|
447
|
andrewm@0
|
448 // stop logging data
|
andrewm@0
|
449 midiInputController_.stopLogging();
|
andrewm@0
|
450 touchkeyController_.stopLogging();
|
andrewm@0
|
451
|
andrewm@0
|
452 // close the log files
|
andrewm@0
|
453 midiInputController_.closeLogFile();
|
andrewm@0
|
454 touchkeyController_.closeLogFile();
|
andrewm@0
|
455
|
andrewm@0
|
456 loggingActive_ = false;
|
andrewm@0
|
457 }
|
andrewm@0
|
458
|
andrewm@0
|
459 void MainApplicationController::setLoggingDirectory(const char *directory) {
|
andrewm@0
|
460 loggingDirectory_ = directory;
|
andrewm@0
|
461 }
|
andrewm@0
|
462
|
andrewm@53
|
463 void MainApplicationController::playLogWithDialog() {
|
andrewm@53
|
464 if(isPlayingLog_)
|
andrewm@53
|
465 return;
|
andrewm@53
|
466
|
andrewm@53
|
467 FileChooser tkChooser ("Select TouchKeys log...",
|
andrewm@53
|
468 File::nonexistent, // File::getSpecialLocation (File::userHomeDirectory),
|
andrewm@53
|
469 "*.bin");
|
andrewm@53
|
470 if(tkChooser.browseForFileToOpen()) {
|
andrewm@53
|
471 FileChooser midiChooser ("Select MIDI log...",
|
andrewm@53
|
472 File::nonexistent, // File::getSpecialLocation (File::userHomeDirectory),
|
andrewm@53
|
473 "*.bin");
|
andrewm@53
|
474 if(midiChooser.browseForFileToOpen()) {
|
andrewm@53
|
475 logPlayback_ = new LogPlayback(keyboardController_, midiInputController_);
|
andrewm@53
|
476 if(logPlayback_ == 0)
|
andrewm@53
|
477 return;
|
andrewm@53
|
478
|
andrewm@53
|
479 if(logPlayback_->openLogFiles(tkChooser.getResult().getFullPathName().toRawUTF8(), midiChooser.getResult().getFullPathName().toRawUTF8())) {
|
andrewm@53
|
480 logPlayback_->startPlayback();
|
andrewm@53
|
481 isPlayingLog_ = true;
|
andrewm@53
|
482 #ifndef TOUCHKEYS_NO_GUI
|
andrewm@53
|
483 // Always show 88 keys for log playback since we won't know which keys were actually recorded
|
andrewm@53
|
484 keyboardDisplay_.setKeyboardRange(21, 108);
|
andrewm@53
|
485 if(keyboardDisplayWindow_ != 0) {
|
andrewm@53
|
486 keyboardDisplayWindow_->getConstrainer()->setFixedAspectRatio(keyboardDisplay_.keyboardAspectRatio());
|
andrewm@53
|
487
|
a@54
|
488 juce::Rectangle<int> bounds = keyboardDisplayWindow_->getBounds();
|
andrewm@53
|
489 if(bounds.getY() < 44)
|
andrewm@53
|
490 bounds.setY(44);
|
andrewm@53
|
491 keyboardDisplayWindow_->setBoundsConstrained(bounds);
|
andrewm@53
|
492 }
|
andrewm@53
|
493 showKeyboardDisplayWindow();
|
andrewm@53
|
494 #endif
|
andrewm@53
|
495 }
|
andrewm@53
|
496 }
|
andrewm@53
|
497 }
|
andrewm@53
|
498 }
|
andrewm@53
|
499
|
andrewm@53
|
500 void MainApplicationController::stopPlayingLog() {
|
andrewm@53
|
501 if(!isPlayingLog_)
|
andrewm@53
|
502 return;
|
andrewm@53
|
503
|
andrewm@53
|
504 if(logPlayback_ != 0) {
|
andrewm@53
|
505 logPlayback_->stopPlayback();
|
andrewm@53
|
506 logPlayback_->closeLogFiles();
|
andrewm@53
|
507 delete logPlayback_;
|
andrewm@53
|
508 logPlayback_ = 0;
|
andrewm@53
|
509 }
|
andrewm@53
|
510
|
andrewm@53
|
511 #ifndef TOUCHKEYS_NO_GUI
|
andrewm@53
|
512 keyboardDisplay_.clearAllTouches();
|
andrewm@53
|
513 #endif
|
andrewm@53
|
514 midiInputController_.allNotesOff();
|
andrewm@53
|
515 isPlayingLog_ = false;
|
andrewm@53
|
516 }
|
andrewm@53
|
517
|
andrewm@0
|
518 // Add a new MIDI keyboard segment. This method also handles numbering of the segments
|
andrewm@0
|
519 MidiKeyboardSegment* MainApplicationController::midiSegmentAdd() {
|
andrewm@0
|
520 // For now, the segment counter increments with each new segment. Eventually, we could
|
andrewm@0
|
521 // consider renumbering every time a segment is removed so that we always have an index
|
andrewm@0
|
522 // 0-N which corresponds to the indexes within MidiInputController (and also the layout
|
andrewm@0
|
523 // of the tabs).
|
andrewm@41
|
524 MidiKeyboardSegment *newSegment = midiInputController_.addSegment(segmentCounter_, 12, 127);
|
andrewm@0
|
525
|
andrewm@0
|
526 // Set up defaults
|
andrewm@0
|
527 newSegment->setModePassThrough();
|
andrewm@0
|
528 newSegment->setPolyphony(8);
|
andrewm@0
|
529 newSegment->setVoiceStealingEnabled(false);
|
andrewm@0
|
530 newSegment->enableAllChannels();
|
andrewm@0
|
531 newSegment->setOutputTransposition(0);
|
andrewm@5
|
532 newSegment->setUsesKeyboardPitchWheel(true);
|
andrewm@0
|
533
|
andrewm@41
|
534 // Enable the MIDI output for this segment if it exists in the preferences
|
andrewm@41
|
535 loadMIDIOutputFromApplicationPreferences(segmentCounter_);
|
andrewm@41
|
536
|
andrewm@0
|
537 // Enable standalone mode on the new segment if generally enabled
|
andrewm@0
|
538 if(touchkeyStandaloneModeEnabled_)
|
andrewm@0
|
539 newSegment->enableTouchkeyStandaloneMode();
|
andrewm@0
|
540
|
andrewm@41
|
541 segmentCounter_++;
|
andrewm@41
|
542
|
andrewm@0
|
543 return newSegment;
|
andrewm@0
|
544 }
|
andrewm@0
|
545
|
andrewm@13
|
546 // Remove a MIDI keyboard segment.
|
andrewm@13
|
547 void MainApplicationController::midiSegmentRemove(MidiKeyboardSegment *segment) {
|
andrewm@13
|
548 if(segment == 0)
|
andrewm@13
|
549 return;
|
andrewm@13
|
550 // Check if this segment uses a virtual output port. Right now, we have a unique
|
andrewm@13
|
551 // output per segment. If it does, then disable the virtual output port.
|
andrewm@13
|
552 int identifier = segment->outputPort();
|
andrewm@13
|
553 if(midiOutputController_.enabledPort(identifier) == MidiOutputController::kMidiVirtualOutputPortNumber)
|
andrewm@13
|
554 midiOutputController_.disablePort(identifier);
|
andrewm@13
|
555 midiInputController_.removeSegment(segment);
|
andrewm@13
|
556 }
|
andrewm@13
|
557
|
andrewm@41
|
558 // Enable one MIDI input port either as primary or auxiliary
|
andrewm@41
|
559 void MainApplicationController::enableMIDIInputPort(int portNumber, bool isPrimary) {
|
andrewm@41
|
560 midiInputController_.enablePort(portNumber, isPrimary);
|
andrewm@41
|
561 if(isPrimary)
|
andrewm@41
|
562 applicationProperties_.getUserSettings()->setValue("MIDIInputPrimary",
|
andrewm@41
|
563 midiInputController_.deviceName(portNumber));
|
andrewm@41
|
564 else
|
andrewm@41
|
565 applicationProperties_.getUserSettings()->setValue("MIDIInputAuxiliary",
|
andrewm@41
|
566 midiInputController_.deviceName(portNumber));
|
andrewm@41
|
567 }
|
andrewm@41
|
568
|
andrewm@41
|
569 // Enable all available MIDI input ports, with one in particular selected as primary
|
andrewm@41
|
570 void MainApplicationController::enableAllMIDIInputPorts(int primaryPortNumber) {
|
andrewm@41
|
571 midiInputController_.enableAllPorts(primaryPortNumber);
|
andrewm@41
|
572 applicationProperties_.getUserSettings()->setValue("MIDIInputPrimary",
|
andrewm@41
|
573 midiInputController_.deviceName(primaryPortNumber));
|
andrewm@41
|
574 applicationProperties_.getUserSettings()->setValue("MIDIInputAuxiliary", "__all__");
|
andrewm@41
|
575 }
|
andrewm@41
|
576
|
andrewm@41
|
577 // Disable a particular MIDI input port number
|
andrewm@41
|
578 // For now, the preferences for auxiliary ports don't update; could add a complete list of enabled aux ports
|
andrewm@41
|
579 void MainApplicationController::disableMIDIInputPort(int portNumber) {
|
andrewm@41
|
580 if(portNumber == selectedMIDIPrimaryInputPort())
|
andrewm@41
|
581 applicationProperties_.getUserSettings()->setValue("MIDIInputPrimary", "");
|
andrewm@41
|
582 midiInputController_.disablePort(portNumber);
|
andrewm@41
|
583 }
|
andrewm@41
|
584
|
andrewm@41
|
585 // Disable the current primary MIDI input port
|
andrewm@41
|
586 void MainApplicationController::disablePrimaryMIDIInputPort() {
|
andrewm@41
|
587 applicationProperties_.getUserSettings()->setValue("MIDIInputPrimary", "");
|
andrewm@41
|
588 midiInputController_.disablePrimaryPort();
|
andrewm@41
|
589 }
|
andrewm@41
|
590
|
andrewm@41
|
591 // Disable either all MIDI input ports or all auxiliary inputs
|
andrewm@41
|
592 void MainApplicationController::disableAllMIDIInputPorts(bool auxiliaryOnly) {
|
andrewm@41
|
593 applicationProperties_.getUserSettings()->setValue("MIDIInputAuxiliary", "");
|
andrewm@41
|
594 if(!auxiliaryOnly)
|
andrewm@41
|
595 applicationProperties_.getUserSettings()->setValue("MIDIInputPrimary", "");
|
andrewm@41
|
596 midiInputController_.disableAllPorts(auxiliaryOnly);
|
andrewm@41
|
597 }
|
andrewm@41
|
598
|
andrewm@41
|
599 // Enable a particular MIDI output port, associating it with a segment
|
andrewm@41
|
600 void MainApplicationController::enableMIDIOutputPort(int identifier, int deviceNumber) {
|
andrewm@41
|
601 midiOutputController_.enablePort(identifier, deviceNumber);
|
andrewm@41
|
602
|
andrewm@41
|
603 String zoneName = "MIDIOutputZone";
|
andrewm@41
|
604 zoneName += identifier;
|
andrewm@41
|
605 applicationProperties_.getUserSettings()->setValue(zoneName, midiOutputController_.deviceName(deviceNumber));
|
andrewm@41
|
606 }
|
andrewm@41
|
607
|
andrewm@41
|
608 #ifndef JUCE_WINDOWS
|
andrewm@41
|
609 // Create a virtual (inter-application) MIDI output port
|
andrewm@41
|
610 void MainApplicationController::enableMIDIOutputVirtualPort(int identifier, const char *name) {
|
andrewm@41
|
611 midiOutputController_.enableVirtualPort(identifier, name);
|
andrewm@41
|
612
|
andrewm@41
|
613 String zoneName = "MIDIOutputZone";
|
andrewm@41
|
614 zoneName += identifier;
|
andrewm@41
|
615 String zoneValue = "__virtual__";
|
andrewm@41
|
616 zoneValue += String(name);
|
andrewm@41
|
617 applicationProperties_.getUserSettings()->setValue(zoneName, zoneValue);
|
andrewm@41
|
618 }
|
andrewm@41
|
619 #endif
|
andrewm@41
|
620
|
andrewm@41
|
621 // Disable a particular MIDI output port
|
andrewm@41
|
622 void MainApplicationController::disableMIDIOutputPort(int identifier) {
|
andrewm@41
|
623 String zoneName = "MIDIOutputZone";
|
andrewm@41
|
624 zoneName += identifier;
|
andrewm@41
|
625 applicationProperties_.getUserSettings()->setValue(zoneName, "");
|
andrewm@41
|
626
|
andrewm@41
|
627 midiOutputController_.disablePort(identifier);
|
andrewm@41
|
628 }
|
andrewm@41
|
629
|
andrewm@41
|
630 // Disable all MIDI output ports
|
andrewm@41
|
631 void MainApplicationController::disableAllMIDIOutputPorts() {
|
andrewm@41
|
632 std::vector<std::pair<int, int> > enabledPorts = midiOutputController_.enabledPorts();
|
andrewm@41
|
633 for(int i = 0; i < enabledPorts.size(); i++) {
|
andrewm@41
|
634 // For each active zone, set output port to disabled in preferences
|
andrewm@41
|
635 String zoneName = "MIDIOutputZone";
|
andrewm@41
|
636 zoneName += enabledPorts[i].first;
|
andrewm@41
|
637 applicationProperties_.getUserSettings()->setValue(zoneName, "");
|
andrewm@41
|
638 }
|
andrewm@41
|
639
|
andrewm@41
|
640 midiOutputController_.disableAllPorts();
|
andrewm@41
|
641 }
|
andrewm@13
|
642
|
andrewm@0
|
643 // Enable TouchKeys standalone mode
|
andrewm@0
|
644 void MainApplicationController::midiTouchkeysStandaloneModeEnable() {
|
andrewm@0
|
645 touchkeyStandaloneModeEnabled_ = true;
|
andrewm@0
|
646 // Go through all segments and enable standalone mode
|
andrewm@0
|
647 for(int i = 0; i < midiInputController_.numSegments(); i++) {
|
andrewm@0
|
648 midiInputController_.segment(i)->enableTouchkeyStandaloneMode();
|
andrewm@0
|
649 }
|
andrewm@41
|
650
|
andrewm@41
|
651 applicationProperties_.getUserSettings()->setValue("MIDIInputPrimary", "__standalone__");
|
andrewm@0
|
652 }
|
andrewm@0
|
653
|
andrewm@0
|
654 void MainApplicationController::midiTouchkeysStandaloneModeDisable() {
|
andrewm@0
|
655 touchkeyStandaloneModeEnabled_ = false;
|
andrewm@0
|
656 // Go through all segments and disable standalone mode
|
andrewm@0
|
657 for(int i = 0; i < midiInputController_.numSegments(); i++) {
|
andrewm@28
|
658 midiInputController_.segment(i)->disableTouchkeyStandaloneMode();
|
andrewm@0
|
659 }
|
andrewm@41
|
660
|
andrewm@41
|
661 if(applicationProperties_.getUserSettings()->getValue("MIDIInputPrimary") == "__standalone__")
|
andrewm@41
|
662 applicationProperties_.getUserSettings()->setValue("MIDIInputPrimary", "");
|
andrewm@41
|
663 }
|
andrewm@41
|
664
|
andrewm@41
|
665 // *** OSC device methods ***
|
andrewm@41
|
666
|
andrewm@41
|
667 // Return whether OSC transmission is enabled
|
andrewm@41
|
668 bool MainApplicationController::oscTransmitEnabled() {
|
andrewm@41
|
669 return oscTransmitter_.enabled();
|
andrewm@41
|
670 }
|
andrewm@41
|
671
|
andrewm@41
|
672 // Set whether OSC transmission is enabled
|
andrewm@41
|
673 void MainApplicationController::oscTransmitSetEnabled(bool enable) {
|
andrewm@41
|
674 oscTransmitter_.setEnabled(enable);
|
andrewm@41
|
675 applicationProperties_.getUserSettings()->setValue("OSCTransmitEnabled", enable);
|
andrewm@41
|
676 }
|
andrewm@41
|
677
|
andrewm@41
|
678 // Return whether raw frame transmission is enabled
|
andrewm@41
|
679 bool MainApplicationController::oscTransmitRawDataEnabled() {
|
andrewm@41
|
680 return touchkeyController_.transmitRawDataEnabled();
|
andrewm@41
|
681 }
|
andrewm@41
|
682
|
andrewm@41
|
683 // Set whether raw frame transmission is enabled
|
andrewm@41
|
684 void MainApplicationController::oscTransmitSetRawDataEnabled(bool enable) {
|
andrewm@41
|
685 touchkeyController_.setTransmitRawData(enable);
|
andrewm@41
|
686 applicationProperties_.getUserSettings()->setValue("OSCTransmitRawDataEnabled", enable);
|
andrewm@41
|
687 }
|
andrewm@41
|
688
|
andrewm@41
|
689 // Return the addresses to which OSC messages are sent
|
andrewm@41
|
690 std::vector<lo_address> MainApplicationController::oscTransmitAddresses() {
|
andrewm@41
|
691 return oscTransmitter_.addresses();
|
andrewm@41
|
692 }
|
andrewm@41
|
693
|
andrewm@41
|
694 // Add a new address for sending OSC messages to
|
andrewm@41
|
695 int MainApplicationController::oscTransmitAddAddress(const char * host, const char * port, int proto) {
|
andrewm@41
|
696 int indexOfNewAddress = oscTransmitter_.addAddress(host, port, proto);
|
andrewm@41
|
697
|
andrewm@41
|
698 if(indexOfNewAddress >= 0) {
|
andrewm@41
|
699 // Successfully added; update preferences
|
andrewm@41
|
700 String keyName = "OSCTransmitHost";
|
andrewm@41
|
701 keyName += indexOfNewAddress;
|
andrewm@41
|
702 applicationProperties_.getUserSettings()->setValue(keyName, String(host));
|
andrewm@41
|
703
|
andrewm@41
|
704 keyName = "OSCTransmitPort";
|
andrewm@41
|
705 keyName += indexOfNewAddress;
|
andrewm@41
|
706 applicationProperties_.getUserSettings()->setValue(keyName, String(port));
|
andrewm@41
|
707
|
andrewm@41
|
708 keyName = "OSCTransmitProtocol";
|
andrewm@41
|
709 keyName += indexOfNewAddress;
|
andrewm@41
|
710 applicationProperties_.getUserSettings()->setValue(keyName, proto);
|
andrewm@41
|
711 }
|
andrewm@41
|
712
|
andrewm@41
|
713 return indexOfNewAddress;
|
andrewm@41
|
714 }
|
andrewm@41
|
715
|
andrewm@41
|
716 // Remove a particular OSC address from the send list
|
andrewm@41
|
717 void MainApplicationController::oscTransmitRemoveAddress(int index) {
|
andrewm@41
|
718 oscTransmitter_.removeAddress(index);
|
andrewm@41
|
719
|
andrewm@41
|
720 // Remove this destination from the preferences, if it exists
|
andrewm@41
|
721 String keyName = "OSCTransmitHost";
|
andrewm@41
|
722 keyName += index;
|
andrewm@41
|
723
|
andrewm@41
|
724 if(applicationProperties_.getUserSettings()->containsKey(keyName)) {
|
andrewm@41
|
725 applicationProperties_.getUserSettings()->setValue(keyName, "");
|
andrewm@41
|
726
|
andrewm@41
|
727 keyName = "OSCTransmitPort";
|
andrewm@41
|
728 keyName += index;
|
andrewm@41
|
729 applicationProperties_.getUserSettings()->setValue(keyName, "");
|
andrewm@41
|
730
|
andrewm@41
|
731 keyName = "OSCTransmitProtocol";
|
andrewm@41
|
732 keyName += index;
|
andrewm@41
|
733 applicationProperties_.getUserSettings()->setValue(keyName, (int)0);
|
andrewm@41
|
734 }
|
andrewm@41
|
735 }
|
andrewm@41
|
736
|
andrewm@41
|
737 // Remove all OSC addresses from the send list
|
andrewm@41
|
738 void MainApplicationController::oscTransmitClearAddresses() {
|
andrewm@41
|
739 oscTransmitter_.clearAddresses();
|
andrewm@41
|
740
|
andrewm@41
|
741 for(int index = 0; index < 16; index++) {
|
andrewm@41
|
742 // Go through and clear preferences for recent OSC hosts;
|
andrewm@41
|
743 // 16 hosts is a sanity check
|
andrewm@41
|
744
|
andrewm@41
|
745 String keyName = "OSCTransmitHost";
|
andrewm@41
|
746 keyName += index;
|
andrewm@41
|
747
|
andrewm@41
|
748 if(applicationProperties_.getUserSettings()->containsKey(keyName)) {
|
andrewm@41
|
749 applicationProperties_.getUserSettings()->setValue(keyName, "");
|
andrewm@41
|
750
|
andrewm@41
|
751 keyName = "OSCTransmitPort";
|
andrewm@41
|
752 keyName += index;
|
andrewm@41
|
753 applicationProperties_.getUserSettings()->setValue(keyName, "");
|
andrewm@41
|
754
|
andrewm@41
|
755 keyName = "OSCTransmitProtocol";
|
andrewm@41
|
756 keyName += index;
|
andrewm@41
|
757 applicationProperties_.getUserSettings()->setValue(keyName, (int)0);
|
andrewm@41
|
758 }
|
andrewm@41
|
759 }
|
andrewm@41
|
760
|
andrewm@41
|
761 }
|
andrewm@41
|
762
|
andrewm@41
|
763 // OSC Input (receiver) methods
|
andrewm@41
|
764 // Enable or disable on the OSC receive, and report is status
|
andrewm@41
|
765 bool MainApplicationController::oscReceiveEnabled() {
|
andrewm@41
|
766 return oscReceiveEnabled_;
|
andrewm@41
|
767 }
|
andrewm@41
|
768
|
andrewm@41
|
769 // Enable method returns true on success (false only if it was
|
andrewm@41
|
770 // unable to set the port)
|
andrewm@41
|
771 bool MainApplicationController::oscReceiveSetEnabled(bool enable) {
|
andrewm@41
|
772 applicationProperties_.getUserSettings()->setValue("OSCReceiveEnabled", enable);
|
andrewm@41
|
773
|
andrewm@41
|
774 if(enable && !oscReceiveEnabled_) {
|
andrewm@41
|
775 oscReceiveEnabled_ = true;
|
andrewm@41
|
776 return oscReceiver_.setPort(oscReceivePort_);
|
andrewm@41
|
777 }
|
andrewm@41
|
778 else if(!enable && oscReceiveEnabled_) {
|
andrewm@41
|
779 oscReceiveEnabled_ = false;
|
andrewm@41
|
780 return oscReceiver_.setPort(0);
|
andrewm@41
|
781 }
|
andrewm@41
|
782 return true;
|
andrewm@41
|
783 }
|
andrewm@41
|
784
|
andrewm@41
|
785 // Whether the OSC server is running (false means couldn't open port)
|
andrewm@41
|
786 bool MainApplicationController::oscReceiveRunning() {
|
andrewm@41
|
787 return oscReceiver_.running();
|
andrewm@41
|
788 }
|
andrewm@41
|
789
|
andrewm@41
|
790 // Get the current OSC receive port
|
andrewm@41
|
791 int MainApplicationController::oscReceivePort() {
|
andrewm@41
|
792 return oscReceivePort_;
|
andrewm@41
|
793 }
|
andrewm@41
|
794
|
andrewm@41
|
795 // Set the current OSC receive port (returns true on success)
|
andrewm@41
|
796 bool MainApplicationController::oscReceiveSetPort(int port) {
|
andrewm@41
|
797 applicationProperties_.getUserSettings()->setValue("OSCReceivePort", port);
|
andrewm@41
|
798
|
andrewm@41
|
799 oscReceivePort_ = port;
|
andrewm@41
|
800 return oscReceiver_.setPort(port);
|
andrewm@0
|
801 }
|
andrewm@0
|
802
|
andrewm@0
|
803 // OSC handler method
|
andrewm@0
|
804 bool MainApplicationController::oscHandlerMethod(const char *path, const char *types, int numValues, lo_arg **values, void *data) {
|
andrewm@49
|
805 std::cout << path << endl;
|
andrewm@49
|
806
|
andrewm@49
|
807 if(!strcmp(path, "/midi/noteon")) {
|
andrewm@49
|
808 if(touchkeyAutodetecting_ && numValues > 0) {
|
andrewm@49
|
809 // std::cout << "/midi/noteon\n";
|
andrewm@49
|
810 // Found a MIDI note. Look for a unique touch on this pitch class to
|
andrewm@49
|
811 // determine which octave the keyboard is set to
|
andrewm@49
|
812 if(types[0] != 'i')
|
andrewm@49
|
813 return false; // Ill-formed message
|
andrewm@49
|
814 int midiNote = values[0]->i;
|
andrewm@49
|
815 if(midiNote < 0 || midiNote > 127)
|
andrewm@49
|
816 return false;
|
andrewm@49
|
817
|
andrewm@49
|
818 // Go through each octave and see if a touch is present
|
andrewm@49
|
819 int midiTestNote = midiNote % 12;
|
andrewm@49
|
820 int count = 0;
|
andrewm@49
|
821 int lastFoundTouchNote = 0;
|
andrewm@49
|
822 while(midiTestNote <= 127) {
|
andrewm@49
|
823 if(keyboardController_.key(midiTestNote) != 0) {
|
andrewm@49
|
824 if(keyboardController_.key(midiTestNote)->touchIsActive()) {
|
andrewm@49
|
825 count++;
|
andrewm@49
|
826 lastFoundTouchNote = midiTestNote;
|
andrewm@49
|
827 }
|
andrewm@0
|
828 }
|
andrewm@49
|
829 midiTestNote += 12;
|
andrewm@41
|
830 }
|
andrewm@0
|
831
|
andrewm@49
|
832 // We return success if exactly one note had a touch on this pitch class
|
andrewm@49
|
833 if(count == 1) {
|
andrewm@49
|
834 int noteDifference = lastFoundTouchNote - midiNote;
|
andrewm@49
|
835 int currentMinNote = touchkeyController_.lowestMidiNote();
|
andrewm@49
|
836
|
andrewm@49
|
837 // std::cout << "Found difference of " << noteDifference << std::endl;
|
andrewm@49
|
838
|
andrewm@49
|
839 currentMinNote -= noteDifference;
|
andrewm@49
|
840 if(currentMinNote >= 0 && currentMinNote <= 127) {
|
andrewm@49
|
841 touchkeyController_.setLowestMidiNote(currentMinNote);
|
andrewm@49
|
842 applicationProperties_.getUserSettings()->setValue("TouchKeysLowestMIDINote", currentMinNote);
|
andrewm@49
|
843 }
|
andrewm@49
|
844
|
andrewm@49
|
845 touchkeyDeviceStopAutodetecting();
|
andrewm@49
|
846 }
|
andrewm@49
|
847 return false; // Others may still want to handle this message
|
andrewm@0
|
848 }
|
andrewm@0
|
849 }
|
andrewm@0
|
850
|
andrewm@0
|
851 return false;
|
andrewm@0
|
852 }
|
andrewm@0
|
853
|
andrewm@33
|
854 // Save the current settings to an XML file
|
andrewm@33
|
855 // Returns true on success
|
andrewm@33
|
856 bool MainApplicationController::savePresetToFile(const char *filename) {
|
andrewm@33
|
857 File outputFile(filename);
|
andrewm@33
|
858
|
andrewm@33
|
859 return savePresetHelper(outputFile);
|
andrewm@33
|
860 }
|
andrewm@33
|
861
|
andrewm@33
|
862 // Load settings from a saved XML file
|
andrewm@33
|
863 // Returns true on success
|
andrewm@33
|
864 bool MainApplicationController::loadPresetFromFile(const char *filename) {
|
andrewm@33
|
865 File inputFile(filename);
|
andrewm@33
|
866
|
andrewm@33
|
867 return loadPresetHelper(inputFile);
|
andrewm@33
|
868 }
|
andrewm@33
|
869
|
andrewm@33
|
870 #ifndef TOUCHKEYS_NO_GUI
|
andrewm@33
|
871 // Present the user with a Save dialog and then save the preset
|
andrewm@33
|
872 bool MainApplicationController::savePresetWithDialog() {
|
andrewm@33
|
873 FileChooser myChooser ("Save preset...",
|
andrewm@33
|
874 File::nonexistent, // File::getSpecialLocation (File::userHomeDirectory),
|
andrewm@33
|
875 "*.tkpreset");
|
andrewm@33
|
876 if(myChooser.browseForFileToSave(true)) {
|
andrewm@33
|
877 File outputFile(myChooser.getResult());
|
andrewm@33
|
878 return savePresetHelper(outputFile);
|
andrewm@33
|
879 }
|
andrewm@33
|
880 // User clicked cancel...
|
andrewm@33
|
881 return true;
|
andrewm@33
|
882 }
|
andrewm@33
|
883
|
andrewm@33
|
884
|
andrewm@33
|
885 // Present the user with a Load dialog and then save the preset
|
andrewm@33
|
886 bool MainApplicationController::loadPresetWithDialog() {
|
andrewm@33
|
887 FileChooser myChooser ("Select a preset...",
|
andrewm@33
|
888 File::nonexistent, // File::getSpecialLocation (File::userHomeDirectory),
|
andrewm@33
|
889 "*.tkpreset");
|
andrewm@33
|
890 if(myChooser.browseForFileToOpen()) {
|
andrewm@33
|
891 return loadPresetHelper(myChooser.getResult());
|
andrewm@33
|
892 }
|
andrewm@33
|
893 // User clicked cancel...
|
andrewm@33
|
894 return true;
|
andrewm@33
|
895 }
|
andrewm@33
|
896 #endif
|
andrewm@33
|
897
|
andrewm@33
|
898 bool MainApplicationController::loadPresetHelper(File const& inputFile) {
|
andrewm@33
|
899 if(!inputFile.existsAsFile())
|
andrewm@33
|
900 return false;
|
andrewm@33
|
901
|
andrewm@33
|
902 // Load the XML element from the file and check that it is valid
|
andrewm@33
|
903 XmlDocument document(inputFile);
|
andrewm@40
|
904 ScopedPointer<XmlElement> mainElement(document.getDocumentElement());
|
andrewm@33
|
905
|
andrewm@33
|
906 if(mainElement == 0)
|
andrewm@33
|
907 return false;
|
andrewm@33
|
908 if(mainElement->getTagName() != "TouchKeysPreset")
|
andrewm@33
|
909 return false;
|
andrewm@33
|
910 XmlElement *segmentsElement = mainElement->getChildByName("KeyboardSegments");
|
andrewm@33
|
911 if(segmentsElement == 0)
|
andrewm@33
|
912 return false;
|
andrewm@33
|
913
|
andrewm@33
|
914 // Load the preset from this element
|
andrewm@39
|
915 bool result = midiInputController_.loadSegmentPreset(segmentsElement);
|
andrewm@39
|
916
|
andrewm@55
|
917 // Enable any necessary MIDI outputs
|
andrewm@55
|
918 for(int i = 0; i < midiInputController_.numSegments(); i++)
|
andrewm@55
|
919 loadMIDIOutputFromApplicationPreferences(i);
|
andrewm@55
|
920
|
andrewm@39
|
921 // Loading a preset won't set standalone mode; so re-enable it when finished
|
andrewm@39
|
922 // if needed
|
andrewm@39
|
923 if(touchkeyStandaloneModeEnabled_) {
|
andrewm@39
|
924 midiTouchkeysStandaloneModeEnable();
|
andrewm@39
|
925 }
|
andrewm@39
|
926
|
andrewm@39
|
927 return result;
|
andrewm@33
|
928 }
|
andrewm@33
|
929
|
andrewm@33
|
930 bool MainApplicationController::savePresetHelper(File& outputFile) {
|
andrewm@33
|
931 XmlElement mainElement("TouchKeysPreset");
|
andrewm@33
|
932 mainElement.setAttribute("format", "0.1");
|
andrewm@33
|
933
|
andrewm@33
|
934 XmlElement* segmentsElement = midiInputController_.getSegmentPreset();
|
andrewm@33
|
935 mainElement.addChildElement(segmentsElement);
|
andrewm@33
|
936
|
andrewm@41
|
937 bool result = mainElement.writeToFile(outputFile, "");
|
andrewm@41
|
938
|
andrewm@41
|
939 if(result) {
|
andrewm@41
|
940 applicationProperties_.getUserSettings()->setValue("LastSavedPreset", outputFile.getFullPathName());
|
andrewm@41
|
941 }
|
andrewm@41
|
942
|
andrewm@41
|
943 return result;
|
andrewm@33
|
944 }
|
andrewm@33
|
945
|
andrewm@37
|
946 // Clear the current preset and restore default settings
|
andrewm@37
|
947 void MainApplicationController::clearPreset() {
|
andrewm@37
|
948 midiInputController_.removeAllSegments();
|
andrewm@39
|
949 //midiOutputController_.disableAllPorts();
|
andrewm@37
|
950 segmentCounter_ = 0;
|
andrewm@37
|
951
|
andrewm@37
|
952 // Re-add a new segment, starting at 0
|
andrewm@37
|
953 midiSegmentAdd();
|
andrewm@37
|
954 }
|
andrewm@37
|
955
|
andrewm@41
|
956 // Whether to automatically start the TouchKeys on startup
|
andrewm@41
|
957 bool MainApplicationController::getPrefsAutoStartTouchKeys() {
|
andrewm@41
|
958 if(!applicationProperties_.getUserSettings()->containsKey("StartupStartTouchKeys"))
|
andrewm@41
|
959 return false;
|
andrewm@41
|
960 return applicationProperties_.getUserSettings()->getBoolValue("StartupStartTouchKeys");
|
andrewm@41
|
961 }
|
andrewm@41
|
962
|
andrewm@41
|
963 void MainApplicationController::setPrefsAutoStartTouchKeys(bool autoStart) {
|
andrewm@41
|
964 applicationProperties_.getUserSettings()->setValue("StartupStartTouchKeys", autoStart);
|
andrewm@41
|
965 }
|
andrewm@41
|
966
|
andrewm@41
|
967 // Whether to automatically detect the TouchKeys octave when they start
|
andrewm@41
|
968 bool MainApplicationController::getPrefsAutodetectOctave() {
|
andrewm@41
|
969 if(!applicationProperties_.getUserSettings()->containsKey("StartupAutodetectTouchKeysOctave"))
|
andrewm@41
|
970 return false;
|
andrewm@41
|
971 return applicationProperties_.getUserSettings()->getBoolValue("StartupAutodetectTouchKeysOctave");
|
andrewm@41
|
972 }
|
andrewm@41
|
973
|
andrewm@41
|
974 void MainApplicationController::setPrefsAutodetectOctave(bool autoDetect) {
|
andrewm@41
|
975 applicationProperties_.getUserSettings()->setValue("StartupAutodetectTouchKeysOctave", autoDetect);
|
andrewm@41
|
976 }
|
andrewm@41
|
977
|
andrewm@41
|
978 // Which preset (if any) to load at startup
|
andrewm@41
|
979 void MainApplicationController::setPrefsStartupPresetNone() {
|
andrewm@41
|
980 applicationProperties_.getUserSettings()->setValue("StartupPreset", "__none__");
|
andrewm@41
|
981 }
|
andrewm@41
|
982 bool MainApplicationController::getPrefsStartupPresetNone() {
|
andrewm@41
|
983 // By default, no prefs means no preset
|
andrewm@41
|
984 if(!applicationProperties_.getUserSettings()->containsKey("StartupPreset"))
|
andrewm@41
|
985 return true;
|
andrewm@41
|
986 if(applicationProperties_.getUserSettings()->getValue("StartupPreset") == "__none__")
|
andrewm@41
|
987 return true;
|
andrewm@41
|
988 return false;
|
andrewm@41
|
989 }
|
andrewm@41
|
990
|
andrewm@41
|
991 void MainApplicationController::setPrefsStartupPresetVibratoPitchBend() {
|
andrewm@41
|
992 applicationProperties_.getUserSettings()->setValue("StartupPreset", "__vib_pb__");
|
andrewm@41
|
993 }
|
andrewm@41
|
994 bool MainApplicationController::getPrefsStartupPresetVibratoPitchBend() {
|
andrewm@41
|
995 if(!applicationProperties_.getUserSettings()->containsKey("StartupPreset"))
|
andrewm@41
|
996 return false;
|
andrewm@41
|
997 if(applicationProperties_.getUserSettings()->getValue("StartupPreset") == "__vib_pb__")
|
andrewm@41
|
998 return true;
|
andrewm@41
|
999 return false;
|
andrewm@41
|
1000 }
|
andrewm@41
|
1001
|
andrewm@41
|
1002 void MainApplicationController::setPrefsStartupPresetLastSaved() {
|
andrewm@41
|
1003 applicationProperties_.getUserSettings()->setValue("StartupPreset", "__last__");
|
andrewm@41
|
1004 }
|
andrewm@41
|
1005 bool MainApplicationController::getPrefsStartupPresetLastSaved() {
|
andrewm@41
|
1006 if(!applicationProperties_.getUserSettings()->containsKey("StartupPreset"))
|
andrewm@41
|
1007 return false;
|
andrewm@41
|
1008 if(applicationProperties_.getUserSettings()->getValue("StartupPreset") == "__last__")
|
andrewm@41
|
1009 return true;
|
andrewm@41
|
1010 return false;
|
andrewm@41
|
1011 }
|
andrewm@41
|
1012
|
andrewm@41
|
1013 void MainApplicationController::setPrefsStartupPreset(String const& path) {
|
andrewm@41
|
1014 applicationProperties_.getUserSettings()->setValue("StartupPreset", path);
|
andrewm@41
|
1015 }
|
andrewm@41
|
1016 String MainApplicationController::getPrefsStartupPreset() {
|
andrewm@41
|
1017 if(!applicationProperties_.getUserSettings()->containsKey("StartupPreset"))
|
andrewm@41
|
1018 return "";
|
andrewm@41
|
1019 return applicationProperties_.getUserSettings()->getValue("StartupPreset");
|
andrewm@41
|
1020 }
|
andrewm@41
|
1021
|
andrewm@41
|
1022 // Reset application preferences to defaults
|
andrewm@41
|
1023 void MainApplicationController::resetPreferences() {
|
andrewm@41
|
1024 // TODO: reset settings now, not after restart
|
andrewm@41
|
1025 applicationProperties_.getUserSettings()->clear();
|
andrewm@41
|
1026
|
andrewm@41
|
1027 setPrefsStartupPresetVibratoPitchBend();
|
andrewm@41
|
1028 setPrefsAutodetectOctave(true);
|
andrewm@41
|
1029 }
|
andrewm@41
|
1030
|
andrewm@41
|
1031 // Load the current devices from a global preferences file
|
andrewm@41
|
1032 void MainApplicationController::loadApplicationPreferences(){
|
andrewm@41
|
1033 PropertiesFile *props = applicationProperties_.getUserSettings();
|
andrewm@41
|
1034
|
andrewm@41
|
1035 if(props == 0)
|
andrewm@41
|
1036 return;
|
andrewm@41
|
1037
|
andrewm@41
|
1038 // A few first-time defaults if the properties file is missing
|
andrewm@41
|
1039 if(props->getAllProperties().size() == 0) {
|
andrewm@41
|
1040 resetPreferences();
|
andrewm@41
|
1041 }
|
andrewm@41
|
1042
|
andrewm@41
|
1043 // Load TouchKeys settings
|
andrewm@41
|
1044 if(props->containsKey("TouchKeysDevice")) {
|
andrewm@41
|
1045 // TODO
|
andrewm@41
|
1046 }
|
andrewm@41
|
1047 if(props->containsKey("TouchKeysLowestMIDINote")) {
|
andrewm@41
|
1048 int note = props->getIntValue("TouchKeysLowestMIDINote");
|
andrewm@41
|
1049 if(note >= 0 && note <= 127)
|
andrewm@41
|
1050 touchkeyDeviceSetLowestMidiNote(note);
|
andrewm@41
|
1051 }
|
andrewm@41
|
1052
|
andrewm@41
|
1053 // Load MIDI input settings
|
andrewm@41
|
1054 if(props->containsKey("MIDIInputPrimary")) {
|
andrewm@41
|
1055 String deviceName = props->getValue("MIDIInputPrimary");
|
andrewm@41
|
1056 if(deviceName == "__standalone__") {
|
andrewm@41
|
1057 midiTouchkeysStandaloneModeEnable();
|
andrewm@41
|
1058 }
|
andrewm@41
|
1059 else {
|
andrewm@41
|
1060 int index = midiInputController_.indexOfDeviceNamed(deviceName);
|
andrewm@41
|
1061 // cout << "primary input id " << index << " name " << deviceName << endl;
|
andrewm@41
|
1062 if(index >= 0)
|
andrewm@41
|
1063 enableMIDIInputPort(index, true);
|
andrewm@41
|
1064 }
|
andrewm@41
|
1065 }
|
andrewm@41
|
1066 if(props->containsKey("MIDIInputAuxiliary")) {
|
andrewm@41
|
1067 String deviceName = props->getValue("MIDIInputAuxiliary");
|
andrewm@41
|
1068 int index = midiInputController_.indexOfDeviceNamed(deviceName);
|
andrewm@41
|
1069 // cout << "aux input id " << index << " name " << deviceName << endl;
|
andrewm@41
|
1070 if(index >= 0)
|
andrewm@41
|
1071 enableMIDIInputPort(index, false);
|
andrewm@41
|
1072 }
|
andrewm@41
|
1073
|
andrewm@41
|
1074 // MIDI output settings are loaded when segments are created
|
andrewm@41
|
1075
|
andrewm@41
|
1076 // OSC settings
|
andrewm@41
|
1077 if(props->containsKey("OSCTransmitEnabled")) {
|
andrewm@41
|
1078 bool enable = props->getBoolValue("OSCTransmitEnabled");
|
andrewm@41
|
1079 oscTransmitSetEnabled(enable);
|
andrewm@41
|
1080 }
|
andrewm@41
|
1081 if(props->containsKey("OSCTransmitRawDataEnabled")) {
|
andrewm@41
|
1082 bool enable = props->getBoolValue("OSCTransmitRawDataEnabled");
|
andrewm@41
|
1083 oscTransmitSetRawDataEnabled(enable);
|
andrewm@41
|
1084 }
|
andrewm@41
|
1085
|
andrewm@41
|
1086 for(int i = 0; i < 16; i++) {
|
andrewm@41
|
1087 String keyName = "OSCTransmitHost";
|
andrewm@41
|
1088 String host, port;
|
andrewm@41
|
1089 int protocol = LO_UDP;
|
andrewm@41
|
1090
|
andrewm@41
|
1091 keyName += i;
|
andrewm@41
|
1092 if(props->containsKey(keyName)) {
|
andrewm@41
|
1093 host = props->getValue(keyName);
|
andrewm@41
|
1094 }
|
andrewm@41
|
1095 else
|
andrewm@41
|
1096 continue;
|
andrewm@41
|
1097
|
andrewm@41
|
1098 keyName = "OSCTransmitPort";
|
andrewm@41
|
1099 keyName += i;
|
andrewm@41
|
1100 if(props->containsKey(keyName)) {
|
andrewm@41
|
1101 port = props->getValue(keyName);
|
andrewm@41
|
1102 }
|
andrewm@41
|
1103 else
|
andrewm@41
|
1104 continue;
|
andrewm@41
|
1105
|
andrewm@41
|
1106 keyName = "OSCTransmitProtocol";
|
andrewm@41
|
1107 keyName += i;
|
andrewm@41
|
1108 if(props->containsKey(keyName)) {
|
andrewm@41
|
1109 protocol = props->getIntValue(keyName);
|
andrewm@41
|
1110 }
|
andrewm@41
|
1111 // okay to go ahead without protocol; use default
|
andrewm@41
|
1112
|
andrewm@41
|
1113 // Check for validity
|
andrewm@41
|
1114 if(host != "" && port != "" && (protocol == LO_UDP || protocol == LO_TCP)) {
|
andrewm@41
|
1115 oscTransmitter_.addAddress(host.toUTF8(), port.toUTF8(), protocol);
|
andrewm@41
|
1116 }
|
andrewm@41
|
1117 }
|
andrewm@41
|
1118
|
andrewm@41
|
1119 if(props->containsKey("OSCReceiveEnabled")) {
|
andrewm@41
|
1120 bool enable = props->getBoolValue("OSCReceiveEnabled");
|
andrewm@41
|
1121 oscReceiveSetEnabled(enable);
|
andrewm@41
|
1122 }
|
andrewm@41
|
1123 if(props->containsKey("OSCReceivePort")) {
|
andrewm@41
|
1124 int port = props->getIntValue("OSCReceivePort");
|
andrewm@41
|
1125 if(port >= 1 && port <= 65535)
|
andrewm@41
|
1126 oscReceiveSetPort(port);
|
andrewm@41
|
1127 }
|
andrewm@41
|
1128
|
andrewm@41
|
1129 }
|
andrewm@41
|
1130
|
andrewm@41
|
1131 // Load the MIDI output device for a given zone
|
andrewm@41
|
1132 void MainApplicationController::loadMIDIOutputFromApplicationPreferences(int zone) {
|
andrewm@41
|
1133 PropertiesFile *props = applicationProperties_.getUserSettings();
|
andrewm@41
|
1134
|
andrewm@41
|
1135 String keyName = "MIDIOutputZone";
|
andrewm@41
|
1136 keyName += zone;
|
andrewm@41
|
1137
|
andrewm@41
|
1138 if(props->containsKey(keyName)) {
|
andrewm@41
|
1139 String output = props->getValue(keyName);
|
andrewm@41
|
1140 if(output.startsWith("__virtual__")) {
|
andrewm@41
|
1141 #ifndef JUCE_WINDOWS
|
andrewm@41
|
1142 // Open virtual port with the name that follows
|
andrewm@41
|
1143 String virtualPortName = output.substring(11); // length of "__virtual__"
|
andrewm@41
|
1144 midiOutputController_.enableVirtualPort(zone, virtualPortName.toUTF8());
|
andrewm@41
|
1145 #endif
|
andrewm@41
|
1146 }
|
andrewm@41
|
1147 else {
|
andrewm@41
|
1148 String deviceName = props->getValue(keyName);
|
andrewm@41
|
1149 int index = midiOutputController_.indexOfDeviceNamed(deviceName);
|
andrewm@41
|
1150 // cout << "zone " << zone << " id " << index << " name " << deviceName << endl;
|
andrewm@41
|
1151 if(index >= 0)
|
andrewm@41
|
1152 enableMIDIOutputPort(zone, index);
|
andrewm@41
|
1153 }
|
andrewm@41
|
1154 }
|
andrewm@41
|
1155 }
|
andrewm@41
|
1156
|
andrewm@17
|
1157 #ifdef ENABLE_TOUCHKEYS_SENSOR_TEST
|
andrewm@17
|
1158 // Start testing the TouchKeys sensors. Returns true on success.
|
andrewm@17
|
1159 bool MainApplicationController::touchkeySensorTestStart(const char *path, int firstKey) {
|
andrewm@17
|
1160 #ifndef TOUCHKEYS_NO_GUI
|
andrewm@17
|
1161 if(path == 0 || firstKey < touchkeyController_.lowestMidiNote())
|
andrewm@17
|
1162 return false;
|
andrewm@17
|
1163 if(keyboardTesterDisplay_ != 0)
|
andrewm@17
|
1164 return true;
|
andrewm@17
|
1165
|
andrewm@17
|
1166 // First, close the existing device which stops the data autogathering
|
andrewm@17
|
1167 closeTouchkeyDevice();
|
andrewm@17
|
1168
|
andrewm@17
|
1169 // Now reopen the TouchKeys device
|
andrewm@17
|
1170 if(!touchkeyController_.openDevice(path)) {
|
andrewm@17
|
1171 touchkeyErrorMessage_ = "Failed to open";
|
andrewm@17
|
1172 touchkeyErrorOccurred_ = true;
|
andrewm@17
|
1173 return false;
|
andrewm@17
|
1174 }
|
andrewm@17
|
1175
|
andrewm@17
|
1176 // Next, see if a real TouchKeys device is present at the other end
|
andrewm@17
|
1177 if(!touchkeyDeviceCheckForPresence()) {
|
andrewm@17
|
1178 touchkeyErrorMessage_ = "Device not recognized";
|
andrewm@17
|
1179 touchkeyErrorOccurred_ = true;
|
andrewm@17
|
1180 return false;
|
andrewm@17
|
1181 }
|
andrewm@17
|
1182
|
andrewm@17
|
1183 // Now, create the KeyboardTesterDisplay object which will handle processing
|
andrewm@17
|
1184 // raw data and displaying the results. Also a new window to hold it.
|
andrewm@17
|
1185 keyboardTesterDisplay_ = new KeyboardTesterDisplay(*this, keyboardController_);
|
andrewm@17
|
1186 keyboardTesterDisplay_->setKeyboardRange(touchkeyController_.lowestKeyPresentMidiNote(), touchkeyController_.highestMidiNote());
|
andrewm@17
|
1187 keyboardTesterWindow_ = new GraphicsDisplayWindow("TouchKeys Sensor Test", *keyboardTesterDisplay_);
|
andrewm@17
|
1188
|
andrewm@17
|
1189 // Start raw data gathering from the indicated key (converted to octave/key notation)
|
andrewm@18
|
1190 int keyOffset = firstKey - touchkeyController_.lowestMidiNote();
|
andrewm@17
|
1191 if(keyOffset < 0) // Shouldn't happen...
|
andrewm@17
|
1192 keyOffset = 0;
|
andrewm@17
|
1193
|
andrewm@49
|
1194 if(!touchkeyController_.startRawDataCollection(keyOffset / 12, keyOffset % 12, 3, 2)) {
|
andrewm@17
|
1195 touchkeyErrorMessage_ = "Failed to start";
|
andrewm@17
|
1196 touchkeyErrorOccurred_ = true;
|
andrewm@17
|
1197 return false;
|
andrewm@17
|
1198 }
|
andrewm@17
|
1199
|
andrewm@49
|
1200 keyboardTesterWindow_->addToDesktop(keyboardTesterWindow_->getDesktopWindowStyleFlags()
|
andrewm@49
|
1201 | ComponentPeer::windowHasCloseButton);
|
andrewm@42
|
1202 keyboardTesterWindow_->setVisible(true);
|
andrewm@49
|
1203 keyboardTesterWindow_->toFront(true);
|
andrewm@42
|
1204
|
andrewm@17
|
1205 touchkeyErrorMessage_ = "";
|
andrewm@17
|
1206 touchkeyErrorOccurred_ = false;
|
andrewm@17
|
1207 return true;
|
andrewm@17
|
1208 #endif
|
andrewm@17
|
1209 }
|
andrewm@17
|
1210
|
andrewm@17
|
1211 // Stop testing the TouchKeys sensors
|
andrewm@17
|
1212 void MainApplicationController::touchkeySensorTestStop() {
|
andrewm@17
|
1213 #ifndef TOUCHKEYS_NO_GUI
|
andrewm@17
|
1214 if(keyboardTesterDisplay_ == 0)
|
andrewm@17
|
1215 return;
|
andrewm@17
|
1216
|
andrewm@17
|
1217 // Stop raw data gathering first and close device
|
andrewm@17
|
1218 touchkeyController_.stopAutoGathering();
|
andrewm@17
|
1219 touchkeyController_.closeDevice();
|
andrewm@17
|
1220
|
andrewm@17
|
1221 // Delete the testing objects
|
andrewm@17
|
1222 delete keyboardTesterWindow_;
|
andrewm@17
|
1223 delete keyboardTesterDisplay_;
|
andrewm@17
|
1224
|
andrewm@17
|
1225 keyboardTesterWindow_ = 0;
|
andrewm@17
|
1226 keyboardTesterDisplay_ = 0;
|
andrewm@17
|
1227
|
andrewm@17
|
1228 touchkeyErrorMessage_ = "";
|
andrewm@17
|
1229 touchkeyErrorOccurred_ = false;
|
andrewm@17
|
1230 #endif
|
andrewm@17
|
1231 }
|
andrewm@17
|
1232
|
andrewm@17
|
1233 // Is the sensor test running?
|
andrewm@17
|
1234 bool MainApplicationController::touchkeySensorTestIsRunning() {
|
andrewm@17
|
1235 #ifdef TOUCHKEYS_NO_GUI
|
andrewm@17
|
1236 return false;
|
andrewm@17
|
1237 #else
|
andrewm@17
|
1238 return (keyboardTesterDisplay_ != 0);
|
andrewm@17
|
1239 #endif
|
andrewm@17
|
1240 }
|
andrewm@17
|
1241
|
andrewm@17
|
1242 // Set the current key that is begin tested
|
andrewm@17
|
1243 void MainApplicationController::touchkeySensorTestSetKey(int key) {
|
andrewm@17
|
1244 #ifndef TOUCHKEYS_NO_GUI
|
andrewm@17
|
1245 if(keyboardTesterDisplay_ == 0 || key < touchkeyController_.lowestMidiNote())
|
andrewm@17
|
1246 return;
|
andrewm@17
|
1247
|
andrewm@17
|
1248 int keyOffset = key - touchkeyController_.lowestMidiNote();
|
andrewm@17
|
1249 if(keyOffset < 0) // Shouldn't happen...
|
andrewm@17
|
1250 keyOffset = 0;
|
andrewm@17
|
1251
|
andrewm@17
|
1252 touchkeyController_.rawDataChangeKeyAndMode(keyOffset / 12, keyOffset % 12, 3, 2);
|
andrewm@17
|
1253 #endif
|
andrewm@17
|
1254 }
|
andrewm@17
|
1255
|
andrewm@17
|
1256 // Reset the testing state to all sensors off
|
andrewm@17
|
1257 void MainApplicationController::touchkeySensorTestResetState() {
|
andrewm@17
|
1258 #ifndef TOUCHKEYS_NO_GUI
|
andrewm@17
|
1259 if(keyboardTesterDisplay_ == 0)
|
andrewm@17
|
1260 return;
|
andrewm@17
|
1261 for(int key = 0; key < 128; key++)
|
andrewm@17
|
1262 keyboardTesterDisplay_->resetSensorState(key);
|
andrewm@17
|
1263 #endif
|
andrewm@17
|
1264 }
|
andrewm@17
|
1265
|
andrewm@17
|
1266 #endif // ENABLE_TOUCHKEYS_SENSOR_TEST
|
andrewm@17
|
1267
|
andrewm@53
|
1268 #ifdef ENABLE_TOUCHKEYS_FIRMWARE_UPDATE
|
andrewm@53
|
1269 // Put TouchKeys controller board into bootloader mode, for receiving firmware updates
|
andrewm@53
|
1270 // (supplied by a different utility)
|
andrewm@53
|
1271 bool MainApplicationController::touchkeyJumpToBootloader(const char *path) {
|
andrewm@53
|
1272 // First, close the existing device which stops the data autogathering
|
andrewm@53
|
1273 closeTouchkeyDevice();
|
andrewm@53
|
1274
|
andrewm@53
|
1275 // Now reopen the TouchKeys device
|
andrewm@53
|
1276 if(!touchkeyController_.openDevice(path)) {
|
andrewm@53
|
1277 touchkeyErrorMessage_ = "Failed to open";
|
andrewm@53
|
1278 touchkeyErrorOccurred_ = true;
|
andrewm@53
|
1279 return false;
|
andrewm@53
|
1280 }
|
andrewm@53
|
1281
|
andrewm@53
|
1282 touchkeyController_.jumpToBootloader();
|
andrewm@53
|
1283
|
andrewm@53
|
1284 // Set an "error" condition to display this message, and because
|
andrewm@53
|
1285 // after jumping to bootloader mode, the device will not open properly
|
andrewm@53
|
1286 // until it has been reset.
|
andrewm@53
|
1287 touchkeyErrorMessage_ = "Firmware update mode";
|
andrewm@53
|
1288 touchkeyErrorOccurred_ = true;
|
andrewm@53
|
1289 return true;
|
andrewm@53
|
1290 }
|
andrewm@53
|
1291 #endif // ENABLE_TOUCHKEYS_FIRMWARE_UPDATE
|
andrewm@53
|
1292
|
andrewm@0
|
1293 // Return the name of a MIDI note given its number
|
andrewm@0
|
1294 std::string MainApplicationController::midiNoteName(int noteNumber) {
|
andrewm@0
|
1295 if(noteNumber < 0 || noteNumber > 127)
|
andrewm@0
|
1296 return "";
|
andrewm@0
|
1297 char name[6];
|
andrewm@20
|
1298 #ifdef _MSC_VER
|
andrewm@20
|
1299 _snprintf_s(name, 6, _TRUNCATE, "%s%d", kNoteNames[noteNumber % 12], (noteNumber / 12) - 1);
|
andrewm@20
|
1300 #else
|
andrewm@0
|
1301 snprintf(name, 6, "%s%d", kNoteNames[noteNumber % 12], (noteNumber / 12) - 1);
|
andrewm@20
|
1302 #endif
|
andrewm@0
|
1303
|
andrewm@0
|
1304 return name;
|
andrewm@0
|
1305 }
|
andrewm@0
|
1306
|
andrewm@0
|
1307 // Get the number of a MIDI note given its name
|
andrewm@0
|
1308 int MainApplicationController::midiNoteNumberForName(std::string const& name) {
|
andrewm@0
|
1309 // Any valid note name will have at least two characters
|
andrewm@0
|
1310 if(name.length() < 2)
|
andrewm@0
|
1311 return -1;
|
andrewm@0
|
1312
|
andrewm@0
|
1313 // Find the pitch class first, then the octave
|
andrewm@0
|
1314 int pitchClass = -1;
|
andrewm@0
|
1315 int startIndex = 1;
|
andrewm@0
|
1316 if(!name.compare(0, 2, "C#") ||
|
andrewm@0
|
1317 !name.compare(0, 2, "c#") ||
|
andrewm@0
|
1318 !name.compare(0, 2, "Db") ||
|
andrewm@0
|
1319 !name.compare(0, 2, "db")) {
|
andrewm@0
|
1320 pitchClass = 1;
|
andrewm@0
|
1321 startIndex = 2;
|
andrewm@0
|
1322 }
|
andrewm@0
|
1323 else if(!name.compare(0, 2, "D#") ||
|
andrewm@0
|
1324 !name.compare(0, 2, "d#") ||
|
andrewm@0
|
1325 !name.compare(0, 2, "Eb") ||
|
andrewm@0
|
1326 !name.compare(0, 2, "eb")) {
|
andrewm@0
|
1327 pitchClass = 3;
|
andrewm@0
|
1328 startIndex = 2;
|
andrewm@0
|
1329 }
|
andrewm@0
|
1330 else if(!name.compare(0, 2, "F#") ||
|
andrewm@0
|
1331 !name.compare(0, 2, "f#") ||
|
andrewm@0
|
1332 !name.compare(0, 2, "Gb") ||
|
andrewm@0
|
1333 !name.compare(0, 2, "gb")){
|
andrewm@0
|
1334 pitchClass = 6;
|
andrewm@0
|
1335 startIndex = 2;
|
andrewm@0
|
1336 }
|
andrewm@0
|
1337 else if(!name.compare(0, 2, "G#") ||
|
andrewm@0
|
1338 !name.compare(0, 2, "g#") ||
|
andrewm@0
|
1339 !name.compare(0, 2, "Ab") ||
|
andrewm@0
|
1340 !name.compare(0, 2, "ab")){
|
andrewm@0
|
1341 pitchClass = 8;
|
andrewm@0
|
1342 startIndex = 2;
|
andrewm@0
|
1343 }
|
andrewm@0
|
1344 else if(!name.compare(0, 2, "A#") ||
|
andrewm@0
|
1345 !name.compare(0, 2, "a#") ||
|
andrewm@0
|
1346 !name.compare(0, 2, "Bb") ||
|
andrewm@0
|
1347 !name.compare(0, 2, "bb")){
|
andrewm@0
|
1348 pitchClass = 10;
|
andrewm@0
|
1349 startIndex = 2;
|
andrewm@0
|
1350 }
|
andrewm@0
|
1351 else if(!name.compare(0, 1, "C") ||
|
andrewm@0
|
1352 !name.compare(0, 1, "c"))
|
andrewm@0
|
1353 pitchClass = 0;
|
andrewm@0
|
1354 else if(!name.compare(0, 1, "D") ||
|
andrewm@0
|
1355 !name.compare(0, 1, "d"))
|
andrewm@0
|
1356 pitchClass = 2;
|
andrewm@0
|
1357 else if(!name.compare(0, 1, "E") ||
|
andrewm@0
|
1358 !name.compare(0, 1, "e"))
|
andrewm@0
|
1359 pitchClass = 4;
|
andrewm@0
|
1360 else if(!name.compare(0, 1, "F") ||
|
andrewm@0
|
1361 !name.compare(0, 1, "f"))
|
andrewm@0
|
1362 pitchClass = 5;
|
andrewm@0
|
1363 else if(!name.compare(0, 1, "G") ||
|
andrewm@0
|
1364 !name.compare(0, 1, "g"))
|
andrewm@0
|
1365 pitchClass = 7;
|
andrewm@0
|
1366 else if(!name.compare(0, 1, "A") ||
|
andrewm@0
|
1367 !name.compare(0, 1, "a"))
|
andrewm@0
|
1368 pitchClass = 9;
|
andrewm@0
|
1369 else if(!name.compare(0, 1, "B") ||
|
andrewm@0
|
1370 !name.compare(0, 1, "b"))
|
andrewm@0
|
1371 pitchClass = 11;
|
andrewm@0
|
1372
|
andrewm@0
|
1373 if(pitchClass < 0) // No valid note found
|
andrewm@0
|
1374 return -1;
|
andrewm@0
|
1375
|
andrewm@0
|
1376 int octave = atoi(name.substr(startIndex).c_str());
|
andrewm@0
|
1377 int noteNumber = (octave + 1) * 12 + pitchClass;
|
andrewm@0
|
1378
|
andrewm@0
|
1379 if(noteNumber < 0 || noteNumber > 127)
|
andrewm@0
|
1380 return -1;
|
andrewm@0
|
1381 return noteNumber;
|
andrewm@49
|
1382 }
|
andrewm@49
|
1383
|
andrewm@49
|
1384
|
andrewm@49
|
1385 // ***** External OSC Control *****
|
andrewm@49
|
1386
|
andrewm@49
|
1387 bool MainApplicationOSCController::oscHandlerMethod(const char *path, const char *types, int numValues, lo_arg **values, void *data) {
|
andrewm@49
|
1388 if(!strncmp(path, "/control", 8)) {
|
andrewm@49
|
1389 // OSC messages that start with /touchkeys/control are used to control the operation of the
|
andrewm@49
|
1390 // software and mappings
|
andrewm@49
|
1391
|
andrewm@49
|
1392 // First check if the message belongs to one of the segments
|
andrewm@49
|
1393 if(!strncmp(path, "/control/segment", 16) && strlen(path) > 16) {
|
andrewm@49
|
1394 // Pick out which segment based on the following number: e.g. /control/segment0/...
|
andrewm@49
|
1395
|
andrewm@49
|
1396 std::string subpath(&path[16]);
|
andrewm@49
|
1397 int separatorLoc = subpath.find_first_of('/');
|
andrewm@49
|
1398 if(separatorLoc == std::string::npos || separatorLoc == subpath.length() - 1) {
|
andrewm@49
|
1399 // Malformed input (no slash or it's the last character): ignore
|
andrewm@49
|
1400 return false;
|
andrewm@49
|
1401 }
|
andrewm@49
|
1402 std::stringstream segmentNumberSStream(subpath.substr(0, separatorLoc));
|
andrewm@49
|
1403
|
andrewm@49
|
1404 int segmentNumber = 0;
|
andrewm@49
|
1405 segmentNumberSStream >> segmentNumber;
|
andrewm@49
|
1406
|
andrewm@49
|
1407 if(segmentNumber < 0) // Unknown segment number
|
andrewm@49
|
1408 return false;
|
andrewm@49
|
1409
|
andrewm@49
|
1410 // Pass this message onto the corresponding segment in MidiInputController
|
andrewm@49
|
1411 // If the segment doesn't exist, it will return false. All further handling is
|
andrewm@49
|
1412 // done within MidiInputController with its corresponding mutex locked so
|
andrewm@49
|
1413 // the segments can't change while this message is processed.
|
andrewm@49
|
1414
|
andrewm@49
|
1415 subpath = subpath.substr(separatorLoc); // Start at the '/'
|
andrewm@49
|
1416
|
andrewm@49
|
1417 if(subpath == "/set-midi-out") {
|
andrewm@49
|
1418 // Special case for setting the MIDI output, which is done in the main controller
|
andrewm@49
|
1419 // rather than in the segment itself
|
andrewm@49
|
1420
|
andrewm@49
|
1421 if(numValues >= 1) {
|
andrewm@49
|
1422 if(types[0] == 'i') {
|
andrewm@49
|
1423 MidiKeyboardSegment* segment = controller_.midiInputController_.segment(segmentNumber);
|
andrewm@49
|
1424 if(segment == 0)
|
andrewm@49
|
1425 oscControlTransmitResult(1); // Failure response
|
andrewm@49
|
1426 else {
|
andrewm@49
|
1427 if(values[0]->i < 0) {
|
andrewm@49
|
1428 // Negative value means disable
|
andrewm@49
|
1429 controller_.disableMIDIOutputPort(segment->outputPort());
|
andrewm@49
|
1430 }
|
andrewm@49
|
1431 else {
|
andrewm@49
|
1432 controller_.enableMIDIOutputPort(segment->outputPort(), values[0]->i);
|
andrewm@49
|
1433 }
|
andrewm@49
|
1434 oscControlTransmitResult(0);
|
andrewm@49
|
1435 }
|
andrewm@49
|
1436 }
|
andrewm@49
|
1437 #ifndef JUCE_WINDOWS
|
andrewm@49
|
1438 else if(types[0] == 's') {
|
andrewm@49
|
1439 MidiKeyboardSegment* segment = controller_.midiInputController_.segment(segmentNumber);
|
andrewm@49
|
1440 if(segment == 0)
|
andrewm@49
|
1441 oscControlTransmitResult(1); // Failure response
|
andrewm@49
|
1442 else {
|
andrewm@49
|
1443 if(!strcmp(&values[0]->s, "virtual")) {
|
andrewm@49
|
1444 char st[20];
|
andrewm@49
|
1445 snprintf(st, 20, "TouchKeys %d", segment->outputPort());
|
andrewm@49
|
1446 controller_.enableMIDIOutputVirtualPort(segment->outputPort(), st);
|
andrewm@49
|
1447 oscControlTransmitResult(0);
|
andrewm@49
|
1448 }
|
andrewm@49
|
1449 }
|
andrewm@49
|
1450 }
|
andrewm@49
|
1451 #endif
|
andrewm@49
|
1452 }
|
andrewm@49
|
1453 }
|
andrewm@49
|
1454 else {
|
andrewm@49
|
1455 // All other segment messages are handled within MidiKeyboardSegment
|
andrewm@49
|
1456
|
andrewm@49
|
1457 OscMessage* response = controller_.midiInputController_.oscControlMessageForSegment(segmentNumber, subpath.c_str(), types, numValues, values, data);
|
andrewm@49
|
1458 if(response != 0) {
|
andrewm@49
|
1459 // Add the right prefix to the response. If it is a simple result status,
|
andrewm@49
|
1460 // then give it the generic prefix. Otherwise add the zone beforehand
|
andrewm@49
|
1461 if(!strcmp(response->path(), "/result"))
|
andrewm@49
|
1462 response->prependPath("/touchkeys/control");
|
andrewm@49
|
1463 else {
|
andrewm@49
|
1464 char prefix[28];
|
andrewm@49
|
1465 #ifdef _MSC_VER
|
andrewm@49
|
1466 _snprintf_s(prefix, 28, _TRUNCATE, "/touchkeys/control/segment%d", segmentNumber);
|
andrewm@49
|
1467 #else
|
andrewm@49
|
1468 snprintf(prefix, 28, "/touchkeys/control/segment%d", segmentNumber);
|
andrewm@49
|
1469 #endif
|
andrewm@49
|
1470 response->prependPath(prefix);
|
andrewm@49
|
1471 }
|
andrewm@49
|
1472
|
andrewm@49
|
1473 // Send the message and free it
|
andrewm@49
|
1474 controller_.oscTransmitter_.sendMessage(response->path(), response->type(), response->message());
|
andrewm@49
|
1475 delete response;
|
andrewm@49
|
1476 }
|
andrewm@49
|
1477 }
|
andrewm@49
|
1478 }
|
andrewm@49
|
1479 else if(!strcmp(path, "/control/preset-load")) {
|
andrewm@49
|
1480 // Load preset from file
|
andrewm@49
|
1481 // Argument 0 is the path to the file
|
andrewm@49
|
1482
|
andrewm@49
|
1483 if(numValues > 0) {
|
andrewm@49
|
1484 if(types[0] == 's') {
|
andrewm@49
|
1485 bool result = controller_.loadPresetFromFile(&values[0]->s);
|
andrewm@49
|
1486
|
andrewm@49
|
1487 // Send back a message on success/failure
|
andrewm@49
|
1488 oscControlTransmitResult(result == true ? 0 : 1);
|
andrewm@49
|
1489 return true;
|
andrewm@49
|
1490 }
|
andrewm@49
|
1491 else if(types[0] == 'i') {
|
andrewm@49
|
1492 // TODO: take a second form of the message which has a numerical
|
andrewm@49
|
1493 // input for selecting presets
|
andrewm@49
|
1494 }
|
andrewm@49
|
1495 }
|
andrewm@49
|
1496 return false;
|
andrewm@49
|
1497 }
|
andrewm@49
|
1498 else if(!strcmp(path, "/control/preset-save")) {
|
andrewm@49
|
1499 // Save preset to file
|
andrewm@49
|
1500
|
andrewm@49
|
1501 if(numValues > 0) {
|
andrewm@49
|
1502 if(types[0] == 's') {
|
andrewm@49
|
1503 bool result = controller_.savePresetToFile(&values[0]->s);
|
andrewm@49
|
1504
|
andrewm@49
|
1505 // Send back a message on success/failure
|
andrewm@49
|
1506 oscControlTransmitResult(result == true ? 0 : 1);
|
andrewm@49
|
1507 return true;
|
andrewm@49
|
1508 }
|
andrewm@49
|
1509 else if(types[0] == 'i') {
|
andrewm@49
|
1510 // TODO: take a second form of the message which has a numerical
|
andrewm@49
|
1511 // input for selecting presets
|
andrewm@49
|
1512 }
|
andrewm@49
|
1513 }
|
andrewm@49
|
1514 return false;
|
andrewm@49
|
1515 }
|
andrewm@49
|
1516 else if(!strcmp(path, "/control/preset-clear")) {
|
andrewm@49
|
1517 // Clear everything in preset
|
andrewm@49
|
1518 controller_.clearPreset();
|
andrewm@49
|
1519 oscControlTransmitResult(0);
|
andrewm@49
|
1520 return true;
|
andrewm@49
|
1521 }
|
andrewm@49
|
1522 else if(!strcmp(path, "/control/tk-list-devices")) {
|
andrewm@49
|
1523 // Return a list of TouchKeys devices
|
andrewm@49
|
1524
|
andrewm@49
|
1525 OscMessage *response = OscTransmitter::createMessage("/touchkeys/control/tk-list-devices/result", "i",
|
andrewm@49
|
1526 controller_.availableTouchkeyDevices().size(), LO_ARGS_END);
|
andrewm@49
|
1527
|
andrewm@49
|
1528 vector<std::string> devices = controller_.availableTouchkeyDevices();
|
andrewm@49
|
1529 vector<string>::iterator it;
|
andrewm@49
|
1530 for(it = devices.begin(); it != devices.end(); ++it) {
|
andrewm@49
|
1531 lo_message_add_string(response->message(), it->c_str());
|
andrewm@49
|
1532 }
|
andrewm@49
|
1533
|
andrewm@49
|
1534 controller_.oscTransmitter_.sendMessage(response->path(), response->type(), response->message());
|
andrewm@49
|
1535 delete response;
|
andrewm@49
|
1536
|
andrewm@49
|
1537 return true;
|
andrewm@49
|
1538 }
|
andrewm@49
|
1539 else if(!strcmp(path, "/control/tk-start")) {
|
andrewm@49
|
1540 // Start the TouchKeys device with the given path
|
andrewm@49
|
1541 if(numValues > 0) {
|
andrewm@49
|
1542 if(types[0] == 's') {
|
andrewm@49
|
1543 char *device = &values[0]->s;
|
andrewm@49
|
1544 bool result = controller_.touchkeyDeviceStartupSequence(device);
|
andrewm@49
|
1545
|
andrewm@49
|
1546 oscControlTransmitResult(result == true ? 0 : 1);
|
andrewm@49
|
1547 return true;
|
andrewm@49
|
1548 }
|
andrewm@49
|
1549 }
|
andrewm@49
|
1550 }
|
andrewm@49
|
1551 else if(!strcmp(path, "/control/tk-stop")) {
|
andrewm@49
|
1552 // Stop TouchKeys
|
andrewm@49
|
1553 if(controller_.touchkeyDeviceIsOpen()) {
|
andrewm@49
|
1554 controller_.closeTouchkeyDevice();
|
andrewm@49
|
1555 oscControlTransmitResult(0);
|
andrewm@49
|
1556 }
|
andrewm@49
|
1557 else {
|
andrewm@49
|
1558 // Not running, can't close
|
andrewm@49
|
1559 oscControlTransmitResult(1);
|
andrewm@49
|
1560 }
|
andrewm@49
|
1561 return true;
|
andrewm@49
|
1562 }
|
andrewm@49
|
1563 else if(!strcmp(path, "/control/tk-set-lowest-midi-note")) {
|
andrewm@49
|
1564 // Set TouchKeys octave such that the lowest key is at the
|
andrewm@49
|
1565 // given note. Only 'C' notes are valid.
|
andrewm@49
|
1566
|
andrewm@49
|
1567 if(numValues > 0) {
|
andrewm@49
|
1568 if(types[0] == 'i') {
|
andrewm@49
|
1569 int note = values[0]->i;
|
andrewm@49
|
1570
|
andrewm@49
|
1571 if(note % 12 == 0 && note >= 12 && note < 127) {
|
andrewm@49
|
1572 controller_.touchkeyDeviceSetLowestMidiNote(note);
|
andrewm@49
|
1573 oscControlTransmitResult(0);
|
andrewm@49
|
1574 }
|
andrewm@49
|
1575 else {
|
andrewm@49
|
1576 // Invalid note
|
andrewm@49
|
1577 oscControlTransmitResult(1);
|
andrewm@49
|
1578 }
|
andrewm@49
|
1579 return true;
|
andrewm@49
|
1580 }
|
andrewm@49
|
1581 }
|
andrewm@49
|
1582 }
|
andrewm@49
|
1583 else if(!strcmp(path, "/control/tk-autodetect")) {
|
andrewm@49
|
1584 // Autodetect lowest TouchKeys octave
|
andrewm@49
|
1585 controller_.touchkeyDeviceAutodetectLowestMidiNote();
|
andrewm@49
|
1586 oscControlTransmitResult(0);
|
andrewm@49
|
1587 return true;
|
andrewm@49
|
1588 }
|
andrewm@49
|
1589 else if(!strcmp(path, "/control/tk-autodetect-stop")) {
|
andrewm@49
|
1590 // Stop autodetecting TouchKeys octave
|
andrewm@49
|
1591 controller_.touchkeyDeviceStopAutodetecting();
|
andrewm@49
|
1592 oscControlTransmitResult(0);
|
andrewm@49
|
1593 return true;
|
andrewm@49
|
1594 }
|
andrewm@49
|
1595 else if(!strcmp(path, "/control/list-midi-in")) {
|
andrewm@49
|
1596 // List available MIDI input devices
|
andrewm@49
|
1597 std::vector<std::pair<int, std::string> > midiInputs = controller_.availableMIDIInputDevices();
|
andrewm@49
|
1598
|
andrewm@49
|
1599 OscMessage *response = OscTransmitter::createMessage("/list-midi-in/result", "i", midiInputs.size(), LO_ARGS_END);
|
andrewm@49
|
1600
|
andrewm@49
|
1601 std::vector<std::pair<int, std::string> >::iterator it;
|
andrewm@49
|
1602 for(it = midiInputs.begin(); it != midiInputs.end(); ++it) {
|
andrewm@49
|
1603 lo_message_add_int32(response->message(), it->first);
|
andrewm@49
|
1604 lo_message_add_string(response->message(), it->second.c_str());
|
andrewm@49
|
1605 }
|
andrewm@49
|
1606
|
andrewm@49
|
1607 controller_.oscTransmitter_.sendMessage(response->path(), response->type(), response->message());
|
andrewm@49
|
1608 delete response;
|
andrewm@49
|
1609
|
andrewm@49
|
1610 return true;
|
andrewm@49
|
1611 }
|
andrewm@49
|
1612 else if(!strcmp(path, "/control/list-midi-out")) {
|
andrewm@49
|
1613 // List available MIDI output devices
|
andrewm@49
|
1614 std::vector<std::pair<int, std::string> > midiOutputs = controller_.availableMIDIOutputDevices();
|
andrewm@49
|
1615
|
andrewm@49
|
1616 OscMessage *response = OscTransmitter::createMessage("/list-midi-out/result", "i", midiOutputs.size(), LO_ARGS_END);
|
andrewm@49
|
1617
|
andrewm@49
|
1618 std::vector<std::pair<int, std::string> >::iterator it;
|
andrewm@49
|
1619 for(it = midiOutputs.begin(); it != midiOutputs.end(); ++it) {
|
andrewm@49
|
1620 lo_message_add_int32(response->message(), it->first);
|
andrewm@49
|
1621 lo_message_add_string(response->message(), it->second.c_str());
|
andrewm@49
|
1622 }
|
andrewm@49
|
1623
|
andrewm@49
|
1624 controller_.oscTransmitter_.sendMessage(response->path(), response->type(), response->message());
|
andrewm@49
|
1625 delete response;
|
andrewm@49
|
1626
|
andrewm@49
|
1627 return true;
|
andrewm@49
|
1628 }
|
andrewm@49
|
1629 else if(!strcmp(path, "/control/set-midi-in-keyboard")) {
|
andrewm@49
|
1630 // Set MIDI input device for keyboard
|
andrewm@49
|
1631 if(numValues > 0) {
|
andrewm@49
|
1632 if(types[0] == 'i') {
|
andrewm@49
|
1633 if(controller_.midiTouchkeysStandaloneModeIsEnabled())
|
andrewm@49
|
1634 controller_.midiTouchkeysStandaloneModeDisable();
|
andrewm@49
|
1635 if(values[0]->i < 0) {
|
andrewm@49
|
1636 // Negative means disable
|
andrewm@49
|
1637 controller_.disablePrimaryMIDIInputPort();
|
andrewm@49
|
1638 }
|
andrewm@49
|
1639 else {
|
andrewm@49
|
1640 controller_.enableMIDIInputPort(values[0]->i, true);
|
andrewm@49
|
1641 }
|
andrewm@49
|
1642
|
andrewm@49
|
1643 oscControlTransmitResult(0);
|
andrewm@49
|
1644 return true;
|
andrewm@49
|
1645 }
|
andrewm@49
|
1646 else if(types[0] == 's') {
|
andrewm@49
|
1647 if(!strncmp(&values[0]->s, "stand", 5)) {
|
andrewm@49
|
1648 // Enable TouchKeys standalone mode in place of MIDI input
|
andrewm@49
|
1649 controller_.disablePrimaryMIDIInputPort();
|
andrewm@49
|
1650 controller_.midiTouchkeysStandaloneModeEnable();
|
andrewm@49
|
1651
|
andrewm@49
|
1652 oscControlTransmitResult(0);
|
andrewm@49
|
1653 return true;
|
andrewm@49
|
1654 }
|
andrewm@49
|
1655 }
|
andrewm@49
|
1656 }
|
andrewm@49
|
1657 }
|
andrewm@49
|
1658 else if(!strcmp(path, "/control/set-midi-in-aux")) {
|
andrewm@49
|
1659 // Set MIDI auxiliary input device
|
andrewm@49
|
1660 if(numValues > 0) {
|
andrewm@49
|
1661 if(types[0] == 'i') {
|
andrewm@49
|
1662 controller_.disableAllMIDIInputPorts(true);
|
andrewm@49
|
1663 if(values[0]->i >= 0) {
|
andrewm@49
|
1664 // Negative values mean leave the port disabled
|
andrewm@49
|
1665 controller_.enableMIDIInputPort(values[0]->i, false);
|
andrewm@49
|
1666 }
|
andrewm@49
|
1667
|
andrewm@49
|
1668 oscControlTransmitResult(0);
|
andrewm@49
|
1669 return true;
|
andrewm@49
|
1670 }
|
andrewm@49
|
1671 }
|
andrewm@49
|
1672
|
andrewm@49
|
1673 }
|
andrewm@49
|
1674 else if(!strcmp(path, "/control/add-segment")) {
|
andrewm@49
|
1675 // Add a new keyboard segment
|
andrewm@49
|
1676 if(controller_.midiSegmentsCount() >= 8) {
|
andrewm@49
|
1677 // Max of 8 segments possible
|
andrewm@49
|
1678 oscControlTransmitResult(1);
|
andrewm@49
|
1679 }
|
andrewm@49
|
1680 else {
|
andrewm@49
|
1681 controller_.midiSegmentAdd();
|
andrewm@49
|
1682 oscControlTransmitResult(0);
|
andrewm@49
|
1683 }
|
andrewm@49
|
1684 return true;
|
andrewm@49
|
1685 }
|
andrewm@49
|
1686 else if(!strcmp(path, "/control/delete-segment")) {
|
andrewm@49
|
1687 // Remove a keyboard segment by number
|
andrewm@49
|
1688 if(numValues > 0) {
|
andrewm@49
|
1689 if(types[0] == 'i') {
|
andrewm@49
|
1690 int segmentNumber = values[0]->i;
|
andrewm@49
|
1691
|
andrewm@49
|
1692 bool result = controller_.midiInputController_.removeSegment(segmentNumber);
|
andrewm@49
|
1693 oscControlTransmitResult(result == true ? 0 : 1);
|
andrewm@49
|
1694 return true;
|
andrewm@49
|
1695 }
|
andrewm@49
|
1696 }
|
andrewm@49
|
1697 }
|
andrewm@49
|
1698 }
|
andrewm@49
|
1699
|
andrewm@49
|
1700 return false;
|
andrewm@49
|
1701 }
|
andrewm@49
|
1702
|
andrewm@49
|
1703 // Send back an OSC message to indicate the result of a control command
|
andrewm@49
|
1704 void MainApplicationOSCController::oscControlTransmitResult(int result) {
|
andrewm@49
|
1705 controller_.oscTransmitter_.sendMessage("/touchkeys/control/result", "i", result, LO_ARGS_END);
|
andrewm@55
|
1706 }
|