10#include <pluginterfaces/vst/ivsteditcontroller.h>
11#include <pluginterfaces/vst/ivstparameterchanges.h>
13#include <wx/tokenzr.h>
34 Steinberg::Vst::ParamID rootUnitProgramChangeParameterID { Steinberg::Vst::kNoParamId };
35 Steinberg::Vst::ProgramListID rootUnitProgramListID { Steinberg::Vst::kNoProgramListId };
36 Steinberg::int32 rootUnitProgramCount { 0 };
43 const auto key = effectUid.toString();
52 const auto key = effectUid.toString();
55 return result.first->second;
59 int32_t channelsCount, Steinberg::Vst::SpeakerArrangement defaultArragment)
61 if (channelsCount == 1)
62 return defaultArragment;
64 return Steinberg::Vst::SpeakerArr::kStereo;
80 std::map<Steinberg::Vst::ParamID, Steinberg::Vst::ParamValue> result;
81 wxStringTokenizer tokenizer(
str,
";");
82 while(tokenizer.HasMoreTokens())
84 auto token = tokenizer.GetNextToken();
86 const auto split = token.Find(
'=');
87 if(split == wxNOT_FOUND)
92 if(!token.Left(split).ToULong(&
id) ||
93 !token.Right(token.Length() - split - 1).ToDouble(&value))
105 result.Append(wxString::Format(
106 "%lu=%f;",
static_cast<unsigned long>(p.first), p.second));
113 assert(vst3settings);
114 return *vst3settings;
120 assert(vst3settings);
121 return *vst3settings;
130 constexpr int32 MaxChannelsPerAudioBus = 2;
132 std::vector<Vst::SpeakerArrangement> defaultInputSpeakerArrangements;
133 std::vector<Vst::SpeakerArrangement> defaultOutputSpeakerArrangements;
135 const auto processor = FUnknownPtr<Vst::IAudioProcessor>(&component);
137 for(
int i = 0, count = component.getBusCount(Vst::kAudio, Vst::kInput); i < count; ++i)
139 Vst::BusInfo busInfo {};
140 Vst::SpeakerArrangement arrangement {0ull};
142 component.getBusInfo(Vst::kAudio, Vst::kInput, i, busInfo);
144 Vst::SpeakerArrangement defaultArragement {};
145 processor->getBusArrangement(Vst::kInput, i, defaultArragement);
148 busInfo.busType == Vst::kMain
152 component.activateBus(Vst::kAudio, Vst::kInput, i, busInfo.busType == Vst::kMain);
153 defaultInputSpeakerArrangements.push_back(arrangement);
155 for(
int i = 0, count = component.getBusCount(Vst::kAudio, Vst::kOutput); i < count; ++i)
157 Vst::BusInfo busInfo {};
158 Vst::SpeakerArrangement arrangement {0ull};
160 component.getBusInfo(Vst::kAudio, Vst::kOutput, i, busInfo);
162 Vst::SpeakerArrangement defaultArragement {};
163 processor->getBusArrangement(Vst::kOutput, i, defaultArragement);
166 busInfo.busType == Vst::kMain
170 component.activateBus(Vst::kAudio, Vst::kOutput, i, busInfo.busType == Vst::kMain);
171 defaultOutputSpeakerArrangements.push_back(arrangement);
173 for(
int i = 0, count = component.getBusCount(Vst::kEvent, Vst::kInput); i < count; ++i)
174 component.activateBus(Vst::kEvent, Vst::kInput, i, 0);
175 for(
int i = 0, count = component.getBusCount(Vst::kEvent, Vst::kOutput); i < count; ++i)
176 component.activateBus(Vst::kEvent, Vst::kOutput, i, 0);
178 auto result = processor->setBusArrangements(
179 defaultInputSpeakerArrangements.empty() ?
nullptr : defaultInputSpeakerArrangements.data(), defaultInputSpeakerArrangements.size(),
180 defaultOutputSpeakerArrangements.empty() ?
nullptr : defaultOutputSpeakerArrangements.data(), defaultOutputSpeakerArrangements.size()
183 return result == kResultOk;
187bool SetupProcessing(Steinberg::Vst::IComponent& component, Steinberg::Vst::ProcessSetup& setup)
190 auto processor = FUnknownPtr<Vst::IAudioProcessor>(&component);
192 if(processor->setupProcessing(setup) == kResultOk)
209 : mParameterQueues(queues), mParameterCount(
values.
size())
215 queues[queueIndex++].
Set(p.first, p.second);
223 Steinberg::Vst::IParamValueQueue* PLUGIN_API
231 return mParameterCount;
233 Steinberg::Vst::IParamValueQueue* PLUGIN_API
getParameterData(Steinberg::int32 index)
override
235 return &mParameterQueues[index];
242 Steinberg::Vst::IParameterChanges::iid);
258 : mThreadId(
std::this_thread::get_id()), mWrapper(wrapper)
266 const auto paramsCount = mWrapper.
mEditController->getParameterCount();
268 for (
int i = 0; i < paramsCount; ++i)
270 using Steinberg::Vst::ParameterInfo;
271 ParameterInfo info {};
274 if ((info.flags & ParameterInfo::kIsReadOnly) != 0)
277 mCurrentParamValues[info.id] =
293 assert(mStateChangeSettings !=
nullptr);
294 FlushCache(*mStateChangeSettings);
295 mStateChangeSettings =
nullptr;
300 if(mParametersCache.empty())
304 for(
auto& p : mParametersCache)
305 vst3settings.parameterChanges[p.first] = p.second;
306 mParametersCache.clear();
311 mParametersCache.clear();
315 Steinberg::Vst::ParamID
id, Steinberg::Vst::ParamValue valueNormalized)
317 auto it = mCurrentParamValues.find(
id);
319 if (it == mCurrentParamValues.end())
326 constexpr auto epsilon = Steinberg::Vst::ParamValue(1e-5);
328 if (std::abs(it->second - valueNormalized) < epsilon)
331 it->second = valueNormalized;
337 Steinberg::tresult PLUGIN_API
beginEdit(Steinberg::Vst::ParamID
id)
override {
return Steinberg::kResultOk; }
339 Steinberg::tresult PLUGIN_API
performEdit(Steinberg::Vst::ParamID
id, Steinberg::Vst::ParamValue valueNormalized)
override
341 if(std::this_thread::get_id() != mThreadId)
342 return Steinberg::kResultFalse;
344 NotifyParamChange(
id, valueNormalized);
346 if(mStateChangeSettings !=
nullptr || !mWrapper.
IsActive())
349 mParametersCache[
id] = valueNormalized;
355 vst3settings.parameterChanges[
id] = valueNormalized;
360 return Steinberg::kResultOk;
363 Steinberg::tresult PLUGIN_API
endEdit(Steinberg::Vst::ParamID
id)
override {
return Steinberg::kResultOk; }
365 Steinberg::tresult PLUGIN_API
restartComponent(Steinberg::int32 flags)
override {
return Steinberg::kNotImplemented; }
367 DECLARE_FUNKNOWN_METHODS
382 Steinberg::int32& index)
384 return Steinberg::kResultFalse;
393 Steinberg::Vst::ParamValue& value)
397 return Steinberg::kResultOk;
409 , mEffectClassInfo { effectClassInfo }
413 const auto& pluginFactory = module.getFactory();
415 auto effectComponent = pluginFactory.createInstance<Vst::IComponent>(effectClassInfo.ID());
417 throw std::runtime_error(
"Cannot create VST3 effect component");
419 throw std::runtime_error(
"Cannot initialize VST3 effect component");
421 auto audioProcessor = FUnknownPtr<Vst::IAudioProcessor>(effectComponent);
424 throw std::runtime_error(
"VST3 plugin does not provide audio processor interface");
426 if(audioProcessor->canProcessSampleSize(Vst::kSample32) != kResultTrue)
427 throw std::runtime_error(
"32-bit sample size not supported");
433 if(editController.get() ==
nullptr)
438 editController = pluginFactory.createInstance<Vst::IEditController>(VST3::UID(controllerCID));
441 if(editController.get() ==
nullptr)
442 throw std::runtime_error(
"Failed to instantiate edit controller");
451 const auto componentConnectionPoint = FUnknownPtr<Vst::IConnectionPoint>{
mEffectComponent };
452 const auto controllerConnectionPoint = FUnknownPtr<Vst::IConnectionPoint>{
mEditController };
454 if (componentConnectionPoint && controllerConnectionPoint)
469 for(int32 parameterIndex = 0, parametersCount =
mEditController->getParameterCount();
470 parameterIndex < parametersCount;
473 Vst::ParameterInfo parameterInfo {};
474 if(
mEditController->getParameterInfo(parameterIndex, parameterInfo) != kResultOk)
477 if(parameterInfo.unitId != Vst::kRootUnitId)
479 if((parameterInfo.flags & Vst::ParameterInfo::kIsProgramChange) == 0)
483 if(!unitInfoProvider)
487 for(int32 unitIndex = 0, unitCount = unitInfoProvider->getUnitCount();
488 unitIndex < unitCount;
491 Vst::UnitInfo unitInfo{};
492 if(unitInfoProvider->getUnitInfo(unitIndex, unitInfo) != kResultOk)
495 if(unitInfo.id != Vst::kRootUnitId)
498 for(int32 programListIndex = 0, programListCount = unitInfoProvider->getProgramListCount();
499 programListIndex < programListCount;
502 Vst::ProgramListInfo programListInfo{};
503 if(unitInfoProvider->getProgramListInfo(programListIndex, programListInfo) != kResultOk)
506 if(programListInfo.id != unitInfo.programListId)
509 cache.rootUnitProgramListID = programListInfo.id;
510 cache.rootUnitProgramCount = programListInfo.programCount;
514 if(cache.rootUnitProgramListID == Vst::kNoProgramListId)
515 cache.rootUnitProgramCount = parameterInfo.stepCount + 1;
517 cache.rootUnitProgramChangeParameterID = parameterInfo.id;
551 mSetup.maxSamplesPerBlock = 512;
552 mSetup.processMode = Vst::kOffline;
553 mSetup.symbolicSampleSize = Vst::kSample32;
554 mSetup.sampleRate = 44100.0;
557 throw std::runtime_error(
"bus configuration not supported");
566 stateStream.
seek(0, IBStream::kIBSeekSet, &unused);
572 if(!cache->defaultSettings.has_value())
580 ->LoadCurrentParamValues();
598 componentHandler->ResetCache();
599 componentHandler->BeginStateChange(
settings);
600 auto cleanup =
finally([&] { componentHandler->EndStateChange(); });
604 if(!vst3settings->processorState.has_value())
607 if(vst3settings->processorState.has_value())
610 processorState->seek(0, Steinberg::IBStream::kIBSeekSet);
613 processorState->seek(0, Steinberg::IBStream::kIBSeekSet);
614 if(
mEditController->setComponentState(processorState) == Steinberg::kResultOk)
616 if(vst3settings->controllerState.has_value())
619 controllerState->seek(0, Steinberg::IBStream::kIBSeekSet);
628 for(
auto& p : vst3setting.parameterChanges)
636 VST3EffectSettings vst3settings;
641 vst3settings.processorState = processorState.
toString();
646 vst3settings.controllerState = controllerState.
toString();
658 if(cache->rootUnitProgramChangeParameterID != Vst::kNoParamId &&
659 cache->rootUnitProgramCount > 0)
664 programIndex >= 0 && programIndex < cache->rootUnitProgramCount)
666 auto paramValueNormalized =
static_cast<Vst::ParamValue
>(programIndex);
667 if(cache->rootUnitProgramCount > 1)
668 paramValueNormalized /=
static_cast<Vst::ParamValue
>(cache->rootUnitProgramCount - 1);
671 cache->rootUnitProgramChangeParameterID,
672 paramValueNormalized);
677 auto commit =
finally([&] {
mComponentHandler->endEdit(cache->rootUnitProgramChangeParameterID); });
679 cache->rootUnitProgramChangeParameterID,
680 paramValueNormalized);
687 auto fileStream = owned(Vst::FileStream::open(presetId.c_str(),
"rb"));
695 XO(
"Unable to apply VST3 preset file %s").
Format(presetId),
704 auto fileStream = owned(Vst::FileStream::open(filepath.c_str(),
"wb"));
711 XO(
"Failed to save VST3 preset to file"),
720 return Vst::PresetFile::loadPreset
734 return Vst::PresetFile::savePreset
748 Vst::ProcessSetup setup = {
806 for(
auto& p : vst3settings.parameterChanges)
808 auto it = std::find_if(
mParameters.begin(),
mParameters.end(), [&p](
const auto& v) { return v.first == p.first; });
810 it->second = p.second;
830 componentHandler->FlushCache(
settings);
834 if(hasChanges !=
nullptr)
835 *hasChanges = doProcessing;
856 else if(hasChanges !=
nullptr)
867 Vst::ProcessData data;
868 data.processMode =
mSetup.processMode;
869 data.symbolicSampleSize =
mSetup.symbolicSampleSize;
870 data.inputParameterChanges = &inputParameterChanges;
873 static_assert(std::numeric_limits<
decltype(blockLen)>::max()
874 >= std::numeric_limits<
decltype(data.numSamples)>::max());
876 data.numSamples =
static_cast<decltype(data.numSamples)
>(
std::min(
878 static_cast<decltype(blockLen)
>(
mSetup.maxSamplesPerBlock)
881 data.numInputs = inBlock ==
nullptr ? 0 :
mEffectComponent->getBusCount(Vst::kAudio, Vst::kInput);
882 data.numOutputs = outBlock ==
nullptr ? 0 :
mEffectComponent->getBusCount(Vst::kAudio, Vst::kOutput);
884 if(data.numInputs > 0)
886 int inputBlocksOffset {0};
888 data.inputs =
static_cast<Vst::AudioBusBuffers*
>(
889 alloca(
sizeof(Vst::AudioBusBuffers) * data.numInputs));
891 for(
int busIndex = 0; busIndex < data.numInputs; ++busIndex)
893 Vst::BusInfo busInfo { };
894 if(
mEffectComponent->getBusInfo(Vst::kAudio, Vst::kInput, busIndex, busInfo) != kResultOk)
898 if(busInfo.busType == Vst::kMain)
900 data.inputs[busIndex].numChannels = busInfo.channelCount;
901 data.inputs[busIndex].channelBuffers32 =
const_cast<float**
>(inBlock + inputBlocksOffset);
902 inputBlocksOffset += busInfo.channelCount;
907 data.inputs[busIndex].numChannels = 0;
908 data.inputs[busIndex].channelBuffers32 =
nullptr;
910 data.inputs[busIndex].silenceFlags = 0UL;
913 if(data.numOutputs > 0)
915 int outputBlocksOffset {0};
917 data.outputs =
static_cast<Vst::AudioBusBuffers*
>(
918 alloca(
sizeof(Vst::AudioBusBuffers) * data.numOutputs));
919 for(
int busIndex = 0; busIndex < data.numOutputs; ++busIndex)
921 Vst::BusInfo busInfo { };
922 if(
mEffectComponent->getBusInfo(Vst::kAudio, Vst::kOutput, busIndex, busInfo) != kResultOk)
926 if(busInfo.busType == Vst::kMain)
928 data.outputs[busIndex].numChannels = busInfo.channelCount;
929 data.outputs[busIndex].channelBuffers32 =
const_cast<float**
>(outBlock + outputBlocksOffset);
930 outputBlocksOffset += busInfo.channelCount;
935 data.outputs[busIndex].numChannels = 0;
936 data.outputs[busIndex].channelBuffers32 =
nullptr;
938 data.outputs[busIndex].silenceFlags = 0UL;
944 return processResult == kResultOk ?
967 componentHandler->SetAccess(
nullptr);
977 std::vector<FactoryPresetDesc> result;
978 for(
auto& path : paths)
980 wxFileName filename(path);
981 result.push_back({ filename.GetFullPath(), filename.GetName() });
985 if(cache->rootUnitProgramChangeParameterID != Vst::kNoParamId &&
986 cache->rootUnitProgramCount > 0)
988 Vst::String128 programName;
989 if(cache->rootUnitProgramListID != Vst::kNoProgramListId)
993 for(int32 programIndex = 0, programCount = cache->rootUnitProgramCount;
994 programIndex < programCount;
997 if(unitInfoProvider->getProgramName(cache->rootUnitProgramListID, programIndex, programName) != kResultOk)
1000 if(presetDisplayName.empty())
1001 presetDisplayName = wxString::Format(
"Unit %03d - %04d", Vst::kRootUnitId, programIndex);
1011 for(int32_t programIndex = 0; programIndex < cache->rootUnitProgramCount; ++programIndex)
1013 auto normalizedValue =
mEditController->plainParamToNormalized(cache->rootUnitProgramChangeParameterID, programIndex);
1014 if(
mEditController->getParamStringByValue(cache->rootUnitProgramChangeParameterID, normalizedValue, programName) == kResultOk)
1036 return EffectSettings::Make<VST3EffectSettings>();
1041 VST3EffectSettings vst3settings;
1059 if(vst3settings.processorState.has_value())
1061 if(vst3settings.controllerState.has_value())
1063 if(!vst3settings.parameterChanges.empty())
1070 VST3EffectSettings vst3settings;
1072 wxString processorStateStr;
1075 vst3settings.processorState = processorStateStr;
1076 wxString controllerStateStr;
1078 vst3settings.controllerState = controllerStateStr;
1080 wxString parametersStr;
1093 if(vst3settings.processorState.has_value())
1096 if(vst3settings.controllerState.has_value())
1099 if(!vst3settings.parameterChanges.empty())
1109 std::swap(from.parameterChanges, to.parameterChanges);
Declare abstract class AudacityException, some often-used subclasses, and GuardedCall.
@ BadEnvironment
Indicates problems with environment, such as a full disk.
EffectDistortionSettings params
std::optional< std::unique_ptr< EffectSettingsAccess::Message > > OptionalMessage
MessageBoxException for failures of file operations.
static Settings & settings()
IMPLEMENT_FUNKNOWN_METHODS(SingleInputParameterValue, Steinberg::Vst::IParamValueQueue, Steinberg::Vst::IParamValueQueue::iid)
static IHostApplication & Get()
CommandParameters, derived from wxFileConfig, is essentially doing the same things as the SettingsVis...
virtual bool HasEntry(const wxString &strName) const override
EffectDefinitionInterface is a ComponentInterface that adds some basic read-only information about ef...
Thrown for failure of file or database operations in deeply nested places.
static Steinberg::IPtr< PresetsBufferStream > fromString(const wxString &str)
wxString toString() const
A MessageBoxException that shows a given, unvarying string.
tresult PLUGIN_API seek(int64 pos, int32 mode, int64 *result) SMTG_OVERRIDE
static bool ParseFactoryPresetID(const wxString &presetId, Steinberg::Vst::UnitID &unitId, Steinberg::int32 &programIndex)
static wxString GetFactoryPresetsPath(const VST3::Hosting::ClassInfo &effectClassInfo)
static wxString MakeFactoryPresetID(Steinberg::Vst::UnitID unitId, Steinberg::int32 programIndex)
static wxString ToWxString(const Steinberg::Vst::TChar *str)
void BeginParameterEdit(EffectSettingsAccess &access)
const VST3::Hosting::ClassInfo & GetEffectClassInfo() const
size_t Process(const float *const *inBlock, float *const *outBlock, size_t blockLen)
static EffectSettings MakeSettings()
Steinberg::IPtr< Steinberg::Vst::IConnectionPoint > mControllerConnectionProxy
void LoadPreset(const wxString &presetId)
void ProcessBlockStart(const EffectSettings &settings)
Prepares effect to process next block with changes written to the settings object.
Steinberg::IPtr< Steinberg::Vst::IEditController > mEditController
Steinberg::IPtr< Steinberg::Vst::IComponent > mEffectComponent
static void SaveUserPreset(const EffectDefinitionInterface &effect, const RegistryPath &name, const EffectSettings &settings)
Steinberg::IPtr< Steinberg::Vst::IComponentHandler > mComponentHandler
Steinberg::Vst::ProcessContext mProcessContext
Steinberg::int32 GetLatencySamples() const
void FetchSettings(EffectSettings &)
Fetch state from settings object, may change internal runtime data.
static void SaveSettings(const EffectSettings &settings, CommandParameters &parms)
const VST3::Hosting::ClassInfo & mEffectClassInfo
std::unique_ptr< SingleInputParameterValue[]> mParameterQueues
std::function< void(Steinberg::Vst::ParamID, Steinberg::Vst::ParamValue)> ParamChangedHandler
std::vector< FactoryPresetDesc > FindFactoryPresets() const
bool SavePresetToStream(Steinberg::IBStream *fileStream) const
static void CopySettingsContents(const EffectSettings &src, EffectSettings &dst)
bool IsActive() const noexcept
void InitializeComponents()
Should be called once before almost any other method call.
bool Initialize(EffectSettings &settings, Steinberg::Vst::SampleRate sampleRate, Steinberg::int32 processMode, Steinberg::int32 maxSamplesPerBlock)
Initializes effect for processing using settings.
void SavePresetToFile(const wxString &filepath) const
void StoreSettings(EffectSettings &) const
Saves current state inside settings object, clears all runtime data.
static void LoadSettings(const CommandParameters &parms, EffectSettings &settings)
Steinberg::IPtr< Steinberg::Vst::IConnectionPoint > mComponentConnectionProxy
Steinberg::IPtr< Steinberg::Vst::IAudioProcessor > mAudioProcessor
void ConsumeChanges(const EffectSettings &settings)
Steinberg::Vst::ProcessSetup mSetup
std::vector< std::pair< Steinberg::Vst::ParamID, Steinberg::Vst::ParamValue > > mParameters
void FlushParameters(EffectSettings &settings, bool *hasChanges=nullptr)
void Finalize(EffectSettings *settings)
VST3Wrapper(VST3::Hosting::Module &module, const VST3::Hosting::ClassInfo &effectClassInfo)
bool LoadPresetFromStream(Steinberg::IBStream *fileStream)
static OptionalMessage LoadUserPreset(const EffectDefinitionInterface &effect, const RegistryPath &name, EffectSettings &settings)
EffectSettingsAccess * GetAccess()
void BeginStateChange(EffectSettings &settings)
void LoadCurrentParamValues()
const std::thread::id mThreadId
std::map< Steinberg::Vst::ParamID, Steinberg::Vst::ParamValue > mParametersCache
Steinberg::tresult PLUGIN_API endEdit(Steinberg::Vst::ParamID id) override
void SetAccess(EffectSettingsAccess *access)
std::map< Steinberg::Vst::ParamID, Steinberg::Vst::ParamValue > mCurrentParamValues
void NotifyParamChange(Steinberg::Vst::ParamID id, Steinberg::Vst::ParamValue valueNormalized)
ComponentHandler(VST3Wrapper &wrapper)
Steinberg::tresult PLUGIN_API beginEdit(Steinberg::Vst::ParamID id) override
Steinberg::tresult PLUGIN_API performEdit(Steinberg::Vst::ParamID id, Steinberg::Vst::ParamValue valueNormalized) override
virtual ~ComponentHandler()
Steinberg::tresult PLUGIN_API restartComponent(Steinberg::int32 flags) override
void FlushCache(EffectSettings &settings)
Host's proxy object between connection points.
bool SetConfig(const EffectDefinitionInterface &ident, ConfigurationType type, const RegistryPath &group, const RegistryPath &key, const Value &value)
bool GetConfig(const EffectDefinitionInterface &ident, ConfigurationType type, const RegistryPath &group, const RegistryPath &key, Value &var, const Value &defval)
constexpr auto sampleRate
void swap(std::unique_ptr< Alg_seq > &a, std::unique_ptr< Alg_seq > &b)
bool ActivateMainAudioBuses(Steinberg::Vst::IComponent &component)
constexpr auto controllerStateKey
constexpr auto processorStateKey
std::map< Steinberg::Vst::ParamID, Steinberg::Vst::ParamValue > ParametersFromString(const wxString &str)
Steinberg::Vst::SpeakerArrangement GetBusArragementForChannels(int32_t channelsCount, Steinberg::Vst::SpeakerArrangement defaultArragment)
constexpr auto parametersKey
VST3PluginCache & CreateCache(const VST3::UID &effectUid)
bool SetupProcessing(Steinberg::Vst::IComponent &component, Steinberg::Vst::ProcessSetup &setup)
VST3PluginCache * GetCache(const VST3::UID &effectUid)
std::map< std::string, VST3PluginCache > sVST3PluginCache
const VST3EffectSettings & GetSettings(const EffectSettings &settings)
wxString ParametersToString(const std::map< Steinberg::Vst::ParamID, Steinberg::Vst::ParamValue > ¶ms)
Externalized state of a plug-in.
std::optional< wxString > controllerState
Holds the last known controller state, rarely updates (usually only on UI or preset change)
std::map< Steinberg::Vst::ParamID, Steinberg::Vst::ParamValue > parameterChanges
Holds the parameter that has been changed since last processing pass.
std::optional< wxString > processorState
Holds the last known processor/component state, rarely updates (usually only on UI or preset change)
EffectSettings defaultSettings