AudioFormatReader leaks


#1

I know... I know... yet another silly question about pointer management. Sorry about that.

But I've been stuck with this for a day now. I am using a copy of the code used by Jules in the Juce Demo to play audio files:

    void loadFileIntoTransport (const File& audioFile)

    {

        // unload the previous file source and delete it..

        transportSource.stop();

        transportSource.setSource (nullptr);

        currentAudioFileSource = nullptr;


        AudioFormatReader* reader = formatManager.createReaderFor (audioFile);


        if (reader != nullptr)

        {

            currentAudioFileSource = new AudioFormatReaderSource (reader, true);


            // ..and plug it into our transport source

            transportSource.setSource (currentAudioFileSource,

                                       32768,                   // tells it to buffer this many samples ahead

                                       &thread,                 // this is the background thread to use for reading-ahead

                                       reader->sampleRate);     // allows for sample rate correction

        }

    }

It works fine in my code but I get Leaks when I exit the app if I call this routine more than once.

The line that generates the leaks is 

        AudioFormatReader* reader = formatManager.createReaderFor (audioFile);

I could understand that the reader pointed to by "reader" would not be deleted after the first call (if I call it 4 times I will get 4 leaks), but why does it work in Jules code and not in mine ??? I tried many (bad) things, but could not get rid of the problem. Any hint please ?


#2

This is the key line in the JUCE demo:

currentAudioFileSource = new AudioFormatReaderSource (reader, true);

The second argument (true) tell the AudioFormatReaderSource to take ownership of the reader and therefore delete it when itself is deleted.


#3

I know. But why doesn't it work in MY code ?

 


#4

What objects are you leaking?


#5

Nevermind


#6

OK. Here is one way I found that seems to work. But I still don't understand why using Jules' clean code did not do it.

1 - Define currentAudioFileSource as a regular pointer (not a ScopedPointer)

2 - Define the InputStream as a regular pointer (not a ScopedPointer)

3 - Remove the following 3 lines from the loadFileIntoTransport method

    transportSource.stop();
    transportSource.setSource (nullptr);
    currentAudioFileSource = nullptr;

4 - Use the following code in the caller:

            transportSource.stop();
            transportSource.setSource (nullptr);
            delete currentAudioFileSource;
            audioFileInputStream = new MemoryInputStream (fileToRead, fileSize, false);
            loadFileIntoTransport(audioFileInputStream);

5 - Use the following code in the Destructor:

    transportSource.setSource (nullptr);
    audioSourcePlayer.setSource (nullptr);
    audioSourcePlayer2.setSource (nullptr);
    delete currentAudioFileSource;
    delete midiFileInputStream;

> No more leaks.

If anyone can explain why I needed to go through all this instead of using the same code as in the Juce Demo, I'm a taker...

:)

Phil.


#7

If you've had to resort to raw pointers you still have a problem somewhere! You're probably either deleting an object owned by the 
AudioFormatReaderSource by keeping a ScopedPointer to it in your class or failing to delete an object somewhere. This is why I asked to see the error message, there are two that come from the JUCE_LEAK_DETECTOR, one a double deletion, one a leak.

Also try and keep objects scoped as narrowly as possible, preferring to declare them on the stack. This avoids you having to manage their lifetimes.

The fact that loadFileIntoTransport takes a pointer that is owned by something else sets off a few alarm bells. Why are you passing something called fileToRead into a MemoryInputStream? It's impossible to tell from the snippets what the problem is, it doesn't show the whole picture.
 


#8

Thank you for the hints. I will re-check when I have a little time (not now...). I will let you (and others) know what was wrong, if anything. Right now what I have works but it is more painful because I have to take care of some pointed objects lifetimes...

Regarding fileToRead etc. it is just a bad copy/paste as I use the same scheme to read from external files.

In this particular case I read the data from BinaryData, fileToRead being the pointer and fileSize the size.