Reference a parameter value in prepareToPlay?

Is it possible to reference a parameter value for prepareToPlay? This code is from a JUCE ADC conference (simple delay). I would like to replace the fixed delay value (delayMilliseconds = 200.0f) with a variable value from the delayLength slider. I can’t figure out how to correct the error generated by the variable delayMilliseconds: “expression must have arithmetic or unscoped enum type” .
I would appreciate any guidance … I am a beginner with C++.
Thank You.
Bruno

AudioProcessor::AudioProcessor()
#ifndef JucePlugin_PreferredChannelConfigurations
     : AudioProcessor (BusesProperties()
                     #if ! JucePlugin_IsMidiEffect
                      #if ! JucePlugin_IsSynth
                       .withInput  ("Input",  juce::AudioChannelSet::stereo(), true)
                      #endif
                       .withOutput ("Output", juce::AudioChannelSet::stereo(), true)
                     #endif
                       )
#endif
************************************************************************
    , state(*this, nullptr, "STATE", {
        std::make_unique<juce::AudioParameterFloat>("gain",     "Gain",           0.0f, 1.0f, 0.5f),
        std::make_unique<juce::AudioParameterFloat>("feedback", "Delay Feedback", 0.0f, 1.0f, 0.35f),
        std::make_unique<juce::AudioParameterFloat>("mix",      "Dry / Wet",      0.0f, 1.0f, 0.5f),
        std::make_unique<juce::AudioParameterFloat>("delayLength", "DelayL",       1.0f, 20.0f, 10.0f)
        })
{
}

void AudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{

//  Original code uses fixed delay value ... delayMilliseconds = 200.0f
//  float delayMilliseconds = 200.0f;
    auto delayMilliseconds = state.getRawParameterValue("delayLength");
    auto delaySamples = ((int)std::round(sampleRate * delayMilliseconds / 1000.0f));
    delayBuffer.setSize(2, delaySamples);
    delayBuffer.clear();
    delayBufferPos = 0;

}

The parameters are updated by the host prior top every processBlock() call. So you should not rely on it’s value outside of processBlock.

It is common practice to allocate the resources for the worst case, i.e. the maximum delay length.

2 Likes

I don’t think it’s worth reallocating a buffer of a handful of Mb.

the error must be because the value is a pointer.

2 Likes

i actually have a plugin where a parameter triggers a prepareToPlay call resizing a delay and it’s for a good reason, so never say never :slight_smile:

but ofc it’s not good for most delays.

if you, the person who reads this, need to trigger prepareToPlay from a parameter change, let the processor inherit from Timer and do it on timerCallback, because it’s on the message thread. use suspendProcess before and after prepare to make it threadsafe.

also useful for oversampling for instance

1 Like

Not sure how you would “trigger” prepareToPlay(), but probably better not to call it yourself. You could end up passing different values than what the host thinks those values should be. If you need to call the code that prepareToPlay() uses, better to write a function that prepareToPlay() and your other code can call to do that common work.

3 Likes

i didn’t have any problems with that yet.

suspendProcessing(true);
prepareToPlay(getSampleRate(), getBlockSize());
suspendProcessing(false);

easy as that. why would the getters for the samplerate and block size ever return a wrong information? i have seen people arguing like that before but i don’t understand how that’s supposed to happen yet.

or do you just mean one shouldn’t call it like
prepareToPlay(44100., 512) thinking you can just decide the samplerate etc yourself like that? maybe it should be mentioned explicitely that this is not how it’s done… but i kinda think that’s common sense

1 Like

That was exactly what I was thinking you might be doing. Glad that’s not the case! :upside_down_face:

2 Likes

yeah ok. it might not’ve been that 'common sense’y, since i mentioned oversampling and it could have been read as ‘just call prepare with your own samplerate, bro’. so just to make it clear to everyone who hasn’t tried all this yet: no, i just mean calling prepare with the exact same arguments it was called with already, just to trigger the buffers to resize again

1 Like

FWIW it is best practice not to call callbacks yourself. It might bite you later when you refactor and expect this to be called only from the host.

Instead you should create a prepareBuffers() or similar method, that you call when it is necessary. That way your future you might not make false assumptions.

And for getSampleRate() have a look at the docs for getSampleRate():

This can be called from your processBlock() method - it’s not guaranteed to be valid at any other time, and may return 0 if it’s unknown.

Ideally you store the values you get from prepareToPlay():

void prepareToPlay (double newSampleRate, int newBlockSize) override
{
    sampleRate = newSampleRate;
    blockSize = newBlockSize();
    prepareBuffers();
}

void whenYourProgramChanged()
{
    JUCE_ASSERT_MESSAGE_THREAD;

    suspendProcessing (true);
    prepareBuffers();
    suspendProcessing (false);    
}

And in the prepareBuffers() you can use your own sampleRate and blockSize safely

1 Like

I appreciate all of your responses. I will focus on the ProcessBlock and avoid any complications within prepareToPlay.
Thank You.
Bruno

1 Like

i still couldn’t find a situation that triggers getSampleRate() to return anything else than the sample rate. maybe when the processor was just initialized and prepareToPlay hadn’t even been called. that would make sense. the value must come from somewhere after all. another thing i could imagine if the user changed the sample rate of the project, which would trigger prepareToPlay, and during that call the user would click on something in the plugin interface that causes the timerCallback to also call prepareToPlay. but that’s pretty unlikely as it would require the ability to move the mouse from the project settings of the DAW to the plugin super instantly. maybe a good challenge for the speedrunner community of music production, if it exists, but apart from that something i decide to just ignore, unless someone can come up with a more realistic situation where calling prepareToPlay manually can go wrong