ConvoEngine: Make max channel counts configurable.
[wdl/wdl-ol.git] / IPlugExamples / IPlugConvoEngine / app_wrapper / app_main.cpp
blob5567ac3112a3ff54ac732b8803acda19e2cfb086
1 #include "app_main.h"
3 #ifdef OS_WIN
4 #include <windows.h>
5 #include <shlobj.h>
6 #include <sys/stat.h>
7 #endif
9 HWND gHWND;
11 HINSTANCE gHINST;
12 UINT gScrollMessage;
13 IPlug* gPluginInstance;
14 RtAudio* gDAC = 0;
15 RtMidiIn *gMidiIn = 0;
16 RtMidiOut *gMidiOut = 0;
18 AppState *gState;
19 AppState *gTempState;
20 AppState *gActiveState;
22 char *gINIPath = new char[200]; // path of ini file
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
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;
36 void UpdateINI()
38 char buf[100]; // temp buffer for writing integers to profile strings
40 sprintf(buf, "%u", gState->mAudioDriverType);
41 WritePrivateProfileString("audio", "driver", buf, gINIPath);
43 WritePrivateProfileString("audio", "indev", gState->mAudioInDev, gINIPath);
44 WritePrivateProfileString("audio", "outdev", gState->mAudioOutDev, gINIPath);
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);
57 WritePrivateProfileString("audio", "iovs", gState->mAudioIOVS, gINIPath);
58 WritePrivateProfileString("audio", "sigvs", gState->mAudioSigVS, gINIPath);
60 WritePrivateProfileString("audio", "sr", gState->mAudioSR, gINIPath);
62 WritePrivateProfileString("midi", "indev", gState->mMidiInDev, gINIPath);
63 WritePrivateProfileString("midi", "outdev", gState->mMidiOutDev, gINIPath);
65 sprintf(buf, "%u", gState->mMidiInChan);
66 WritePrivateProfileString("midi", "inchan", buf, gINIPath);
67 sprintf(buf, "%u", gState->mMidiOutChan);
68 WritePrivateProfileString("midi", "outchan", buf, gINIPath);
71 // returns the device name. Core Audio device names are truncated
72 std::string GetAudioDeviceName(int idx)
74 return gAudioIDDevNames.at(idx);
77 // returns the rtaudio device ID, based on the (truncated) device name
78 int GetAudioDeviceID(char* deviceNameToTest)
80 TRACE;
82 for(int i = 0; i < gAudioIDDevNames.size(); i++)
84 if(!strcmp(deviceNameToTest, gAudioIDDevNames.at(i).c_str() ))
85 return i;
88 return -1;
91 unsigned int GetMIDIInPortNumber(const char* nameToTest)
93 int start = 1;
95 if(!strcmp(nameToTest, "off")) return 0;
97 #ifdef OS_OSX
98 start = 2;
99 if(!strcmp(nameToTest, "virtual input")) return 1;
100 #endif
102 for (int i = 0; i < gMidiIn->getPortCount(); i++)
104 if(!strcmp(nameToTest, gMidiIn->getPortName(i).c_str()))
105 return (i + start);
108 return -1;
111 unsigned int GetMIDIOutPortNumber(const char* nameToTest)
113 int start = 1;
115 if(!strcmp(nameToTest, "off")) return 0;
117 #ifdef OS_OSX
118 start = 2;
119 if(!strcmp(nameToTest, "virtual output")) return 1;
120 #endif
122 for (int i = 0; i < gMidiOut->getPortCount(); i++)
124 if(!strcmp(nameToTest, gMidiOut->getPortName(i).c_str()))
125 return (i + start);
128 return -1;
131 // find out which devices have input channels & which have output channels, add their ids to the lists
132 void ProbeAudioIO()
134 TRACE;
136 RtAudio::DeviceInfo info;
138 gAudioInputDevs.clear();
139 gAudioOutputDevs.clear();
140 gAudioIDDevNames.clear();
142 unsigned int nDevices = gDAC->getDeviceCount();
144 for (int i=0; i<nDevices; i++)
146 info = gDAC->getDeviceInfo(i);
147 std::string deviceName = info.name;
149 #ifdef OS_OSX
150 size_t colonIdx = deviceName.rfind(": ");
152 if(colonIdx != std::string::npos && deviceName.length() >= 2)
153 deviceName = deviceName.substr(colonIdx + 2, deviceName.length() - colonIdx - 2);
155 #endif
157 gAudioIDDevNames.push_back(deviceName);
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
165 if(info.inputChannels > 0)
166 gAudioInputDevs.push_back(i);
168 if(info.outputChannels > 0)
169 gAudioOutputDevs.push_back(i);
174 void ProbeMidiIO()
176 if ( !gMidiIn || !gMidiOut )
177 return;
178 else
180 int nInputPorts = gMidiIn->getPortCount();
182 gMIDIInputDevNames.push_back("off");
184 #ifndef OS_WIN
185 gMIDIInputDevNames.push_back("virtual input");
186 #endif
188 for (int i=0; i<nInputPorts; i++ )
190 gMIDIInputDevNames.push_back(gMidiIn->getPortName(i));
193 int nOutputPorts = gMidiOut->getPortCount();
195 gMIDIOutputDevNames.push_back("off");
197 #ifndef _WIN32
198 gMIDIOutputDevNames.push_back("virtual output");
199 #endif
201 for (int i=0; i<nOutputPorts; i++ )
203 gMIDIOutputDevNames.push_back(gMidiOut->getPortName(i));
204 //This means the virtual output port wont be added as an input
209 bool AudioSettingsInStateAreEqual(AppState* os, AppState* ns)
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;
223 return true;
226 bool MIDISettingsInStateAreEqual(AppState* os, AppState* ns)
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;
233 return true;
236 void MIDICallback( double deltatime, std::vector< unsigned char > *message, void *userData )
238 if ( message->size() )
240 IMidiMsg *myMsg;
242 switch (message->size())
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;
258 IMidiMsg msg(*myMsg);
260 delete myMsg;
262 // filter midi messages based on channel, if gStatus.mMidiInChan != all (0)
263 if (gState->mMidiInChan)
265 if (gState->mMidiInChan == msg.Channel() + 1 )
266 gPluginInstance->ProcessMidiMsg(&msg);
268 else
270 gPluginInstance->ProcessMidiMsg(&msg);
275 int AudioCallback(void *outputBuffer,
276 void *inputBuffer,
277 unsigned int nFrames,
278 double streamTime,
279 RtAudioStreamStatus status,
280 void *userData )
282 if ( status )
283 std::cout << "Stream underflow detected!" << std::endl;
285 double* inputBufferD = (double*)inputBuffer;
286 double* outputBufferD = (double*)outputBuffer;
288 int inRightOffset = 0;
290 if(!gState->mAudioInIsMono)
291 inRightOffset = nFrames;
293 if (gVecElapsed > N_VECTOR_WAIT) // wait N_VECTOR_WAIT * iovs before processing audio, to avoid clicks
295 for (int i=0; i<nFrames; i++)
297 gBufIndex %= gSigVS;
299 if (gBufIndex == 0)
301 double* inputs[2] = {inputBufferD + i, inputBufferD + inRightOffset + i};
302 double* outputs[2] = {outputBufferD + i, outputBufferD + nFrames + i};
304 gPluginInstance->LockMutexAndProcessDoubleReplacing(inputs, outputs, gSigVS);
307 // fade in
308 if (gFadeMult < 1.)
310 gFadeMult += (1. / nFrames);
313 outputBufferD[i] *= gFadeMult;
314 outputBufferD[i + nFrames] *= gFadeMult;
316 outputBufferD[i] *= APP_MULT;
317 outputBufferD[i + nFrames] *= APP_MULT;
319 gBufIndex++;
322 else
324 memset(outputBuffer, 0, nFrames * 2 * sizeof(double));
327 gVecElapsed++;
329 return 0;
332 bool TryToChangeAudioDriverType()
334 TRACE;
336 if (gDAC)
338 if (gDAC->isStreamOpen())
340 gDAC->closeStream();
343 DELETE_NULL(gDAC);
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
358 if(gDAC)
359 return true;
360 else
361 return false;
364 bool TryToChangeAudio()
366 TRACE;
368 int inputID = -1;
369 int outputID = -1;
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
380 outputID = GetAudioDeviceID(gState->mAudioOutDev);
382 int samplerate = atoi(gState->mAudioSR);
383 int iovs = atoi(gState->mAudioIOVS);
385 if (inputID != -1 && outputID != -1)
387 return InitialiseAudio(inputID, outputID, samplerate, iovs, NUM_CHANNELS, gState->mAudioInChanL - 1, gState->mAudioOutChanL - 1);
390 return false;
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
402 TRACE;
404 if (gDAC->isStreamOpen())
406 if (gDAC->isStreamRunning())
410 gDAC->abortStream();
412 catch (RtError& e)
414 e.printMessage();
418 gDAC->closeStream();
421 RtAudio::StreamParameters iParams, oParams;
422 iParams.deviceId = inId;
423 iParams.nChannels = chnls;
424 iParams.firstChannel = inChanL;
426 oParams.deviceId = outId;
427 oParams.nChannels = chnls;
428 oParams.firstChannel = outChanL;
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
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());
435 RtAudio::StreamOptions options;
436 options.flags = RTAUDIO_NONINTERLEAVED;
437 // options.streamName = BUNDLE_NAME; // JACK stream name, not used on other streams
439 gBufIndex = 0;
440 gVecElapsed = 0;
441 gFadeMult = 0.;
443 gPluginInstance->SetBlockSize(gSigVS);
444 gPluginInstance->SetSampleRate(sr);
445 gPluginInstance->Reset();
449 TRACE;
450 gDAC->openStream( &oParams, &iParams, RTAUDIO_FLOAT64, sr, &gIOVS, &AudioCallback, NULL, &options);
451 gDAC->startStream();
453 memcpy(gActiveState, gState, sizeof(AppState)); // copy state to active state
455 catch ( RtError& e )
457 e.printMessage();
458 return false;
461 return true;
464 bool InitialiseMidi()
468 gMidiIn = new RtMidiIn();
470 catch ( RtError &error )
472 FREE_NULL(gMidiIn);
473 error.printMessage();
474 return false;
479 gMidiOut = new RtMidiOut();
481 catch ( RtError &error )
483 FREE_NULL(gMidiOut);
484 error.printMessage();
485 return false;
488 gMidiIn->setCallback( &MIDICallback );
489 gMidiIn->ignoreTypes( !ENABLE_SYSEX, !ENABLE_MIDICLOCK, !ENABLE_ACTIVE_SENSING );
491 return true;
494 bool ChooseMidiInput(const char* pPortName)
496 unsigned int port = GetMIDIInPortNumber(pPortName);
498 if(port == -1)
500 strcpy(gState->mMidiInDev, "off");
501 UpdateINI();
502 port = 0;
505 IMidiMsg msg;
506 msg.MakeControlChangeMsg(IMidiMsg::kAllNotesOff, 127, 0);
508 std::vector<unsigned char> message;
509 message.push_back( msg.mStatus );
510 message.push_back( msg.mData1 );
511 message.push_back( msg.mData2 );
513 gPluginInstance->ProcessMidiMsg(&msg);
515 if (gMidiIn)
517 gMidiIn->closePort();
519 if (port == 0)
521 return true;
523 #ifdef OS_WIN
524 else
526 gMidiIn->openPort(port-1);
527 return true;
529 #else
530 else if(port == 1)
532 std::string virtualMidiInputName = "To ";
533 virtualMidiInputName += BUNDLE_NAME;
534 gMidiIn->openVirtualPort(virtualMidiInputName);
535 return true;
537 else
539 gMidiIn->openPort(port-2);
540 return true;
542 #endif
545 return false;
548 bool ChooseMidiOutput(const char* pPortName)
550 unsigned int port = GetMIDIOutPortNumber(pPortName);
552 if(port == -1)
554 strcpy(gState->mMidiOutDev, "off");
555 UpdateINI();
556 port = 0;
559 if (gMidiOut)
562 IMidiMsg msg;
563 msg.MakeControlChangeMsg(IMidiMsg::kAllNotesOff, 127, 0);
565 std::vector<unsigned char> message;
566 message.push_back( msg.mStatus );
567 message.push_back( msg.mData1 );
568 message.push_back( msg.mData2 );
570 gMidiOut->sendMessage( &message );
572 gMidiOut->closePort();
574 if (port == 0)
576 return true;
578 #ifdef OS_WIN
579 else
581 gMidiOut->openPort(port-1);
582 return true;
584 #else
585 else if(port == 1)
587 std::string virtualMidiOutputName = "From ";
588 virtualMidiOutputName += BUNDLE_NAME;
589 gMidiOut->openVirtualPort(virtualMidiOutputName);
590 return true;
592 else
594 gMidiOut->openPort(port-2);
595 return true;
597 #endif
600 return false;
603 extern bool AttachGUI()
605 IGraphics* pGraphics = gPluginInstance->GetGUI();
607 if (pGraphics)
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)
618 gPluginInstance->OnGUIOpen();
619 return true;
623 return false;
626 void Init()
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
633 // Initialise the plugin
634 gPluginInstance = MakePlug(gMidiOut, &gState->mMidiOutChan);
635 gPluginInstance->RestorePreset(0);
637 ChooseMidiInput(gState->mMidiInDev);
638 ChooseMidiOutput(gState->mMidiOutDev);
640 TryToChangeAudio();
643 void Cleanup()
647 // Stop the stream
648 gDAC->stopStream();
650 catch (RtError& e)
652 e.printMessage();
655 gMidiIn->cancelCallback();
656 gMidiIn->closePort();
657 gMidiOut->closePort();
659 if ( gDAC->isStreamOpen() ) gDAC->closeStream();
661 delete gPluginInstance;
662 delete gState;
663 delete gTempState;
664 delete gActiveState;
665 delete gMidiIn;
666 delete gMidiOut;
667 delete gDAC;
668 delete [] gINIPath;
671 #ifdef OS_WIN
672 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nShowCmd)
674 // first check to make sure this is the only instance running
675 // http://www.bcbjournal.org/articles/vol3/9911/Single-instance_applications.htm
678 // Try to open the mutex.
679 HANDLE hMutex = OpenMutex(
680 MUTEX_ALL_ACCESS, 0, BUNDLE_NAME);
682 // If hMutex is 0 then the mutex doesn't exist.
683 if (!hMutex)
684 hMutex = CreateMutex(0, 0, BUNDLE_NAME);
685 else
687 // This is a second instance. Bring the
688 // original instance to the top.
689 HWND hWnd = FindWindow(0, BUNDLE_NAME);
690 SetForegroundWindow(hWnd);
692 return 0;
695 gHINST=hInstance;
697 InitCommonControls();
698 gScrollMessage = RegisterWindowMessage("MSWHEEL_ROLLMSG");
700 gState = new AppState();
701 gTempState = new AppState();
702 gActiveState = new AppState();
704 if (SHGetFolderPathA( NULL, CSIDL_LOCAL_APPDATA, NULL, 0, gINIPath ) != S_OK)
706 DBGMSG("could not retrieve the user's application data directory!\n");
708 //TODO error msg?
709 return 1;
712 sprintf(gINIPath, "%s\\%s", gINIPath, BUNDLE_NAME); // Add the app name to the path
714 struct stat st;
715 if(stat(gINIPath, &st) == 0) // if directory exists
717 sprintf(gINIPath, "%s\\%s", gINIPath, "settings.ini"); // add file name to path
719 if(stat(gINIPath, &st) == 0) // if settings file exists read values into state
721 gState->mAudioDriverType = GetPrivateProfileInt("audio", "driver", 0, gINIPath);
723 GetPrivateProfileString("audio", "indev", DEFAULT_INPUT_DEV, gState->mAudioInDev, 100, gINIPath);
724 GetPrivateProfileString("audio", "outdev", DEFAULT_OUTPUT_DEV, gState->mAudioOutDev, 100, gINIPath);
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);
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);
737 //midi
738 GetPrivateProfileString("midi", "indev", "no input", gState->mMidiInDev, 100, gINIPath);
739 GetPrivateProfileString("midi", "outdev", "no output", gState->mMidiOutDev, 100, gINIPath);
741 gState->mMidiInChan = GetPrivateProfileInt("midi", "inchan", 0, gINIPath); // 0 is any
742 gState->mMidiOutChan = GetPrivateProfileInt("midi", "outchan", 0, gINIPath); // 1 is first chan
744 UpdateINI(); // this will write over any invalid values in the file
746 else // settings file doesn't exist, so populate with default values
748 UpdateINI();
751 else
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
759 Init();
761 CreateDialog(gHINST,MAKEINTRESOURCE(IDD_DIALOG_MAIN),GetDesktopWindow(),MainDlgProc);
763 for(;;)
765 MSG msg= {0,};
766 int vvv = GetMessage(&msg,NULL,0,0);
767 if (!vvv) break;
769 if (vvv<0)
771 Sleep(10);
772 continue;
774 if (!msg.hwnd)
776 DispatchMessage(&msg);
777 continue;
780 if (gHWND && IsDialogMessage(gHWND,&msg)) continue;
782 // default processing for other dialogs
783 HWND hWndParent=NULL;
784 HWND temphwnd = msg.hwnd;
787 if (GetClassLong(temphwnd, GCW_ATOM) == (INT)32770)
789 hWndParent=temphwnd;
790 if (!(GetWindowLong(temphwnd,GWL_STYLE)&WS_CHILD)) break; // not a child, exit
793 while (temphwnd = GetParent(temphwnd));
795 if (hWndParent && IsDialogMessage(hWndParent,&msg)) continue;
797 TranslateMessage(&msg);
798 DispatchMessage(&msg);
802 // in case gHWND didnt get destroyed -- this corresponds to SWELLAPP_DESTROY roughly
803 if (gHWND) DestroyWindow(gHWND);
805 Cleanup();
807 ReleaseMutex(hMutex);
809 catch(...)
811 //TODO proper error catching
812 DBGMSG("another instance running");
814 return 0;
816 #else
818 extern HMENU SWELL_app_stocksysmenu;
819 const char *homeDir;
821 INT_PTR SWELLAppMain(int msg, INT_PTR parm1, INT_PTR parm2)
823 switch (msg)
825 case SWELLAPP_ONLOAD:
827 gState = new AppState();
828 gTempState = new AppState();
829 gActiveState = new AppState();
831 homeDir = getenv("HOME");
832 sprintf(gINIPath, "%s/Library/Application Support/%s/", homeDir, BUNDLE_NAME);
834 struct stat st;
835 if(stat(gINIPath, &st) == 0) // if directory exists
837 sprintf(gINIPath, "%s%s", gINIPath, "settings.ini"); // add file name to path
839 if(stat(gINIPath, &st) == 0) // if settings file exists read values into state
841 gState->mAudioDriverType = GetPrivateProfileInt("audio", "driver", 0, gINIPath);
843 GetPrivateProfileString("audio", "indev", "Built-in Input", gState->mAudioInDev, 100, gINIPath);
844 GetPrivateProfileString("audio", "outdev", "Built-in Output", gState->mAudioOutDev, 100, gINIPath);
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);
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);
857 //midi
858 GetPrivateProfileString("midi", "indev", "no input", gState->mMidiInDev, 100, gINIPath);
859 GetPrivateProfileString("midi", "outdev", "no output", gState->mMidiOutDev, 100, gINIPath);
861 gState->mMidiInChan = GetPrivateProfileInt("midi", "inchan", 0, gINIPath); // 0 is any
862 gState->mMidiOutChan = GetPrivateProfileInt("midi", "outchan", 0, gINIPath); // 1 is first chan
864 UpdateINI(); // this will write over any invalid values in the file
866 else // settings file doesn't exist, so populate with default values
868 UpdateINI();
872 else // folder doesn't exist - make folder and make file
874 // http://blog.tremend.ro/2008/10/06/create-directories-in-c-using-mkdir-with-proper-permissions/
876 mode_t process_mask = umask(0);
877 int result_code = mkdir(gINIPath, S_IRWXU | S_IRWXG | S_IRWXO);
878 umask(process_mask);
880 if(result_code) return 1;
881 else
883 sprintf(gINIPath, "%s%s", gINIPath, "settings.ini"); // add file name to path
884 UpdateINI(); // will write file if doesn't exist
887 break;
888 #pragma mark loaded
889 case SWELLAPP_LOADED:
891 Init();
893 HMENU menu = SWELL_GetCurrentMenu();
895 if (menu)
897 // other windows will get the stock (bundle) menus
898 //SWELL_SetDefaultModalWindowMenu(menu);
899 //SWELL_SetDefaultWindowMenu(menu);
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++)
907 HMENU sm = GetSubMenu(src,x);
908 if (sm)
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);
922 if (menu)
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
928 // remove any trailing separators
929 int a= GetMenuItemCount(sm);
930 while (a > 0 && GetMenuItemID(sm,a-1)==0) DeleteMenu(sm,--a,MF_BYPOSITION);
932 DeleteMenu(menu,1,MF_BYPOSITION); // delete file menu
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.
938 HWND hwnd = CreateDialog(gHINST,MAKEINTRESOURCE(IDD_DIALOG_MAIN),NULL,MainDlgProc);
939 if (menu)
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
944 // we need to set it manually (and obviously we've edited the menu anyway)
947 if(!AttachGUI()) DBGMSG("couldn't attach gui\n"); //todo error
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:
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;
964 return 0;
967 #endif
970 #ifndef OS_WIN
971 #include "swell-dlggen.h"
973 #define SET_IDD_SCALE 1.
974 #define SET_IDD_STYLE SWELL_DLG_WS_FLIPPED|SWELL_DLG_WS_NOAUTOSIZE
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
981 SWELL_DEFINE_DIALOG_RESOURCE_END(IDD_DIALOG_MAIN)
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
987 LTEXT "Driver Type", IDC_STATIC, 20, 32, 60, 20
988 COMBOBOX IDC_COMBO_AUDIO_DRIVER, 20, 50, 150, 100, CBS_DROPDOWNLIST
990 LTEXT "Input Device", IDC_STATIC, 20, 75, 80, 20
991 COMBOBOX IDC_COMBO_AUDIO_IN_DEV, 20, 90, 150, 100, CBS_DROPDOWNLIST
993 LTEXT "Output Device", IDC_STATIC, 20, 115, 80, 20
994 COMBOBOX IDC_COMBO_AUDIO_OUT_DEV, 20, 130, 150, 100, CBS_DROPDOWNLIST
996 LTEXT "In 1 (L)", IDC_STATIC, 20, 155, 90, 20
997 COMBOBOX IDC_COMBO_AUDIO_IN_L, 20, 170, 46, 100, CBS_DROPDOWNLIST
999 LTEXT "In 2 (R)", IDC_STATIC, 75, 155, 90, 20
1000 COMBOBOX IDC_COMBO_AUDIO_IN_R, 75, 170, 46, 100, CBS_DROPDOWNLIST
1002 CHECKBOX "Mono", IDC_CB_MONO_INPUT, 125, 128, 56, 100, 0
1004 LTEXT "Out 1 (L)", IDC_STATIC, 20, 195, 60, 20
1005 COMBOBOX IDC_COMBO_AUDIO_OUT_L, 20, 210, 46, 100, CBS_DROPDOWNLIST
1007 LTEXT "Out 2 (R)", IDC_STATIC, 75, 195, 60, 20
1008 COMBOBOX IDC_COMBO_AUDIO_OUT_R, 75, 210, 46, 100, CBS_DROPDOWNLIST
1010 LTEXT "IO Vector Size", IDC_STATIC, 200, 32, 80, 20
1011 COMBOBOX IDC_COMBO_AUDIO_IOVS, 200, 50, 90, 100, CBS_DROPDOWNLIST
1013 LTEXT "Signal Vector Size", IDC_STATIC, 200, 75, 100, 20
1014 COMBOBOX IDC_COMBO_AUDIO_SIGVS, 200, 90, 90, 100, CBS_DROPDOWNLIST
1016 LTEXT "Sampling Rate", IDC_STATIC, 200, 115, 80, 20
1017 COMBOBOX IDC_COMBO_AUDIO_SR, 200, 130, 90, 100, CBS_DROPDOWNLIST
1019 PUSHBUTTON "Audio Midi Setup...", IDC_BUTTON_ASIO, 180, 170, 110, 40
1021 GROUPBOX "MIDI Settings", IDC_STATIC, 5, 255, 300, 120
1023 LTEXT "Input Device", IDC_STATIC, 20, 275, 100, 20
1024 COMBOBOX IDC_COMBO_MIDI_IN_DEV, 20, 293, 150, 100, CBS_DROPDOWNLIST
1026 LTEXT "Output Device", IDC_STATIC, 20, 320, 100, 20
1027 COMBOBOX IDC_COMBO_MIDI_OUT_DEV, 20, 338, 150, 100, CBS_DROPDOWNLIST
1029 LTEXT "Input Channel", IDC_STATIC, 200, 275, 100, 20
1030 COMBOBOX IDC_COMBO_MIDI_IN_CHAN, 200, 293, 90, 100, CBS_DROPDOWNLIST
1032 LTEXT "Output Channel", IDC_STATIC, 200, 320, 100, 20
1033 COMBOBOX IDC_COMBO_MIDI_OUT_CHAN, 200, 338, 90, 100, CBS_DROPDOWNLIST
1035 DEFPUSHBUTTON "OK", IDOK, 192, 383, 50, 20
1036 PUSHBUTTON "Apply", IDAPPLY, 132, 383, 50, 20
1037 PUSHBUTTON "Cancel", IDCANCEL, 252, 383, 50, 20
1039 SWELL_DEFINE_DIALOG_RESOURCE_END(IDD_DIALOG_PREF)
1041 #include "swell-menugen.h"
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
1050 POPUP "&Help"
1051 BEGIN
1052 MENUITEM "&About", ID_ABOUT
1054 SWELL_DEFINE_MENU_RESOURCE_END(IDR_MENU1)
1056 #endif