Allpass interpolation latency

DSP, Plugin and Host development discussion.
Post Reply New Topic
RELATED
PRODUCTS

Post

Hi guys,
there's a way to calculate the latency samples for an AP interpolator used for oversampling?

Thanks!

Post

Audiority wrote:Hi guys,
there's a way to calculate the latency samples for an AP interpolator used for oversampling?
Well .. you can certainly calculate the delay an any given frequency (calculate unwrapped phase-response, divide by normalised frequency), but for anything other than a linear-phase FIR it will be frequency dependent (and integer almost nowhere) so it won't really do you any good as a "latency" value.

Post

I disagree with mystran. If we look for the delay in a famous AP interpolator used for oversampling, it is possible to see that there is a minimum integer value over all the frequencies, depending on the number of the APs in cascade. This value can be obtained by calculating the group delay using the continuous phase response, which isn't that trivial to do. An other method is to do it "by ear" listening to the sound of the plug-in when using a dry/wet of 50%, with an additional delay process (with variable delay value). The comb filtering is very noticeable if the delay is not compensated, and it is really becoming less significant with the right delay value.

If we're talking about the files BandLimit.h and BandLimit.cpp, I can give you the latency values to report if you want :wink:

Post

yea, that is lol even if I heavily modified the original code to integrate my framework... but I'm having an issue with the oversampler buzzing like a beast and I guess that maybe that would be caused by a non reported latency or something wrong with the buffer. I'm using a 4th order filter, non steep (2 + 2 coeffs).

Post

but I'm having an issue with the oversampler buzzing like a beast
I don't think this is caused by the latency not correctly reported. At worst, what you can get in this context is a comb filtering effect if some dry signal is mixed with the oversampled signal. You should have a look for bugs in your implementation :wink:

Post

Ivan_C wrote:If we're talking about the files BandLimit.h and BandLimit.cpp, I can give you the latency values to report if you want :wink:
Oh, I'd like to see your thoughts on this. :)

Post

random_id wrote:
Ivan_C wrote:If we're talking about the files BandLimit.h and BandLimit.cpp, I can give you the latency values to report if you want :wink:
Oh, I'd like to see your thoughts on this. :)
So, since I didn't write down the actual values, I have done a study of that thing again :D First thing comes first, if you have not noticed yet, there is a mistake in the values written on the musicdsp files, as said in the comments on the website (12th order, steep, 0.06329609551399348 should be 0.6329609551399348). Moreover, the processing isn't optimized at all, so I would suggest not using the original file in a commercial product, unless you rewrite some parts of it. I know also that Laurent De Soras did already in his library HIIR a rewrite of that class, it can be interesting for you guys.

So, I started writing a plug-in which only does one thing, oversampling two times the input signal, using the filters two times (upsampling -> filtering -> nonlinear processing -> filtering -> downsampling). Here, I don't do anything in the nonlinear processing, hence the use of a filter two times (two different instances, with the same input parameters but different state variables of course). That plug-in allows me via a combobox to choose my filter design between all twelve choices given in BandLimit.cpp.

Then, I'm going to estimate the extra added latency in samples I get by doing that. Since I do upsampling two times, the latency of the filter is supposed to be halved if considered in the original sample rate. But I use the filter twice (in the upsampling and in the downsampling), so the total latency in the original sample rate is filter latency x 2 / 2 = filter latency.

Next, I open Reaper. I create one track and I put some audio there with some frequency content on all the frequencies (a white noise, the death metal song of your choice). I send the output of that track to two different tracks (in parallel), one of them being put in phase opposition. Without any FX, the audio you get in the master bus is supposed to be zero. Then, I add my oversampling two times plug-in in the first send track, and a delay in the second where I can tweak the value of the delay in samples. The idea here is to find by ear or by looking to the meters the value in the delay which will minimize, for a given filter design, the magnitude in the master bus. If my filters were FIR with linear phase, the right value would give me an absolute silence in the master meters. Since here it's a cascade of polyphase IIR allpass filters, the right value will give a significant decrease in magnitude, but never a silence. So I try to get the lowest value for every filter design specification, and I write the value I get in a table. Here are the results :

Steep
Order = 2 (-36 dB, 0.1) => best delay = 1 sample
Order = 4 (-53 dB, 0.05) => best delay = 2 samples
Order = 6 (-51 dB, 0.01) => best delay = 2 samples
Order = 8 (-69 dB, 0.01) => best delay = 3 samples
Order = 10 (-86 dB, 0.01) => best delay = 3 and 4 very close
Order = 12 (-104 dB, 0.01) => best delay = 4 samples

Not Steep
Order = 2 (-36 dB, 0.1) => best delay = 1 sample
Order = 4 (-70 dB, 0.1) => best delay = 2 samples
Order = 6 (-80 dB, 0.05) => best delay = 3 samples
Order = 8 (-106 dB, 0.05) => best delay = 4 samples
Order = 10 (-133 dB, 0.05) => best delay = 5 samples
Order = 12 (-150 dB, 0.05) => best delay = 6 samples

It's interesting to see here that the best delay is a factor of the order for the not steep designs, and that's not the case for the steep designs. At that point, everything is done by ear and with a look in the meters, so it's not very scientific... The thing is, as mystran said before, the actual delay in samples in this design varies with the frequency, whereas in FIR linear phase - by definition - the delay is constant for all the frequencies (half the size of the filter actually). That's why it might be difficult to find an objective value for a delay to report absolutely when we use these filters in the oversampling context.

However, what I said is that this delay, depending on the frequency, even if it varies across the frequency values, has a minimum which can be used objectively. If the delay from 0 Hz to Fs/2 goes from 2 to 6 samples, then at least we should report 2 samples of added latency in the plug-in. Here is a demonstration for the case not steep / order = 12.

Image

As we can see here (that's an application I'm working on right now :D ), the phase delay - which can be obtained from the continuous phase of the total IIR filter made from the multiplication and addition of all the all-pass filters - has a minimum around 5.3 samples. So the minimum integer delay in samples is at 5. Then, an additional question arises : should we use another value, like the average delay for all the frequencies ? I don't know what's the best, but using my "ear and meter look criterion" with the minimization of the output meter value, 6 seems to be better in this particular case. That might be interpreted as "too much delay on bass frequencies is not important, enough on mid and high is always better" or something like that, I'll let you decide of what you think there.

I hope that was understandable enough :wink:

Post

I don't recall details, but the only time I used those allpass halfband filters was in combination with some other "cheap" processes for generic samplerate conversion. It was a long time ago.

The allpass halfband filters were the "most expensive" of the routines I used. The halfband filters and other processes were written in FPU asm. I picked a bunch of different combinations of the processes, then tested them "nonrealtime" on long slow sine sweeps, writing the results to disk. I tabulated execution time for each combination, and measured the output disk files of the sine sweeps to evaluate frequency response and amount of aliasing for each combination.

It was to offer user-selectable SRC quality choices from an audio application. The combination of processes that ran "fast" and also had the least aliasing and flattest frequency response was chosen for the "Fast" choice. Then the combination that had somewhat slower execution time with the best audio quality was selected for the "Better" choice, and the combination with the best audio fidelity chosen as "Best" choice even if execution might be slow. As best I recall there were more than one "slow" combinations which had similar audio fidelity, and the slowest combination was not necessarily the highest-fidelity combination.

So anyway, depending on the quality level and the nature of the SRC, the latency could vary. Didn't know how to calculate the latency programmatically and there were too many combinations to just store a table of all latencies. All the choices were fairly "quick'n'dirty". For instance the "best" conversion for 44.1 k to 48 k SRC might have been 8X oversample, linear interpolation, then decimate with multiple passes of fairly high-order allpass halfband filters. But maybe the lower quality "better" conversion would only oversample 4X and use some combination of IIR lowpass filters or "lower quality, lower order" allpass halfband filters. Can't recall specifics.

As best I recall, I just measured the latency every time after setting the SRC object for a conversion ratio and quality level. Before returning from the object setting function, I just ran some simple test signal thru the newly-set SRC object to auto-measure its conversion latency. For audio application purposes, I think it was also involved with the size of the soundcard audio buffers versus the conversion ratio. It had to "play ahead" enough to always have sufficient samples samplerate-converted for the next requested audio buffer, so the internal SRC input and output buffers had to be sized accordingly. Which was not very complicated for integer-ratio conversions such as 96 k to 48 k or whatever, but seemed somewhat tricky for things like 96 k to 44.1 k or whatever.

Post

The allpass halfband filters were the "most expensive" of the routines I used.
For me, in the context of strict oversampling (SRC with integer ratios), the main point of using IIR filters instead of FIR filters is the low added latency. Even if it is not null at all as I have shown, for purposes where latency might be an issue but not the magnitude and the phase at high frequencies, it is difficult to find a better method from what I know.

It's totally fine to use a linear phase FIR filter for mastering / mixing audio effects, which seems to be better in quality and speed than optimized IIR polyphase AP filters. But for a guitar amp simulator for example, the IIR filters are mandatory to use IMHO.

Post

Thanks Ivan. Anyway, looks like I'm VERY unlucky with resamplers. So far I tried FIR, AP and Polynomial and I ALWAYS get that buzzing. It looks like an oscillating DC offset. the problem is.. it happens more often when any kind of delay is involved, even a simple z-1 and I can't figure out what's wrong. Even with the most trivial FIR filter, it happens.

Post

Something is wrong there, but that might be a trivial issue... Do you have a different buzz sound if you change the audio buffer size ? Can you give us more information, provide some code to look ?

Post

Yes, the buzz is a different pitch when I change the buffer. I also tried filtering the DC during the process stage, but it gets worse

Post

found the issue. Logic / MainStage allocate the maximum blockSize available in the prepare stage while using the correct one during the processBlock. Nasty to spot, easy to fix lol

Thanks again!

Post Reply

Return to “DSP and Plugin Development”