1
$\begingroup$

I'm trying to implement a simple digital delay line. I want it so that when the user changes the delay amount, it sounds smooth and not glitchy. Currently I'm implementing a fractional delay line but I'm still getting a very glitchy sound when I change the delay amount.

What else do I need to implement besides a fractional implementation? I can post code if need be.

EDIT: Here's some code-

- (void)setDelay:(Float32)dly {
    // get delay amount
    delay = dly*srate;
    if (delay != 0) delay -= 1;

    // Get Delay difference
    Float32 outPointer = w - delay;
    // wrap write
    while (outPointer < 0) outPointer += DELAY_MAX;

    // Integer conversion
    r = (int)outPointer;
    // Wrap read
    if (r == DELAY_MAX) r = 0;
    // Fractional Calculation
    alpha = outPointer - r;
    // Get interpolation values
    omAlpha = 1.f-alpha;
}

// interpolation method
- (Float32)nextOut {
    // If we can get the next output
    if (doNextOut) {
        // First 1/2 of interpolation
        nextOutput = cBuf[r]*omAlpha;
        // Second 1/2 of interpolation
        if (r+1 < DELAY_MAX) {
            nextOutput += (cBuf[r+1]*alpha);
        }
        else {
            nextOutput += (cBuf[0]*alpha);
        }
        // set false
        doNextOut = false;
     }
     // return interpolation
     return nextOutput;
}
$\endgroup$
  • $\begingroup$ how are you implementing the fractional-sample delay? $\endgroup$ – robert bristow-johnson Nov 18 '15 at 3:29
  • $\begingroup$ @robertbristow-johnson just added code for calculating the fractional part and interpolation $\endgroup$ – yun Nov 18 '15 at 17:09
2
$\begingroup$

If you change the delay parameter suddenly, there will be a jump to another point in time in the data, resulting in a glitch. The easiest is to filter the delay parameter with a one-pole low-pass filter:

$$\text{out}[k] = \text{out}[k-1] + a(\text{in}[k] - \text{out}[k-1]),$$

where $a$ is a constant between 0 and 1, $\text{in}[k]$ is the delay parameter controlled by the user and $\text{out}[k]$ is the delay parameter actually used in the delay line, for integer time index $k$. ($\text{out}[k-1]$ is the previous filtered value.) You can cascade these stages in series to get further smoothing. Two stages should sound good because it will get rid of discontinuities in the pitch shift due to a kind of doppler effect that changing the delay length creates.

The constant $a$ can be tuned manually. A good value might be the highest value that does not produce disturbing glitches. For a better explanation of $a$, useful if you need to adapt to a different sampling frequency:

$$a \approx (1-p)^{\frac{f_s}{t_p}},$$

where $p$ between 0 and 1 represents the percentage that the filtered delay parameter has come towards a new value of the input delay parameter in time $t_p$, and $f_s$ is the sampling frequency. The formula is for a single filtering stage. If you have multiple stages the meaning of $t_p$ changes but you can still use it to go from one sampling frequency to another. The -3 dB cutoff frequency $f_\text{cutoff}$ for a stage will be approximated by:

$$f_\text{cutoff} \approx \frac{-f_s\ln a}{2\pi} $$

$\endgroup$
  • $\begingroup$ So what decides the constant a? I am also assuming t stands for time? What is t-1? The previous time constant? $\endgroup$ – yun Nov 17 '15 at 18:56
  • $\begingroup$ I changed the answer to explain those, also changed t->k. $\endgroup$ – Olli Niemitalo Nov 17 '15 at 20:55
  • $\begingroup$ Thanks for the more thorough explanation, one more question, what should the corner frequency be in this situation? $\endgroup$ – yun Nov 17 '15 at 21:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.