Browse Source

VST3 Host: Ensure AudioProcessor parameter indices are used when appropriate

Previously, IEditController parameter indices were being used to index
into the AudioProcessor parameter array, but these parameter indices are
not guaranteed to point to the same parameter (parameter groups may
cause reordering on JUCE's side). Now, we use the IEditController
indices universally.
v6.1.6
reuk 4 years ago
parent
commit
f35c2d90e2
No known key found for this signature in database GPG Key ID: 9ADCD339CFC98A11
3 changed files with 61 additions and 60 deletions
  1. +4
    -4
      modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp
  2. +15
    -4
      modules/juce_audio_processors/format_types/juce_VST3Common.h
  3. +42
    -52
      modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp

+ 4
- 4
modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp View File

@@ -437,7 +437,7 @@ public:
Vst::ParamID getProgramParamID() const noexcept { return programParamID; }
bool isBypassRegularParameter() const noexcept { return bypassIsRegularParameter; }
void setParameterValue (size_t paramIndex, float value)
void setParameterValue (Steinberg::int32 paramIndex, float value)
{
cachedParamValues.set (paramIndex, value);
}
@@ -445,7 +445,7 @@ public:
template <typename Callback>
void forAllChangedParameters (Callback&& callback)
{
cachedParamValues.ifSet ([&] (size_t index, float value)
cachedParamValues.ifSet ([&] (Steinberg::int32 index, float value)
{
callback (cachedParamValues.getParamID (index), value);
});
@@ -1176,7 +1176,7 @@ public:
endEdit (vstParamId);
}
void paramChanged (int parameterIndex, Vst::ParamID vstParamId, double newValue)
void paramChanged (Steinberg::int32 parameterIndex, Vst::ParamID vstParamId, double newValue)
{
if (inParameterChangedCallback.get())
return;
@@ -1189,7 +1189,7 @@ public:
}
else
{
audioProcessor->setParameterValue ((size_t) parameterIndex, (float) newValue);
audioProcessor->setParameterValue (parameterIndex, (float) newValue);
}
}


+ 15
- 4
modules/juce_audio_processors/format_types/juce_VST3Common.h View File

@@ -991,6 +991,11 @@ private:
We must iterate all parameters on each processBlock call to check whether any
parameter value has changed. This class attempts to make this polling process
as quick as possible.
The indices here are of type Steinberg::int32, as they are expected to correspond
to parameter information obtained from the IEditController. These indices may not
match the indices of parameters returned from AudioProcessor::getParameters(), so
be careful!
*/
class CachedParamValues
{
@@ -1002,14 +1007,20 @@ public:
size_t size() const noexcept { return floatCache.size(); }
Steinberg::Vst::ParamID getParamID (size_t index) const noexcept { return paramIds[index]; }
Steinberg::Vst::ParamID getParamID (Steinberg::int32 index) const noexcept { return paramIds[(size_t) index]; }
void set (size_t index, float value) { floatCache.set (index, value); }
void set (Steinberg::int32 index, float value) { floatCache.set ((size_t) index, value); }
float get (size_t index) const noexcept { return floatCache.get (index); }
float get (Steinberg::int32 index) const noexcept { return floatCache.get ((size_t) index); }
template <typename Callback>
void ifSet (Callback&& callback) { floatCache.ifSet (std::forward<Callback> (callback)); }
void ifSet (Callback&& callback)
{
floatCache.ifSet ([&] (size_t index, float value)
{
callback ((Steinberg::int32) index, value);
});
}
private:
std::vector<Steinberg::Vst::ParamID> paramIds;


+ 42
- 52
modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp View File

@@ -103,7 +103,7 @@ class EditControllerParameterDispatcher : private Timer
public:
~EditControllerParameterDispatcher() override { stopTimer(); }
void push (size_t index, float value)
void push (Steinberg::int32 index, float value)
{
if (controller == nullptr)
return;
@@ -123,7 +123,7 @@ public:
void flush()
{
cache.ifSet ([this] (size_t index, float value)
cache.ifSet ([this] (Steinberg::int32 index, float value)
{
controller->setParamNormalized (cache.getParamID (index), value);
});
@@ -1839,7 +1839,7 @@ struct VST3ComponentHolder
class ParamValueQueue : public Vst::IParamValueQueue
{
public:
ParamValueQueue (Vst::ParamID idIn, size_t parameterIndexIn)
ParamValueQueue (Vst::ParamID idIn, Steinberg::int32 parameterIndexIn)
: paramId (idIn), parameterIndex (parameterIndexIn) {}
virtual ~ParamValueQueue() = default;
@@ -1849,7 +1849,7 @@ public:
Vst::ParamID PLUGIN_API getParameterId() override { return paramId; }
size_t getParameterIndex() const noexcept { return parameterIndex; }
Steinberg::int32 getParameterIndex() const noexcept { return parameterIndex; }
Steinberg::int32 PLUGIN_API getPointCount() override { return size; }
@@ -1892,7 +1892,7 @@ public:
private:
const Vst::ParamID paramId;
const size_t parameterIndex;
const Steinberg::int32 parameterIndex;
float cachedValue;
Steinberg::int32 size = 0;
Atomic<int> refCount;
@@ -1981,10 +1981,10 @@ public:
void initialise (const std::vector<Vst::ParamID>& idsIn)
{
size_t index = 0;
Steinberg::int32 index = 0;
for (const auto& id : idsIn)
map.emplace (id, Entry { std::make_unique<ParamValueQueue> (id, index++) });
map.emplace (id, Entry { std::make_unique<ParamValueQueue> (id, Steinberg::int32 { index++ }) });
queues.reserve (map.size());
queues.clear();
@@ -2014,7 +2014,7 @@ public:
struct VST3Parameter final : public Parameter
{
VST3Parameter (VST3PluginInstance& parent,
int vstParameterIndex,
Steinberg::int32 vstParameterIndex,
Steinberg::Vst::ParamID parameterID,
bool parameterIsAutomatable)
: pluginInstance (parent),
@@ -2026,15 +2026,15 @@ public:
float getValue() const override
{
return pluginInstance.cachedParamValues.get ((size_t) vstParamIndex);
return pluginInstance.cachedParamValues.get (vstParamIndex);
}
/* The 'normal' setValue call, which will update both the processor and editor.
*/
void setValue (float newValue) override
{
pluginInstance.cachedParamValues.set ((size_t) vstParamIndex, newValue);
pluginInstance.parameterDispatcher.push ((size_t) vstParamIndex, newValue);
pluginInstance.cachedParamValues.set (vstParamIndex, newValue);
pluginInstance.parameterDispatcher.push (vstParamIndex, newValue);
}
/* If the editor set the value, there's no need to notify it that the parameter
@@ -2044,7 +2044,7 @@ public:
*/
void setValueFromEditor (float newValue)
{
pluginInstance.cachedParamValues.set ((size_t) vstParamIndex, newValue);
pluginInstance.cachedParamValues.set (vstParamIndex, newValue);
sendValueChangedMessageToListeners (newValue);
}
@@ -2122,7 +2122,7 @@ public:
}
VST3PluginInstance& pluginInstance;
const int vstParamIndex;
const Steinberg::int32 vstParamIndex;
const Steinberg::Vst::ParamID paramID;
const bool automatable;
const bool discrete = getNumSteps() != AudioProcessor::getDefaultNumParameterSteps();
@@ -2373,10 +2373,18 @@ public:
}
//==============================================================================
VST3Parameter* getParameterForID (Vst::ParamID paramID)
/* Important: It is strongly recommended to use this function if you need to
find the JUCE parameter corresponding to a particular IEditController
parameter.
Note that a parameter at a given index in the IEditController does not
necessarily correspond to the parameter at the same index in
AudioProcessor::getParameters().
*/
VST3Parameter* getParameterForID (Vst::ParamID paramID) const
{
const auto index = getIndexOfParamID (paramID);
return index < 0 ? nullptr : static_cast<VST3Parameter*> (getParameters()[index]);
const auto it = idToParamMap.find (paramID);
return it != idToParamMap.end() ? it->second : nullptr;
}
//==============================================================================
@@ -2459,14 +2467,14 @@ public:
associateWith (data, buffer);
associateWith (data, midiMessages);
cachedParamValues.ifSet ([&] (size_t index, float value)
cachedParamValues.ifSet ([&] (Steinberg::int32 index, float value)
{
inputParameterChanges->set (cachedParamValues.getParamID (index), value);
});
processor->process (data);
outputParameterChanges->forEach ([&] (size_t index, float value)
outputParameterChanges->forEach ([&] (Steinberg::int32 index, float value)
{
parameterDispatcher.push (index, value);
});
@@ -2886,38 +2894,7 @@ private:
StringArray programNames;
Vst::ParamID programParameterID = (Vst::ParamID) -1;
std::map<Vst::ParamID, int> paramToIndexMap;
int getMappedParamID (Vst::ParamID paramID) const
{
auto it = paramToIndexMap.find (paramID);
return it != paramToIndexMap.end() ? it->second : -1;
}
int getIndexOfParamID (Vst::ParamID paramID)
{
if (editController == nullptr)
return -1;
auto result = getMappedParamID (paramID);
if (result < 0)
{
auto numParams = editController->getParameterCount();
for (int i = 0; i < numParams; ++i)
{
Vst::ParameterInfo paramInfo;
editController->getParameterInfo (i, paramInfo);
paramToIndexMap[paramInfo.id] = i;
}
result = getMappedParamID (paramID);
}
return result;
}
std::map<Vst::ParamID, VST3Parameter*> idToParamMap;
EditControllerParameterDispatcher parameterDispatcher;
//==============================================================================
@@ -3045,6 +3022,19 @@ private:
}
setParameterTree (std::move (newParameterTree));
idToParamMap = [this]
{
std::map<Vst::ParamID, VST3Parameter*> result;
for (auto* parameter : getParameters())
{
auto* vst3Param = static_cast<VST3Parameter*> (parameter);
result.emplace (vst3Param->getParamID(), vst3Param);
}
return result;
}();
}
void synchroniseStates()
@@ -3216,12 +3206,12 @@ private:
destination.processContext = &timingInfo;
}
Vst::ParameterInfo getParameterInfoForIndex (int index) const
Vst::ParameterInfo getParameterInfoForIndex (Steinberg::int32 index) const
{
Vst::ParameterInfo paramInfo{};
if (processor != nullptr)
editController->getParameterInfo (index, paramInfo);
editController->getParameterInfo ((int32) index, paramInfo);
return paramInfo;
}


Loading…
Cancel
Save