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; } } }
void IPlugProcess::EffectInit() { TRACE; if (mPlug) { AddControl(new CPluginControl_OnOff('bypa', "Master Bypass\nMastrByp\nMByp\nByp", false, true)); // Default to off DefineMasterBypassControlIndex(1); int paramCount = mPlug->NParams(); for (int i=0; i<paramCount; i++) { IParam *p = mPlug->GetParam(i); switch (p->Type()) { case IParam::kTypeDouble: AddControl(new CPluginControl_Linear(' ld '+i, p->GetNameForHost(), p->GetMin(), p->GetMax(), p->GetStep(), p->GetDefault(), p->GetCanAutomate())); break; case IParam::kTypeInt: AddControl(new CPluginControl_Discrete(' ld '+i, p->GetNameForHost(), (long) p->GetMin(), (long) p->GetMax(), (long) p->GetDefault(), p->GetCanAutomate())); break; case IParam::kTypeEnum: case IParam::kTypeBool: { std::vector<std::string> displayTexts; for (int j=0; j<p->GetNDisplayTexts(); j++) { displayTexts.push_back(p->GetDisplayTextAtIdx(j)); } assert(displayTexts.size()); AddControl(new CPluginControl_List(' ld '+i, p->GetNameForHost(), displayTexts, (long) p->GetDefault(), p->GetCanAutomate())); break; } default: break; } } #if PLUG_DOES_MIDI if (!IsAS()) { ComponentResult result = noErr; Cmn_Int32 requestedVersion = 7; std::string midiNodeName(PLUG_NAME" Midi"); while (requestedVersion) { result = DirectMidi_RegisterClient(requestedVersion, this, reinterpret_cast<Cmn_UInt32>(this), (void **)&mDirectMidiInterface); if (result == noErr && mDirectMidiInterface != NULL) { mDirectMidiInterface->CreateRTASBufferedMidiNode(0, const_cast<char *>(midiNodeName.c_str()), 1); break; } requestedVersion--; } } #endif mPlug->SetIO(GetNumInputs(), GetNumOutputs()); mPlug->SetSampleRate(GetSampleRate()); mPlug->Reset(); } }
tresult PLUGIN_API IPlugVST3::initialize (FUnknown* context) { TRACE; tresult result = SingleComponentEffect::initialize (context); if (result == kResultOk) { addAudioInput (STR16("Audio Input"), getSpeakerArrForChans(NInChannels()) ); addAudioOutput (STR16("Audio Output"), getSpeakerArrForChans(NOutChannels()) ); if (mScChans == 1) addAudioInput(STR16("Sidechain Input"), SpeakerArr::kMono, kAux, 0); else if (mScChans >= 2) { mScChans = 2; addAudioInput(STR16("Sidechain Input"), SpeakerArr::kStereo, kAux, 0); } if(mDoesMidi) { addEventInput (STR16("MIDI In"), 1); addEventOutput(STR16("MIDI Out"), 1); } for (int i=0;i<NParams();i++) { IParam *p = GetParam(i); int32 flags = 0; 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(), p->GetStep(), flags); 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); 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; } } } return result; }
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; }
AAX_Result IPlugAAX::EffectInit() { TRACE; AAX_CString bypassID = NULL; this->GetMasterBypassParameter( &bypassID ); mBypassParameter = new AAX_CParameter<bool>(bypassID.CString(), AAX_CString("Master Bypass"), false, AAX_CBinaryTaperDelegate<bool>(), AAX_CBinaryDisplayDelegate<bool>("bypass", "on"), true); mBypassParameter->SetNumberOfSteps( 2 ); mBypassParameter->SetType( AAX_eParameterType_Discrete ); mParameterManager.AddParameter(mBypassParameter); for (int i=0;i<NParams();i++) { IParam *p = GetParam(i); AAX_IParameter* param = 0; WDL_String* paramID = new WDL_String("_", 1); paramID->SetFormatted(32, "%i", i+kAAXParamIdxOffset); mParamIDs.Add(paramID); switch (p->Type()) { case IParam::kTypeDouble: { param = new AAX_CParameter<double>(paramID->Get(), AAX_CString(p->GetNameForHost()), p->GetDefault(), AAX_CIPlugTaperDelegate<double>(p->GetMin(), p->GetMax(), p->GetShape()), AAX_CUnitDisplayDelegateDecorator<double>( AAX_CNumberDisplayDelegate<double>(), AAX_CString(p->GetLabelForHost())), p->GetCanAutomate()); param->SetNumberOfSteps(128); // TODO: check this https://developer.digidesign.com/index.php?L1=5&L2=13&L3=56 param->SetType(AAX_eParameterType_Continuous); break; } case IParam::kTypeInt: { param = new AAX_CParameter<int>(paramID->Get(), AAX_CString(p->GetNameForHost()), (int)p->GetDefault(), AAX_CLinearTaperDelegate<int>((int)p->GetMin(), (int)p->GetMax()), AAX_CUnitDisplayDelegateDecorator<int>( AAX_CNumberDisplayDelegate<int>(), AAX_CString(p->GetLabelForHost())), p->GetCanAutomate()); param->SetNumberOfSteps(128); param->SetType(AAX_eParameterType_Continuous); break; } case IParam::kTypeEnum: case IParam::kTypeBool: { int nTexts = p->GetNDisplayTexts(); std::map<int, AAX_CString> displayTexts; for (int j=0; j<p->GetNDisplayTexts(); j++) { int value; const char* text = p->GetDisplayTextAtIdx(j, &value); displayTexts.insert(std::pair<int, AAX_CString>(value, AAX_CString(text)) ); } param = new AAX_CParameter<int>(paramID->Get(), AAX_CString(p->GetNameForHost()), (int)p->GetDefault(), AAX_CLinearTaperDelegate<int>((int)p->GetMin(), (int)p->GetMax()), AAX_CStringDisplayDelegate<int>(displayTexts), p->GetCanAutomate()); param->SetNumberOfSteps(nTexts); param->SetType(AAX_eParameterType_Discrete); break; } default: break; } mParameterManager.AddParameter(param); } AAX_CSampleRate sr; Controller()->GetSampleRate(&sr); SetSampleRate(sr); Reset(); return AAX_SUCCESS; }