AudioPlugin MultiTrack Player

Hi Everyone,
I’m playing multiple fixed wavFiles through my plugin according to the AverageRMSofAllChannels. Everything plays fine but i keep having that Error message coming up when i click at the “cross case” to close my plugin (none when i stop the build ):

if (numObjects.value > 0.1)
            {
                DBG ("*** Leaked objects detected: " << numObjects.value << " instance(s) of class " << getLeakedObjectClassName());

                /** If you hit this, then you've leaked one or more objects of the type specified by
                    the 'OwnerClass' template parameter - the name should have been printed by the line above.

                    If you're leaking, it's probably because you're using old-fashioned, non-RAII techniques for
                    your object management. Tut, tut. Always, always use std::unique_ptrs, OwnedArrays,
                    ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
                */
                jassertfalse;
            }

in my constructor:

 auto reader = formatManager.createReaderFor(std::make_unique<juce::MemoryInputStream>(BinaryData::Test1_wav, BinaryData::Test1_wavSize, false));
    if (reader != nullptr)
    {

        std::unique_ptr<juce::AudioFormatReaderSource> newSource(new juce::AudioFormatReaderSource(reader, true));
        newSource->setLooping(true);
        transportSource.setSource(newSource.release());
        mixer.addInputSource(&transportSource, false);

        

    }

    auto reader2 = formatManager.createReaderFor(std::make_unique<juce::MemoryInputStream>(BinaryData::Test2_wav, BinaryData::Test2_wavSize, false));
    if (reader2 != nullptr)
    {

        std::unique_ptr<juce::AudioFormatReaderSource> newSource2(new juce::AudioFormatReaderSource(reader2, true));
        newSource2->setLooping(true);
        transportSource2.setSource(newSource2.release());
        mixer.addInputSource(&transportSource2, false);
      

    }

and into the processBlock

    juce::ScopedNoDenormals noDenormals;
    auto totalNumInputChannels  = getTotalNumInputChannels();
    auto totalNumOutputChannels = getTotalNumOutputChannels();


    for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
        buffer.clear(i, 0, buffer.getNumSamples());



    if (getAverageRMSofAllChannels(buffer) > 0.1 ) 
    { 
        if (onDragIsStart == false)
        {
            play();
        }
    }
    else
    {
        stop();
    }


    mixer.getNextAudioBlock(juce::AudioSourceChannelInfo(buffer));

I’m struggling figuring out what i do wrong :wink: would anybody get a clue ? thanks a lot!

float FXAudioProcessor::getAverageRMSofAllChannels(const juce::AudioBuffer<float>& buffer)
{
    const auto numSamples = buffer.getNumSamples();
    const auto numChannels = buffer.getNumChannels();

    auto avg = buffer.getRMSLevel(0, 0, numSamples);

    for (int chan = 1; chan < numChannels; chan++)
        avg += buffer.getRMSLevel(chan, 0, numSamples);

    avg /= (float)numChannels;

    return avg;
}

From the docs of AudioTransportSource:

The source passed in will not be deleted by this object, so must be managed by the caller.

When you call

transportSource.setSource(newSource.release());

the ownership of newSource is no longer managed.

The solution is to make the

std::unique_ptr<juce::AudioFormatReaderSource> newSource;

a class member, so it will be still managed.

1 Like

Thanks a lot Daniel !

Sorry but there s obvously something i keep misunderstanding :frowning:
i ve made the newSource a class member using a ScopedPointer

private:
  juce::ScopedPointer<juce::AudioFormatReaderSource> newSource;

then still to my constructor

    auto reader = formatManager.createReaderFor(std::make_unique<juce::MemoryInputStream>(BinaryData::Test1_wav, BinaryData::Test1_wavSize, false));
    if (reader != nullptr)
    {

        newSource = new juce::AudioFormatReaderSource(reader, true);
        newSource->setLooping(true);
        transportSource.setSource(newSource.release());
        mixer.addInputSource(&transportSource, false);

        

    }

and yet having same trouble

You still release the ownership here. If you use this instead:

transportSource.setSource (newSource.get());

the newSource lifetime is still managed and is not leaking.

You might need to call transportSource.setSource (nullptr); in case the newSource is deleted before the transportSource stops working.

1 Like

Brilliant ! Thanks a lot Daniel :wink: you have made my week!