f@0
|
1 #include "app_main.h"
|
f@0
|
2
|
f@0
|
3 #ifdef OS_WIN
|
f@0
|
4 #include <windows.h>
|
f@0
|
5 #include <shlobj.h>
|
f@0
|
6 #include <sys/stat.h>
|
f@0
|
7 #endif
|
f@0
|
8
|
f@0
|
9 HWND gHWND;
|
f@0
|
10
|
f@0
|
11 HINSTANCE gHINST;
|
f@0
|
12 UINT gScrollMessage;
|
f@0
|
13 IPlug* gPluginInstance;
|
f@0
|
14 RtAudio* gDAC = 0;
|
f@0
|
15 RtMidiIn *gMidiIn = 0;
|
f@0
|
16 RtMidiOut *gMidiOut = 0;
|
f@0
|
17
|
f@0
|
18 AppState *gState;
|
f@0
|
19 AppState *gTempState;
|
f@0
|
20 AppState *gActiveState;
|
f@0
|
21
|
f@0
|
22 char *gINIPath = new char[200]; // path of ini file
|
f@0
|
23
|
f@0
|
24 unsigned int gIOVS = 512;
|
f@0
|
25 unsigned int gSigVS = 32;
|
f@0
|
26 unsigned int gBufIndex = 0; // Loops 0 to SigVS
|
f@0
|
27 unsigned int gVecElapsed = 0;
|
f@0
|
28 double gFadeMult = 0.; // Fade multiplier
|
f@0
|
29
|
f@0
|
30 std::vector<unsigned int> gAudioInputDevs;
|
f@0
|
31 std::vector<unsigned int> gAudioOutputDevs;
|
f@0
|
32 std::vector<std::string> gMIDIInputDevNames;
|
f@0
|
33 std::vector<std::string> gMIDIOutputDevNames;
|
f@0
|
34 std::vector<std::string> gAudioIDDevNames;
|
f@0
|
35
|
f@0
|
36 void UpdateINI()
|
f@0
|
37 {
|
f@0
|
38 char buf[100]; // temp buffer for writing integers to profile strings
|
f@0
|
39
|
f@0
|
40 sprintf(buf, "%u", gState->mAudioDriverType);
|
f@0
|
41 WritePrivateProfileString("audio", "driver", buf, gINIPath);
|
f@0
|
42
|
f@0
|
43 WritePrivateProfileString("audio", "indev", gState->mAudioInDev, gINIPath);
|
f@0
|
44 WritePrivateProfileString("audio", "outdev", gState->mAudioOutDev, gINIPath);
|
f@0
|
45
|
f@0
|
46 sprintf(buf, "%u", gState->mAudioInChanL);
|
f@0
|
47 WritePrivateProfileString("audio", "in1", buf, gINIPath);
|
f@0
|
48 sprintf(buf, "%u", gState->mAudioInChanR);
|
f@0
|
49 WritePrivateProfileString("audio", "in2", buf, gINIPath);
|
f@0
|
50 sprintf(buf, "%u", gState->mAudioOutChanL);
|
f@0
|
51 WritePrivateProfileString("audio", "out1", buf, gINIPath);
|
f@0
|
52 sprintf(buf, "%u", gState->mAudioOutChanR);
|
f@0
|
53 WritePrivateProfileString("audio", "out2", buf, gINIPath);
|
f@0
|
54 sprintf(buf, "%u", gState->mAudioInIsMono);
|
f@0
|
55 WritePrivateProfileString("audio", "monoinput", buf, gINIPath);
|
f@0
|
56
|
f@0
|
57 WritePrivateProfileString("audio", "iovs", gState->mAudioIOVS, gINIPath);
|
f@0
|
58 WritePrivateProfileString("audio", "sigvs", gState->mAudioSigVS, gINIPath);
|
f@0
|
59
|
f@0
|
60 WritePrivateProfileString("audio", "sr", gState->mAudioSR, gINIPath);
|
f@0
|
61
|
f@0
|
62 WritePrivateProfileString("midi", "indev", gState->mMidiInDev, gINIPath);
|
f@0
|
63 WritePrivateProfileString("midi", "outdev", gState->mMidiOutDev, gINIPath);
|
f@0
|
64
|
f@0
|
65 sprintf(buf, "%u", gState->mMidiInChan);
|
f@0
|
66 WritePrivateProfileString("midi", "inchan", buf, gINIPath);
|
f@0
|
67 sprintf(buf, "%u", gState->mMidiOutChan);
|
f@0
|
68 WritePrivateProfileString("midi", "outchan", buf, gINIPath);
|
f@0
|
69 }
|
f@0
|
70
|
f@0
|
71 // returns the device name. Core Audio device names are truncated
|
f@0
|
72 std::string GetAudioDeviceName(int idx)
|
f@0
|
73 {
|
f@0
|
74 return gAudioIDDevNames.at(idx);
|
f@0
|
75 }
|
f@0
|
76
|
f@0
|
77 // returns the rtaudio device ID, based on the (truncated) device name
|
f@0
|
78 int GetAudioDeviceID(char* deviceNameToTest)
|
f@0
|
79 {
|
f@0
|
80 TRACE;
|
f@0
|
81
|
f@0
|
82 for(int i = 0; i < gAudioIDDevNames.size(); i++)
|
f@0
|
83 {
|
f@0
|
84 if(!strcmp(deviceNameToTest, gAudioIDDevNames.at(i).c_str() ))
|
f@0
|
85 return i;
|
f@0
|
86 }
|
f@0
|
87
|
f@0
|
88 return -1;
|
f@0
|
89 }
|
f@0
|
90
|
f@0
|
91 unsigned int GetMIDIInPortNumber(const char* nameToTest)
|
f@0
|
92 {
|
f@0
|
93 int start = 1;
|
f@0
|
94
|
f@0
|
95 if(!strcmp(nameToTest, "off")) return 0;
|
f@0
|
96
|
f@0
|
97 #ifdef OS_OSX
|
f@0
|
98 start = 2;
|
f@0
|
99 if(!strcmp(nameToTest, "virtual input")) return 1;
|
f@0
|
100 #endif
|
f@0
|
101
|
f@0
|
102 for (int i = 0; i < gMidiIn->getPortCount(); i++)
|
f@0
|
103 {
|
f@0
|
104 if(!strcmp(nameToTest, gMidiIn->getPortName(i).c_str()))
|
f@0
|
105 return (i + start);
|
f@0
|
106 }
|
f@0
|
107
|
f@0
|
108 return -1;
|
f@0
|
109 }
|
f@0
|
110
|
f@0
|
111 unsigned int GetMIDIOutPortNumber(const char* nameToTest)
|
f@0
|
112 {
|
f@0
|
113 int start = 1;
|
f@0
|
114
|
f@0
|
115 if(!strcmp(nameToTest, "off")) return 0;
|
f@0
|
116
|
f@0
|
117 #ifdef OS_OSX
|
f@0
|
118 start = 2;
|
f@0
|
119 if(!strcmp(nameToTest, "virtual output")) return 1;
|
f@0
|
120 #endif
|
f@0
|
121
|
f@0
|
122 for (int i = 0; i < gMidiOut->getPortCount(); i++)
|
f@0
|
123 {
|
f@0
|
124 if(!strcmp(nameToTest, gMidiOut->getPortName(i).c_str()))
|
f@0
|
125 return (i + start);
|
f@0
|
126 }
|
f@0
|
127
|
f@0
|
128 return -1;
|
f@0
|
129 }
|
f@0
|
130
|
f@0
|
131 // find out which devices have input channels & which have output channels, add their ids to the lists
|
f@0
|
132 void ProbeAudioIO()
|
f@0
|
133 {
|
f@0
|
134 TRACE;
|
f@0
|
135
|
f@0
|
136 RtAudio::DeviceInfo info;
|
f@0
|
137
|
f@0
|
138 gAudioInputDevs.clear();
|
f@0
|
139 gAudioOutputDevs.clear();
|
f@0
|
140 gAudioIDDevNames.clear();
|
f@0
|
141
|
f@0
|
142 unsigned int nDevices = gDAC->getDeviceCount();
|
f@0
|
143
|
f@0
|
144 for (int i=0; i<nDevices; i++)
|
f@0
|
145 {
|
f@0
|
146 info = gDAC->getDeviceInfo(i);
|
f@0
|
147 std::string deviceName = info.name;
|
f@0
|
148
|
f@0
|
149 #ifdef OS_OSX
|
f@0
|
150 size_t colonIdx = deviceName.rfind(": ");
|
f@0
|
151
|
f@0
|
152 if(colonIdx != std::string::npos && deviceName.length() >= 2)
|
f@0
|
153 deviceName = deviceName.substr(colonIdx + 2, deviceName.length() - colonIdx - 2);
|
f@0
|
154
|
f@0
|
155 #endif
|
f@0
|
156
|
f@0
|
157 gAudioIDDevNames.push_back(deviceName);
|
f@0
|
158
|
f@0
|
159 if ( info.probed == false )
|
f@0
|
160 std::cout << deviceName << ": Probe Status = Unsuccessful\n";
|
f@0
|
161 else if ( !strcmp("Generic Low Latency ASIO Driver", deviceName.c_str() ))
|
f@0
|
162 std::cout << deviceName << ": Probe Status = Unsuccessful\n";
|
f@0
|
163 else
|
f@0
|
164 {
|
f@0
|
165 if(info.inputChannels > 0)
|
f@0
|
166 gAudioInputDevs.push_back(i);
|
f@0
|
167
|
f@0
|
168 if(info.outputChannels > 0)
|
f@0
|
169 gAudioOutputDevs.push_back(i);
|
f@0
|
170 }
|
f@0
|
171 }
|
f@0
|
172 }
|
f@0
|
173
|
f@0
|
174 void ProbeMidiIO()
|
f@0
|
175 {
|
f@0
|
176 if ( !gMidiIn || !gMidiOut )
|
f@0
|
177 return;
|
f@0
|
178 else
|
f@0
|
179 {
|
f@0
|
180 int nInputPorts = gMidiIn->getPortCount();
|
f@0
|
181
|
f@0
|
182 gMIDIInputDevNames.push_back("off");
|
f@0
|
183
|
f@0
|
184 #ifndef OS_WIN
|
f@0
|
185 gMIDIInputDevNames.push_back("virtual input");
|
f@0
|
186 #endif
|
f@0
|
187
|
f@0
|
188 for (int i=0; i<nInputPorts; i++ )
|
f@0
|
189 {
|
f@0
|
190 gMIDIInputDevNames.push_back(gMidiIn->getPortName(i));
|
f@0
|
191 }
|
f@0
|
192
|
f@0
|
193 int nOutputPorts = gMidiOut->getPortCount();
|
f@0
|
194
|
f@0
|
195 gMIDIOutputDevNames.push_back("off");
|
f@0
|
196
|
f@0
|
197 #ifndef _WIN32
|
f@0
|
198 gMIDIOutputDevNames.push_back("virtual output");
|
f@0
|
199 #endif
|
f@0
|
200
|
f@0
|
201 for (int i=0; i<nOutputPorts; i++ )
|
f@0
|
202 {
|
f@0
|
203 gMIDIOutputDevNames.push_back(gMidiOut->getPortName(i));
|
f@0
|
204 //This means the virtual output port wont be added as an input
|
f@0
|
205 }
|
f@0
|
206 }
|
f@0
|
207 }
|
f@0
|
208
|
f@0
|
209 bool AudioSettingsInStateAreEqual(AppState* os, AppState* ns)
|
f@0
|
210 {
|
f@0
|
211 if (os->mAudioDriverType != ns->mAudioDriverType) return false;
|
f@0
|
212 if (strcmp(os->mAudioInDev, ns->mAudioInDev)) return false;
|
f@0
|
213 if (strcmp(os->mAudioOutDev, ns->mAudioOutDev)) return false;
|
f@0
|
214 if (strcmp(os->mAudioSR, ns->mAudioSR)) return false;
|
f@0
|
215 if (strcmp(os->mAudioIOVS, ns->mAudioIOVS)) return false;
|
f@0
|
216 if (strcmp(os->mAudioSigVS, ns->mAudioSigVS)) return false;
|
f@0
|
217 if (os->mAudioInChanL != ns->mAudioInChanL) return false;
|
f@0
|
218 if (os->mAudioInChanR != ns->mAudioInChanR) return false;
|
f@0
|
219 if (os->mAudioOutChanL != ns->mAudioOutChanL) return false;
|
f@0
|
220 if (os->mAudioOutChanR != ns->mAudioOutChanR) return false;
|
f@0
|
221 if (os->mAudioInIsMono != ns->mAudioInIsMono) return false;
|
f@0
|
222
|
f@0
|
223 return true;
|
f@0
|
224 }
|
f@0
|
225
|
f@0
|
226 bool MIDISettingsInStateAreEqual(AppState* os, AppState* ns)
|
f@0
|
227 {
|
f@0
|
228 if (strcmp(os->mMidiInDev, ns->mMidiInDev)) return false;
|
f@0
|
229 if (strcmp(os->mMidiOutDev, ns->mMidiOutDev)) return false;
|
f@0
|
230 if (os->mMidiInChan != ns->mMidiInChan) return false;
|
f@0
|
231 if (os->mMidiOutChan != ns->mMidiOutChan) return false;
|
f@0
|
232
|
f@0
|
233 return true;
|
f@0
|
234 }
|
f@0
|
235
|
f@0
|
236 void MIDICallback( double deltatime, std::vector< unsigned char > *message, void *userData )
|
f@0
|
237 {
|
f@0
|
238 if ( message->size() )
|
f@0
|
239 {
|
f@0
|
240 IMidiMsg *myMsg;
|
f@0
|
241
|
f@0
|
242 switch (message->size())
|
f@0
|
243 {
|
f@0
|
244 case 1:
|
f@0
|
245 myMsg = new IMidiMsg(0, message->at(0), 0, 0);
|
f@0
|
246 break;
|
f@0
|
247 case 2:
|
f@0
|
248 myMsg = new IMidiMsg(0, message->at(0), message->at(1), 0);
|
f@0
|
249 break;
|
f@0
|
250 case 3:
|
f@0
|
251 myMsg = new IMidiMsg(0, message->at(0), message->at(1), message->at(2));
|
f@0
|
252 break;
|
f@0
|
253 default:
|
f@0
|
254 DBGMSG("NOT EXPECTING %d midi callback msg len\n", (int) message->size());
|
f@0
|
255 break;
|
f@0
|
256 }
|
f@0
|
257
|
f@0
|
258 IMidiMsg msg(*myMsg);
|
f@0
|
259
|
f@0
|
260 delete myMsg;
|
f@0
|
261
|
f@0
|
262 // filter midi messages based on channel, if gStatus.mMidiInChan != all (0)
|
f@0
|
263 if (gState->mMidiInChan)
|
f@0
|
264 {
|
f@0
|
265 if (gState->mMidiInChan == msg.Channel() + 1 )
|
f@0
|
266 gPluginInstance->ProcessMidiMsg(&msg);
|
f@0
|
267 }
|
f@0
|
268 else
|
f@0
|
269 {
|
f@0
|
270 gPluginInstance->ProcessMidiMsg(&msg);
|
f@0
|
271 }
|
f@0
|
272 }
|
f@0
|
273 }
|
f@0
|
274
|
f@0
|
275 int AudioCallback(void *outputBuffer,
|
f@0
|
276 void *inputBuffer,
|
f@0
|
277 unsigned int nFrames,
|
f@0
|
278 double streamTime,
|
f@0
|
279 RtAudioStreamStatus status,
|
f@0
|
280 void *userData )
|
f@0
|
281 {
|
f@0
|
282 if ( status )
|
f@0
|
283 std::cout << "Stream underflow detected!" << std::endl;
|
f@0
|
284
|
f@0
|
285 double* inputBufferD = (double*)inputBuffer;
|
f@0
|
286 double* outputBufferD = (double*)outputBuffer;
|
f@0
|
287
|
f@0
|
288 int inRightOffset = 0;
|
f@0
|
289
|
f@0
|
290 if(!gState->mAudioInIsMono)
|
f@0
|
291 inRightOffset = nFrames;
|
f@0
|
292
|
f@0
|
293 if (gVecElapsed > N_VECTOR_WAIT) // wait N_VECTOR_WAIT * iovs before processing audio, to avoid clicks
|
f@0
|
294 {
|
f@0
|
295 for (int i=0; i<nFrames; i++)
|
f@0
|
296 {
|
f@0
|
297 gBufIndex %= gSigVS;
|
f@0
|
298
|
f@0
|
299 if (gBufIndex == 0)
|
f@0
|
300 {
|
f@0
|
301 double* inputs[2] = {inputBufferD + i, inputBufferD + inRightOffset + i};
|
f@0
|
302 double* outputs[2] = {outputBufferD + i, outputBufferD + nFrames + i};
|
f@0
|
303
|
f@0
|
304 gPluginInstance->LockMutexAndProcessDoubleReplacing(inputs, outputs, gSigVS);
|
f@0
|
305 }
|
f@0
|
306
|
f@0
|
307 // fade in
|
f@0
|
308 if (gFadeMult < 1.)
|
f@0
|
309 {
|
f@0
|
310 gFadeMult += (1. / nFrames);
|
f@0
|
311 }
|
f@0
|
312
|
f@0
|
313 outputBufferD[i] *= gFadeMult;
|
f@0
|
314 outputBufferD[i + nFrames] *= gFadeMult;
|
f@0
|
315
|
f@0
|
316 outputBufferD[i] *= APP_MULT;
|
f@0
|
317 outputBufferD[i + nFrames] *= APP_MULT;
|
f@0
|
318
|
f@0
|
319 gBufIndex++;
|
f@0
|
320 }
|
f@0
|
321 }
|
f@0
|
322 else
|
f@0
|
323 {
|
f@0
|
324 memset(outputBuffer, 0, nFrames * 2 * sizeof(double));
|
f@0
|
325 }
|
f@0
|
326
|
f@0
|
327 gVecElapsed++;
|
f@0
|
328
|
f@0
|
329 return 0;
|
f@0
|
330 }
|
f@0
|
331
|
f@0
|
332 bool TryToChangeAudioDriverType()
|
f@0
|
333 {
|
f@0
|
334 TRACE;
|
f@0
|
335
|
f@0
|
336 if (gDAC)
|
f@0
|
337 {
|
f@0
|
338 if (gDAC->isStreamOpen())
|
f@0
|
339 {
|
f@0
|
340 gDAC->closeStream();
|
f@0
|
341 }
|
f@0
|
342
|
f@0
|
343 DELETE_NULL(gDAC);
|
f@0
|
344 }
|
f@0
|
345
|
f@0
|
346 #ifdef OS_WIN
|
f@0
|
347 if(gState->mAudioDriverType == DAC_ASIO)
|
f@0
|
348 gDAC = new RtAudio(RtAudio::WINDOWS_ASIO);
|
f@0
|
349 else
|
f@0
|
350 gDAC = new RtAudio(RtAudio::WINDOWS_DS);
|
f@0
|
351 #elif defined OS_OSX
|
f@0
|
352 if(gState->mAudioDriverType == DAC_COREAUDIO)
|
f@0
|
353 gDAC = new RtAudio(RtAudio::MACOSX_CORE);
|
f@0
|
354 //else
|
f@0
|
355 //gDAC = new RtAudio(RtAudio::UNIX_JACK);
|
f@0
|
356 #endif
|
f@0
|
357
|
f@0
|
358 if(gDAC)
|
f@0
|
359 return true;
|
f@0
|
360 else
|
f@0
|
361 return false;
|
f@0
|
362 }
|
f@0
|
363
|
f@0
|
364 bool TryToChangeAudio()
|
f@0
|
365 {
|
f@0
|
366 TRACE;
|
f@0
|
367
|
f@0
|
368 int inputID = -1;
|
f@0
|
369 int outputID = -1;
|
f@0
|
370
|
f@0
|
371 #ifdef OS_WIN
|
f@0
|
372 if(gState->mAudioDriverType == DAC_ASIO)
|
f@0
|
373 inputID = GetAudioDeviceID(gState->mAudioOutDev);
|
f@0
|
374 else
|
f@0
|
375 inputID = GetAudioDeviceID(gState->mAudioInDev);
|
f@0
|
376 #else
|
f@0
|
377 inputID = GetAudioDeviceID(gState->mAudioInDev);
|
f@0
|
378 #endif
|
f@0
|
379
|
f@0
|
380 outputID = GetAudioDeviceID(gState->mAudioOutDev);
|
f@0
|
381
|
f@0
|
382 int samplerate = atoi(gState->mAudioSR);
|
f@0
|
383 int iovs = atoi(gState->mAudioIOVS);
|
f@0
|
384
|
f@0
|
385 if (inputID != -1 && outputID != -1)
|
f@0
|
386 {
|
f@0
|
387 return InitialiseAudio(inputID, outputID, samplerate, iovs, NUM_CHANNELS, gState->mAudioInChanL - 1, gState->mAudioOutChanL - 1);
|
f@0
|
388 }
|
f@0
|
389
|
f@0
|
390 return false;
|
f@0
|
391 }
|
f@0
|
392
|
f@0
|
393 bool InitialiseAudio(unsigned int inId,
|
f@0
|
394 unsigned int outId,
|
f@0
|
395 unsigned int sr,
|
f@0
|
396 unsigned int iovs,
|
f@0
|
397 unsigned int chnls,
|
f@0
|
398 unsigned int inChanL,
|
f@0
|
399 unsigned int outChanL
|
f@0
|
400 )
|
f@0
|
401 {
|
f@0
|
402 TRACE;
|
f@0
|
403
|
f@0
|
404 if (gDAC->isStreamOpen())
|
f@0
|
405 {
|
f@0
|
406 if (gDAC->isStreamRunning())
|
f@0
|
407 {
|
f@0
|
408 try
|
f@0
|
409 {
|
f@0
|
410 gDAC->abortStream();
|
f@0
|
411 }
|
f@0
|
412 catch (RtError& e)
|
f@0
|
413 {
|
f@0
|
414 e.printMessage();
|
f@0
|
415 }
|
f@0
|
416 }
|
f@0
|
417
|
f@0
|
418 gDAC->closeStream();
|
f@0
|
419 }
|
f@0
|
420
|
f@0
|
421 RtAudio::StreamParameters iParams, oParams;
|
f@0
|
422 iParams.deviceId = inId;
|
f@0
|
423 iParams.nChannels = chnls;
|
f@0
|
424 iParams.firstChannel = inChanL;
|
f@0
|
425
|
f@0
|
426 oParams.deviceId = outId;
|
f@0
|
427 oParams.nChannels = chnls;
|
f@0
|
428 oParams.firstChannel = outChanL;
|
f@0
|
429
|
f@0
|
430 gIOVS = iovs; // gIOVS may get changed by stream
|
f@0
|
431 gSigVS = atoi(gState->mAudioSigVS); // This is done here so that it changes when the callback is stopped
|
f@0
|
432
|
f@0
|
433 DBGMSG("\ntrying to start audio stream @ %i sr, %i iovs, %i sigvs\nindev = %i:%s\noutdev = %i:%s\n", sr, iovs, gSigVS, inId, GetAudioDeviceName(inId).c_str(), outId, GetAudioDeviceName(outId).c_str());
|
f@0
|
434
|
f@0
|
435 RtAudio::StreamOptions options;
|
f@0
|
436 options.flags = RTAUDIO_NONINTERLEAVED;
|
f@0
|
437 // options.streamName = BUNDLE_NAME; // JACK stream name, not used on other streams
|
f@0
|
438
|
f@0
|
439 gBufIndex = 0;
|
f@0
|
440 gVecElapsed = 0;
|
f@0
|
441 gFadeMult = 0.;
|
f@0
|
442
|
f@0
|
443 gPluginInstance->SetBlockSize(gSigVS);
|
f@0
|
444 gPluginInstance->SetSampleRate(sr);
|
f@0
|
445 gPluginInstance->Reset();
|
f@0
|
446
|
f@0
|
447 try
|
f@0
|
448 {
|
f@0
|
449 TRACE;
|
f@0
|
450 gDAC->openStream( &oParams, &iParams, RTAUDIO_FLOAT64, sr, &gIOVS, &AudioCallback, NULL, &options);
|
f@0
|
451 gDAC->startStream();
|
f@0
|
452
|
f@0
|
453 memcpy(gActiveState, gState, sizeof(AppState)); // copy state to active state
|
f@0
|
454 }
|
f@0
|
455 catch ( RtError& e )
|
f@0
|
456 {
|
f@0
|
457 e.printMessage();
|
f@0
|
458 return false;
|
f@0
|
459 }
|
f@0
|
460
|
f@0
|
461 return true;
|
f@0
|
462 }
|
f@0
|
463
|
f@0
|
464 bool InitialiseMidi()
|
f@0
|
465 {
|
f@0
|
466 try
|
f@0
|
467 {
|
f@0
|
468 gMidiIn = new RtMidiIn();
|
f@0
|
469 }
|
f@0
|
470 catch ( RtError &error )
|
f@0
|
471 {
|
f@0
|
472 FREE_NULL(gMidiIn);
|
f@0
|
473 error.printMessage();
|
f@0
|
474 return false;
|
f@0
|
475 }
|
f@0
|
476
|
f@0
|
477 try
|
f@0
|
478 {
|
f@0
|
479 gMidiOut = new RtMidiOut();
|
f@0
|
480 }
|
f@0
|
481 catch ( RtError &error )
|
f@0
|
482 {
|
f@0
|
483 FREE_NULL(gMidiOut);
|
f@0
|
484 error.printMessage();
|
f@0
|
485 return false;
|
f@0
|
486 }
|
f@0
|
487
|
f@0
|
488 gMidiIn->setCallback( &MIDICallback );
|
f@0
|
489 gMidiIn->ignoreTypes( !ENABLE_SYSEX, !ENABLE_MIDICLOCK, !ENABLE_ACTIVE_SENSING );
|
f@0
|
490
|
f@0
|
491 return true;
|
f@0
|
492 }
|
f@0
|
493
|
f@0
|
494 bool ChooseMidiInput(const char* pPortName)
|
f@0
|
495 {
|
f@0
|
496 unsigned int port = GetMIDIInPortNumber(pPortName);
|
f@0
|
497
|
f@0
|
498 if(port == -1)
|
f@0
|
499 {
|
f@0
|
500 strcpy(gState->mMidiInDev, "off");
|
f@0
|
501 UpdateINI();
|
f@0
|
502 port = 0;
|
f@0
|
503 }
|
f@0
|
504 /*
|
f@0
|
505 IMidiMsg msg;
|
f@0
|
506 msg.MakeControlChangeMsg(IMidiMsg::kAllNotesOff, 127, 0);
|
f@0
|
507
|
f@0
|
508 std::vector<unsigned char> message;
|
f@0
|
509 message.push_back( msg.mStatus );
|
f@0
|
510 message.push_back( msg.mData1 );
|
f@0
|
511 message.push_back( msg.mData2 );
|
f@0
|
512
|
f@0
|
513 gPluginInstance->ProcessMidiMsg(&msg);
|
f@0
|
514 */
|
f@0
|
515 if (gMidiIn)
|
f@0
|
516 {
|
f@0
|
517 gMidiIn->closePort();
|
f@0
|
518
|
f@0
|
519 if (port == 0)
|
f@0
|
520 {
|
f@0
|
521 return true;
|
f@0
|
522 }
|
f@0
|
523 #ifdef OS_WIN
|
f@0
|
524 else
|
f@0
|
525 {
|
f@0
|
526 gMidiIn->openPort(port-1);
|
f@0
|
527 return true;
|
f@0
|
528 }
|
f@0
|
529 #else
|
f@0
|
530 else if(port == 1)
|
f@0
|
531 {
|
f@0
|
532 std::string virtualMidiInputName = "To ";
|
f@0
|
533 virtualMidiInputName += BUNDLE_NAME;
|
f@0
|
534 gMidiIn->openVirtualPort(virtualMidiInputName);
|
f@0
|
535 return true;
|
f@0
|
536 }
|
f@0
|
537 else
|
f@0
|
538 {
|
f@0
|
539 gMidiIn->openPort(port-2);
|
f@0
|
540 return true;
|
f@0
|
541 }
|
f@0
|
542 #endif
|
f@0
|
543 }
|
f@0
|
544
|
f@0
|
545 return false;
|
f@0
|
546 }
|
f@0
|
547
|
f@0
|
548 bool ChooseMidiOutput(const char* pPortName)
|
f@0
|
549 {
|
f@0
|
550 unsigned int port = GetMIDIOutPortNumber(pPortName);
|
f@0
|
551
|
f@0
|
552 if(port == -1)
|
f@0
|
553 {
|
f@0
|
554 strcpy(gState->mMidiOutDev, "off");
|
f@0
|
555 UpdateINI();
|
f@0
|
556 port = 0;
|
f@0
|
557 }
|
f@0
|
558
|
f@0
|
559 if (gMidiOut)
|
f@0
|
560 {
|
f@0
|
561 /*
|
f@0
|
562 IMidiMsg msg;
|
f@0
|
563 msg.MakeControlChangeMsg(IMidiMsg::kAllNotesOff, 127, 0);
|
f@0
|
564
|
f@0
|
565 std::vector<unsigned char> message;
|
f@0
|
566 message.push_back( msg.mStatus );
|
f@0
|
567 message.push_back( msg.mData1 );
|
f@0
|
568 message.push_back( msg.mData2 );
|
f@0
|
569
|
f@0
|
570 gMidiOut->sendMessage( &message );
|
f@0
|
571 */
|
f@0
|
572 gMidiOut->closePort();
|
f@0
|
573
|
f@0
|
574 if (port == 0)
|
f@0
|
575 {
|
f@0
|
576 return true;
|
f@0
|
577 }
|
f@0
|
578 #ifdef OS_WIN
|
f@0
|
579 else
|
f@0
|
580 {
|
f@0
|
581 gMidiOut->openPort(port-1);
|
f@0
|
582 return true;
|
f@0
|
583 }
|
f@0
|
584 #else
|
f@0
|
585 else if(port == 1)
|
f@0
|
586 {
|
f@0
|
587 std::string virtualMidiOutputName = "From ";
|
f@0
|
588 virtualMidiOutputName += BUNDLE_NAME;
|
f@0
|
589 gMidiOut->openVirtualPort(virtualMidiOutputName);
|
f@0
|
590 return true;
|
f@0
|
591 }
|
f@0
|
592 else
|
f@0
|
593 {
|
f@0
|
594 gMidiOut->openPort(port-2);
|
f@0
|
595 return true;
|
f@0
|
596 }
|
f@0
|
597 #endif
|
f@0
|
598 }
|
f@0
|
599
|
f@0
|
600 return false;
|
f@0
|
601 }
|
f@0
|
602
|
f@0
|
603 extern bool AttachGUI()
|
f@0
|
604 {
|
f@0
|
605 IGraphics* pGraphics = gPluginInstance->GetGUI();
|
f@0
|
606
|
f@0
|
607 if (pGraphics)
|
f@0
|
608 {
|
f@0
|
609 #ifdef OS_WIN
|
f@0
|
610 if (!pGraphics->OpenWindow(gHWND))
|
f@0
|
611 pGraphics=0;
|
f@0
|
612 #else // Cocoa OSX
|
f@0
|
613 if (!pGraphics->OpenWindow(gHWND))
|
f@0
|
614 pGraphics=0;
|
f@0
|
615 #endif
|
f@0
|
616 if (pGraphics)
|
f@0
|
617 {
|
f@0
|
618 gPluginInstance->OnGUIOpen();
|
f@0
|
619 return true;
|
f@0
|
620 }
|
f@0
|
621 }
|
f@0
|
622
|
f@0
|
623 return false;
|
f@0
|
624 }
|
f@0
|
625
|
f@0
|
626 void Init()
|
f@0
|
627 {
|
f@0
|
628 TryToChangeAudioDriverType(); // will init RTAudio with an API type based on gState->mAudioDriverType
|
f@0
|
629 ProbeAudioIO(); // find out what audio IO devs are available and put their IDs in the global variables gAudioInputDevs / gAudioOutputDevs
|
f@0
|
630 InitialiseMidi(); // creates RTMidiIn and RTMidiOut objects
|
f@0
|
631 ProbeMidiIO(); // find out what midi IO devs are available and put their names in the global variables gMidiInputDevs / gMidiOutputDevs
|
f@0
|
632
|
f@0
|
633 // Initialise the plugin
|
f@0
|
634 gPluginInstance = MakePlug(gMidiOut, &gState->mMidiOutChan);
|
f@0
|
635 gPluginInstance->RestorePreset(0);
|
f@0
|
636
|
f@0
|
637 ChooseMidiInput(gState->mMidiInDev);
|
f@0
|
638 ChooseMidiOutput(gState->mMidiOutDev);
|
f@0
|
639
|
f@0
|
640 TryToChangeAudio();
|
f@0
|
641 }
|
f@0
|
642
|
f@0
|
643 void Cleanup()
|
f@0
|
644 {
|
f@0
|
645 try
|
f@0
|
646 {
|
f@0
|
647 // Stop the stream
|
f@0
|
648 gDAC->stopStream();
|
f@0
|
649 }
|
f@0
|
650 catch (RtError& e)
|
f@0
|
651 {
|
f@0
|
652 e.printMessage();
|
f@0
|
653 }
|
f@0
|
654
|
f@0
|
655 gMidiIn->cancelCallback();
|
f@0
|
656 gMidiIn->closePort();
|
f@0
|
657 gMidiOut->closePort();
|
f@0
|
658
|
f@0
|
659 if ( gDAC->isStreamOpen() ) gDAC->closeStream();
|
f@0
|
660
|
f@0
|
661 delete gPluginInstance;
|
f@0
|
662 delete gState;
|
f@0
|
663 delete gTempState;
|
f@0
|
664 delete gActiveState;
|
f@0
|
665 delete gMidiIn;
|
f@0
|
666 delete gMidiOut;
|
f@0
|
667 delete gDAC;
|
f@0
|
668 delete [] gINIPath;
|
f@0
|
669 }
|
f@0
|
670
|
f@0
|
671 #ifdef OS_WIN
|
f@0
|
672 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nShowCmd)
|
f@0
|
673 {
|
f@0
|
674 // first check to make sure this is the only instance running
|
f@0
|
675 // http://www.bcbjournal.org/articles/vol3/9911/Single-instance_applications.htm
|
f@0
|
676 try
|
f@0
|
677 {
|
f@0
|
678 // Try to open the mutex.
|
f@0
|
679 HANDLE hMutex = OpenMutex(
|
f@0
|
680 MUTEX_ALL_ACCESS, 0, BUNDLE_NAME);
|
f@0
|
681
|
f@0
|
682 // If hMutex is 0 then the mutex doesn't exist.
|
f@0
|
683 if (!hMutex)
|
f@0
|
684 hMutex = CreateMutex(0, 0, BUNDLE_NAME);
|
f@0
|
685 else
|
f@0
|
686 {
|
f@0
|
687 // This is a second instance. Bring the
|
f@0
|
688 // original instance to the top.
|
f@0
|
689 HWND hWnd = FindWindow(0, BUNDLE_NAME);
|
f@0
|
690 SetForegroundWindow(hWnd);
|
f@0
|
691
|
f@0
|
692 return 0;
|
f@0
|
693 }
|
f@0
|
694
|
f@0
|
695 gHINST=hInstance;
|
f@0
|
696
|
f@0
|
697 InitCommonControls();
|
f@0
|
698 gScrollMessage = RegisterWindowMessage("MSWHEEL_ROLLMSG");
|
f@0
|
699
|
f@0
|
700 gState = new AppState();
|
f@0
|
701 gTempState = new AppState();
|
f@0
|
702 gActiveState = new AppState();
|
f@0
|
703
|
f@0
|
704 if (SHGetFolderPathA( NULL, CSIDL_LOCAL_APPDATA, NULL, 0, gINIPath ) != S_OK)
|
f@0
|
705 {
|
f@0
|
706 DBGMSG("could not retrieve the user's application data directory!\n");
|
f@0
|
707
|
f@0
|
708 //TODO error msg?
|
f@0
|
709 return 1;
|
f@0
|
710 }
|
f@0
|
711
|
f@0
|
712 sprintf(gINIPath, "%s\\%s", gINIPath, BUNDLE_NAME); // Add the app name to the path
|
f@0
|
713
|
f@0
|
714 struct stat st;
|
f@0
|
715 if(stat(gINIPath, &st) == 0) // if directory exists
|
f@0
|
716 {
|
f@0
|
717 sprintf(gINIPath, "%s\\%s", gINIPath, "settings.ini"); // add file name to path
|
f@0
|
718
|
f@0
|
719 if(stat(gINIPath, &st) == 0) // if settings file exists read values into state
|
f@0
|
720 {
|
f@0
|
721 gState->mAudioDriverType = GetPrivateProfileInt("audio", "driver", 0, gINIPath);
|
f@0
|
722
|
f@0
|
723 GetPrivateProfileString("audio", "indev", DEFAULT_INPUT_DEV, gState->mAudioInDev, 100, gINIPath);
|
f@0
|
724 GetPrivateProfileString("audio", "outdev", DEFAULT_OUTPUT_DEV, gState->mAudioOutDev, 100, gINIPath);
|
f@0
|
725
|
f@0
|
726 //audio
|
f@0
|
727 gState->mAudioInChanL = GetPrivateProfileInt("audio", "in1", 1, gINIPath); // 1 is first audio input
|
f@0
|
728 gState->mAudioInChanR = GetPrivateProfileInt("audio", "in2", 2, gINIPath);
|
f@0
|
729 gState->mAudioOutChanL = GetPrivateProfileInt("audio", "out1", 1, gINIPath); // 1 is first audio output
|
f@0
|
730 gState->mAudioOutChanR = GetPrivateProfileInt("audio", "out2", 2, gINIPath);
|
f@0
|
731 gState->mAudioInIsMono = GetPrivateProfileInt("audio", "monoinput", 0, gINIPath);
|
f@0
|
732
|
f@0
|
733 GetPrivateProfileString("audio", "iovs", "512", gState->mAudioIOVS, 100, gINIPath);
|
f@0
|
734 GetPrivateProfileString("audio", "sigvs", "32", gState->mAudioSigVS, 100, gINIPath);
|
f@0
|
735 GetPrivateProfileString("audio", "sr", "44100", gState->mAudioSR, 100, gINIPath);
|
f@0
|
736
|
f@0
|
737 //midi
|
f@0
|
738 GetPrivateProfileString("midi", "indev", "no input", gState->mMidiInDev, 100, gINIPath);
|
f@0
|
739 GetPrivateProfileString("midi", "outdev", "no output", gState->mMidiOutDev, 100, gINIPath);
|
f@0
|
740
|
f@0
|
741 gState->mMidiInChan = GetPrivateProfileInt("midi", "inchan", 0, gINIPath); // 0 is any
|
f@0
|
742 gState->mMidiOutChan = GetPrivateProfileInt("midi", "outchan", 0, gINIPath); // 1 is first chan
|
f@0
|
743
|
f@0
|
744 UpdateINI(); // this will write over any invalid values in the file
|
f@0
|
745 }
|
f@0
|
746 else // settings file doesn't exist, so populate with default values
|
f@0
|
747 {
|
f@0
|
748 UpdateINI();
|
f@0
|
749 }
|
f@0
|
750 }
|
f@0
|
751 else
|
f@0
|
752 {
|
f@0
|
753 // folder doesn't exist - make folder and make file
|
f@0
|
754 CreateDirectory(gINIPath, NULL);
|
f@0
|
755 sprintf(gINIPath, "%s\\%s", gINIPath, "settings.ini"); // add file name to path
|
f@0
|
756 UpdateINI(); // will write file if doesn't exist
|
f@0
|
757 }
|
f@0
|
758
|
f@0
|
759 Init();
|
f@0
|
760
|
f@0
|
761 CreateDialog(gHINST,MAKEINTRESOURCE(IDD_DIALOG_MAIN),GetDesktopWindow(),MainDlgProc);
|
f@0
|
762
|
f@0
|
763 for(;;)
|
f@0
|
764 {
|
f@0
|
765 MSG msg= {0,};
|
f@0
|
766 int vvv = GetMessage(&msg,NULL,0,0);
|
f@0
|
767 if (!vvv) break;
|
f@0
|
768
|
f@0
|
769 if (vvv<0)
|
f@0
|
770 {
|
f@0
|
771 Sleep(10);
|
f@0
|
772 continue;
|
f@0
|
773 }
|
f@0
|
774 if (!msg.hwnd)
|
f@0
|
775 {
|
f@0
|
776 DispatchMessage(&msg);
|
f@0
|
777 continue;
|
f@0
|
778 }
|
f@0
|
779
|
f@0
|
780 if (gHWND && IsDialogMessage(gHWND,&msg)) continue;
|
f@0
|
781
|
f@0
|
782 // default processing for other dialogs
|
f@0
|
783 HWND hWndParent=NULL;
|
f@0
|
784 HWND temphwnd = msg.hwnd;
|
f@0
|
785 do
|
f@0
|
786 {
|
f@0
|
787 if (GetClassLong(temphwnd, GCW_ATOM) == (INT)32770)
|
f@0
|
788 {
|
f@0
|
789 hWndParent=temphwnd;
|
f@0
|
790 if (!(GetWindowLong(temphwnd,GWL_STYLE)&WS_CHILD)) break; // not a child, exit
|
f@0
|
791 }
|
f@0
|
792 }
|
f@0
|
793 while (temphwnd = GetParent(temphwnd));
|
f@0
|
794
|
f@0
|
795 if (hWndParent && IsDialogMessage(hWndParent,&msg)) continue;
|
f@0
|
796
|
f@0
|
797 TranslateMessage(&msg);
|
f@0
|
798 DispatchMessage(&msg);
|
f@0
|
799
|
f@0
|
800 }
|
f@0
|
801
|
f@0
|
802 // in case gHWND didnt get destroyed -- this corresponds to SWELLAPP_DESTROY roughly
|
f@0
|
803 if (gHWND) DestroyWindow(gHWND);
|
f@0
|
804
|
f@0
|
805 Cleanup();
|
f@0
|
806
|
f@0
|
807 ReleaseMutex(hMutex);
|
f@0
|
808 }
|
f@0
|
809 catch(...)
|
f@0
|
810 {
|
f@0
|
811 //TODO proper error catching
|
f@0
|
812 DBGMSG("another instance running");
|
f@0
|
813 }
|
f@0
|
814 return 0;
|
f@0
|
815 }
|
f@0
|
816 #else
|
f@0
|
817
|
f@0
|
818 extern HMENU SWELL_app_stocksysmenu;
|
f@0
|
819 const char *homeDir;
|
f@0
|
820
|
f@0
|
821 INT_PTR SWELLAppMain(int msg, INT_PTR parm1, INT_PTR parm2)
|
f@0
|
822 {
|
f@0
|
823 switch (msg)
|
f@0
|
824 {
|
f@0
|
825 case SWELLAPP_ONLOAD:
|
f@0
|
826
|
f@0
|
827 gState = new AppState();
|
f@0
|
828 gTempState = new AppState();
|
f@0
|
829 gActiveState = new AppState();
|
f@0
|
830
|
f@0
|
831 homeDir = getenv("HOME");
|
f@0
|
832 sprintf(gINIPath, "%s/Library/Application Support/%s/", homeDir, BUNDLE_NAME);
|
f@0
|
833
|
f@0
|
834 struct stat st;
|
f@0
|
835 if(stat(gINIPath, &st) == 0) // if directory exists
|
f@0
|
836 {
|
f@0
|
837 sprintf(gINIPath, "%s%s", gINIPath, "settings.ini"); // add file name to path
|
f@0
|
838
|
f@0
|
839 if(stat(gINIPath, &st) == 0) // if settings file exists read values into state
|
f@0
|
840 {
|
f@0
|
841 gState->mAudioDriverType = GetPrivateProfileInt("audio", "driver", 0, gINIPath);
|
f@0
|
842
|
f@0
|
843 GetPrivateProfileString("audio", "indev", "Built-in Input", gState->mAudioInDev, 100, gINIPath);
|
f@0
|
844 GetPrivateProfileString("audio", "outdev", "Built-in Output", gState->mAudioOutDev, 100, gINIPath);
|
f@0
|
845
|
f@0
|
846 //audio
|
f@0
|
847 gState->mAudioInChanL = GetPrivateProfileInt("audio", "in1", 1, gINIPath); // 1 is first audio input
|
f@0
|
848 gState->mAudioInChanR = GetPrivateProfileInt("audio", "in2", 2, gINIPath);
|
f@0
|
849 gState->mAudioOutChanL = GetPrivateProfileInt("audio", "out1", 1, gINIPath); // 1 is first audio output
|
f@0
|
850 gState->mAudioOutChanR = GetPrivateProfileInt("audio", "out2", 2, gINIPath);
|
f@0
|
851 gState->mAudioInIsMono = GetPrivateProfileInt("audio", "monoinput", 0, gINIPath);
|
f@0
|
852
|
f@0
|
853 GetPrivateProfileString("audio", "iovs", "512", gState->mAudioIOVS, 100, gINIPath);
|
f@0
|
854 GetPrivateProfileString("audio", "sigvs", "32", gState->mAudioSigVS, 100, gINIPath);
|
f@0
|
855 GetPrivateProfileString("audio", "sr", "44100", gState->mAudioSR, 100, gINIPath);
|
f@0
|
856
|
f@0
|
857 //midi
|
f@0
|
858 GetPrivateProfileString("midi", "indev", "no input", gState->mMidiInDev, 100, gINIPath);
|
f@0
|
859 GetPrivateProfileString("midi", "outdev", "no output", gState->mMidiOutDev, 100, gINIPath);
|
f@0
|
860
|
f@0
|
861 gState->mMidiInChan = GetPrivateProfileInt("midi", "inchan", 0, gINIPath); // 0 is any
|
f@0
|
862 gState->mMidiOutChan = GetPrivateProfileInt("midi", "outchan", 0, gINIPath); // 1 is first chan
|
f@0
|
863
|
f@0
|
864 UpdateINI(); // this will write over any invalid values in the file
|
f@0
|
865 }
|
f@0
|
866 else // settings file doesn't exist, so populate with default values
|
f@0
|
867 {
|
f@0
|
868 UpdateINI();
|
f@0
|
869 }
|
f@0
|
870
|
f@0
|
871 }
|
f@0
|
872 else // folder doesn't exist - make folder and make file
|
f@0
|
873 {
|
f@0
|
874 // http://blog.tremend.ro/2008/10/06/create-directories-in-c-using-mkdir-with-proper-permissions/
|
f@0
|
875
|
f@0
|
876 mode_t process_mask = umask(0);
|
f@0
|
877 int result_code = mkdir(gINIPath, S_IRWXU | S_IRWXG | S_IRWXO);
|
f@0
|
878 umask(process_mask);
|
f@0
|
879
|
f@0
|
880 if(result_code) return 1;
|
f@0
|
881 else
|
f@0
|
882 {
|
f@0
|
883 sprintf(gINIPath, "%s%s", gINIPath, "settings.ini"); // add file name to path
|
f@0
|
884 UpdateINI(); // will write file if doesn't exist
|
f@0
|
885 }
|
f@0
|
886 }
|
f@0
|
887 break;
|
f@0
|
888 #pragma mark loaded
|
f@0
|
889 case SWELLAPP_LOADED:
|
f@0
|
890 {
|
f@0
|
891 Init();
|
f@0
|
892
|
f@0
|
893 HMENU menu = SWELL_GetCurrentMenu();
|
f@0
|
894
|
f@0
|
895 if (menu)
|
f@0
|
896 {
|
f@0
|
897 // other windows will get the stock (bundle) menus
|
f@0
|
898 //SWELL_SetDefaultModalWindowMenu(menu);
|
f@0
|
899 //SWELL_SetDefaultWindowMenu(menu);
|
f@0
|
900
|
f@0
|
901 // work on a new menu
|
f@0
|
902 menu = SWELL_DuplicateMenu(menu);
|
f@0
|
903 HMENU src = LoadMenu(NULL,MAKEINTRESOURCE(IDR_MENU1));
|
f@0
|
904 int x;
|
f@0
|
905 for (x=0; x<GetMenuItemCount(src)-1; x++)
|
f@0
|
906 {
|
f@0
|
907 HMENU sm = GetSubMenu(src,x);
|
f@0
|
908 if (sm)
|
f@0
|
909 {
|
f@0
|
910 char str[1024];
|
f@0
|
911 MENUITEMINFO mii= {sizeof(mii),MIIM_TYPE,};
|
f@0
|
912 mii.dwTypeData=str;
|
f@0
|
913 mii.cch=sizeof(str);
|
f@0
|
914 str[0]=0;
|
f@0
|
915 GetMenuItemInfo(src,x,TRUE,&mii);
|
f@0
|
916 MENUITEMINFO mi= {sizeof(mi),MIIM_STATE|MIIM_SUBMENU|MIIM_TYPE,MFT_STRING,0,0,SWELL_DuplicateMenu(sm),NULL,NULL,0,str};
|
f@0
|
917 InsertMenuItem(menu,x+1,TRUE,&mi);
|
f@0
|
918 }
|
f@0
|
919 }
|
f@0
|
920 }
|
f@0
|
921
|
f@0
|
922 if (menu)
|
f@0
|
923 {
|
f@0
|
924 HMENU sm=GetSubMenu(menu,1);
|
f@0
|
925 DeleteMenu(sm,ID_QUIT,MF_BYCOMMAND); // remove QUIT from our file menu, since it is in the system menu on OSX
|
f@0
|
926 DeleteMenu(sm,ID_PREFERENCES,MF_BYCOMMAND); // remove PREFERENCES from the file menu, since it is in the system menu on OSX
|
f@0
|
927
|
f@0
|
928 // remove any trailing separators
|
f@0
|
929 int a= GetMenuItemCount(sm);
|
f@0
|
930 while (a > 0 && GetMenuItemID(sm,a-1)==0) DeleteMenu(sm,--a,MF_BYPOSITION);
|
f@0
|
931
|
f@0
|
932 DeleteMenu(menu,1,MF_BYPOSITION); // delete file menu
|
f@0
|
933 }
|
f@0
|
934
|
f@0
|
935 // if we want to set any default modifiers for items in the menus, we can use:
|
f@0
|
936 // SetMenuItemModifier(menu,commandID,MF_BYCOMMAND,'A',FCONTROL) etc.
|
f@0
|
937
|
f@0
|
938 HWND hwnd = CreateDialog(gHINST,MAKEINTRESOURCE(IDD_DIALOG_MAIN),NULL,MainDlgProc);
|
f@0
|
939 if (menu)
|
f@0
|
940 {
|
f@0
|
941 SetMenu(hwnd, menu); // set the menu for the dialog to our menu (on Windows that menu is set from the .rc, but on SWELL
|
f@0
|
942 SWELL_SetDefaultModalWindowMenu(menu); // other windows will get the stock (bundle) menus
|
f@0
|
943 }
|
f@0
|
944 // we need to set it manually (and obviously we've edited the menu anyway)
|
f@0
|
945 }
|
f@0
|
946
|
f@0
|
947 if(!AttachGUI()) DBGMSG("couldn't attach gui\n"); //todo error
|
f@0
|
948
|
f@0
|
949 break;
|
f@0
|
950 case SWELLAPP_ONCOMMAND:
|
f@0
|
951 // this is to catch commands coming from the system menu etc
|
f@0
|
952 if (gHWND && (parm1&0xffff)) SendMessage(gHWND,WM_COMMAND,parm1&0xffff,0);
|
f@0
|
953 break;
|
f@0
|
954 #pragma mark destroy
|
f@0
|
955 case SWELLAPP_DESTROY:
|
f@0
|
956
|
f@0
|
957 if (gHWND) DestroyWindow(gHWND);
|
f@0
|
958 Cleanup();
|
f@0
|
959 break;
|
f@0
|
960 case SWELLAPP_PROCESSMESSAGE: // can hook keyboard input here
|
f@0
|
961 // parm1 = (MSG*), should we want it -- look in swell.h to see what the return values refer to
|
f@0
|
962 break;
|
f@0
|
963 }
|
f@0
|
964 return 0;
|
f@0
|
965 }
|
f@0
|
966
|
f@0
|
967 #endif
|
f@0
|
968
|
f@0
|
969
|
f@0
|
970 #ifndef OS_WIN
|
f@0
|
971 #include "swell-dlggen.h"
|
f@0
|
972
|
f@0
|
973 #define SET_IDD_SCALE 1.
|
f@0
|
974 #define SET_IDD_STYLE SWELL_DLG_WS_FLIPPED|SWELL_DLG_WS_NOAUTOSIZE
|
f@0
|
975
|
f@0
|
976 SWELL_DEFINE_DIALOG_RESOURCE_BEGIN(IDD_DIALOG_MAIN, SET_IDD_STYLE, BUNDLE_NAME, GUI_WIDTH, GUI_HEIGHT, SET_IDD_SCALE)
|
f@0
|
977 BEGIN
|
f@0
|
978 // EDITTEXT IDC_EDIT1,59,50,145,14,ES_AUTOHSCROLL
|
f@0
|
979 // LTEXT "Enter some text here:",IDC_STATIC,59,39,73,8
|
f@0
|
980 END
|
f@0
|
981 SWELL_DEFINE_DIALOG_RESOURCE_END(IDD_DIALOG_MAIN)
|
f@0
|
982
|
f@0
|
983 SWELL_DEFINE_DIALOG_RESOURCE_BEGIN(IDD_DIALOG_PREF,SET_IDD_STYLE,"Preferences",320,420,SET_IDD_SCALE)
|
f@0
|
984 BEGIN
|
f@0
|
985 GROUPBOX "Audio Settings", IDC_STATIC, 5, 10, 300, 230
|
f@0
|
986
|
f@0
|
987 LTEXT "Driver Type", IDC_STATIC, 20, 32, 60, 20
|
f@0
|
988 COMBOBOX IDC_COMBO_AUDIO_DRIVER, 20, 50, 150, 100, CBS_DROPDOWNLIST
|
f@0
|
989
|
f@0
|
990 LTEXT "Input Device", IDC_STATIC, 20, 75, 80, 20
|
f@0
|
991 COMBOBOX IDC_COMBO_AUDIO_IN_DEV, 20, 90, 150, 100, CBS_DROPDOWNLIST
|
f@0
|
992
|
f@0
|
993 LTEXT "Output Device", IDC_STATIC, 20, 115, 80, 20
|
f@0
|
994 COMBOBOX IDC_COMBO_AUDIO_OUT_DEV, 20, 130, 150, 100, CBS_DROPDOWNLIST
|
f@0
|
995
|
f@0
|
996 LTEXT "In 1 (L)", IDC_STATIC, 20, 155, 90, 20
|
f@0
|
997 COMBOBOX IDC_COMBO_AUDIO_IN_L, 20, 170, 46, 100, CBS_DROPDOWNLIST
|
f@0
|
998
|
f@0
|
999 LTEXT "In 2 (R)", IDC_STATIC, 75, 155, 90, 20
|
f@0
|
1000 COMBOBOX IDC_COMBO_AUDIO_IN_R, 75, 170, 46, 100, CBS_DROPDOWNLIST
|
f@0
|
1001
|
f@0
|
1002 CHECKBOX "Mono", IDC_CB_MONO_INPUT, 125, 128, 56, 100, 0
|
f@0
|
1003
|
f@0
|
1004 LTEXT "Out 1 (L)", IDC_STATIC, 20, 195, 60, 20
|
f@0
|
1005 COMBOBOX IDC_COMBO_AUDIO_OUT_L, 20, 210, 46, 100, CBS_DROPDOWNLIST
|
f@0
|
1006
|
f@0
|
1007 LTEXT "Out 2 (R)", IDC_STATIC, 75, 195, 60, 20
|
f@0
|
1008 COMBOBOX IDC_COMBO_AUDIO_OUT_R, 75, 210, 46, 100, CBS_DROPDOWNLIST
|
f@0
|
1009
|
f@0
|
1010 LTEXT "IO Vector Size", IDC_STATIC, 200, 32, 80, 20
|
f@0
|
1011 COMBOBOX IDC_COMBO_AUDIO_IOVS, 200, 50, 90, 100, CBS_DROPDOWNLIST
|
f@0
|
1012
|
f@0
|
1013 LTEXT "Signal Vector Size", IDC_STATIC, 200, 75, 100, 20
|
f@0
|
1014 COMBOBOX IDC_COMBO_AUDIO_SIGVS, 200, 90, 90, 100, CBS_DROPDOWNLIST
|
f@0
|
1015
|
f@0
|
1016 LTEXT "Sampling Rate", IDC_STATIC, 200, 115, 80, 20
|
f@0
|
1017 COMBOBOX IDC_COMBO_AUDIO_SR, 200, 130, 90, 100, CBS_DROPDOWNLIST
|
f@0
|
1018
|
f@0
|
1019 PUSHBUTTON "Audio Midi Setup...", IDC_BUTTON_ASIO, 180, 170, 110, 40
|
f@0
|
1020
|
f@0
|
1021 GROUPBOX "MIDI Settings", IDC_STATIC, 5, 255, 300, 120
|
f@0
|
1022
|
f@0
|
1023 LTEXT "Input Device", IDC_STATIC, 20, 275, 100, 20
|
f@0
|
1024 COMBOBOX IDC_COMBO_MIDI_IN_DEV, 20, 293, 150, 100, CBS_DROPDOWNLIST
|
f@0
|
1025
|
f@0
|
1026 LTEXT "Output Device", IDC_STATIC, 20, 320, 100, 20
|
f@0
|
1027 COMBOBOX IDC_COMBO_MIDI_OUT_DEV, 20, 338, 150, 100, CBS_DROPDOWNLIST
|
f@0
|
1028
|
f@0
|
1029 LTEXT "Input Channel", IDC_STATIC, 200, 275, 100, 20
|
f@0
|
1030 COMBOBOX IDC_COMBO_MIDI_IN_CHAN, 200, 293, 90, 100, CBS_DROPDOWNLIST
|
f@0
|
1031
|
f@0
|
1032 LTEXT "Output Channel", IDC_STATIC, 200, 320, 100, 20
|
f@0
|
1033 COMBOBOX IDC_COMBO_MIDI_OUT_CHAN, 200, 338, 90, 100, CBS_DROPDOWNLIST
|
f@0
|
1034
|
f@0
|
1035 DEFPUSHBUTTON "OK", IDOK, 192, 383, 50, 20
|
f@0
|
1036 PUSHBUTTON "Apply", IDAPPLY, 132, 383, 50, 20
|
f@0
|
1037 PUSHBUTTON "Cancel", IDCANCEL, 252, 383, 50, 20
|
f@0
|
1038 END
|
f@0
|
1039 SWELL_DEFINE_DIALOG_RESOURCE_END(IDD_DIALOG_PREF)
|
f@0
|
1040
|
f@0
|
1041 #include "swell-menugen.h"
|
f@0
|
1042
|
f@0
|
1043 SWELL_DEFINE_MENU_RESOURCE_BEGIN(IDR_MENU1)
|
f@0
|
1044 POPUP "&File"
|
f@0
|
1045 BEGIN
|
f@0
|
1046 // MENUITEM SEPARATOR
|
f@0
|
1047 MENUITEM "Preferences...", ID_PREFERENCES
|
f@0
|
1048 MENUITEM "&Quit", ID_QUIT
|
f@0
|
1049 END
|
f@0
|
1050 POPUP "&Help"
|
f@0
|
1051 BEGIN
|
f@0
|
1052 MENUITEM "&About", ID_ABOUT
|
f@0
|
1053 END
|
f@0
|
1054 SWELL_DEFINE_MENU_RESOURCE_END(IDR_MENU1)
|
f@0
|
1055
|
f@0
|
1056 #endif |