ComponentResult IPlugProcess::SetChunk(OSType chunkID, SFicPlugInChunk *chunk) { TRACE; if (chunkID == mPluginID) { int dataSize = chunk->fSize - sizeof(SFicPlugInChunkHeader); ByteChunk IPlugChunk; IPlugChunk.PutBytes(chunk->fData, dataSize); mPlug->UnserializeState(&IPlugChunk, 0); for (int i = 0; i< mPlug->NParams(); i++) { IParam *p = mPlug->GetParam(i); int idx = i+kPTParamIdxOffset; switch (p->Type()) { case IParam::kTypeDouble: { CPluginControl_Continuous *control = dynamic_cast<CPluginControl_Continuous*>(GetControl(idx)); SetControlValue(idx, control->ConvertContinuousToControl( p->Value() )); break; } case IParam::kTypeInt: case IParam::kTypeEnum: case IParam::kTypeBool: { CPluginControl_Discrete *control = dynamic_cast<CPluginControl_Discrete*>(GetControl(idx)); SetControlValue(idx, control->ConvertDiscreteToControl( p->Int() )); break; } default: break; } } fNumPlugInChanges++; return noErr; } return kChunkRangeErr; }
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 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; }
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 LRESULT CALLBACK IGraphicsWin::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { if (msg == WM_CREATE) { LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lParam; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LPARAM) (lpcs->lpCreateParams)); int mSec = int(1000.0 / sFPS); SetTimer(hWnd, IPLUG_TIMER_ID, mSec, NULL); SetFocus(hWnd); return 0; } IGraphicsWin* pGraphics = (IGraphicsWin*) GetWindowLongPtr(hWnd, GWLP_USERDATA); char txt[MAX_EDIT_LEN]; if (!pGraphics || hWnd != pGraphics->mPlugWnd) { return DefWindowProc(hWnd, msg, wParam, lParam); } if (pGraphics->mParamEditWnd && pGraphics->mParamEditMsg == kEditing) { if (msg == WM_RBUTTONDOWN) { pGraphics->mParamEditMsg = kCancel; return 0; } return DefWindowProc(hWnd, msg, wParam, lParam); } switch (msg) { case WM_TIMER: { if (wParam == IPLUG_TIMER_ID) { if (pGraphics->mParamEditWnd && pGraphics->mParamEditMsg != kNone) { switch (pGraphics->mParamEditMsg) { case kUpdate: { if (!pGraphics->mEdParam) break; pGraphics->mEdParam->GetDisplayForHost(txt); char currentText[MAX_PARAM_LEN]; SendMessage(pGraphics->mParamEditWnd, WM_GETTEXT, MAX_PARAM_LEN, (LPARAM) currentText); if (strcmp(txt, currentText)) { IParam* pParam = pGraphics->mEdParam; if (pParam->GetNDisplayTexts() && (pParam->Type() == IParam::kTypeEnum || pParam->Type() == IParam::kTypeBool)) SendMessage(pGraphics->mParamEditWnd, CB_SELECTSTRING, -1, (LPARAM) txt); else SendMessage(pGraphics->mParamEditWnd, WM_SETTEXT, 0, (LPARAM) txt); } break; } case kCommit: { SendMessage(pGraphics->mParamEditWnd, WM_GETTEXT, MAX_EDIT_LEN, (LPARAM) txt); pGraphics->SetFromStringAfterPrompt(pGraphics->mEdControl, pGraphics->mEdParam, txt); // Fall through. } case kCancel: { SetWindowLongPtr(pGraphics->mParamEditWnd, GWLP_WNDPROC, (LPARAM) pGraphics->mDefEditProc); DestroyWindow(pGraphics->mParamEditWnd); pGraphics->mParamEditWnd = 0; pGraphics->mEdParam = 0; pGraphics->mEdControl = 0; pGraphics->mDefEditProc = 0; } break; } pGraphics->mParamEditMsg = kNone; //return 0; } IRECT dirtyR; if (pGraphics->IsDirty(&dirtyR)) { RECT r = { dirtyR.L, dirtyR.T, dirtyR.R, dirtyR.B }; InvalidateRect(hWnd, &r, FALSE); UpdateWindow(hWnd); if (pGraphics->mParamEditWnd) { pGraphics->mParamEditMsg = kUpdate; } } } return 0; } case WM_RBUTTONDOWN: { if (pGraphics->mParamEditWnd) { pGraphics->mParamEditMsg = kCancel; return 0; } // Else fall through. } case WM_LBUTTONDOWN: { if (pGraphics->mParamEditWnd) pGraphics->mParamEditMsg = kCommit; SetCapture(hWnd); pGraphics->OnMouseDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), &GetMouseMod(wParam)); return 0; } case WM_MOUSEMOVE: { if (!(wParam & (MK_LBUTTON | MK_RBUTTON))) { if (pGraphics->OnMouseOver(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), &GetMouseMod(wParam))) { TRACKMOUSEEVENT eventTrack = { sizeof(TRACKMOUSEEVENT), TME_LEAVE, hWnd, HOVER_DEFAULT }; TrackMouseEvent(&eventTrack); } } else if (GetCapture() == hWnd) { pGraphics->OnMouseDrag(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), &GetMouseMod(wParam)); } return 0; } case WM_MOUSELEAVE: { pGraphics->OnMouseOut(); return 0; } case WM_LBUTTONUP: case WM_RBUTTONUP: { ReleaseCapture(); pGraphics->OnMouseUp(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), &GetMouseMod(wParam)); return 0; } case WM_LBUTTONDBLCLK: { if (pGraphics->OnMouseDblClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), &GetMouseMod(wParam))) { SetCapture(hWnd); } return 0; } case WM_MOUSEACTIVATE: { SetFocus(hWnd); return MA_ACTIVATE; } case WM_MOUSEWHEEL: { int d = GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA; int x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam); RECT r; GetWindowRect(hWnd, &r); pGraphics->OnMouseWheel(x - r.left, y - r.top, &GetMouseMod(wParam), d); return 0; } case WM_KEYDOWN: { bool ok = true; int key; if (wParam == VK_SPACE) key = KEY_SPACE; else if (wParam == VK_UP) key = KEY_UPARROW; else if (wParam == VK_DOWN) key = KEY_DOWNARROW; else if (wParam == VK_LEFT) key = KEY_LEFTARROW; else if (wParam == VK_RIGHT) key = KEY_RIGHTARROW; else if (wParam >= '0' && wParam <= '9') key = KEY_DIGIT_0+wParam-'0'; else if (wParam >= 'A' && wParam <= 'Z') key = KEY_ALPHA_A+wParam-'A'; else if (wParam >= 'a' && wParam <= 'z') key = KEY_ALPHA_A+wParam-'a'; else ok = false; if (ok) { POINT p; GetCursorPos(&p); ScreenToClient(hWnd, &p); pGraphics->OnKeyDown(p.x, p.y, key); } } return 0; case WM_PAINT: { RECT r; if (GetUpdateRect(hWnd, &r, FALSE)) { IRECT ir(r.left, r.top, r.right, r.bottom); pGraphics->Draw(&ir); } return 0; } //case WM_CTLCOLOREDIT: { // // An edit control just opened. // HDC dc = (HDC) wParam; // SetTextColor(dc, ///); // return 0; //} case WM_CLOSE: { pGraphics->CloseWindow(); return 0; } } return DefWindowProc(hWnd, msg, wParam, lParam); }
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; }
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; }