[Solved (Beginner Error)] juce::dsp::Oscillator producing artifacts

Hey!

I am trying to build a simple chorus plugin using DSP modules such as the Fractional Delay Line and the Oscillator class (for creating the LFO). I believe I have been able to set up the delay correctly, but I get audible artifacts that seem to come from modulating the delay line (The artifacts sound periodic and change when I adjust the LFO Frequency/Amplitude parameters).

I have attached the preparetoplay method and processblock method below, but if you would like me to post also my attribute delcarations in my header file, I am happy to show that too!

void ChorusAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
    mSampleRate = sampleRate;
    //prepare lfo
    juce::dsp::ProcessSpec lfoSpec = { sampleRate,samplesPerBlock,getMainBusNumOutputChannels() };
    lfo.prepare(lfoSpec);
    //type of oscillator
    lfo.initialise([](float x){return std::sin(x);}, 128);    
    //prepare delay line
    mDelayLine = juce::dsp::DelayLine<float, juce::dsp::DelayLineInterpolationTypes::Lagrange3rd>(sampleRate * MAXDELAY); 
    juce::dsp::ProcessSpec delayLineSpec = { sampleRate,samplesPerBlock,getMainBusNumOutputChannels() };
    mDelayLine.prepare(delayLineSpec);
    //set size of delaybuffer
    mDelayBuffer.setSize(2, sampleRate * MAXDELAY);
}

And this is my Process Block code:

void ChorusAudioProcessor::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()); 

    ////////////////////// MY CODE //////////////////////////

    //retrieve parameters from gui
    auto centerDelayInMillis = mParamTree.getRawParameterValue("DELAYID")->load();
    auto wet = mParamTree.getRawParameterValue("DRYWETID")->load();
    auto depth = mParamTree.getRawParameterValue("LFODEPTHID")->load(); //in milliseconds
    auto lforate = mParamTree.getRawParameterValue("LFORATEID")->load();
   
    //derived quantities 
    auto centerDelayInSamples = centerDelayInMillis * 0.001 * mSampleRate;
    float  depthInSamples = depth * 0.001 * mSampleRate;
    
    //update lfo and retrieve the phase offset for the delay
    lfo.setFrequency(lforate);    

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

        for (int sample = 0; sample < buffer.getNumSamples(); ++sample)
        {
            //push dry signal into delay buffer
            auto drySignal = BufferWritePtr[sample];
            mDelayLine.pushSample(channel, drySignal);

            //update lfo and retrieve signal from delay buffer, the max function is to ensure our delay is never negative
            float instantaneousOffsetInSamples = std::max(depthInSamples * lfo.processSample(0.0f), 0.0f);  
            float instanteousDelayedSignal = mDelayLine.popSample(channel, centerDelayInSamples + instantaneousOffsetInSamples); 

            //combine wet and dry signal
            BufferWritePtr[sample] = (wet * instanteousDelayedSignal) + (1.0f - wet)*drySignal;
        }              
    }
}

Here are the individual source files too if you would like to check them out.

PluginEditor.cpp (3.3 KB) PluginEditor.h (1.5 KB) PluginProcessor.cpp (8.0 KB) PluginProcessor.h (2.7 KB)

Probably this:

https://forum.juce.com/t/1-most-common-programming-mistake-that-we-see-on-the-forum/26013

haha oh dear I hold my hands up I am a newbie and I have made a newbie mistake - my LFO implementation is the one that has caused this classic error…

thanks for providing me this link!

No worries; a lot of people run into this. Best of luck with your project.

Matt