comparison app_wrapper/app_main.cpp @ 0:4606bd505630 tip

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