Zipper Noise

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

thanks a bunch for the code snippet Trancey 8)

makes things a whole lot clearer.

For those interest, I found that adding a very simple LPF to the output of the delay lines solved the zipper problem to my satisfaction and let me release my new plugin today instead of 3 weeks from now after I've implemented a whole new method. :shock:

This thread HAS been a valuable learning experience for me, though - so thanks a bunch to all who contributed :)

See the effects forum in about 5 minutes for my new plugin ......

Post

scuzzphut wrote:For those interest, I found that adding a very simple LPF to the output of the delay lines solved the zipper problem to my satisfaction and let me release my new plugin today instead of 3 weeks from now after I've implemented a whole new method. :shock:
But then isn't your delay low-pass-filtering its contents?
Image
Don't do it my way.

Post

euh...
a zip IS high frequencies, so if you filter the highest frequencies it's logical...

Post

Hi Russell,

Yes , there is now an lpf on the delay buffer output. It's set at a high frequency with 0 resonance so there is little impact on the sound. My excuse is that any degradation is an intentional homage to tape based delays :? :D

Post

Borogove wrote:
scuzzphut wrote:For those interest, I found that adding a very simple LPF to the output of the delay lines solved the zipper problem to my satisfaction and let me release my new plugin today instead of 3 weeks from now after I've implemented a whole new method. :shock:
But then isn't your delay low-pass-filtering its contents?
I expect the lopass filter is on the read head position, not the audio data.

Forever,




Kim.

Post

If it is not, there would be a zipper noise.

But try the interpolation, just to hear the difference.

Post

I'll be trying out all of your techniques for my own education and future plugins. Thanks for your help guys :)

Post

I'm surprised at how many of you use linear interpolation. At the same computational cost, you can have a better performing allpass interpolation that doesn't suffer from high frequency flutter and aliasing due to linear interpolation's dynamic zero.

a little explanation of all pass interpolation can be found here:
http://ccrma-www.stanford.edu/~jos/wave ... ation.html

Also look into Jon Dattorro's AES paper on modulated delays.

Post

cheers :)

Post

Using linear or allpass interpolation is just a matter of taste and depend on the application.

AFAIK:
Allpass is good for physical modeling because it models dispersion (i.e. the additionnal delay introduced by the interpolation is frequency dependent).
cf piano strings or coupling of waveguides with the external world.

while Linear interpolation doesn't have this behaviour (i.e. all the frequency components are delayed by the same amount).

cheers

--remy

Post

Now what you all are saying is cool, but AFAIC Kim has nailed it, but he's rather vague. I've spent a few hours with Magnus -of Ambience fame- discussing this:

the coolest would be having a FIXED buffer-length and the same location fo reading and writing into the buffer. Now, you're going to say, how the hell are you going to make the delay shorter and longer?

Well, what you do is basicaly change the samplerate.

buffer = 200 samples
inputIndex = wrap(inputIndex + 1)
outputIndex = wrap(outputIndex + 1)

=> delay = 200 samples

buffer = 200 samples
inputIndex = wrap(inputIndex + 0.5)
outputIndex = wrap(outputIndex + 0.5)

=> delay = 400 samples.


Now obviously this is tricky, because if you'd do +5 instead of +0.5 you'd get places in the delay line that would never get filled! So, it needs a lot more thinking and I'm not spilling ou all our secrets just yet ;) [not to mention the fact that we haven't solved it completely]

Kim, is this what you propose? Have you worked out the "tricky details"?


- bram

Post

I don't think it would work out as being efficient - you would have to resample writing to the buffer AND resample reading from the buffer. The resampling of writes to the buffer could require manipulating a large number of samples at once.

I think using a fixed buffer with an interpolated read pointer with an offset equal to the delay time is a very good solution, so long as the movement of the read 'pointer' is filtered and updated per-sample.
However, the effect of doing it this way is not like how it would actually be on a tape delay.
What would happen would be that the pitch would change of the residual sound in the buffer as you approach the desired read position, and then settle back down to the original pitch.
A tape delay would have to physically change the speed of the tape, so as you increase the speed of the tape, any residual sound in the delay line would permanently change pitch.

I think the suggestion that I made about dynamically resampling AND changing the buffer length would work, and would sound the same, except that the quality would be better when the delay time is static, because no interpolation would have to take place (unless the delay time is not an integer number of samples). The downside is that every buffer position would also have to have an accompanying piece of data which is its samplerate - the interpolation would have to be pretty dynamic in order that lots of changes to the delay time get remembered by the buffer.
It doesn't stop there either. Both buffers would also need to be double buffered. If the result of the interpolation yielded more than one sample, then you would need to insert items into the buffer! As we all know, this is obviously not an option - so the buffer would need to be copied to an additional buffer as it is resampled, and there would need to be a switch between the buffers at wrap time (which is also dynamic!).

Sort of thinking as I was typing there - does it sound like a reasonable solution?

Post

Bram wrote:Now what you all are saying is cool, but AFAIC Kim has nailed it, but he's rather vague.

Kim, is this what you propose? Have you worked out the "tricky details"?
Yes, something like that. A variable-speed read head would have to go with a variable-speed write head. I haven't worked out the details... because I've never had to implement it.

Strictly speaking, I'm not a DSP programmer. I've spent several years programming in Max/MSP, and many many years programming non-DSP code in several languages (not to mention a side interest in CPU archetecture, algorithms and data structures, etc). Just don't show me anything with derivatives in it. :)

Forever,




Kim.

Post

Bram wrote:Now obviously this is tricky, because if you'd do +5 instead of +0.5 you'd get places in the delay line that would never get filled!
Well, that's just silly. You'd need some magic code to interpolate, otherwise you'd get bizzaro artifacts whenever you increase the delay length!

Forever,




Kim.

Post

Bram wrote:buffer = 200 samples
inputIndex = wrap(inputIndex + 1)
outputIndex = wrap(outputIndex + 1)

=> delay = 200 samples

buffer = 200 samples
inputIndex = wrap(inputIndex + 0.5)
outputIndex = wrap(outputIndex + 0.5)

=> delay = 400 samples.
Another way of doing it would be to have a fixed write head, with a read head of variable distance from the write head. Perhaps something like:

Code: Select all

buffer = 200 samples
for each sample
     buffer[wrap(writehead++)] = inputsample
     outputsample = 
          ( buffer[wrap(writehead-floor(delaylength))] + 
          buffer[wrap(writehead-ceiling(delaylength))] ) /2
That way you're only interpolating once (on read), and writing doesn't require any samplerate malarky. You might get some interesting artifacts if delaylength is a static non-integer.

Forever,




Kim.

Post Reply

Return to “DSP and Plugin Development”