Mercurial > hg > apm2s
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app_wrapper/app_main.cpp Sat Jun 13 15:08:10 2015 +0100 @@ -0,0 +1,1056 @@ +#include "app_main.h" + +#ifdef OS_WIN + #include <windows.h> + #include <shlobj.h> + #include <sys/stat.h> +#endif + +HWND gHWND; + +HINSTANCE gHINST; +UINT gScrollMessage; +IPlug* gPluginInstance; +RtAudio* gDAC = 0; +RtMidiIn *gMidiIn = 0; +RtMidiOut *gMidiOut = 0; + +AppState *gState; +AppState *gTempState; +AppState *gActiveState; + +char *gINIPath = new char[200]; // path of ini file + +unsigned int gIOVS = 512; +unsigned int gSigVS = 32; +unsigned int gBufIndex = 0; // Loops 0 to SigVS +unsigned int gVecElapsed = 0; +double gFadeMult = 0.; // Fade multiplier + +std::vector<unsigned int> gAudioInputDevs; +std::vector<unsigned int> gAudioOutputDevs; +std::vector<std::string> gMIDIInputDevNames; +std::vector<std::string> gMIDIOutputDevNames; +std::vector<std::string> gAudioIDDevNames; + +void UpdateINI() +{ + char buf[100]; // temp buffer for writing integers to profile strings + + sprintf(buf, "%u", gState->mAudioDriverType); + WritePrivateProfileString("audio", "driver", buf, gINIPath); + + WritePrivateProfileString("audio", "indev", gState->mAudioInDev, gINIPath); + WritePrivateProfileString("audio", "outdev", gState->mAudioOutDev, gINIPath); + + sprintf(buf, "%u", gState->mAudioInChanL); + WritePrivateProfileString("audio", "in1", buf, gINIPath); + sprintf(buf, "%u", gState->mAudioInChanR); + WritePrivateProfileString("audio", "in2", buf, gINIPath); + sprintf(buf, "%u", gState->mAudioOutChanL); + WritePrivateProfileString("audio", "out1", buf, gINIPath); + sprintf(buf, "%u", gState->mAudioOutChanR); + WritePrivateProfileString("audio", "out2", buf, gINIPath); + sprintf(buf, "%u", gState->mAudioInIsMono); + WritePrivateProfileString("audio", "monoinput", buf, gINIPath); + + WritePrivateProfileString("audio", "iovs", gState->mAudioIOVS, gINIPath); + WritePrivateProfileString("audio", "sigvs", gState->mAudioSigVS, gINIPath); + + WritePrivateProfileString("audio", "sr", gState->mAudioSR, gINIPath); + + WritePrivateProfileString("midi", "indev", gState->mMidiInDev, gINIPath); + WritePrivateProfileString("midi", "outdev", gState->mMidiOutDev, gINIPath); + + sprintf(buf, "%u", gState->mMidiInChan); + WritePrivateProfileString("midi", "inchan", buf, gINIPath); + sprintf(buf, "%u", gState->mMidiOutChan); + WritePrivateProfileString("midi", "outchan", buf, gINIPath); +} + +// returns the device name. Core Audio device names are truncated +std::string GetAudioDeviceName(int idx) +{ + return gAudioIDDevNames.at(idx); +} + +// returns the rtaudio device ID, based on the (truncated) device name +int GetAudioDeviceID(char* deviceNameToTest) +{ + TRACE; + + for(int i = 0; i < gAudioIDDevNames.size(); i++) + { + if(!strcmp(deviceNameToTest, gAudioIDDevNames.at(i).c_str() )) + return i; + } + + return -1; +} + +unsigned int GetMIDIInPortNumber(const char* nameToTest) +{ + int start = 1; + + if(!strcmp(nameToTest, "off")) return 0; + + #ifdef OS_OSX + start = 2; + if(!strcmp(nameToTest, "virtual input")) return 1; + #endif + + for (int i = 0; i < gMidiIn->getPortCount(); i++) + { + if(!strcmp(nameToTest, gMidiIn->getPortName(i).c_str())) + return (i + start); + } + + return -1; +} + +unsigned int GetMIDIOutPortNumber(const char* nameToTest) +{ + int start = 1; + + if(!strcmp(nameToTest, "off")) return 0; + + #ifdef OS_OSX + start = 2; + if(!strcmp(nameToTest, "virtual output")) return 1; + #endif + + for (int i = 0; i < gMidiOut->getPortCount(); i++) + { + if(!strcmp(nameToTest, gMidiOut->getPortName(i).c_str())) + return (i + start); + } + + return -1; +} + +// find out which devices have input channels & which have output channels, add their ids to the lists +void ProbeAudioIO() +{ + TRACE; + + RtAudio::DeviceInfo info; + + gAudioInputDevs.clear(); + gAudioOutputDevs.clear(); + gAudioIDDevNames.clear(); + + unsigned int nDevices = gDAC->getDeviceCount(); + + for (int i=0; i<nDevices; i++) + { + info = gDAC->getDeviceInfo(i); + std::string deviceName = info.name; + + #ifdef OS_OSX + size_t colonIdx = deviceName.rfind(": "); + + if(colonIdx != std::string::npos && deviceName.length() >= 2) + deviceName = deviceName.substr(colonIdx + 2, deviceName.length() - colonIdx - 2); + + #endif + + gAudioIDDevNames.push_back(deviceName); + + if ( info.probed == false ) + std::cout << deviceName << ": Probe Status = Unsuccessful\n"; + else if ( !strcmp("Generic Low Latency ASIO Driver", deviceName.c_str() )) + std::cout << deviceName << ": Probe Status = Unsuccessful\n"; + else + { + if(info.inputChannels > 0) + gAudioInputDevs.push_back(i); + + if(info.outputChannels > 0) + gAudioOutputDevs.push_back(i); + } + } +} + +void ProbeMidiIO() +{ + if ( !gMidiIn || !gMidiOut ) + return; + else + { + int nInputPorts = gMidiIn->getPortCount(); + + gMIDIInputDevNames.push_back("off"); + + #ifndef OS_WIN + gMIDIInputDevNames.push_back("virtual input"); + #endif + + for (int i=0; i<nInputPorts; i++ ) + { + gMIDIInputDevNames.push_back(gMidiIn->getPortName(i)); + } + + int nOutputPorts = gMidiOut->getPortCount(); + + gMIDIOutputDevNames.push_back("off"); + +#ifndef _WIN32 + gMIDIOutputDevNames.push_back("virtual output"); +#endif + + for (int i=0; i<nOutputPorts; i++ ) + { + gMIDIOutputDevNames.push_back(gMidiOut->getPortName(i)); + //This means the virtual output port wont be added as an input + } + } +} + +bool AudioSettingsInStateAreEqual(AppState* os, AppState* ns) +{ + if (os->mAudioDriverType != ns->mAudioDriverType) return false; + if (strcmp(os->mAudioInDev, ns->mAudioInDev)) return false; + if (strcmp(os->mAudioOutDev, ns->mAudioOutDev)) return false; + if (strcmp(os->mAudioSR, ns->mAudioSR)) return false; + if (strcmp(os->mAudioIOVS, ns->mAudioIOVS)) return false; + if (strcmp(os->mAudioSigVS, ns->mAudioSigVS)) return false; + if (os->mAudioInChanL != ns->mAudioInChanL) return false; + if (os->mAudioInChanR != ns->mAudioInChanR) return false; + if (os->mAudioOutChanL != ns->mAudioOutChanL) return false; + if (os->mAudioOutChanR != ns->mAudioOutChanR) return false; + if (os->mAudioInIsMono != ns->mAudioInIsMono) return false; + + return true; +} + +bool MIDISettingsInStateAreEqual(AppState* os, AppState* ns) +{ + if (strcmp(os->mMidiInDev, ns->mMidiInDev)) return false; + if (strcmp(os->mMidiOutDev, ns->mMidiOutDev)) return false; + if (os->mMidiInChan != ns->mMidiInChan) return false; + if (os->mMidiOutChan != ns->mMidiOutChan) return false; + + return true; +} + +void MIDICallback( double deltatime, std::vector< unsigned char > *message, void *userData ) +{ + if ( message->size() ) + { + IMidiMsg *myMsg; + + switch (message->size()) + { + case 1: + myMsg = new IMidiMsg(0, message->at(0), 0, 0); + break; + case 2: + myMsg = new IMidiMsg(0, message->at(0), message->at(1), 0); + break; + case 3: + myMsg = new IMidiMsg(0, message->at(0), message->at(1), message->at(2)); + break; + default: + DBGMSG("NOT EXPECTING %d midi callback msg len\n", (int) message->size()); + break; + } + + IMidiMsg msg(*myMsg); + + delete myMsg; + + // filter midi messages based on channel, if gStatus.mMidiInChan != all (0) + if (gState->mMidiInChan) + { + if (gState->mMidiInChan == msg.Channel() + 1 ) + gPluginInstance->ProcessMidiMsg(&msg); + } + else + { + gPluginInstance->ProcessMidiMsg(&msg); + } + } +} + +int AudioCallback(void *outputBuffer, + void *inputBuffer, + unsigned int nFrames, + double streamTime, + RtAudioStreamStatus status, + void *userData ) +{ + if ( status ) + std::cout << "Stream underflow detected!" << std::endl; + + double* inputBufferD = (double*)inputBuffer; + double* outputBufferD = (double*)outputBuffer; + + int inRightOffset = 0; + + if(!gState->mAudioInIsMono) + inRightOffset = nFrames; + + if (gVecElapsed > N_VECTOR_WAIT) // wait N_VECTOR_WAIT * iovs before processing audio, to avoid clicks + { + for (int i=0; i<nFrames; i++) + { + gBufIndex %= gSigVS; + + if (gBufIndex == 0) + { + double* inputs[2] = {inputBufferD + i, inputBufferD + inRightOffset + i}; + double* outputs[2] = {outputBufferD + i, outputBufferD + nFrames + i}; + + gPluginInstance->LockMutexAndProcessDoubleReplacing(inputs, outputs, gSigVS); + } + + // fade in + if (gFadeMult < 1.) + { + gFadeMult += (1. / nFrames); + } + + outputBufferD[i] *= gFadeMult; + outputBufferD[i + nFrames] *= gFadeMult; + + outputBufferD[i] *= APP_MULT; + outputBufferD[i + nFrames] *= APP_MULT; + + gBufIndex++; + } + } + else + { + memset(outputBuffer, 0, nFrames * 2 * sizeof(double)); + } + + gVecElapsed++; + + return 0; +} + +bool TryToChangeAudioDriverType() +{ + TRACE; + + if (gDAC) + { + if (gDAC->isStreamOpen()) + { + gDAC->closeStream(); + } + + DELETE_NULL(gDAC); + } + +#ifdef OS_WIN + if(gState->mAudioDriverType == DAC_ASIO) + gDAC = new RtAudio(RtAudio::WINDOWS_ASIO); + else + gDAC = new RtAudio(RtAudio::WINDOWS_DS); +#elif defined OS_OSX + if(gState->mAudioDriverType == DAC_COREAUDIO) + gDAC = new RtAudio(RtAudio::MACOSX_CORE); + //else + //gDAC = new RtAudio(RtAudio::UNIX_JACK); +#endif + + if(gDAC) + return true; + else + return false; +} + +bool TryToChangeAudio() +{ + TRACE; + + int inputID = -1; + int outputID = -1; + +#ifdef OS_WIN + if(gState->mAudioDriverType == DAC_ASIO) + inputID = GetAudioDeviceID(gState->mAudioOutDev); + else + inputID = GetAudioDeviceID(gState->mAudioInDev); +#else + inputID = GetAudioDeviceID(gState->mAudioInDev); +#endif + + outputID = GetAudioDeviceID(gState->mAudioOutDev); + + int samplerate = atoi(gState->mAudioSR); + int iovs = atoi(gState->mAudioIOVS); + + if (inputID != -1 && outputID != -1) + { + return InitialiseAudio(inputID, outputID, samplerate, iovs, NUM_CHANNELS, gState->mAudioInChanL - 1, gState->mAudioOutChanL - 1); + } + + return false; +} + +bool InitialiseAudio(unsigned int inId, + unsigned int outId, + unsigned int sr, + unsigned int iovs, + unsigned int chnls, + unsigned int inChanL, + unsigned int outChanL + ) +{ + TRACE; + + if (gDAC->isStreamOpen()) + { + if (gDAC->isStreamRunning()) + { + try + { + gDAC->abortStream(); + } + catch (RtError& e) + { + e.printMessage(); + } + } + + gDAC->closeStream(); + } + + RtAudio::StreamParameters iParams, oParams; + iParams.deviceId = inId; + iParams.nChannels = chnls; + iParams.firstChannel = inChanL; + + oParams.deviceId = outId; + oParams.nChannels = chnls; + oParams.firstChannel = outChanL; + + gIOVS = iovs; // gIOVS may get changed by stream + gSigVS = atoi(gState->mAudioSigVS); // This is done here so that it changes when the callback is stopped + + 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()); + + RtAudio::StreamOptions options; + options.flags = RTAUDIO_NONINTERLEAVED; +// options.streamName = BUNDLE_NAME; // JACK stream name, not used on other streams + + gBufIndex = 0; + gVecElapsed = 0; + gFadeMult = 0.; + + gPluginInstance->SetBlockSize(gSigVS); + gPluginInstance->SetSampleRate(sr); + gPluginInstance->Reset(); + + try + { + TRACE; + gDAC->openStream( &oParams, &iParams, RTAUDIO_FLOAT64, sr, &gIOVS, &AudioCallback, NULL, &options); + gDAC->startStream(); + + memcpy(gActiveState, gState, sizeof(AppState)); // copy state to active state + } + catch ( RtError& e ) + { + e.printMessage(); + return false; + } + + return true; +} + +bool InitialiseMidi() +{ + try + { + gMidiIn = new RtMidiIn(); + } + catch ( RtError &error ) + { + FREE_NULL(gMidiIn); + error.printMessage(); + return false; + } + + try + { + gMidiOut = new RtMidiOut(); + } + catch ( RtError &error ) + { + FREE_NULL(gMidiOut); + error.printMessage(); + return false; + } + + gMidiIn->setCallback( &MIDICallback ); + gMidiIn->ignoreTypes( !ENABLE_SYSEX, !ENABLE_MIDICLOCK, !ENABLE_ACTIVE_SENSING ); + + return true; +} + +bool ChooseMidiInput(const char* pPortName) +{ + unsigned int port = GetMIDIInPortNumber(pPortName); + + if(port == -1) + { + strcpy(gState->mMidiInDev, "off"); + UpdateINI(); + port = 0; + } + /* + IMidiMsg msg; + msg.MakeControlChangeMsg(IMidiMsg::kAllNotesOff, 127, 0); + + std::vector<unsigned char> message; + message.push_back( msg.mStatus ); + message.push_back( msg.mData1 ); + message.push_back( msg.mData2 ); + + gPluginInstance->ProcessMidiMsg(&msg); + */ + if (gMidiIn) + { + gMidiIn->closePort(); + + if (port == 0) + { + return true; + } + #ifdef OS_WIN + else + { + gMidiIn->openPort(port-1); + return true; + } + #else + else if(port == 1) + { + std::string virtualMidiInputName = "To "; + virtualMidiInputName += BUNDLE_NAME; + gMidiIn->openVirtualPort(virtualMidiInputName); + return true; + } + else + { + gMidiIn->openPort(port-2); + return true; + } + #endif + } + + return false; +} + +bool ChooseMidiOutput(const char* pPortName) +{ + unsigned int port = GetMIDIOutPortNumber(pPortName); + + if(port == -1) + { + strcpy(gState->mMidiOutDev, "off"); + UpdateINI(); + port = 0; + } + + if (gMidiOut) + { + /* + IMidiMsg msg; + msg.MakeControlChangeMsg(IMidiMsg::kAllNotesOff, 127, 0); + + std::vector<unsigned char> message; + message.push_back( msg.mStatus ); + message.push_back( msg.mData1 ); + message.push_back( msg.mData2 ); + + gMidiOut->sendMessage( &message ); + */ + gMidiOut->closePort(); + + if (port == 0) + { + return true; + } + #ifdef OS_WIN + else + { + gMidiOut->openPort(port-1); + return true; + } + #else + else if(port == 1) + { + std::string virtualMidiOutputName = "From "; + virtualMidiOutputName += BUNDLE_NAME; + gMidiOut->openVirtualPort(virtualMidiOutputName); + return true; + } + else + { + gMidiOut->openPort(port-2); + return true; + } + #endif + } + + return false; +} + +extern bool AttachGUI() +{ + IGraphics* pGraphics = gPluginInstance->GetGUI(); + + if (pGraphics) + { +#ifdef OS_WIN + if (!pGraphics->OpenWindow(gHWND)) + pGraphics=0; +#else // Cocoa OSX + if (!pGraphics->OpenWindow(gHWND)) + pGraphics=0; +#endif + if (pGraphics) + { + gPluginInstance->OnGUIOpen(); + return true; + } + } + + return false; +} + +void Init() +{ + TryToChangeAudioDriverType(); // will init RTAudio with an API type based on gState->mAudioDriverType + ProbeAudioIO(); // find out what audio IO devs are available and put their IDs in the global variables gAudioInputDevs / gAudioOutputDevs + InitialiseMidi(); // creates RTMidiIn and RTMidiOut objects + ProbeMidiIO(); // find out what midi IO devs are available and put their names in the global variables gMidiInputDevs / gMidiOutputDevs + + // Initialise the plugin + gPluginInstance = MakePlug(gMidiOut, &gState->mMidiOutChan); + gPluginInstance->RestorePreset(0); + + ChooseMidiInput(gState->mMidiInDev); + ChooseMidiOutput(gState->mMidiOutDev); + + TryToChangeAudio(); +} + +void Cleanup() +{ + try + { + // Stop the stream + gDAC->stopStream(); + } + catch (RtError& e) + { + e.printMessage(); + } + + gMidiIn->cancelCallback(); + gMidiIn->closePort(); + gMidiOut->closePort(); + + if ( gDAC->isStreamOpen() ) gDAC->closeStream(); + + delete gPluginInstance; + delete gState; + delete gTempState; + delete gActiveState; + delete gMidiIn; + delete gMidiOut; + delete gDAC; + delete [] gINIPath; +} + +#ifdef OS_WIN +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nShowCmd) +{ + // first check to make sure this is the only instance running + // http://www.bcbjournal.org/articles/vol3/9911/Single-instance_applications.htm + try + { + // Try to open the mutex. + HANDLE hMutex = OpenMutex( + MUTEX_ALL_ACCESS, 0, BUNDLE_NAME); + + // If hMutex is 0 then the mutex doesn't exist. + if (!hMutex) + hMutex = CreateMutex(0, 0, BUNDLE_NAME); + else + { + // This is a second instance. Bring the + // original instance to the top. + HWND hWnd = FindWindow(0, BUNDLE_NAME); + SetForegroundWindow(hWnd); + + return 0; + } + + gHINST=hInstance; + + InitCommonControls(); + gScrollMessage = RegisterWindowMessage("MSWHEEL_ROLLMSG"); + + gState = new AppState(); + gTempState = new AppState(); + gActiveState = new AppState(); + + if (SHGetFolderPathA( NULL, CSIDL_LOCAL_APPDATA, NULL, 0, gINIPath ) != S_OK) + { + DBGMSG("could not retrieve the user's application data directory!\n"); + + //TODO error msg? + return 1; + } + + sprintf(gINIPath, "%s\\%s", gINIPath, BUNDLE_NAME); // Add the app name to the path + + struct stat st; + if(stat(gINIPath, &st) == 0) // if directory exists + { + sprintf(gINIPath, "%s\\%s", gINIPath, "settings.ini"); // add file name to path + + if(stat(gINIPath, &st) == 0) // if settings file exists read values into state + { + gState->mAudioDriverType = GetPrivateProfileInt("audio", "driver", 0, gINIPath); + + GetPrivateProfileString("audio", "indev", DEFAULT_INPUT_DEV, gState->mAudioInDev, 100, gINIPath); + GetPrivateProfileString("audio", "outdev", DEFAULT_OUTPUT_DEV, gState->mAudioOutDev, 100, gINIPath); + + //audio + gState->mAudioInChanL = GetPrivateProfileInt("audio", "in1", 1, gINIPath); // 1 is first audio input + gState->mAudioInChanR = GetPrivateProfileInt("audio", "in2", 2, gINIPath); + gState->mAudioOutChanL = GetPrivateProfileInt("audio", "out1", 1, gINIPath); // 1 is first audio output + gState->mAudioOutChanR = GetPrivateProfileInt("audio", "out2", 2, gINIPath); + gState->mAudioInIsMono = GetPrivateProfileInt("audio", "monoinput", 0, gINIPath); + + GetPrivateProfileString("audio", "iovs", "512", gState->mAudioIOVS, 100, gINIPath); + GetPrivateProfileString("audio", "sigvs", "32", gState->mAudioSigVS, 100, gINIPath); + GetPrivateProfileString("audio", "sr", "44100", gState->mAudioSR, 100, gINIPath); + + //midi + GetPrivateProfileString("midi", "indev", "no input", gState->mMidiInDev, 100, gINIPath); + GetPrivateProfileString("midi", "outdev", "no output", gState->mMidiOutDev, 100, gINIPath); + + gState->mMidiInChan = GetPrivateProfileInt("midi", "inchan", 0, gINIPath); // 0 is any + gState->mMidiOutChan = GetPrivateProfileInt("midi", "outchan", 0, gINIPath); // 1 is first chan + + UpdateINI(); // this will write over any invalid values in the file + } + else // settings file doesn't exist, so populate with default values + { + UpdateINI(); + } + } + else + { + // folder doesn't exist - make folder and make file + CreateDirectory(gINIPath, NULL); + sprintf(gINIPath, "%s%s", gINIPath, "settings.ini"); // add file name to path + UpdateINI(); // will write file if doesn't exist + } + + Init(); + + CreateDialog(gHINST,MAKEINTRESOURCE(IDD_DIALOG_MAIN),GetDesktopWindow(),MainDlgProc); + + for(;;) + { + MSG msg= {0,}; + int vvv = GetMessage(&msg,NULL,0,0); + if (!vvv) break; + + if (vvv<0) + { + Sleep(10); + continue; + } + if (!msg.hwnd) + { + DispatchMessage(&msg); + continue; + } + + if (gHWND && IsDialogMessage(gHWND,&msg)) continue; + + // default processing for other dialogs + HWND hWndParent=NULL; + HWND temphwnd = msg.hwnd; + do + { + if (GetClassLong(temphwnd, GCW_ATOM) == (INT)32770) + { + hWndParent=temphwnd; + if (!(GetWindowLong(temphwnd,GWL_STYLE)&WS_CHILD)) break; // not a child, exit + } + } + while (temphwnd = GetParent(temphwnd)); + + if (hWndParent && IsDialogMessage(hWndParent,&msg)) continue; + + TranslateMessage(&msg); + DispatchMessage(&msg); + + } + + // in case gHWND didnt get destroyed -- this corresponds to SWELLAPP_DESTROY roughly + if (gHWND) DestroyWindow(gHWND); + + Cleanup(); + + ReleaseMutex(hMutex); + } + catch(...) + { + //TODO proper error catching + DBGMSG("another instance running"); + } + return 0; +} +#else + +extern HMENU SWELL_app_stocksysmenu; +const char *homeDir; + +INT_PTR SWELLAppMain(int msg, INT_PTR parm1, INT_PTR parm2) +{ + switch (msg) + { + case SWELLAPP_ONLOAD: + + gState = new AppState(); + gTempState = new AppState(); + gActiveState = new AppState(); + + homeDir = getenv("HOME"); + sprintf(gINIPath, "%s/Library/Application Support/%s/", homeDir, BUNDLE_NAME); + + struct stat st; + if(stat(gINIPath, &st) == 0) // if directory exists + { + sprintf(gINIPath, "%s%s", gINIPath, "settings.ini"); // add file name to path + + if(stat(gINIPath, &st) == 0) // if settings file exists read values into state + { + gState->mAudioDriverType = GetPrivateProfileInt("audio", "driver", 0, gINIPath); + + GetPrivateProfileString("audio", "indev", "Built-in Input", gState->mAudioInDev, 100, gINIPath); + GetPrivateProfileString("audio", "outdev", "Built-in Output", gState->mAudioOutDev, 100, gINIPath); + + //audio + gState->mAudioInChanL = GetPrivateProfileInt("audio", "in1", 1, gINIPath); // 1 is first audio input + gState->mAudioInChanR = GetPrivateProfileInt("audio", "in2", 2, gINIPath); + gState->mAudioOutChanL = GetPrivateProfileInt("audio", "out1", 1, gINIPath); // 1 is first audio output + gState->mAudioOutChanR = GetPrivateProfileInt("audio", "out2", 2, gINIPath); + gState->mAudioInIsMono = GetPrivateProfileInt("audio", "monoinput", 0, gINIPath); + + GetPrivateProfileString("audio", "iovs", "512", gState->mAudioIOVS, 100, gINIPath); + GetPrivateProfileString("audio", "sigvs", "32", gState->mAudioSigVS, 100, gINIPath); + GetPrivateProfileString("audio", "sr", "44100", gState->mAudioSR, 100, gINIPath); + + //midi + GetPrivateProfileString("midi", "indev", "no input", gState->mMidiInDev, 100, gINIPath); + GetPrivateProfileString("midi", "outdev", "no output", gState->mMidiOutDev, 100, gINIPath); + + gState->mMidiInChan = GetPrivateProfileInt("midi", "inchan", 0, gINIPath); // 0 is any + gState->mMidiOutChan = GetPrivateProfileInt("midi", "outchan", 0, gINIPath); // 1 is first chan + + UpdateINI(); // this will write over any invalid values in the file + } + else // settings file doesn't exist, so populate with default values + { + UpdateINI(); + } + + } + else // folder doesn't exist - make folder and make file + { + // http://blog.tremend.ro/2008/10/06/create-directories-in-c-using-mkdir-with-proper-permissions/ + + mode_t process_mask = umask(0); + int result_code = mkdir(gINIPath, S_IRWXU | S_IRWXG | S_IRWXO); + umask(process_mask); + + if(result_code) return 1; + else + { + sprintf(gINIPath, "%s%s", gINIPath, "settings.ini"); // add file name to path + UpdateINI(); // will write file if doesn't exist + } + } + break; +#pragma mark loaded + case SWELLAPP_LOADED: + { + Init(); + + HMENU menu = SWELL_GetCurrentMenu(); + + if (menu) + { + // other windows will get the stock (bundle) menus + //SWELL_SetDefaultModalWindowMenu(menu); + //SWELL_SetDefaultWindowMenu(menu); + + // work on a new menu + menu = SWELL_DuplicateMenu(menu); + HMENU src = LoadMenu(NULL,MAKEINTRESOURCE(IDR_MENU1)); + int x; + for (x=0; x<GetMenuItemCount(src)-1; x++) + { + HMENU sm = GetSubMenu(src,x); + if (sm) + { + char str[1024]; + MENUITEMINFO mii= {sizeof(mii),MIIM_TYPE,}; + mii.dwTypeData=str; + mii.cch=sizeof(str); + str[0]=0; + GetMenuItemInfo(src,x,TRUE,&mii); + MENUITEMINFO mi= {sizeof(mi),MIIM_STATE|MIIM_SUBMENU|MIIM_TYPE,MFT_STRING,0,0,SWELL_DuplicateMenu(sm),NULL,NULL,0,str}; + InsertMenuItem(menu,x+1,TRUE,&mi); + } + } + } + + if (menu) + { + HMENU sm=GetSubMenu(menu,1); + DeleteMenu(sm,ID_QUIT,MF_BYCOMMAND); // remove QUIT from our file menu, since it is in the system menu on OSX + DeleteMenu(sm,ID_PREFERENCES,MF_BYCOMMAND); // remove PREFERENCES from the file menu, since it is in the system menu on OSX + + // remove any trailing separators + int a= GetMenuItemCount(sm); + while (a > 0 && GetMenuItemID(sm,a-1)==0) DeleteMenu(sm,--a,MF_BYPOSITION); + + DeleteMenu(menu,1,MF_BYPOSITION); // delete file menu + } + + // if we want to set any default modifiers for items in the menus, we can use: + // SetMenuItemModifier(menu,commandID,MF_BYCOMMAND,'A',FCONTROL) etc. + + HWND hwnd = CreateDialog(gHINST,MAKEINTRESOURCE(IDD_DIALOG_MAIN),NULL,MainDlgProc); + if (menu) + { + SetMenu(hwnd, menu); // set the menu for the dialog to our menu (on Windows that menu is set from the .rc, but on SWELL + SWELL_SetDefaultModalWindowMenu(menu); // other windows will get the stock (bundle) menus + } + // we need to set it manually (and obviously we've edited the menu anyway) + } + + if(!AttachGUI()) DBGMSG("couldn't attach gui\n"); //todo error + + break; + case SWELLAPP_ONCOMMAND: + // this is to catch commands coming from the system menu etc + if (gHWND && (parm1&0xffff)) SendMessage(gHWND,WM_COMMAND,parm1&0xffff,0); + break; +#pragma mark destroy + case SWELLAPP_DESTROY: + + if (gHWND) DestroyWindow(gHWND); + Cleanup(); + break; + case SWELLAPP_PROCESSMESSAGE: // can hook keyboard input here + // parm1 = (MSG*), should we want it -- look in swell.h to see what the return values refer to + break; + } + return 0; +} + +#endif + + +#ifndef OS_WIN +#include "swell-dlggen.h" + +#define SET_IDD_SCALE 1. +#define SET_IDD_STYLE SWELL_DLG_WS_FLIPPED|SWELL_DLG_WS_NOAUTOSIZE + +SWELL_DEFINE_DIALOG_RESOURCE_BEGIN(IDD_DIALOG_MAIN, SET_IDD_STYLE, BUNDLE_NAME, GUI_WIDTH, GUI_HEIGHT, SET_IDD_SCALE) +BEGIN +// EDITTEXT IDC_EDIT1,59,50,145,14,ES_AUTOHSCROLL +// LTEXT "Enter some text here:",IDC_STATIC,59,39,73,8 +END +SWELL_DEFINE_DIALOG_RESOURCE_END(IDD_DIALOG_MAIN) + +SWELL_DEFINE_DIALOG_RESOURCE_BEGIN(IDD_DIALOG_PREF,SET_IDD_STYLE,"Preferences",320,420,SET_IDD_SCALE) +BEGIN +GROUPBOX "Audio Settings", IDC_STATIC, 5, 10, 300, 230 + +LTEXT "Driver Type", IDC_STATIC, 20, 32, 60, 20 +COMBOBOX IDC_COMBO_AUDIO_DRIVER, 20, 50, 150, 100, CBS_DROPDOWNLIST + +LTEXT "Input Device", IDC_STATIC, 20, 75, 80, 20 +COMBOBOX IDC_COMBO_AUDIO_IN_DEV, 20, 90, 150, 100, CBS_DROPDOWNLIST + +LTEXT "Output Device", IDC_STATIC, 20, 115, 80, 20 +COMBOBOX IDC_COMBO_AUDIO_OUT_DEV, 20, 130, 150, 100, CBS_DROPDOWNLIST + +LTEXT "In 1 (L)", IDC_STATIC, 20, 155, 90, 20 +COMBOBOX IDC_COMBO_AUDIO_IN_L, 20, 170, 46, 100, CBS_DROPDOWNLIST + +LTEXT "In 2 (R)", IDC_STATIC, 75, 155, 90, 20 +COMBOBOX IDC_COMBO_AUDIO_IN_R, 75, 170, 46, 100, CBS_DROPDOWNLIST + +CHECKBOX "Mono", IDC_CB_MONO_INPUT, 125, 128, 56, 100, 0 + +LTEXT "Out 1 (L)", IDC_STATIC, 20, 195, 60, 20 +COMBOBOX IDC_COMBO_AUDIO_OUT_L, 20, 210, 46, 100, CBS_DROPDOWNLIST + +LTEXT "Out 2 (R)", IDC_STATIC, 75, 195, 60, 20 +COMBOBOX IDC_COMBO_AUDIO_OUT_R, 75, 210, 46, 100, CBS_DROPDOWNLIST + +LTEXT "IO Vector Size", IDC_STATIC, 200, 32, 80, 20 +COMBOBOX IDC_COMBO_AUDIO_IOVS, 200, 50, 90, 100, CBS_DROPDOWNLIST + +LTEXT "Signal Vector Size", IDC_STATIC, 200, 75, 100, 20 +COMBOBOX IDC_COMBO_AUDIO_SIGVS, 200, 90, 90, 100, CBS_DROPDOWNLIST + +LTEXT "Sampling Rate", IDC_STATIC, 200, 115, 80, 20 +COMBOBOX IDC_COMBO_AUDIO_SR, 200, 130, 90, 100, CBS_DROPDOWNLIST + +PUSHBUTTON "Audio Midi Setup...", IDC_BUTTON_ASIO, 180, 170, 110, 40 + +GROUPBOX "MIDI Settings", IDC_STATIC, 5, 255, 300, 120 + +LTEXT "Input Device", IDC_STATIC, 20, 275, 100, 20 +COMBOBOX IDC_COMBO_MIDI_IN_DEV, 20, 293, 150, 100, CBS_DROPDOWNLIST + +LTEXT "Output Device", IDC_STATIC, 20, 320, 100, 20 +COMBOBOX IDC_COMBO_MIDI_OUT_DEV, 20, 338, 150, 100, CBS_DROPDOWNLIST + +LTEXT "Input Channel", IDC_STATIC, 200, 275, 100, 20 +COMBOBOX IDC_COMBO_MIDI_IN_CHAN, 200, 293, 90, 100, CBS_DROPDOWNLIST + +LTEXT "Output Channel", IDC_STATIC, 200, 320, 100, 20 +COMBOBOX IDC_COMBO_MIDI_OUT_CHAN, 200, 338, 90, 100, CBS_DROPDOWNLIST + +DEFPUSHBUTTON "OK", IDOK, 192, 383, 50, 20 +PUSHBUTTON "Apply", IDAPPLY, 132, 383, 50, 20 +PUSHBUTTON "Cancel", IDCANCEL, 252, 383, 50, 20 +END +SWELL_DEFINE_DIALOG_RESOURCE_END(IDD_DIALOG_PREF) + +#include "swell-menugen.h" + +SWELL_DEFINE_MENU_RESOURCE_BEGIN(IDR_MENU1) +POPUP "&File" +BEGIN +// MENUITEM SEPARATOR +MENUITEM "Preferences...", ID_PREFERENCES +MENUITEM "&Quit", ID_QUIT +END +POPUP "&Help" +BEGIN +MENUITEM "&About", ID_ABOUT +END +SWELL_DEFINE_MENU_RESOURCE_END(IDR_MENU1) + +#endif \ No newline at end of file