writeFromAudioSampleBuffer, wav format problem

Hello,
I am experiencing trouble with .wav format writing. The written file can be read back by VLC, but not Audacity (duration is 0, like also when trying to load it from the JUCE app). Can someone tell what is missing in the file creation ? Some appropriate metadataValues ?
The code is the following:

const File dir (File::getSpecialLocation(File::userDocumentsDirectory).getChildFile ("AudioDocs"));
		dir.createDirectory();
		const File file (dir.getNonexistentChildFile("New", ".wav"));
		
		DBG("FIle FULLPATHNAME : " << file.getFullPathName());
		file.deleteFile();
		ScopedPointer<FileOutputStream> fos (file.createOutputStream());
		WavAudioFormat wavFormat;
		AudioFormatWriter* afw =
		wavFormat.createWriterFor(fos, 44100, buffer.getNumChannels(), 16, StringPairArray(), 0);
		afw->writeFromAudioSampleBuffer(buffer, 0, buffer.getNumSamples());

You’re leaking your writer object. It needs to be allowed to finalise the file in its destructor.

Sorry: what needs to be allowed?

When the destructor of WavAudioFormatWriter is called, it writes the actual length of the file into the header. VLC ignores that and plays anyway, but Audacity takes the value 0 and says the file is empty.

What Jules said is, that in your code you leak

AudioFormatWriter* afw =
	wavFormat.createWriterFor(fos, 44100, buffer.getNumChannels(), 16, StringPairArray(), 0);

So the destructor afw is not properly called.

Change it to e.g.

ScopedPointer<AudioFormatWriter> afw =
	wavFormat.createWriterFor(fos, 44100, buffer.getNumChannels(), 16, StringPairArray(), 0);

and you should be fine…

@jules @daniel why don’t those createWriterFor() methods return a ScopedPointer? Was the idea ever considered?

Before C++11 we couldn’t return ScopedPointers because not everyone’s compiler could handle the move operator correctly. At some point we should move to returning std::unique_ptrs for things like this but as it’ll be a breaking change we’ll wait a little while before doing it.

lol you guys need a “breaking changes” branch on the repo

Thanks to all!
Daniel, when I change from AudioFormatWriter* to ScopedPointer, it triggers the error on the deletion of the fileOutputStream:

        // If the line below triggers a compiler error, it means that you are using
    // an incomplete type for ObjectType (for example, a type that is declared
    // but not defined). This is a problem because then the following delete is
    // undefined behaviour. The purpose of the sizeof is to capture this situation.
    // If this was caused by a ScopedPointer to a forward-declared type, move the
    // implementation of all methods trying to use the ScopedPointer (e.g. the destructor
    // of the class owning it) into cpp files where they can see to the definition
    // of ObjectType. This should fix the error.

Any suggestions ?

It is, because the stream object is already deleted. From the WavAudioFormat::createWriterFor():

streamToWriteTo: the stream that the data will go to - this will be deleted by the
AudioFormatWriter object when it’s no longer needed. If no AudioFormatWriter can
be created by this method, the stream will NOT be deleted, so that the caller can
re-use it to try to open a different format, etc

HTH

Hi ! Did you solve this?

like mentioned before, the WavAudioFormatWriter will own the stream to write to and destroy it, when the writer is destroyed.

To be clear, the returned writer will own the outputStream, so there is no need to put it into a ScopedPointer or similar. You only have to make sure, the lifetime of the writer object is correctly handled.

Thanks, now i got it to work!