Hi,
I’m struggling with an elegant solution to a, I assume, common problem. I’m working on a synthesizer which features different filter models. The user can switch to a different model on the fly. When doing so, inevitably some aliassing will occur because the signal changes immediately. Meaning, the signal out of filter A is different from the signal out of filter B, thus when immediately switching some aliasing will occur.
To mitigate this I’ve created a simple state machine that fades out and in when a change of selection has occured.
It works as follows: user selects a different model than the current. At this point the state is set to ‘FADE_OUT’. The old model is still applied and a .applyGainRamp is applied to the buffer until the gain reaches 0.0. Then, state is changed to ‘FADE_IN’ and the new model will be used. applyGainRamp is applied with an increasing gain over time until gain reaches 1.0. State is reset to ‘NO_FADE’.
See this:
template <typename FloatType>
void MonosynthPluginAudioProcessor::processFilterBlending(AudioBuffer<FloatType>& buffer)
{
int numSamples = buffer.getNumSamples();
int blendTimeSamples = sampleRate * 0.01;
FloatType gainRampCoeff = ( (FloatType)numSamples / (FloatType)blendTimeSamples);
if (lastFilterChoice != *filterSelectParam)
{
if (filterBlendState == NO_FADE) filterBlendState = FADE_OUT;
}
// APPLY FILTER
LadderFilterBase* curFilter;
switch (lastFilterChoice) {
case 0:
curFilter = filterA.get();
break;
case 1:
curFilter = filterB.get();
break;
case 2:
curFilter = filterC.get();
break;
}
applyFilterEnvelope(buffer, curFilter);
applyFilter(buffer, curFilter);
switch (filterBlendState)
{
case FADE_OUT : {
FloatType beginGain = filterGain;
filterGain -= gainRampCoeff;
buffer.applyGainRamp(0, 0, numSamples, beginGain, filterGain);
if (filterGain <= 0.0) {
lastFilterChoice = *filterSelectParam;
filterBlendState = FADE_IN;
}
return;
}
case FADE_IN: {
FloatType beginGain = filterGain;
filterGain += gainRampCoeff;
buffer.applyGainRamp(0, 0, numSamples, beginGain, filterGain);
if (filterGain >= 1.0) {
filterBlendState = NO_FADE;
filterGain = 1.0;
}
return;
}
case NO_FADE: {
return;
}
}
}
But this solution is not perfect. On other effects such as a chorus, aliasing is still very noticable, except of course when I increase the fade in/out time.
So my question is, are there any other techniques that I could apply to solve this problem?