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