Hi Ivan, I’m currently working on code that uses your Oversampling class and I have a few comments/questions.
Due to 10.6.8 compatibility, I so far used the hiir oversampling class (http://ldesoras.free.fr/prod.html) which is similar to your IIR implementation. I think it uses the exact same math for the filters, but the recommendations for bandwidth and attenuation are different. In hiir, Laurent de Soras writes:
For example, let's suppose one wants 16x downsampling, with 96 dB of stopband
attenuation and a 0.49*Fs passband. You'll need the following specifications
for each stage:
2x -> 1x: TBW = 0.01
4x -> 2x: TBW = 0.01/2 + 1/4 = 0.255
8x -> 4x: TBW = 0.01/4 + 1/8 + 1/4 = 0.3775
16x -> 8x: TBW = 0.01/8 + 1/16 + 1/8 + 1/4 = 0.43865
The reason is that you do not need to preserve spectrum parts that will be
wiped out by subsequent stages. Only the spectrum part present after the
final stage has to be preserved.
More generally:
TBW[stage] = (TBW[stage-1] + 0.5) / 2
or
TBW[stage] = TBW[0] * (0.5^stage) + 0.5 * (1 - 0.5^stage)
Your code has this logic:
numStages = newFactor;
for (size_t n = 0; n < numStages; ++n)
{
auto twUp = (isMaximumQuality ? 0.10f : 0.12f) * (n == 0 ? 0.5f : 1.f);
auto twDown = (isMaximumQuality ? 0.12f : 0.15f) * (n == 0 ? 0.5f : 1.f);
auto gaindBStartUp = (isMaximumQuality ? -75.f : -65.f);
auto gaindBStartDown = (isMaximumQuality ? -70.f : -60.f);
auto gaindBFactorUp = (isMaximumQuality ? 10.f : 8.f);
auto gaindBFactorDown = (isMaximumQuality ? 10.f : 8.f);
engines.add (new Oversampling2TimesPolyphaseIIR<SampleType> (numChannels,
twUp, gaindBStartUp + gaindBFactorUp * n,
twDown, gaindBStartDown + gaindBFactorDown * n));
}
The issue is I got better quality with hiir and it looks like your code uses narrower bandwidth than necessary on higher stages and therefore wastes CPU. For me, it would be very nice if the attenuation in dB could be a constructor parameter instead of that isMaximumQuality flag. In my humble opinion, your maximum quality isn’t maximum at all. I am creating a plugin where suppressing aliasing is the most important aspect and -75 dB (+ n*10dB) is not enough for my taste.
If I read your logic right you are assuming that the incoming signal has a maximum frequency slope of 10 dB/oct (gaindBFactorUp/Down) and thus later stages can use less attenuation. IMHO that is a faulty assumption, there are signals that have more high-frequency content, especially in cases where oversampling is needed the most. I don’t understand why gaindBFactorUp is higher for maximum quality? I think it would be better to just keep attenuation constant for all stages and increase bandwidth more.
One more question here: Why are the quality constants different for the IIR and the FIR oversamplers?
I will now create my own constructor to replace that logic and thank you for hinting at that in the description, but I also think this could lead to an interesting discussion and maybe some improvement or more flexibility for the non-subclassed oversampler.
Lastly… is it possible to use the juce dsp oversampler with SSE instructions? And I also mean the one-channel case. The mentioned hiir library uses SSE to calculate both polyphase filters at the same time and that seems a great use of SSE, but as far as I can tell this is not possible with the JUCE class. It looks like it might be able to do multi-channel oversampling using SIMDRegister, but that would mean interleaving the data, correct?