Mercurial > hg > asa
view app_wrapper/app_main.cpp @ 1:2ca5d7440b5c tip
added README
author | Fiore Martin <f.martin@qmul.ac.uk> |
---|---|
date | Fri, 26 Feb 2016 16:11:20 +0000 |
parents | 3004dd663202 |
children |
line wrap: on
line source
#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