Delay plugin with ARA support

Hi, I am new to ARA based plugin development. I am developing a plugin with delay effect with ARA support to draw the waveforms and realtime position tracking. I have cloned the ARADemoPlugin as starting point.

Can someone help out with the best place to put the delay code?
I have defined circular buffers for the delay logic and I am processing the input buffer in the processBlock of the AudioProcess and putting the updated samples back into the buffer and then calling the processBlock of the ARAPlaybackRenderer.

buffer.setSample(0, i, buffer.getSample(0, i) *  (1 - m_mix) + delaySampleLeft * m_mix);
buffer.setSample(1, i, buffer.getSample(1, i) *  (1 - m_mix) + delaySampleRight * m_mix);

It is playing fine as long as delay is off but as soon as I put a delay time > 0, there is a lag in the playback and the playhead position on the waveform. Can someone help with the issue?

Thanks.

Any help from the community is appreciated.

Thanks.

It feels like a lot more information is required in order to help you here, maybe you could post more details about how you get delaySampleLeft/Right.
Another thing to note is that your plugin will only work with a stereo channel layout if you hardcode the channel indexes like that.

1 Like

the code just shows how you dry/wet the delay. would look the same without ARA

I understand the point. I am using an open source logic for the delay effect. Here’s the delay logic used.

**float** delayInSamplesFrac = mSampleRate * (time / 1000.f);

**int** delayInSamplesInt = **static_cast**<**int**> (delayInSamplesFrac);

**float** frac = delayInSamplesFrac - delayInSamplesInt;

// Add delay into buffer

**for** (**auto** channel = 0; channel < buffer.getNumChannels(); ++channel)

{

// Get smoothed parameter values

**float** FB = m_feedback;

**float** W = m_mix;

**float** G = m_gain;

**const** **float*** input = buffer.getReadPointer(channel);

**float*** output = buffer.getWritePointer(channel);

**for** (**auto** sample = 0; sample < buffer.getNumSamples(); ++sample)

{

**float** delayedSample = 0.f;

// Fractal delay with liner interpolation if neede

**if** (frac != 0)

{

**float** y0 = mDelayLines[channel].get(delayInSamplesInt);

**float** ym1 = mDelayLines[channel].get(delayInSamplesInt + 1);

delayedSample = linearInterp(y0, ym1, frac);

}

**else**

{

delayedSample = mDelayLines[channel].get(delayInSamplesInt);

}

**auto** inputSample = input[sample];

mDelayLines[channel].push(inputSample + delayedSample * FB);

output[sample] = inputSample * G + delayedSample * W;

}

}

After this, the ARA processBlock is called which is exaclty same as in the JUCE ARAPluginDemo like this

if (!processBlockForARA (buffer, isRealtime(), audioPlayHead))
        processBlockBypassed (buffer, midiMessages);
    
    playHeadState.update (audioPlayHead->getPosition());

My point is delay works fine but as soon as the delay is applied the play head in the ARA demo plugin is moving ahead from the currently played audio block means i am getting wrong play position.

@moritzsur

The playback stops for a second and then the delay is getting applied

Hi, can anyone help out?

Regards.

I am new to the ARA sdk implementation. Where should we add the delay logic, in the AudioProcessor’s processBlock or ARARenderer’s?

The core functionality should almost certainly go into your ARAPlaybackRenderer’s processBlock() function.

Your AudioProcessor::processBlock() should only call processBlockForARA(). You can see an example for this in ARAPluginDemo.h among the JUCE examples.

I have put the basic delay logic inside the renderer’s processBlock now and the delay is applied as expected but the only problem is audio playback is starting a bit later once i hit play but the playhead moves before that, is it because of processing delay? I am testing on Reaper.

I kept everything same as the demo code and just added the delay. Any pointers for help? @attila

The playhead’s position is controlled by Reaper and isn’t affected by contents of the processBlock() function.

It could be that your delay logic is causing the playback to start later, but we can’t say much without seeing the full picture. Even in this case the playhead will always move immediately after you press play.

I am applying the delay to the readBuffer in the processBlock of the renderer like this. -

            auto& readBuffer = (didRenderAnyRegion) ? *tempBuffer : buffer;

            if (! reader.get()->read (&readBuffer, startInBuffer, numSamplesToRead, startInSource, true, true))
            {
                success = false;
                continue;
            }
            

            mDelay.process(readBuffer);

where the mDelay processing is this logic -

**float** delayInSamplesFrac = mSampleRate * (time / 1000.f);

**int** delayInSamplesInt = **static_cast**<**int**> (delayInSamplesFrac);

**float** frac = delayInSamplesFrac - delayInSamplesInt;

// Add delay into buffer

**for** (**auto** channel = 0; channel < buffer.getNumChannels(); ++channel)

{

// Get smoothed parameter values

**float** FB = m_feedback;

**float** W = m_mix;

**float** G = m_gain;

**const** **float*** input = buffer.getReadPointer(channel);

**float*** output = buffer.getWritePointer(channel);

**for** (**auto** sample = 0; sample < buffer.getNumSamples(); ++sample)

{

**float** delayedSample = 0.f;

// Fractal delay with liner interpolation if neede

**if** (frac != 0)

{

**float** y0 = mDelayLines[channel].get(delayInSamplesInt);

**float** ym1 = mDelayLines[channel].get(delayInSamplesInt + 1);

delayedSample = linearInterp(y0, ym1, frac);

}

**else**

{

delayedSample = mDelayLines[channel].get(delayInSamplesInt);

}

**auto** inputSample = input[sample];

output[sample] = inputSample * G + delayedSample * W;

mDelayLines[channel].push(inputSample + delayedSample * FB);

}

}

There is lag in the playback vs the playhead as soon as i put a delay and feedback value of more than 0. Can you help out with the issue from the code shared? @attila