DelayLine - how to pop them samples

I’m trying to implement the DelayLine class in the DSP module, I would like to modulate the delay time in order to play with some various dsp effects. Would someone mind taking a look at this and showing me the error of my ways!

Here’s how I constructed it in my processor.h

juce::dsp::DelayLine<float, juce::dsp::DelayLineInterpolationTypes::Linear> mDelayLine;

This is my prepare to play function!

juce::dsp::ProcessSpec spec;
spec.sampleRate = sampleRate;
spec.maximumBlockSize = samplesPerBlock;
spec.numChannels = getTotalNumOutputChannels();


This is my process block!

void FeedPitchAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)


juce::ScopedNoDenormals noDenormals;
auto totalNumInputChannels  = getTotalNumInputChannels();
auto totalNumOutputChannels = getTotalNumOutputChannels();

// if you've got more output channels than input clears extra outputs
for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
    buffer.clear (i, 0, buffer.getNumSamples());

const int bufferLength = buffer.getNumSamples();

mSliderDelayTime = treeState.getRawParameterValue(DELAY_TIME_ID)->load();

for (int channel = 0; channel < totalNumInputChannels; ++channel)
    auto* inData = buffer.getReadPointer(channel);
    auto* outData = buffer.getWritePointer(channel);

    for (int i = 0; i < bufferLength; i++)
        mDelayLine.pushSample(channel, inData[i]);
        outData[i] = mDelayLine.popSample(channel, mSliderDelayTime);

This is my first post on the forum so apologies if there are some rookie errors. Much appreciated! Henry.

I see a couple of problems :

  • You don’t seem to be initializing the DelayLine with a maximum size. The default constructor gives it a size of 4 samples, you will probably want construct it with at least 44100 samples or something… Like juce::dsp::DelayLine<float, juce::dsp::DelayLineInterpolationTypes::Linear> mDelayLine{44100};
  • You are not smoothing the delay time from the parameter, which will lead to audio glitches when changing the delay time. You could use a SmoothedValue or a simple 1st order low pass filter for that.
1 Like

Just to check - mSliderDelayTime - is this measured in ‘number of samples’? If it is in seconds or milliseconds, you will need to convert it to number of samples by multiplying it by the sample rate (assuming the variable is measured in seconds).

1 Like

Yes, mSliderDelayTime is measured in number of samples, ranging from 1 - 500 in 1 sample steps.

Thanks for the reply!

Ah okay yes makes sense, I’ve now initialized with a default sample rate.

Smoothing the delay was on my list of things to do! But wanted to get some sort of delayed effect first as cannot even get that right now. I can hear the audio glitches if I move the slider quickly now at least! So I think that’s a step forward. But still no delay effect.
SampleType popSample (int channel, SampleType delayInSamples = -1, bool updateReadPointer = true);
Does delayInSamples need to be a negative number? Tried it and doesn’t make a difference.
Many thanks for your help!

Disclamer: I roll my own delay lines so don’t use the inbuilt JUCE ones.

By hearing the “delay effect” I assume you mean the gradual decaying echo effect? It looks like you are just replacing the signal in your audio buffer with the output of the delay line. This will be delaying the signal but because you are only hearing a delayed output it will sound exactly the same as the input signal - just with a bit of latency. To get a delay with a couple of edits…

for (int channel = 0; channel < totalNumInputChannels; ++channel)
    auto* data = buffer.getWritePointer(channel);

    for (int i = 0; i < bufferLength; i++)
        mDelayLine.pushSample(channel, data[i]);
        data[i] += mDelayLine.popSample(channel, mSliderDelayTime);

I have changed it so you are using only one pointer - only one is needed as they are pointing to the same thing (write pointers can read as well). This is of course unless pushSample requires a read pointer. Also have changed the = in your loop to a += so that the delayed signal isn’t replacing the input signal; it will be combined. This means you will hear both the original and delayed signal. From here you could introduce a feedback to get the classic decaying echo effect.

Hope this helps!

1 Like

Excellent the += has done the job so I can hear the mix of the two signals now, makes total sense that before I was only hearing the delayed signal, so thank you! Makes sense about the write pointer so I have only one write pointer now like suggested.

And by “delay effect” I mean to automate the delay time using a phasor as per this Max MSP tutorial to achieve pitch shifting! (there’s three parts as it’s old YouTube 10min constraints I think)

Thanks for the help!

1 Like

Great to hear it’s working!

Very cool, I hadn’t thought about doing pitch shifting that way before, thanks for linking that.

1 Like

Yes same glad it’s working!

Awesome, if you try it and get it working let me know! Would love to hear it in action.

Smoothing would definitely be helpful. One thing to note is your use of the “pop” function.
The delay line has some handy things in in terms of its process. Likely what you’re best doing is instead of popping a sample at the position of your delay slider, is using your sample to set the delay within delay line and using the process function to do all of the maths within that. All you’d need to do then is handle the updating of your slider, which can take floats and handle all of your interpolation too.

I’m working on a similar project to create a vibrato so haven’t had chance to test but would love to discuss more about this!

I’ve had a look today and it seems I was totally confused by the term “pop”, which I took to mean, take the last sample, remove it from the buffer and use that rather than what is here, read the sample at delay point and advance the read head. My bad!
Sorry for leaving a misleading comment. Hope your project went well, would be exciting to hear it!

Ah that’s a shame, yes I will post some results soon! I did get a vague pitch shifting sound but have since broken it by fiddling with it too much! So going to go back and re-create it with all I’ve learnt in the past weeks.

I had a look at this DelayLine class. It seems with the above implementation you just get a single echo rather than a set of trailing echos, is this what you have found too? I presume to get a set of trailing echos you need to implement an additional feedback mechanism, in which case this is not really a delay per se, just part of it. I actually implemented my own delay function which works with a set of trailing delays and filtering, but I’m having difficulty with (the classic) glitches due to parameter changes.

I just working on a delay effect and still have some issue to understand the need of smoothing value for this kind of thing. @xenakios Could you give a little example or refer to one that explain this? It will be helpful

So fare I come to this:

void prepare(...) {
  smoothedRegularDelay_.reset(sampleRate_, 0.1f);

void setDelay(float newDelay) {

void process(const Context& context) {
  const auto ioblock = context.getOutputBlock();

  for (int channelIndex = 0; channelIndex < channelCount; channelIndex++) {
    auto channelData = ioblock.getChannelPointer(channelIndex);

    for (int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++) {
      const auto delay = smoothedRegularDelay_.getNextValue();
      const auto output = delayLine_.popSample(channelIndex, delay);

      auto sample = channelData[sampleIndex] + feedback_ * output;
      sample = juce::jlimit(-feedbackGainLimit_, feedbackGainLimit_, sample);
      delayLine_.pushSample(channelIndex, sample);

      if (isRegularEnabled) {
        const auto drySample = channelData[sampleIndex];
        channelData[sampleIndex] = (drySample * dry) + (output * wet);

But the moothedRegularDelay_.reset(sampleRate_, 0.1f); give a weird pitched effect. Do we have a specific rampInSeconds value to use? I tried few different but didn’t manage to find a good one :thinking: