Sample buffer size is always minor of delayBuffer size (from juice demo plugin)

Hi again Juicers,
I’m rewriting my vst to fit some needs and I encountered this problem:
in luce plugin demo the delayBuffer is set to 1, 12000.
And in the for getnumsamples loop to process buffers, I have a buffer size of 512, so I get noise when I launch my vst in Cubase…

How can I fix this issue?

void AudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
// Prepare chains
baseProcessChain.prepare(preset.preset01);

// Allocating Buffers
if (isUsingDoublePrecision())
{
    delayBufferDouble.setSize (2, 12000);
    delayBufferFloat.setSize (1, 1);
}
else
{
    delayBufferFloat.setSize(2, 12000);
    delayBufferDouble.setSize(1, 1);
}

reset();

}

I’ve tried to set the buffer size here to 512, and the result is that the buffer has a size of 256…

PS. Use or not to use the double precision in a vst?

Hi @arstudio,

I htink you misunderstood the use of delayBuffer. The original processBuffer methods are in the header file, and they call the process function with an additional buffer, which provides a fifo storage for the audio data to implement the delay effect the demo is showing.

So if you resize the delayBuffer to 512 samples, the delay cannot store anything, and the delay time is zero.

You don’t need to support double processing. If you want to do so, override bool AudioProcessor::supportsDoublePrecisionProcessing() to return true and implement both, void processBlock (AudioBuffer< float > &buffer, MidiBuffer &midiMessages) and void processBlockBypassed (AudioBuffer< double > &buffer, MidiBuffer &midiMessages). Only some DAW hosts support double processing.

The plugin demo shows a nice way to implement single and double float processing using templates, so you don’t need to write code twice.

Hope that helps

1 Like

Ok, I have a delay from STK implemented in my vst, and I used the same structure of the for loop.
Here the code (I use STK effects in series):

void BaseProcessChain::process(AudioBuffer& buffer, AudioBuffer& delayBuffer)
{
const int numSamples = buffer.getNumSamples();

float* const channelData = buffer.getWritePointer(0);
float* const effectData = delayBuffer.getWritePointer(jmin(0, delayBuffer.getNumChannels() - 1));

DBG(buffer.getNumSamples());
DBG(delayBuffer.getNumSamples());

for (int i = 0; i < numSamples; ++i)
{
    channelData[i] = chorus.tick(channelData[i]);
    
    float in = channelData[i];
    channelData[i] += effectData[i];
    effectData[i] = delay.tick(effectData[i]) + in;
    
    channelData[i] = reverb.tick(channelData[i]);
}

}

Is it correct?

PS. It can be that I hear noise or silence the first time I launch the vst in Cubase for the double precision select?

the forum formatting ate your template brackets, I think you wrote:

void BaseProcessChain::process(AudioBuffer<FloatType>& buffer, AudioBuffer<FloatType>& delayBuffer)

You can avoid that, if you indent your code in the forum with four spaces. Then you also get that fancy syntax highlighting.

To tell, if your DSP code is correct, I cannot say. I don’t know enough of what you want to achieve and the surrounding code, like what chorus.tick means etc. :wink:

That can be, if you didn’t clear the buffer when you created it, see AudioBuffer< Type >::setSize (int newNumChannels, int newNumSamples, bool keepExistingContent = false, bool clearExtraSpace = false, bool avoidReallocating = false). For performance reason the default is not to clear the buffer. Either set clearExtraSpace to true or call an explicit AudioBuffer< Type >::clear () afterwards.

Excuse me for the format of my posts… I’ll take care.

I’ve already cleared the buffers after I?ve created them…

The reverb.tick() is a method of STK modules.

…no worries, I was just about to write, that you are missing the template type, when I remembered, that you probably had them when writing…

Unfortunately I never used these STK modules, so I can’t help here. Maybe somebody who knows that module can take over here…

Good luck

The noise that you are hearing could be distortion. It’s a good idea to scale your sample values when you mix them in the for loop, something like:

 channelData[i] = (channelData[i] + effectData[i]) / 2.0f;

So, I’ve cleared my buffers, I set the channelData / 2.0f to buffer in the for numSamples loop, but when I apply delay, when i star the vst i ear a noise and then mute. If i disable and re-enable the vst all is fine but the output of cubase, that is at 0db for both stereo out channels (but the sound is good).

void BaseProcessChain::process(AudioBuffer& buffer, AudioBuffer& delayBuffer)
{
const int numSamples = buffer.getNumSamples();

float* const channelData = buffer.getWritePointer(0);
float* const delayData = delayBuffer.getWritePointer(jmin(0, delayBuffer.getNumChannels() - 1));

DBG(buffer.getNumSamples());
DBG(delayBuffer.getNumSamples());

for (int i = 0; i < numSamples; ++i)
{
    channelData[i] = chorus.tick(channelData[i]);
    
    float in = channelData[i];
    channelData[i] += delayData[i];
    delayData[i] = delay.tick(delayData[i]);
    channelData[i] = (channelData[i] + delayData[i]) / 2.0f;
    
    channelData[i] = reverb.tick(channelData[i]);
}

}

Could it depends by the delay buffer size that is major than the buffer size?

It’s difficult to know what’s going on without seeing the rest of your processing chain. You can get rid of

jmin(0, delayBuffer.getNumChannels() - 1)

for a start. This will only ever be 0 (or -1 if you haven’t set things up correctly, and this would be bad!). You’re also not using

float in

anywhere. Is this deliberate?

Where is your delay buffer filled with samples from an input channel?

Here I call the object function:

void IntellifexAudioProcessor::process (AudioBuffer& buffer,
AudioBuffer& delayBuffer)
{
const int numSamples = buffer.getNumSamples();

applyGain(buffer, delayBuffer);

baseProcessChain.process(buffer, delayBuffer);
//pithchProcessChain.process(buffer, delayBuffer);

// In case we have more outputs than inputs, we'll clear any output
// channels that didn't contain input data, (because these aren't
// guaranteed to be empty - they may contain garbage).
for (int i = getTotalNumInputChannels(); i < getTotalNumOutputChannels(); ++i)
    buffer.clear (i, 0, numSamples);

}

This is from PluginPorcessor.cpp.
The chain is all in ::process() of the previous post (chorus, delay, reverb).
The tick method of these objects returns a buffer filled with effected data.
The var in is unused to test the

channelData[i] = (channelData[i] + delayData[i]) / 2.0f;

line.

I get snippets of code in the examples…
In effect I don’t know where is the input read pointer, but in the PluginProcessor.cpp i have these lines in prepareTpPlay() call:

delayBufferFloat.setSize(2, 12000, false, true, false);

reset();

}

void IntellifexAudioProcessor::reset()
{
// Use this method as the place to clear any delay lines, buffers, etc, as it
// means there’s been a break in the audio’s continuity.
delayBufferFloat.clear();
}

PS. If i set delay gain to 0.0, the vst starts immediatly and without noise…

Well is the delay part of your algorithm working correctly by itself? If you create a plug-in that only does a delay then can you hear what you expect?

So far, in all your code that you posted, I can’t see where an input signal is provided to your delay algorithm. All you have is

delayData[i] = delay.tick(delayData[i]);

which is feeding delayData into whatever your delay object is and writing the result into delayData again. So my question is: what is delayData initially? What do you do in processBlock before you call IntellifexAudioProcessor::process?

Yes, if i create a chain with only delay it’s all ok…
I use these lines:

    float in = channelData[i];
    channelData[i] += delayData[i];
    delayData[i] = delay.tick(delayData[i]) + in;

And i ear correctly the delay.
I assume that the delayData take the input in the line

channelData[i] += delayData[i];

Also this from Juce example plugin (that’s have a simple delay implemented).

Anyway the delay.tick() returns the delayed buffer decayed for each loop, so if I set only one like

channelData[i] = delay.tick(channelData[i]);

I ear only the first delay line…

This is not feeding input into the delay array, it is taking the contents of the delay array and adding it to channelData. When you do

float in = channelData[i];
delayData[i] = delay.tick(delayData[i]) + in;

then your input data (contained in channelData) is first assigned to in, which is then added to delay.tick(delayData[i]) and assigned to to your delayBuffer. So your delay buffer is receiving some input. Also when you do

channelData[i] = delay.tick(channelData[i]);

then your input (contained in channelData) is being fed into your delay object. However, when you do just

delayData[i] = delay.tick(delayData[i]);

then there’s no input signal. If your delayBuffer is initially all zeros (which it should be), then here you are always just feeding zeros back into your delay array.

What happens if you replace

delayData[i] = delay.tick(delayData[i]);

with

delayData[i] = delay.tick(channelData[i]);

?

Excuse me I haven’t read your last post.
If i set

delayData[i] = delay.tick(channelData[i]);

I ear only the first delay line…

Now I’ve setted the delayBuffer to 256 (the same of the main buffer) and I ear only silence, no noise.
After some debugging I noticed that Cubase expected a buffer size of 512, like the initial main buffer size of the vst. When i arm the audio track (cubase, yellow button) the main buffer size changes to 256… i’ve set the delayBuffer to half of samplesPerBlock in the prepare method.
In fact i ear no sound till the buffers allineate themselves.

I think the problem is this…

No, excuse me.
The buffers allineate themselves when i disable and re enable the vst.

EDIT:

I’ve make another test with:

delayData[i] = delay.tick(channelData[i]);

No silence, no noise but if i arm the track, the buffers change to 256 (the length of the delayBuffer)
No matter if i enable or disable the plugin.

So now i can use your code?

That would depend how your delay object works… It’s pretty difficult for us to debug a non-JUCE component by guesswork.