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 Main.cpp: main startup routines, connecting to Juce library
|
andrewm@0
|
21 */
|
andrewm@0
|
22
|
andrewm@20
|
23 #include "MainApplicationController.h"
|
andrewm@0
|
24 #include "../JuceLibraryCode/JuceHeader.h"
|
andrewm@0
|
25
|
andrewm@0
|
26 #ifndef TOUCHKEYS_NO_GUI
|
andrewm@0
|
27 #include "GUI/MainWindow.h"
|
andrewm@0
|
28 #include "GUI/GraphicsDisplayWindow.h"
|
andrewm@41
|
29 #include "GUI/PreferencesWindow.h"
|
andrewm@41
|
30 #include "GUI/PreferencesComponent.h"
|
andrewm@0
|
31 #include "Display/OpenGLJuceCanvas.h"
|
andrewm@0
|
32
|
andrewm@0
|
33 //==============================================================================
|
andrewm@0
|
34 class TouchKeysApplication : public JUCEApplication
|
andrewm@0
|
35 {
|
andrewm@0
|
36 public:
|
andrewm@0
|
37 //==============================================================================
|
andrewm@0
|
38 TouchKeysApplication() {}
|
andrewm@0
|
39
|
andrewm@0
|
40 const String getApplicationName() { return ProjectInfo::projectName; }
|
andrewm@0
|
41 const String getApplicationVersion() { return ProjectInfo::versionString; }
|
andrewm@0
|
42 bool moreThanOneInstanceAllowed() { return true; }
|
andrewm@0
|
43
|
andrewm@0
|
44 //==============================================================================
|
andrewm@0
|
45 void initialise (const String& commandLine) {
|
andrewm@0
|
46 // This method is where you should put your application's initialisation code..
|
andrewm@0
|
47
|
andrewm@0
|
48 mainWindow_ = new MainWindow(controller_);
|
andrewm@17
|
49 keyboardDisplayWindow_ = new GraphicsDisplayWindow("TouchKeys Display", controller_.keyboardDisplay());
|
andrewm@41
|
50 preferencesWindow_ = new PreferencesWindow(controller_);
|
andrewm@0
|
51
|
andrewm@0
|
52 controller_.setKeyboardDisplayWindow(keyboardDisplayWindow_);
|
andrewm@41
|
53 controller_.setPreferencesWindow(preferencesWindow_);
|
andrewm@41
|
54 controller_.initialise();
|
andrewm@0
|
55 }
|
andrewm@0
|
56
|
andrewm@0
|
57 void shutdown() {
|
andrewm@0
|
58 // Add your application's shutdown code here..
|
andrewm@28
|
59 if(controller_.touchkeyDeviceIsRunning())
|
andrewm@28
|
60 controller_.stopTouchkeyDevice();
|
andrewm@28
|
61
|
andrewm@0
|
62 mainWindow_ = nullptr; // (deletes our window)
|
andrewm@0
|
63
|
andrewm@0
|
64 controller_.setKeyboardDisplayWindow(0); // Delete display window and disconnect from controller
|
andrewm@41
|
65 controller_.setPreferencesWindow(0);
|
andrewm@0
|
66 keyboardDisplayWindow_ = nullptr;
|
andrewm@41
|
67 preferencesWindow_ = nullptr;
|
andrewm@0
|
68 }
|
andrewm@0
|
69
|
andrewm@0
|
70 //==============================================================================
|
andrewm@0
|
71 void systemRequestedQuit() {
|
andrewm@0
|
72 // This is called when the app is being asked to quit: you can ignore this
|
andrewm@0
|
73 // request and let the app carry on running, or call quit() to allow the app to close.
|
andrewm@0
|
74 quit();
|
andrewm@0
|
75 }
|
andrewm@0
|
76
|
andrewm@0
|
77 void anotherInstanceStarted (const String& commandLine) {
|
andrewm@0
|
78 // When another instance of the app is launched while this one is running,
|
andrewm@0
|
79 // this method is invoked, and the commandLine parameter tells you what
|
andrewm@0
|
80 // the other instance's command-line arguments were.
|
andrewm@0
|
81 }
|
andrewm@0
|
82
|
andrewm@0
|
83 private:
|
andrewm@0
|
84 ScopedPointer<MainWindow> mainWindow_;
|
andrewm@0
|
85 ScopedPointer<GraphicsDisplayWindow> keyboardDisplayWindow_;
|
andrewm@41
|
86 ScopedPointer<PreferencesWindow> preferencesWindow_;
|
andrewm@0
|
87 MainApplicationController controller_;
|
andrewm@0
|
88 };
|
andrewm@0
|
89
|
andrewm@0
|
90 //==============================================================================
|
andrewm@0
|
91 // This macro generates the main() routine that launches the app.
|
andrewm@0
|
92 START_JUCE_APPLICATION (TouchKeysApplication)
|
andrewm@0
|
93
|
andrewm@0
|
94 #else // TOUCHKEYS_NO_GUI
|
andrewm@0
|
95
|
andrewm@0
|
96 #include <getopt.h>
|
andrewm@0
|
97 #include <libgen.h>
|
andrewm@0
|
98 #include <signal.h>
|
andrewm@0
|
99 #include <stdlib.h>
|
andrewm@0
|
100 #include <stdio.h>
|
andrewm@0
|
101
|
andrewm@0
|
102 bool programShouldStop_ = false;
|
andrewm@0
|
103
|
andrewm@0
|
104 static struct option long_options[] = {
|
andrewm@0
|
105 {"help", no_argument, NULL, 'h'},
|
andrewm@0
|
106 {"list", no_argument, NULL, 'l'},
|
andrewm@0
|
107 {"touchkeys", required_argument, NULL, 't'},
|
andrewm@0
|
108 {"midi-input", required_argument, NULL, 'i'},
|
andrewm@0
|
109 {"midi-output", required_argument, NULL, 'o'},
|
andrewm@50
|
110 {"virtual-midi-output", no_argument, NULL, 'V'},
|
andrewm@50
|
111 {"osc-input-port", required_argument, NULL, 'P'},
|
andrewm@0
|
112 {0,0,0,0}
|
andrewm@0
|
113 };
|
andrewm@0
|
114
|
andrewm@0
|
115 void sigint_handler(int s){
|
andrewm@0
|
116 programShouldStop_ = true;
|
andrewm@0
|
117 }
|
andrewm@0
|
118
|
andrewm@0
|
119 void usage(const char * processName) // Print usage information and exit
|
andrewm@0
|
120 {
|
andrewm@0
|
121 cerr << "Usage: " << processName << " [-h] [-l] [-t touchkeys] [-i MIDI-in] [-o MIDI-out]\n";
|
andrewm@0
|
122 cerr << " -h: Print this menu\n";
|
andrewm@0
|
123 cerr << " -l: List available TouchKeys and MIDI devices\n";
|
andrewm@50
|
124 cerr << " -t: Specify TouchKeys device path and autostart\n";
|
andrewm@0
|
125 cerr << " -i: Specify MIDI input device\n";
|
andrewm@0
|
126 cerr << " -o: Specify MIDI output device\n";
|
andrewm@50
|
127 cerr << " -V: Open virtual MIDI output\n";
|
andrewm@50
|
128 cerr << " -P: Specify OSC input port (default: " << kDefaultOscReceivePort << ")\n";
|
andrewm@0
|
129 }
|
andrewm@0
|
130
|
andrewm@0
|
131 void list_devices(MainApplicationController& controller)
|
andrewm@0
|
132 {
|
andrewm@0
|
133 std::vector<std::string> touchkeysDevices(controller.availableTouchkeyDevices());
|
andrewm@0
|
134 std::vector<std::pair<int, std::string> > midiInputDevices(controller.availableMIDIInputDevices());
|
andrewm@0
|
135 std::vector<std::pair<int, std::string> > midiOutputDevices(controller.availableMIDIOutputDevices());
|
andrewm@0
|
136
|
andrewm@0
|
137 cerr << "TouchKeys devices: \n";
|
andrewm@0
|
138 if(touchkeysDevices.empty())
|
andrewm@0
|
139 cerr << " [none found]\n";
|
andrewm@0
|
140 else {
|
andrewm@0
|
141 for(std::vector<std::string>::iterator it = touchkeysDevices.begin(); it != touchkeysDevices.end(); ++it) {
|
andrewm@0
|
142 cerr << " /dev/" << *it << "\n";
|
andrewm@0
|
143 }
|
andrewm@0
|
144 }
|
andrewm@0
|
145
|
andrewm@0
|
146 cerr << "\nMIDI input devices: \n";
|
andrewm@0
|
147 if(midiInputDevices.empty())
|
andrewm@0
|
148 cerr << " [none found]\n";
|
andrewm@0
|
149 else {
|
andrewm@0
|
150 for(std::vector<std::pair<int, std::string> >::iterator it = midiInputDevices.begin();
|
andrewm@0
|
151 it != midiInputDevices.end();
|
andrewm@0
|
152 ++it) {
|
andrewm@0
|
153 cerr << " " << it->first << ": " << it->second << "\n";
|
andrewm@0
|
154 }
|
andrewm@0
|
155 }
|
andrewm@0
|
156
|
andrewm@0
|
157 cerr << "\nMIDI output devices: \n";
|
andrewm@0
|
158 if(midiOutputDevices.empty())
|
andrewm@0
|
159 cerr << " [none found]\n";
|
andrewm@0
|
160 else {
|
andrewm@0
|
161 for(std::vector<std::pair<int, std::string> >::iterator it = midiOutputDevices.begin();
|
andrewm@0
|
162 it != midiOutputDevices.end();
|
andrewm@0
|
163 ++it) {
|
andrewm@0
|
164 cerr << " " << it->first << ": " << it->second << "\n";
|
andrewm@0
|
165 }
|
andrewm@0
|
166 }
|
andrewm@0
|
167 }
|
andrewm@0
|
168
|
andrewm@0
|
169 int main (int argc, char* argv[])
|
andrewm@0
|
170 {
|
andrewm@0
|
171 MainApplicationController controller;
|
andrewm@50
|
172
|
andrewm@0
|
173 int ch, option_index;
|
andrewm@0
|
174 int midiInputNum = 0, midiOutputNum = 0;
|
andrewm@0
|
175 bool useVirtualMidiOutput = false;
|
andrewm@0
|
176 bool shouldStart = true;
|
andrewm@50
|
177 bool autostartTouchkeys = false;
|
andrewm@50
|
178 bool autoopenMidiOut = false, autoopenMidiIn = false;
|
andrewm@50
|
179 int oscInputPort = kDefaultOscReceivePort;
|
andrewm@0
|
180 string touchkeysDevicePath;
|
andrewm@0
|
181
|
andrewm@50
|
182 while((ch = getopt_long(argc, argv, "hli:o:t:VP:", long_options, &option_index)) != -1)
|
andrewm@0
|
183 {
|
andrewm@0
|
184 if(ch == 'l') { // List devices
|
andrewm@0
|
185 list_devices(controller);
|
andrewm@0
|
186 shouldStart = false;
|
andrewm@0
|
187 break;
|
andrewm@0
|
188 }
|
andrewm@0
|
189 else if(ch == 't') { // TouchKeys device
|
andrewm@0
|
190 touchkeysDevicePath = optarg;
|
andrewm@50
|
191 autostartTouchkeys = true;
|
andrewm@0
|
192 }
|
andrewm@0
|
193 else if(ch == 'i') { // MIDI input device
|
andrewm@0
|
194 midiInputNum = atoi(optarg);
|
andrewm@50
|
195 autoopenMidiIn = true;
|
andrewm@0
|
196 }
|
andrewm@0
|
197 else if(ch == 'o') { // MIDI output device
|
andrewm@0
|
198 midiOutputNum = atoi(optarg);
|
andrewm@50
|
199 autoopenMidiOut = true;
|
andrewm@0
|
200 }
|
andrewm@50
|
201 else if(ch == 'V') { // Virtual MIDI output
|
andrewm@0
|
202 useVirtualMidiOutput = true;
|
andrewm@50
|
203 autoopenMidiOut = true;
|
andrewm@50
|
204 }
|
andrewm@50
|
205 else if(ch == 'P') { // OSC port
|
andrewm@50
|
206 oscInputPort = atoi(optarg);
|
andrewm@0
|
207 }
|
andrewm@0
|
208 else {
|
andrewm@0
|
209 usage(basename(argv[0]));
|
andrewm@0
|
210 shouldStart = false;
|
andrewm@0
|
211 break;
|
andrewm@0
|
212 }
|
andrewm@0
|
213 }
|
andrewm@0
|
214
|
andrewm@50
|
215
|
andrewm@0
|
216 if(shouldStart) {
|
andrewm@0
|
217 // Main initialization: open TouchKeys and MIDI devices
|
andrewm@50
|
218 controller.initialise();
|
andrewm@50
|
219
|
andrewm@50
|
220 // Always enable OSC input without GUI, since it is how we control
|
andrewm@50
|
221 // the system
|
andrewm@50
|
222 controller.oscReceiveSetPort(oscInputPort);
|
andrewm@50
|
223 controller.oscReceiveSetEnabled(true);
|
andrewm@50
|
224
|
andrewm@0
|
225 try {
|
andrewm@50
|
226 // Open MIDI devices
|
andrewm@50
|
227 if(autoopenMidiIn) {
|
andrewm@50
|
228 cout << "Opening MIDI input device " << midiInputNum << endl;
|
andrewm@50
|
229 controller.enableMIDIInputPort(midiInputNum, true);
|
andrewm@50
|
230 }
|
andrewm@50
|
231
|
andrewm@50
|
232 // TODO: enable multiple keyboard segments
|
andrewm@50
|
233 if(autoopenMidiOut) {
|
andrewm@50
|
234 if(useVirtualMidiOutput) {
|
andrewm@50
|
235 #ifndef JUCE_WINDOWS
|
andrewm@50
|
236 cout << "Opening virtual MIDI output\n";
|
andrewm@50
|
237 controller.enableMIDIOutputVirtualPort(0, "TouchKeys");
|
andrewm@50
|
238 #endif
|
andrewm@0
|
239 }
|
andrewm@0
|
240 else {
|
andrewm@50
|
241 cout << "Opening MIDI output device " << midiOutputNum << endl;
|
andrewm@50
|
242 controller.enableMIDIOutputPort(0, midiOutputNum);
|
andrewm@0
|
243 }
|
andrewm@0
|
244 }
|
andrewm@0
|
245
|
andrewm@0
|
246 // Start the TouchKeys
|
andrewm@50
|
247 if(autostartTouchkeys) {
|
andrewm@50
|
248 cout << "Starting the TouchKeys on " << touchkeysDevicePath << " ... ";
|
andrewm@50
|
249 if(!controller.touchkeyDeviceStartupSequence(touchkeysDevicePath.c_str())) {
|
andrewm@50
|
250 cout << "failed: " << controller.touchkeyDeviceErrorMessage() << endl;
|
andrewm@50
|
251 throw new exception;
|
andrewm@50
|
252 }
|
andrewm@50
|
253 else
|
andrewm@50
|
254 cout << "succeeded!\n";
|
andrewm@0
|
255 }
|
andrewm@0
|
256
|
andrewm@0
|
257 // Set up interrupt catching so we can stop with Ctrl-C
|
andrewm@50
|
258 struct sigaction sigIntHandler;
|
andrewm@0
|
259
|
andrewm@0
|
260 sigIntHandler.sa_handler = sigint_handler;
|
andrewm@0
|
261 sigemptyset(&sigIntHandler.sa_mask);
|
andrewm@0
|
262 sigIntHandler.sa_flags = 0;
|
andrewm@0
|
263 sigaction(SIGINT, &sigIntHandler, NULL);
|
andrewm@0
|
264
|
andrewm@50
|
265 // Wait until interrupt signal is received
|
andrewm@0
|
266 while(!programShouldStop_) {
|
andrewm@0
|
267 Thread::sleep(50);
|
andrewm@50
|
268 }
|
andrewm@0
|
269 }
|
andrewm@0
|
270 catch(...) {
|
andrewm@0
|
271
|
andrewm@0
|
272 }
|
andrewm@50
|
273
|
andrewm@50
|
274 // Stop TouchKeys if still running
|
andrewm@50
|
275 if(controller.touchkeyDeviceIsRunning())
|
andrewm@50
|
276 controller.stopTouchkeyDevice();
|
andrewm@0
|
277 }
|
andrewm@0
|
278
|
andrewm@0
|
279 // Clean up any MessageManager instance that JUCE creates
|
andrewm@0
|
280 DeletedAtShutdown::deleteAll();
|
andrewm@0
|
281 MessageManager::deleteInstance();
|
andrewm@0
|
282 return 0;
|
andrewm@0
|
283 }
|
andrewm@0
|
284
|
andrewm@0
|
285 #endif // TOUCHKEYS_NO_GUI
|