My team has discovered a bug with the parameter mapping in the VST3->VST2 wrapper.
Our VST2 plugin makes parameter changes to the VST2 layer by calling into Vst2wrapper::performEdit() which uses the paramIndexMap map to find the parameter index where the change is requested. Shortly after the VST host (in our case- Ableton) calls Vst2Wrapper::setParameter() to add these parameter changes, and this is eventually propagated to our controller on vst2wrapper::onTimer().
Vst2Wrapper::setParameter() however uses the parameterMap vector to find the index to addParameterChange(). Since the parameterMap map excludes the master bypass parameter (unlike paramIndexMap) in the case when Vst2Wrapper::mBypassParameterID = 0, we are always off by 1 index every time Vst2Wrapper::setParameter() evaluates the new index.
For example if we make the following changes using Vst2Wrapper::performEdit():
ParamID = 1, value = 0.39
ParamID = 2, value = 0.316
in the next pass when Ableton calls into vst2Wrapper::setParameter(), it uses the parameterMap vector to evaluate the ids for addParameterChange() as the following:
ParamID = 2, value = 0.39
ParamID = 3, value = 0.316
This is eventually propagated to our plugin UI when Vst2Wrapper::onTimer() => controller->setParamNormalized() happens and our plugin UI starts exhibiting weird behavior as a result. This happens 100% of the time we use Vst2Wrapper::performEdit() to make parameter changes.
Our workaround is to do the following in Vst2Wrapper::setParameter(): instead of using the parameterMap vector, evaluate the id from the paramIndexMap map by finding the key in paramIndexMap which has the value equal to the index parameter and using that key as the index in addParameterChange(). We are not sure if these workarounds will cause other instabilities. Alternately, is there something that we can do during setupParameters() to fix this issue?
Attached is a modified version of the again sample plug-in that comes with the VST3 SDK that demonstrates this bug. I made the following changes to the sample project to demonstrate the bug:
- Moved the bypass parameter to index 0 (this is the primary cause of the bug)
- Added two additional parameters (Other and Dummy) after the Gain parameter and before the VuPPM parameter
- Added two additional sliders corresponding to the additional parameters
Upon moving the Gain slider, the change will be propagated to the Other slider. Similarly, moving the Other slider results in changes to the Dummy slider. This is the same behavior we are seeing in our plug-in, where Bypass is also at index 0.
again-modified.zip (165 KB)