AudioBuffer<> General Questions

Hi all, I cannot find a tutorial or forum post that deals with these topics directly.
Firstly, When and where should one call .clear() on an audioBuffer?
Second, Should audioBuffer be initialised in prepareToPlay or ProcessBlock.
Third, How can we stop random, screaming feedback in a plugin, what should one look for or that a case of simply clearing the buffers in the right place. Many thanks

That entirely depends on your application, but releaseResources is a good candidate. Also any time you need to refresh the buffer e.g. your source audio stream or file changes.

You should initialize it in a constructor or prepareToPlay. Or in another method specific to your program, for instance a button callback.

ProcessBlock is called over and over again by the audio thread. Initializing it there would be too slow, as well as cause re-initialization over and over again.

We’ll definitely need more details and the relevant code to help you with that.


Some documentation links:

You need to call clear() on the AudioBuffer if you’re not going to overwrite all its contents yourself. It will initially be filled with junk, hence the screaming feedback.

1 Like

Thank you for your responses people they are very useful.

void AirAbsorption::prepareToPlay (double sampleRate, int samplesPerBlock)
{
    std::cout << "AirAbsorption::prepareToPlay" << std::endl;
    juce::dsp::ProcessSpec spec { sampleRate, static_cast<juce::uint32> (samplesPerBlock), 2 };
    
    //===Prepare the oct filters===
    for (size_t i = 0; i < octFilters.size(); i++) {
        octFilters[i].prepare(spec);
    }


    //==Preapre the airAbsorptionGains array of gains for each octave==
    for (size_t i = 0; i < 11; i++) {
        airAbsorptionGains[i].prepare(spec);
    }

    //clear the buffers to avoid noise
    for (auto& buffer : octBuffers) {
        buffer.clear();
    }

    for (auto& buffer : octBuffersDouble) {
        buffer.clear();
    }

    for( auto& buffer: octBuffers) {
        buffer.setSize(2, samplesPerBlock);
    }

    for (auto& buffer : octBuffersDouble){
        buffer.setSize(2, samplesPerBlock);
    }
}

void AirAbsorption::processBlock (juce::AudioSampleBuffer& buffer, juce::MidiBuffer&) 
{
    std::cout << "NUM CHANNELS: " << buffer.getNumChannels() << std::endl;
    std::cout << "NUM SAMPLES: " << buffer.getNumSamples() << std::endl;

    std::cout << "AirAbsorption::processBlock" << std::endl;
    for ( auto& fb : octBuffers) {
        fb = buffer;
    }
    // Create separate buffer objects for each element of octBuffers
    // for (auto& fb : octBuffers) {
    //     fb.setSize(buffer.getNumChannels(), buffer.getNumSamples());
    //     fb.copyFrom(0, 0, buffer, 0, 0, buffer.getNumSamples());
    // }

    std::cout << "finished AIRAbsorption for loop" << std::endl;
    
    for(size_t i = 0; i < octFilters.size(); i++){
        octFilters[i].setCutoffFrequency(crossoverFrequencies[i]);
    }


    //create filterbuffer block and context
    std::vector<juce::dsp::AudioBlock<float>> fbBlocks;
    for (size_t i = 0; i < octBuffers.size(); i++){
        fbBlocks.emplace_back(octBuffers[i]);
    }

    std::vector<juce::dsp::ProcessContextReplacing<float>> contexts;
    for (size_t i = 0; i < octBuffers.size(); i++){
    contexts.emplace_back(fbBlocks[i]);
    }
    std::cout << "ProcessContextReplacing created" << std::endl;

    //==Vector optimisation version==
    for(size_t i =0; i < octFilters.size(); i++){
        octFilters[i].process(contexts[i]);
    }
    std::cout << "Num channels before last oct: " << buffer.getNumChannels() << std::endl;


    std::cout << "octave filters processed" << std::endl;

    //===Get the values for the air absorption calculation===
    double airPressCurrent = getAirPressure();
    double kelvinTempCurrent = celciusToKelvin();
    double humidityCurrent = getHumidity();
    double distanceMCurrent = getDistance();

                                                                                                                //==Dependency graph variables==
    
    std::vector<float> freqBandNominalValuesHz = {16, 20, 25, 31.5, 40, 50, 63, 80, 100, 125, 160, 
                                                  200, 250, 315, 400, 500, 630, 800, 1000, 1250, 
                                                  1600, 2000, 2500, 3150, 4000, 5000, 6300, 8000, 
                                                  10000, 12500, 16000, 20000};        

    for (size_t i = 0; i < octBuffers.size() - 1; i++) {  
        std::cout << "airAirbsorptionCalc for loop in AirAbsorption" << std::endl;                                                                      
        freqBandNominalValueHz = freqBandNominalValuesHz[i];    
                                                                              
        airAbsorptionCalc->absorptionGain(kelvinTempCurrent, airPressCurrent, humidityCurrent,
                                          freqBandNominalValueHz, distanceMCurrent);
        double gainToApply = airAbsorptionCalc->getGain();                                                     
        airAbsorptionGains[i].setGainLinear(gainToApply);                                                                     
        airAbsorptionGains[i].process(contexts[i]);                                                                                                
    }

    auto numSamples = buffer.getNumSamples();
    auto numChannels = buffer.getNumChannels();

    auto addFilterBand = [nc = numChannels, ns = numSamples](auto& inputBuffer, const auto& source){
        for (auto i = 0; i < nc; ++i){
            inputBuffer.addFrom(i, 0, source, i, 0, ns);
        }

    };

    for (size_t i = 0; i <= 32; ++i) {
    addFilterBand(buffer, octBuffers[i]);
    }
}

Do you have any improvements for this class, relating to my use of audio buffers, clearing them, and making sure they are the correct size, this is an audio plugin, this is one of 3 sub processors using the AudioProcessorGraph class

I would do the buffer.clear() after the buffer.setSize().

You don’t want to be using vectors like that in processBlock(). They’ll be allocating and deallocating memory which is a no-no on the audio thread.

And same goes for std::cout: this is a blocking system call which can cause glitches in your audio processing (the processBlock could miss it’s deadline to fill the buffer with valid signal)

Especially since the vectors are static anyway you can create them outside beforehand.

Thank you very much guys, I shall make those improvements now

I can now see this is a big part of my problem, I am assigning the whole buffer in ProcessBlock to each of the buffers which should be just the part of the buffer for the given octave, is this a process that needs to occur in ProcessBlock, or can this be done elsewhere ( like prepareToPlay or a helper function, but then How will processBlock interact with these buffers, as octBuffers are a buffer designed for each 1/3 octave of the human audiable frequency spectrum, I guess I will need Multithreading so that every 1/3 octave buffer is processed concurrently.

Basically, my question is: How can I rely on the buffer object (the one that is the first argument to ProcessBlock), being able to be used and be applicable when I am trying to work on 1/3 octave sized buffers?

Many thanks