Pitch Shifting Delay, Smoothing Artifacts, and the Doppler Effect

Hello folks, I hope you are well.

Hoping to get some help with smoothing my delayTimes to eliminate artifacts. The goal is to create a delay plugin that pitch shifts as the delayTime is changed, i.e. the Doppler effect.

Prototyping in SuperCollider has shown me that a control rate delay with no interpolation can still produce this response, yet I have had no luck in JUCE. Here is my process block. delayTime is set in the value tree and retrieved with delayTime.get().

void ModDelayAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
{
    juce::ScopedNoDenormals noDenormals;
    auto totalNumInputChannels  = getTotalNumInputChannels();
    auto totalNumOutputChannels = getTotalNumOutputChannels();

    for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
        buffer.clear (i, 0, buffer.getNumSamples());

    if (mustUpdateProcessing)
        update();
    juce::SmoothedValue<float, ValueSmoothingTypes::Linear> delaySmoothed;
    
    delaySmoothed.setTargetValue(delayTime.get() * mSampleRate / 1000); // delay in samples
    delaySmoothed.reset(buffer.getNumSamples());
    
    // initial tap
    for (int channel = 0; channel < totalNumInputChannels; ++channel)
    {
        auto* buffRead = buffer.getReadPointer (channel);
        auto* buffWrite = buffer.getWritePointer(channel);
        
        for (int i = 0; i < buffer.getNumSamples(); ++i)
        {
            delayLine.pushSample(channel, buffRead[i]);
            
            auto dTime = delaySmoothed.getCurrentValue();
            float sample = delayLine.popSample(channel, dTime, true);
            buffWrite[i] = sample;
        }

    }
    
}

This text will be hidden

1 Like

You’re going to need one delayLine per channel.

I’m on it, do you have any advice on how to use feedback with this?

Is it though? The new dsp::DelayLine looks like it handles multiple channels already. I haven’t actually played with it yet, but would certainly appear that way if you pass a ProcessSpec to prepare with numChannels > 1.