void IURLControl::OnMouseDown(int x, int y, IMouseMod* pMod) { bool opened = false; if (CSTR_NOT_EMPTY(mURL)) { opened = mPlug->GetGUI()->OpenURL(mURL, mErrMsg); } if (!opened && CSTR_NOT_EMPTY(mBackupURL)) { opened = mPlug->GetGUI()->OpenURL(mBackupURL, mErrMsg); } }
EHost IPlugVST::GetHost() { EHost host = IPlugBase::GetHost(); if (host == kHostUninit) { char productStr[256]; productStr[0] = '\0'; int version = 0; mHostCallback(&mAEffect, audioMasterGetProductString, 0, 0, productStr, 0.0f); if (CSTR_NOT_EMPTY(productStr)) { int decVer = mHostCallback(&mAEffect, audioMasterGetVendorVersion, 0, 0, 0, 0.0f); int ver = decVer / 10000; int rmaj = (decVer - 10000 * ver) / 100; int rmin = (decVer - 10000 * ver - 100 * rmaj); version = (ver << 16) + (rmaj << 8) + rmin; } SetHost(productStr, version); host = IPlugBase::GetHost(); } return host; }
void IParam::GetDisplayForHost(double value, bool normalized, char* rDisplay, bool withDisplayText) { if (normalized) value = FromNormalizedParam(value, mMin, mMax, mShape); if (withDisplayText) { const char* displayText = GetDisplayText( (int) value); if (CSTR_NOT_EMPTY(displayText)) { strcpy(rDisplay, displayText); return; } } double displayValue = value; if (mNegateDisplay) displayValue = -displayValue; if (mDisplayPrecision == 0) { sprintf(rDisplay, "%d", int(displayValue)); } // else if(mSignDisplay) // { // char fmt[16]; // sprintf(fmt, "%%+.%df", mDisplayPrecision); // sprintf(rDisplay, fmt, displayValue); // } else { sprintf(rDisplay, "%.*f", mDisplayPrecision, displayValue); } }
void IParam::GetDisplayForHost(double value, bool normalized, char* rDisplay) { if (normalized) { value = FromNormalizedParam(value, mMin, mMax, mShape); } const char* displayText = GetDisplayText((int) value); if (CSTR_NOT_EMPTY(displayText)) { strcpy(rDisplay, displayText); return; } double displayValue = value; if (mNegateDisplay) { displayValue = -displayValue; } if (displayValue == 0.0) { strcpy(rDisplay, "0"); } else if (mDisplayPrecision == 0) { sprintf(rDisplay, "%d", int(displayValue)); } else { sprintf(rDisplay, "%.*f", mDisplayPrecision, displayValue); } }
IURLControl::IURLControl(IPlugBase* pPlug, IRECT pR, const char* url, const char* backupURL, const char* errMsgOnFailure) : IControl(pPlug, pR) { memset(mURL, 0, MAX_URL_LEN); memset(mBackupURL, 0, MAX_URL_LEN); memset(mErrMsg, 0, MAX_NET_ERR_MSG_LEN); if (CSTR_NOT_EMPTY(url)) { strcpy(mURL, url); } if (CSTR_NOT_EMPTY(backupURL)) { strcpy(mBackupURL, backupURL); } if (CSTR_NOT_EMPTY(errMsgOnFailure)) { strcpy(mErrMsg, errMsgOnFailure); } }
bool ITextControl::Draw(IGraphics* pGraphics) { char* cStr = mStr.Get(); if (CSTR_NOT_EMPTY(cStr)) { return pGraphics->DrawIText(&mText, cStr, &mRECT); } return true; }
bool IBitmapTextControl::Draw(IGraphics* pGraphics) { char* cStr = mStr.Get(); if (CSTR_NOT_EMPTY(cStr)) { DrawBitmapedText(pGraphics, &mTextBitmap, &mRECT, &mText, &mBlend, cStr, true, false, mCharWidth, mCharHeight, mCharOffset); } return true; }
HWND IGraphicsWin::GetMainWnd() { if (!mMainWnd) { if (mParentWnd) { HWND parentWnd = mParentWnd; while (parentWnd) { mMainWnd = parentWnd; parentWnd = GetParent(mMainWnd); } GetWndClassName(mMainWnd, &mMainWndClassName); } else if (CSTR_NOT_EMPTY(mMainWndClassName.Get())) { mPID = GetCurrentProcessId(); EnumWindows(FindMainWindow, (LPARAM) this); } } return mMainWnd; }
VstIntPtr VSTCALLBACK IPlugVST::VSTDispatcher(AEffect *pEffect, VstInt32 opCode, VstInt32 idx, VstIntPtr value, void *ptr, float opt) { // VSTDispatcher is an IPlugVST class member, we can access anything in IPlugVST from here. IPlugVST* _this = (IPlugVST*) pEffect->object; if (!_this) { return 0; } IPlugBase::IMutexLock lock(_this); // Handle a couple of opcodes here to make debugging easier. switch (opCode) { case effEditIdle: case __effIdleDeprecated: #ifdef USE_IDLE_CALLS _this->OnIdle(); #endif return 0; } Trace(TRACELOC, "%d(%s):%d:%d", opCode, VSTOpcodeStr(opCode), idx, (int) value); switch (opCode) { case effOpen: { _this->HostSpecificInit(); _this->OnParamReset(); return 0; } case effClose: { lock.Destroy(); DELETE_NULL(_this); return 0; } case effGetParamLabel: { if (idx >= 0 && idx < _this->NParams()) { strcpy((char*) ptr, _this->GetParam(idx)->GetLabelForHost()); } return 0; } case effGetParamDisplay: { if (idx >= 0 && idx < _this->NParams()) { _this->GetParam(idx)->GetDisplayForHost((char*) ptr); } return 0; } case effGetParamName: { if (idx >= 0 && idx < _this->NParams()) { strcpy((char*) ptr, _this->GetParam(idx)->GetNameForHost()); } return 0; } //could implement effGetParameterProperties to group parameters, but can't find a host that supports it // case effGetParameterProperties: // { // if (idx >= 0 && idx < _this->NParams()) // { // VstParameterProperties* props = (VstParameterProperties*) ptr; // // props->flags = kVstParameterSupportsDisplayCategory; // props->category = idx+1; // props->numParametersInCategory = 1; // strcpy(props->categoryLabel, "test"); // } // return 1; // } case effGetParameterProperties: { if (idx >= 0 && idx < _this->NParams()) { VstParameterProperties* props = (VstParameterProperties*) ptr; props->flags = 0; IParam* pParam = _this->GetParam(idx); if (pParam->Type() == IParam::kTypeBool) { props->flags |= kVstParameterIsSwitch; } if (pParam->Type() == IParam::kTypeEnum || pParam->Type() == IParam::kTypeInt) { props->flags |= kVstParameterUsesFloatStep; int possibleValuesCount = (int) (pParam->GetMax() - pParam->GetMin()); props->stepFloat = 1.0 / possibleValuesCount; props->smallStepFloat = props->stepFloat; props->largeStepFloat = props->stepFloat; } } return 1; } case effString2Parameter: { if (idx >= 0 && idx < _this->NParams()) { if (ptr) { double v; IParam* pParam = _this->GetParam(idx); if (pParam->GetNDisplayTexts()) { int vi; if (!pParam->MapDisplayText((char*)ptr, &vi)) return 0; v = (double)vi; } else { v = atof((char*)ptr); if (pParam->DisplayIsNegated()) v = -v; } if (_this->GetGUI()) _this->GetGUI()->SetParameterFromPlug(idx, v, false); pParam->Set(v); _this->OnParamChange(idx); } return 1; } return 0; } case effSetSampleRate: { _this->SetSampleRate(opt); _this->Reset(); return 0; } case effSetBlockSize: { _this->SetBlockSize(value); _this->Reset(); return 0; } case effMainsChanged: { if (!value) { _this->OnActivate(false); _this->Reset(); } else { _this->OnActivate(true); } return 0; } case effEditGetRect: { if (ptr && _this->GetGUI()) { *(ERect**) ptr = &(_this->mEditRect); return 1; } ptr = 0; return 0; } case effEditOpen: { IGraphics* pGraphics = _this->GetGUI(); if (pGraphics) { #ifdef _WIN32 if (!pGraphics->OpenWindow(ptr)) pGraphics=0; #else // OSX, check if we are in a Cocoa VST host #if defined(__LP64__) if (!pGraphics->OpenWindow(ptr)) pGraphics=0; #else bool iscocoa = (_this->mHasVSTExtensions&VSTEXT_COCOA); if (iscocoa && !pGraphics->OpenWindow(ptr)) pGraphics=0; if (!iscocoa && !pGraphics->OpenWindow(ptr, 0)) pGraphics=0; #endif #endif if (pGraphics) { _this->OnGUIOpen(); return 1; } } return 0; } case effEditClose: { if (_this->GetGUI()) { _this->OnGUIClose(); _this->GetGUI()->CloseWindow(); return 1; } return 0; } case __effIdentifyDeprecated: { return 'NvEf'; // Random deprecated magic. } case effGetChunk: { BYTE** ppData = (BYTE**) ptr; if (ppData) { bool isBank = (!idx); ByteChunk* pChunk = (isBank ? &(_this->mBankState) : &(_this->mState)); _this->InitChunkWithIPlugVer(pChunk); bool savedOK = true; if (isBank) { _this->ModifyCurrentPreset(); savedOK = _this->SerializePresets(pChunk); } else { savedOK = _this->SerializeState(pChunk); } if (savedOK && pChunk->Size()) { *ppData = pChunk->GetBytes(); return pChunk->Size(); } } return 0; } case effSetChunk: { if (ptr) { bool isBank = (!idx); ByteChunk* pChunk = (isBank ? &(_this->mBankState) : &(_this->mState)); pChunk->Resize(value); memcpy(pChunk->GetBytes(), ptr, value); int pos = 0; int iplugVer = _this->GetIPlugVerFromChunk(pChunk, &pos); isBank &= (iplugVer >= 0x010000); if (isBank) { pos = _this->UnserializePresets(pChunk, pos); } else { pos = _this->UnserializeState(pChunk, pos); _this->ModifyCurrentPreset(); } if (pos >= 0) { _this->RedrawParamControls(); return 1; } } return 0; } case effProcessEvents: { VstEvents* pEvents = (VstEvents*) ptr; if (pEvents && pEvents->events) { for (int i = 0; i < pEvents->numEvents; ++i) { VstEvent* pEvent = pEvents->events[i]; if (pEvent) { if (pEvent->type == kVstMidiType) { VstMidiEvent* pME = (VstMidiEvent*) pEvent; IMidiMsg msg(pME->deltaFrames, pME->midiData[0], pME->midiData[1], pME->midiData[2]); _this->ProcessMidiMsg(&msg); //#ifdef TRACER_BUILD // msg.LogMsg(); //#endif } else if (pEvent->type == kVstSysExType) { VstMidiSysexEvent* pSE = (VstMidiSysexEvent*) pEvent; ISysEx sysex(pSE->deltaFrames, (const BYTE*)pSE->sysexDump, pSE->dumpBytes); _this->ProcessSysEx(&sysex); } } } return 1; } return 0; } case effCanBeAutomated: { return 1; } case effGetInputProperties: { if (ptr && idx >= 0 && idx < _this->NInChannels()) { VstPinProperties* pp = (VstPinProperties*) ptr; pp->flags = kVstPinIsActive; if (!(idx%2) && idx < _this->NInChannels()-1) { pp->flags |= kVstPinIsStereo; } if (_this->GetInputLabel(idx)->GetLength()) { sprintf(pp->label, "%s", _this->GetInputLabel(idx)->Get()); } else { sprintf(pp->label, "Input %d", idx + 1); } return 1; } return 0; } case effGetOutputProperties: { if (ptr && idx >= 0 && idx < _this->NOutChannels()) { VstPinProperties* pp = (VstPinProperties*) ptr; pp->flags = kVstPinIsActive; if (!(idx%2) && idx < _this->NOutChannels()-1) { pp->flags |= kVstPinIsStereo; } if (_this->GetOutputLabel(idx)->GetLength()) { sprintf(pp->label, "%s", _this->GetOutputLabel(idx)->Get()); } else { sprintf(pp->label, "Output %d", idx + 1); } return 1; } return 0; } case effGetPlugCategory: { if (_this->IsInst()) return kPlugCategSynth; return kPlugCategEffect; } case effProcessVarIo: { // VstVariableIo* pIO = (VstVariableIo*) ptr; // For offline processing (of audio files?) return 0; } case effSetSpeakerArrangement: { VstSpeakerArrangement* pInputArr = (VstSpeakerArrangement*) value; VstSpeakerArrangement* pOutputArr = (VstSpeakerArrangement*) ptr; if (pInputArr) { int n = pInputArr->numChannels; _this->SetInputChannelConnections(0, n, true); _this->SetInputChannelConnections(n, _this->NInChannels() - n, false); } if (pOutputArr) { int n = pOutputArr->numChannels; _this->SetOutputChannelConnections(0, n, true); _this->SetOutputChannelConnections(n, _this->NOutChannels() - n, false); } return 1; } case effGetSpeakerArrangement: { VstSpeakerArrangement** ppInputArr = (VstSpeakerArrangement**) value; VstSpeakerArrangement** ppOutputArr = (VstSpeakerArrangement**) ptr; if (ppInputArr) { *ppInputArr = &(_this->mInputSpkrArr); } if (ppOutputArr) { *ppOutputArr = &(_this->mOutputSpkrArr); } return 1; } case effGetEffectName: { if (ptr) { strcpy((char*) ptr, _this->GetEffectName()); return 1; } return 0; } case effGetProductString: { if (ptr) { strcpy((char*) ptr, _this->GetProductName()); return 1; } return 0; } case effGetVendorString: { if (ptr) { strcpy((char*) ptr, _this->GetMfrName()); return 1; } return 0; } case effCanDo: { if (ptr) { Trace(TRACELOC, "VSTCanDo(%s)", (char*) ptr); if (!strcmp((char*) ptr, "receiveVstTimeInfo")) { return 1; } if (_this->DoesMIDI()) { if (!strcmp((char*) ptr, "sendVstEvents") || !strcmp((char*) ptr, "sendVstMidiEvent") || !strcmp((char*) ptr, "receiveVstEvents") || !strcmp((char*) ptr, "receiveVstMidiEvent")) // || { //!strcmp((char*) ptr, "midiProgramNames")) { return 1; } } // Support Reaper VST extensions: http://www.reaper.fm/sdk/vst/ if (!strcmp((char*) ptr, "hasCockosExtensions")) { _this->mHasVSTExtensions |= VSTEXT_COCKOS; return 0xbeef0000; } else if (!strcmp((char*) ptr, "hasCockosViewAsConfig")) { _this->mHasVSTExtensions |= VSTEXT_COCOA; return 0xbeef0000; } } return 0; } case effGetTailSize: { return _this->GetTailSize(); } case effVendorSpecific: { // Support Reaper VST extensions: http://www.reaper.fm/sdk/vst/ if (idx == effGetParamDisplay && ptr) { if (value >= 0 && value < _this->NParams()) { _this->GetParam(value)->GetDisplayForHost((double) opt, true, (char*) ptr); } return 0xbeef; } if (idx == kVstParameterUsesIntStep) { if (value >= 0 && value < _this->NParams()) { if (_this->GetParam(value)->Type() != IParam::kTypeDouble) { return 0xbeef; } } } return 0; } case effGetProgram: { return _this->GetCurrentPresetIdx(); } case effSetProgram: { if (_this->DoesStateChunks() == false) { _this->ModifyCurrentPreset(); // TODO: test, something is funny about this http://forum.cockos.com/showpost.php?p=485113&postcount=22 } _this->RestorePreset((int) value); return 0; } case effGetProgramNameIndexed: { strcpy((char*) ptr, _this->GetPresetName(idx)); return (CSTR_NOT_EMPTY((char*) ptr) ? 1 : 0); } case effSetProgramName: { if (ptr) { _this->ModifyCurrentPreset((char*) ptr); _this->PresetsChangedByHost(); } return 0; } case effGetProgramName: { if (ptr) { int idx = _this->GetCurrentPresetIdx(); strcpy((char*) ptr, _this->GetPresetName(idx)); } return 0; } case effGetMidiKeyName: { if (ptr) { MidiKeyName* pMKN = (MidiKeyName*) ptr; pMKN->keyName[0] = '\0'; if (_this->MidiNoteName(pMKN->thisKeyNumber, pMKN->keyName)) { return 1; } } return 0; } case effGetVstVersion: { return VST_VERSION; } case effEndSetProgram: case effBeginSetProgram: case effGetMidiProgramName: case effHasMidiProgramsChanged: case effGetMidiProgramCategory: case effGetCurrentMidiProgram: case effSetBypass: default: { return 0; } } }
const char* IParam::GetLabelForHost() { const char* displayText = GetDisplayText((int) mValue); return (CSTR_NOT_EMPTY(displayText)) ? "" : mLabel; }
tresult PLUGIN_API IPlugVST3Plugin::initialize (FUnknown* context) { TRACE; tresult result = SingleComponentEffect::initialize(context); String128 tmpStringBuf; char hostNameCString[128]; FUnknownPtr<IHostApplication>app(context); if (app) { app->getName(tmpStringBuf); Steinberg::UString(tmpStringBuf, 128).toAscii(hostNameCString, 128); SetHost(hostNameCString, 0); // Can't get version in VST3 } if (result == kResultOk) { int maxInputs = getSpeakerArrForChans(NInChannels()-mScChans); if(maxInputs < 0) maxInputs = 0; // add io buses with the maximum i/o to start with if (maxInputs) { Steinberg::UString(tmpStringBuf, 128).fromAscii(GetInputBusLabel(0)->Get(), 128); addAudioInput(tmpStringBuf, maxInputs); } if(!mIsInst) // if effect, just add one output bus with max chan count { Steinberg::UString(tmpStringBuf, 128).fromAscii(GetOutputBusLabel(0)->Get(), 128); addAudioOutput(tmpStringBuf, getSpeakerArrForChans(NOutChannels()) ); } else { for (int i = 0, busIdx = 0; i < NOutChannels(); i+=2, busIdx++) { Steinberg::UString(tmpStringBuf, 128).fromAscii(GetOutputBusLabel(busIdx)->Get(), 128); addAudioOutput(tmpStringBuf, SpeakerArr::kStereo ); } } if (mScChans) { if (mScChans > 2) mScChans = 2; Steinberg::UString(tmpStringBuf, 128).fromAscii(GetInputBusLabel(1)->Get(), 128); addAudioInput(tmpStringBuf, getSpeakerArrForChans(mScChans), kAux, 0); } if(DoesMIDI()) { addEventInput (STR16("MIDI Input"), 1); //addEventOutput(STR16("MIDI Output"), 1); } if (NPresets()) { parameters.addParameter(new Parameter(STR16("Preset"), kPresetParam, STR16(""), 0, NPresets(), ParameterInfo::kIsProgramChange)); } if(!mIsInst) { StringListParameter * bypass = new StringListParameter(STR16("Bypass"), kBypassParam, 0, ParameterInfo::kCanAutomate | ParameterInfo::kIsBypass | ParameterInfo::kIsList); bypass->appendString(STR16("off")); bypass->appendString(STR16("on")); parameters.addParameter(bypass); } for (int i=0; i<NParams(); i++) { IParam *p = GetParam(i); int32 flags = 0; UnitID unitID = kRootUnitId; const char* paramGroupName = p->GetParamGroupForHost(); if (CSTR_NOT_EMPTY(paramGroupName)) { for(int j = 0; j < mParamGroups.GetSize(); j++) { if(strcmp(paramGroupName, mParamGroups.Get(j)) == 0) { unitID = j+1; } } if (unitID == kRootUnitId) // new unit, nothing found, so add it { mParamGroups.Add(paramGroupName); unitID = mParamGroups.GetSize(); } } if (p->GetCanAutomate()) { flags |= ParameterInfo::kCanAutomate; } switch (p->Type()) { case IParam::kTypeDouble: case IParam::kTypeInt: { Parameter* param = new RangeParameter( STR16(p->GetNameForHost()), i, STR16(p->GetLabelForHost()), p->GetMin(), p->GetMax(), p->GetDefault(), 0, // continuous flags, unitID); param->setPrecision (p->GetPrecision()); parameters.addParameter(param); break; } case IParam::kTypeEnum: case IParam::kTypeBool: { StringListParameter* param = new StringListParameter (STR16(p->GetNameForHost()), i, STR16(p->GetLabelForHost()), flags | ParameterInfo::kIsList, unitID); int nDisplayTexts = p->GetNDisplayTexts(); assert(nDisplayTexts); for (int j=0; j<nDisplayTexts; j++) { param->appendString(STR16(p->GetDisplayText(j))); } parameters.addParameter(param); break; } default: break; } } } OnHostIdentified(); RestorePreset(0); return result; }
void DrawBitmapedText(IGraphics* pGraphics, IBitmap* pTextBitmap, IRECT* controlRect, IText* pItext, IChannelBlend* pBlend, const char* str, bool vCenter, bool multiline, int charWidth, int charHeight, int charOffset) { if (CSTR_NOT_EMPTY(str)) { int len = strlen(str); int basicYOffset, basicXOffset; if (vCenter) basicYOffset = controlRect->T + ((controlRect->H() - charHeight) / 2); else basicYOffset = controlRect->T; if (pItext->mAlign == IText::kAlignCenter) basicXOffset = controlRect->L + ((controlRect->W() - (len * charWidth)) / 2); else basicXOffset = controlRect->L + charWidth; int widthAsOneLine = charWidth * len; int lineWidth = controlRect->W() - (charWidth * 2); assert(lineWidth > 0); int nLines; int stridx = 0; int lineCount; if(multiline) { if (widthAsOneLine > lineWidth) { lineCount = lineWidth / charWidth; nLines = widthAsOneLine / lineWidth; } else// line is shorter than width of rect { lineCount = len; nLines = 1; } } else { nLines = 1; lineCount = lineWidth / charWidth; } //int newlines = 0; for(int line=0; line<=nLines; line++) { int yOffset = basicYOffset + line * charHeight; for(int linepos=0; linepos<lineCount; linepos++) { if (str[stridx] == '\0') return; // else if(str[stridx] == '\n') // { // yOffset = basicYOffset + line * charHeight; // } int frameOffset = (int) str[stridx++] - 31; // calculate which frame to look up int xOffset = (linepos * (charWidth + charOffset)) + basicXOffset; // calculate xOffset for character we're drawing IRECT charRect = IRECT(xOffset, yOffset, xOffset + charWidth, yOffset + charHeight); pGraphics->DrawBitmap(pTextBitmap, &charRect, frameOffset, pBlend); } } } }
VstIntPtr VSTCALLBACK IPlugVST::VSTDispatcher(AEffect *pEffect, VstInt32 opCode, VstInt32 idx, VstIntPtr value, void *ptr, float opt) { // VSTDispatcher is an IPlugVST class member, we can access anything in IPlugVST from here. IPlugVST* _this = (IPlugVST*) pEffect->object; if (!_this) { return 0; } IPlugBase::IMutexLock lock(_this); // Handle a couple of opcodes here to make debugging easier. switch (opCode) { case effEditIdle: case __effIdleDeprecated: #ifdef USE_IDLE_CALLS _this->OnIdle(); #endif return 0; } Trace(TRACELOC, "%d(%s):%d:%d", opCode, VSTOpcodeStr(opCode), idx, (int) value); switch (opCode) { case effOpen: { _this->HostSpecificInit(); _this->OnParamReset(); return 0; } case effClose: { lock.Destroy(); DELETE_NULL(_this); return 0; } case effGetParamLabel: { if (idx >= 0 && idx < _this->NParams()) { strcpy((char*) ptr, _this->GetParam(idx)->GetLabelForHost()); } return 0; } case effGetParamDisplay: { if (idx >= 0 && idx < _this->NParams()) { _this->GetParam(idx)->GetDisplayForHost((char*) ptr); } return 0; } case effGetParamName: { if (idx >= 0 && idx < _this->NParams()) { strcpy((char*) ptr, _this->GetParam(idx)->GetNameForHost()); } return 0; } case effString2Parameter: { if (idx >= 0 && idx < _this->NParams()) { if (ptr) { IParam* pParam = _this->GetParam(idx); double v = VSTString2Parameter(pParam, (char*)ptr); if (_this->GetGUI()) _this->GetGUI()->SetParameterFromPlug(idx, v, false); pParam->Set(v); _this->OnParamChange(idx); } return 1; } return 0; } case effSetSampleRate: { _this->SetSampleRate(opt); _this->Reset(); return 0; } case effSetBlockSize: { _this->SetBlockSize(value); _this->Reset(); return 0; } case effMainsChanged: { if (!value) { _this->OnActivate(false); _this->Reset(); } else { _this->OnActivate(true); } return 0; } case effEditGetRect: { if (ptr && _this->GetGUI()) { *(ERect**) ptr = &(_this->mEditRect); return 1; } ptr = 0; return 0; } case effEditOpen: { IGraphics* pGraphics = _this->GetGUI(); if (pGraphics) { #if defined(_WIN32) || defined(IPLUG_NO_CARBON_SUPPORT) if (!pGraphics->OpenWindow(ptr)) pGraphics=0; #else // OSX, check if we are in a Cocoa VST host bool iscocoa = (_this->mHasVSTExtensions&VSTEXT_COCOA); if (iscocoa && !pGraphics->OpenWindow(ptr)) pGraphics=0; if (!iscocoa && !pGraphics->OpenWindow(ptr, 0)) pGraphics=0; #endif if (pGraphics) { _this->OnGUIOpen(); return 1; } } return 0; } case effEditClose: { if (_this->GetGUI()) { _this->OnGUIClose(); _this->GetGUI()->CloseWindow(); return 1; } return 0; } case __effIdentifyDeprecated: { return 'NvEf'; // Random deprecated magic. } case effGetChunk: { BYTE** ppData = (BYTE**) ptr; if (ppData) { bool isBank = (!idx); ByteChunk* pChunk = (isBank ? &(_this->mBankState) : &(_this->mState)); InitializeVSTChunk(pChunk); bool savedOK = true; if (isBank) { _this->ModifyCurrentPreset(); savedOK = _this->SerializePresets(pChunk); //savedOK = _this->SerializeState(pChunk); } else { savedOK = _this->SerializeState(pChunk); } if (savedOK && pChunk->Size()) { *ppData = pChunk->GetBytes(); return pChunk->Size(); } } return 0; } case effSetChunk: { if (ptr) { bool isBank = (!idx); ByteChunk* pChunk = (isBank ? &(_this->mBankState) : &(_this->mState)); pChunk->Resize(value); memcpy(pChunk->GetBytes(), ptr, value); int pos = 0; int iplugVer = GetIPlugVerFromChunk(pChunk, &pos); isBank &= (iplugVer >= 0x010000); if (isBank) { pos = _this->UnserializePresets(pChunk, pos); //pos = _this->UnserializeState(pChunk, pos); } else { pos = _this->UnserializeState(pChunk, pos); _this->ModifyCurrentPreset(); } if (pos >= 0) { _this->RedrawParamControls(); return 1; } } return 0; } case effProcessEvents: { VstEvents* pEvents = (VstEvents*) ptr; if (pEvents && pEvents->events) { for (int i = 0; i < pEvents->numEvents; ++i) { VstEvent* pEvent = pEvents->events[i]; if (pEvent) { if (pEvent->type == kVstMidiType) { VstMidiEvent* pME = (VstMidiEvent*) pEvent; IMidiMsg msg(pME->deltaFrames, pME->midiData[0], pME->midiData[1], pME->midiData[2]); _this->ProcessMidiMsg(&msg); //#ifdef TRACER_BUILD // msg.LogMsg(); //#endif } else if (pEvent->type == kVstSysExType) { VstMidiSysexEvent* pSE = (VstMidiSysexEvent*) pEvent; ISysEx sysex(pSE->deltaFrames, (const BYTE*)pSE->sysexDump, pSE->dumpBytes); _this->ProcessSysEx(&sysex); } } } return 1; } return 0; } case effCanBeAutomated: { return 1; } case effGetInputProperties: { if (ptr && idx >= 0 && idx < _this->NInChannels()) { VstPinProperties* pp = (VstPinProperties*) ptr; pp->flags = kVstPinIsActive; if (!(idx%2) && idx < _this->NInChannels()-1) { pp->flags |= kVstPinIsStereo; } sprintf(pp->label, "Input %d", idx + 1); return 1; } return 0; } case effGetOutputProperties: { if (ptr && idx >= 0 && idx < _this->NOutChannels()) { VstPinProperties* pp = (VstPinProperties*) ptr; pp->flags = kVstPinIsActive; if (!(idx%2) && idx < _this->NOutChannels()-1) { pp->flags |= kVstPinIsStereo; } sprintf(pp->label, "Output %d", idx + 1); return 1; } return 0; } case effGetPlugCategory: { if (_this->IsInst()) return kPlugCategSynth; return kPlugCategEffect; } case effProcessVarIo: { // VstVariableIo* pIO = (VstVariableIo*) ptr; // For offline processing (of audio files?) return 0; } case effSetSpeakerArrangement: { VstSpeakerArrangement* pInputArr = (VstSpeakerArrangement*) value; VstSpeakerArrangement* pOutputArr = (VstSpeakerArrangement*) ptr; if (pInputArr) { int n = pInputArr->numChannels; _this->SetInputChannelConnections(0, n, true); _this->SetInputChannelConnections(n, _this->NInChannels() - n, false); } if (pOutputArr) { int n = pOutputArr->numChannels; _this->SetOutputChannelConnections(0, n, true); _this->SetOutputChannelConnections(n, _this->NOutChannels() - n, false); } return 1; } case effGetSpeakerArrangement: { VstSpeakerArrangement** ppInputArr = (VstSpeakerArrangement**) value; VstSpeakerArrangement** ppOutputArr = (VstSpeakerArrangement**) ptr; if (ppInputArr) { *ppInputArr = &(_this->mInputSpkrArr); } if (ppOutputArr) { *ppOutputArr = &(_this->mOutputSpkrArr); } return 1; } case effGetEffectName: { if (ptr) { strcpy((char*) ptr, _this->GetEffectName()); return 1; } return 0; } case effGetProductString: { if (ptr) { strcpy((char*) ptr, _this->GetProductName()); return 1; } return 0; } case effGetVendorString: { if (ptr) { strcpy((char*) ptr, _this->GetMfrName()); return 1; } return 0; } case effGetVendorVersion: { return _this->GetEffectVersion(true); } case effCanDo: { if (ptr) { Trace(TRACELOC, "VSTCanDo(%s)", (char*) ptr); if (!strcmp((char*) ptr, "receiveVstTimeInfo")) { return 1; } if (_this->DoesMIDI()) { if (_this->DoesMIDI() & 1) { if (!strcmp((char*) ptr, "sendVstEvents") || !strcmp((char*) ptr, "sendVstMidiEvent")) { return 1; } } if (_this->DoesMIDI() <= 2) { if (!strcmp((char*) ptr, "receiveVstEvents") || !strcmp((char*) ptr, "receiveVstMidiEvent")) { return 1; } } //if (!strcmp((char*) ptr, "midiProgramNames")) { // return 1; //} } // Support Reaper VST extensions: http://www.reaper.fm/sdk/vst/ if (!strcmp((char*) ptr, "hasCockosExtensions")) { _this->mHasVSTExtensions |= VSTEXT_COCKOS; return 0xbeef0000; } else if (!strcmp((char*) ptr, "hasCockosViewAsConfig")) { _this->mHasVSTExtensions |= VSTEXT_COCOA; return 0xbeef0000; } } return 0; } case effVendorSpecific: { switch (idx) { // Mouse wheel case 0x73744341: { if (value == 0x57686565) { IGraphics* pGraphics = _this->GetGUI(); if (pGraphics) { return pGraphics->ProcessMouseWheel(opt); } } break; } // Support Reaper VST extensions: http://www.reaper.fm/sdk/vst/ case effGetParamDisplay: { if (ptr) { if (value >= 0 && value < _this->NParams()) { _this->GetParam(value)->GetDisplayForHost((double) opt, true, (char*) ptr); } return 0xbeef; } break; } case effString2Parameter: { if (ptr && value >= 0 && value < _this->NParams()) { if (*(char*) ptr != '\0') { IParam* pParam = _this->GetParam(value); sprintf((char*) ptr, "%.17f", pParam->GetNormalized(VSTString2Parameter(pParam, (char*) ptr))); } return 0xbeef; } break; } case kVstParameterUsesIntStep: { if (value >= 0 && value < _this->NParams()) { IParam* pParam = _this->GetParam(value); switch (pParam->Type()) { case IParam::kTypeBool: { return 0xbeef; } case IParam::kTypeInt: case IParam::kTypeEnum: { double min, max; pParam->GetBounds(&min, &max); if (fabs(max - min) < 1.5) { return 0xbeef; } break; } } } break; } } return 0; } case effGetProgram: { return _this->GetCurrentPresetIdx(); } case effSetProgram: { //if (!(_this->DoesStateChunks())) { _this->ModifyCurrentPreset(); //} _this->RestorePreset((int) value); return 0; } case effGetProgramNameIndexed: { strcpy((char*) ptr, _this->GetPresetName(idx)); return (CSTR_NOT_EMPTY((char*) ptr) ? 1 : 0); } case effSetProgramName: { if (ptr) { _this->ModifyCurrentPreset((char*) ptr); } return 0; } case effGetProgramName: { if (ptr) { int idx = _this->GetCurrentPresetIdx(); strcpy((char*) ptr, _this->GetPresetName(idx)); } return 0; } case effGetMidiKeyName: { if (ptr) { MidiKeyName* pMKN = (MidiKeyName*) ptr; pMKN->keyName[0] = '\0'; if (_this->MidiNoteName(pMKN->thisKeyNumber, pMKN->keyName)) { return 1; } } return 0; } case effGetVstVersion: { return VST_VERSION; } case effBeginSetProgram: case effEndSetProgram: case effGetMidiProgramName: case effHasMidiProgramsChanged: case effGetMidiProgramCategory: case effGetCurrentMidiProgram: case effSetBypass: default: { return 0; } } }
// static pascal OSStatus IGraphicsCarbon::MainEventHandler(EventHandlerCallRef pHandlerCall, EventRef pEvent, void* pGraphicsCarbon) { IGraphicsCarbon* _this = (IGraphicsCarbon*) pGraphicsCarbon; IGraphicsMac* pGraphicsMac = _this->mGraphicsMac; UInt32 eventClass = GetEventClass(pEvent); UInt32 eventKind = GetEventKind(pEvent); switch (eventClass) { case kEventClassKeyboard: { switch (eventKind) { case kEventRawKeyDown: { if (_this->mTextEntryView) return eventNotHandledErr; bool handle = true; int key; UInt32 k; GetEventParameter(pEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &k); char c; GetEventParameter(pEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &c); if (k == 49) key = KEY_SPACE; else if (k == 125) key = KEY_DOWNARROW; else if (k == 126) key = KEY_UPARROW; else if (k == 123) key = KEY_LEFTARROW; else if (k == 124) key = KEY_RIGHTARROW; else if (c >= '0' && c <= '9') key = KEY_DIGIT_0+c-'0'; else if (c >= 'A' && c <= 'Z') key = KEY_ALPHA_A+c-'A'; else if (c >= 'a' && c <= 'z') key = KEY_ALPHA_A+c-'a'; else handle = false; if(handle) handle = pGraphicsMac->OnKeyDown(_this->mPrevX, _this->mPrevY, key); if(handle) return noErr; else return eventNotHandledErr; } } } case kEventClassControl: { switch (eventKind) { case kEventControlDraw: { int gfxW = pGraphicsMac->Width(), gfxH = pGraphicsMac->Height(); IRECT r = GetRegionRect(pEvent, gfxW, gfxH); if (_this->mIsComposited) { GetEventParameter(pEvent, kEventParamCGContextRef, typeCGContextRef, 0, sizeof(CGContextRef), 0, &(_this->mCGC)); CGContextTranslateCTM(_this->mCGC, 0, gfxH); CGContextScaleCTM(_this->mCGC, 1.0, -1.0); pGraphicsMac->Draw(&r); } #if __MAC_OS_X_VERSION_MAX_ALLOWED <= 1060 else { CGrafPtr port = 0; GetEventParameter(pEvent, kEventParamGrafPort, typeGrafPtr, 0, sizeof(CGrafPtr), 0, &port); QDBeginCGContext(port, &(_this->mCGC)); Rect portBounds; GetPortBounds(port, &portBounds); int offsetW = 0; int offsetH = -portBounds.top; if ((portBounds.right - portBounds.left) >= gfxW) { offsetW = 0.5 * ((portBounds.right - portBounds.left) - gfxW); } CGContextTranslateCTM(_this->mCGC, portBounds.left + offsetW, offsetH); r = IRECT(0, 0, pGraphicsMac->Width(), pGraphicsMac->Height()); pGraphicsMac->Draw(&r); // Carbon non-composited will redraw everything, the IRECT passed here is the entire plugin-gui QDEndCGContext(port, &(_this->mCGC)); } #endif return noErr; } } break; } case kEventClassMouse: { HIPoint hp; GetEventParameter(pEvent, kEventParamWindowMouseLocation, typeHIPoint, 0, sizeof(HIPoint), 0, &hp); #ifdef RTAS_API // Header offset hp.x -= _this->GetLeftOffset(); hp.y -= _this->GetTopOffset(); Rect bounds; GetWindowBounds(_this->mWindow, kWindowTitleBarRgn, &bounds); // adjust x mouse coord if the gui is less wide than the window // int windowWidth = (bounds.right - bounds.left); // // if (windowWidth > pGraphicsMac->Width()) // { // hp.x -= (int) floor((windowWidth - pGraphicsMac->Width()) / 2.); // } // Title bar Y offset hp.y -= bounds.bottom - bounds.top; int x = (int) hp.x; int y = (int) hp.y; #else // NOT RTAS HIPointConvert(&hp, kHICoordSpaceWindow, _this->mWindow, kHICoordSpaceView, _this->mView); int x = (int) hp.x - 2; int y = (int) hp.y - 3; #endif UInt32 mods; GetEventParameter(pEvent, kEventParamKeyModifiers, typeUInt32, 0, sizeof(UInt32), 0, &mods); EventMouseButton button; GetEventParameter(pEvent, kEventParamMouseButton, typeMouseButton, 0, sizeof(EventMouseButton), 0, &button); if (button == kEventMouseButtonPrimary && (mods & cmdKey)) button = kEventMouseButtonSecondary; IMouseMod mmod(true, button == kEventMouseButtonSecondary, (mods & shiftKey), (mods & controlKey), (mods & optionKey)); switch (eventKind) { case kEventMouseDown: { _this->HideTooltip(); if (_this->mTextEntryView) { #if !(USE_MLTE) HIViewRef view; HIViewGetViewForMouseEvent(_this->mView, pEvent, &view); if (view == _this->mTextEntryView) break; #endif _this->EndUserInput(true); } #ifdef RTAS_API // RTAS triple click if (mmod.L && mmod.R && mmod.C && (pGraphicsMac->GetParamIdxForPTAutomation(x, y) > -1)) { return CallNextEventHandler(pHandlerCall, pEvent); } #endif CallNextEventHandler(pHandlerCall, pEvent); UInt32 clickCount = 0; GetEventParameter(pEvent, kEventParamClickCount, typeUInt32, 0, sizeof(UInt32), 0, &clickCount); if (clickCount > 1) { pGraphicsMac->OnMouseDblClick(x, y, &mmod); } else { pGraphicsMac->OnMouseDown(x, y, &mmod); } return noErr; } case kEventMouseUp: { pGraphicsMac->OnMouseUp(x, y, &mmod); return noErr; } case kEventMouseMoved: { _this->mPrevX = x; _this->mPrevY = y; pGraphicsMac->OnMouseOver(x, y, &mmod); if (pGraphicsMac->TooltipsEnabled()) { int c = pGraphicsMac->GetMouseOver(); if (c != _this->mTooltipIdx) { _this->mTooltipIdx = c; _this->HideTooltip(); const char* tooltip = c >= 0 ? pGraphicsMac->GetControl(c)->GetTooltip() : NULL; if (CSTR_NOT_EMPTY(tooltip)) { _this->mTooltip = tooltip; _this->mTooltipTimer = pGraphicsMac->FPS() * 3 / 2; //TODO: remove FPS link } } } return noErr; } case kEventMouseDragged: { if (!_this->mTextEntryView) pGraphicsMac->OnMouseDrag(x, y, &mmod); return noErr; } case kEventMouseWheelMoved: { EventMouseWheelAxis axis; GetEventParameter(pEvent, kEventParamMouseWheelAxis, typeMouseWheelAxis, 0, sizeof(EventMouseWheelAxis), 0, &axis); if (axis == kEventMouseWheelAxisY) { int d; GetEventParameter(pEvent, kEventParamMouseWheelDelta, typeSInt32, 0, sizeof(SInt32), 0, &d); if (_this->mTextEntryView) _this->EndUserInput(false); pGraphicsMac->OnMouseWheel(x, y, &mmod, d); return noErr; } } } break; } case kEventClassWindow: { WindowRef window; if (GetEventParameter(pEvent, kEventParamDirectObject, typeWindowRef, NULL, sizeof (WindowRef), NULL, &window) != noErr) break; switch (eventKind) { case kEventWindowDeactivated: { if (_this->mTextEntryView) _this->EndUserInput(false); break; } } break; } } return eventNotHandledErr; }
void IGraphicsWin::PromptForFile(WDL_String* pFilename, int action, char* dir, char* extensions) { pFilename->Set(""); if (!WindowIsOpen()) { return; } WDL_String pathStr; char fnCStr[MAX_PATH_LEN], dirCStr[MAX_PATH_LEN]; fnCStr[0] = '\0'; dirCStr[0] = '\0'; if (CSTR_NOT_EMPTY(dir)) { pathStr.Set(dir); strcpy(dirCStr, dir); } else { HostPath(&pathStr); } OPENFILENAME ofn; memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = mPlugWnd; ofn.lpstrFile = fnCStr; ofn.nMaxFile = MAX_PATH_LEN - 1; ofn.lpstrInitialDir = dirCStr; ofn.Flags = OFN_PATHMUSTEXIST; //if (!extensions.empty()) { //static char extStr[256]; //static char defExtStr[16]; //int i, j, p; //for (j = 0, p = 0; j < extensions.size(); ++j) { // extStr[p++] = extensions[j++]; //} //extStr[p++] = '\0'; //StrVector exts = SplitStr(extensions); //for (i = 0, p = 0; i < exts.size(); ++i) { // const std::string& ext = exts[i]; // if (i) { // extStr[p++] = ';'; // } // extStr[p++] = '*'; // extStr[p++] = '.'; // for (j = 0; j < ext.size(); ++j) { // extStr[p++] = ext[j]; // } //} //extStr[p++] = '\0'; //extStr[p++] = '\0'; //ofn.lpstrFilter = extStr; // //strcpy(defExtStr, exts.front().c_str()); //ofn.lpstrDefExt = defExtStr; //} bool rc = false; switch (action) { case kFileSave: ofn.Flags |= OFN_OVERWRITEPROMPT; rc = GetSaveFileName(&ofn); break; case kFileOpen: default: ofn.Flags |= OFN_FILEMUSTEXIST; rc = GetOpenFileName(&ofn); break; } if (rc) { pFilename->Set(ofn.lpstrFile); } }
void IGraphicsWin::PromptForFile(WDL_String* pFilename, EFileAction action, WDL_String* pDir, char* extensions) { if (!WindowIsOpen()) { pFilename->Set(""); return; } char fnCStr[MAX_PATH_LEN]; char dirCStr[MAX_PATH_LEN]; if (pFilename->GetLength()) strcpy(fnCStr, pFilename->Get()); else fnCStr[0] = '\0'; dirCStr[0] = '\0'; if (!pDir->GetLength()) { DesktopPath(pDir); } strcpy(dirCStr, pDir->Get()); OPENFILENAME ofn; memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = mPlugWnd; ofn.lpstrFile = fnCStr; ofn.nMaxFile = MAX_PATH_LEN - 1; ofn.lpstrInitialDir = dirCStr; ofn.Flags = OFN_PATHMUSTEXIST; if (CSTR_NOT_EMPTY(extensions)) { char extStr[256]; char defExtStr[16]; int i, p, n = strlen(extensions); bool seperator = true; for (i = 0, p = 0; i < n; ++i) { if (seperator) { if (p) { extStr[p++] = ';'; } seperator = false; extStr[p++] = '*'; extStr[p++] = '.'; } if (extensions[i] == ' ') { seperator = true; } else { extStr[p++] = extensions[i]; } } extStr[p++] = '\0'; strcpy(&extStr[p], extStr); extStr[p + p] = '\0'; ofn.lpstrFilter = extStr; for (i = 0, p = 0; i < n && extensions[i] != ' '; ++i) { defExtStr[p++] = extensions[i]; } defExtStr[p++] = '\0'; ofn.lpstrDefExt = defExtStr; } bool rc = false; switch (action) { case kFileSave: ofn.Flags |= OFN_OVERWRITEPROMPT; rc = GetSaveFileName(&ofn); break; case kFileOpen: default: ofn.Flags |= OFN_FILEMUSTEXIST; rc = GetOpenFileName(&ofn); break; } if (rc) { char drive[_MAX_DRIVE]; if(_splitpath_s(ofn.lpstrFile, drive, sizeof(drive), dirCStr, sizeof(dirCStr), NULL, 0, NULL, 0) == 0) { pDir->SetFormatted(MAX_PATH_LEN, "%s%s", drive, dirCStr); } pFilename->Set(ofn.lpstrFile); } }