FLAC writer broken?


#1

Hello,
I can’t have a non-silent FLAC file written with current Juce revision… modifying the demo’s record page code to replace WaveAudioFormat with FlacAudioFormat can easily show the problem. The resulting recorded file is likely to be silent or just invalid FLAC stream maybe…

Best Regards,


#2

… BTW, tested on Win7, problem was already there on October 15th revision.


#3

Well, I just tried hacking the demo like that and it works fine for me…


#4

weird…

I just took the head revision again, recompiled the (unhacked) juce demo in another folder, recorded with wav AudioFormat, checked the result (it works, generated WAV is OK), changed again the WavAudioFormat line in AudioDemoRecordPage.cpp to FlacAudioFormat, and still had the same problem: generated Flac is valid but silent. I used foobar2k and Winamp to play the files.


#5

Maybe a stupid question, but you did change the file’s extension to “.flac”, right?


#6

Yep

my modified lines are:
from l61:
[code] if (fileStream != 0)
{
// Now create a WAV writer object that writes to our output stream…
/WavAudioFormat wavFormat;
AudioFormatWriter
writer = wavFormat.createWriterFor (fileStream, sampleRate, 1, 16, StringPairArray(), 0);/
FlacAudioFormat wavFormat;
AudioFormatWriter
writer = wavFormat.createWriterFor (fileStream, sampleRate, 1, 16, StringPairArray(), 0);

            if (writer != 0)
            {
                fileStream.release(); // (passes responsibility for deleting the stream to the writer object that is now using it)

                // Now we'll create one of these helper objects which will act as a FIFO buffer, and will
                // write the data to disk on our background thread.
                threadedWriter = new AudioFormatWriter::ThreadedWriter (writer, backgroundThread, 32768);

                // And now, swap over our active writer pointer so that the audio callback will start using it..
                const ScopedLock sl (writerLock);
                activeWriter = threadedWriter;
            }
        }[/code]

and from l226:
[code] else
{
/File file (File::getSpecialLocation (File::userDocumentsDirectory)
.getNonexistentChildFile (“Juce Demo Audio Recording”, “.wav”));
/
File file (File::getSpecialLocation (File::userDocumentsDirectory)
.getNonexistentChildFile (“Juce Demo Audio Recording”, “.flac”));

        recorder->startRecording (file);
    }[/code]

The output FLAC file is valid and seen by foobar/winamp as such:
[attachment=0]JuceDemo_RecordedFLAC_File_Foobar2k_Properties.png[/attachment]

The only problem is that it’s silent instead of what me whistling in the microphone during the recording (the waveform meter moved accordingly during the record).


#7

Try playing it back in the juce demo itself, that worked for me, and it also played ok in VLC. Or do some debugging and see if you can follow the audio data to see whether it’s getting lost somewhere.


#8

Hello
Well , I had sometime today to do some debugging on it and found this in juce_FlacAudioFormat.cpp (l 360):

[code] bool write (const int** samplesToWrite, int numSamples)
{
using namespace FlacNamespace;
if (! ok)
return false;

    int* buf[3];
    const int bitsToShift = 32 - bitsPerSample;

    if (bitsToShift > 0)
    {
        const int numChannelsToWrite = (samplesToWrite[1] == 0) ? 1 : 2;
        HeapBlock<int> temp (numSamples * numChannelsToWrite);

        buf[0] = temp.getData();
        buf[1] = temp.getData() + numSamples;
        buf[2] = 0;

        for (int i = numChannelsToWrite; --i >= 0;)
        {
            if (samplesToWrite[i] != 0)
            {
                for (int j = 0; j < numSamples; ++j)
                    buf [i][j] = (samplesToWrite [i][j] >> bitsToShift);
            }
        }

        samplesToWrite = const_cast<const int**> (buf);
    }

    return FLAC__stream_encoder_process (encoder,
                                         (const FLAC__int32**) samplesToWrite,
                                         numSamples) != 0;

[/code]

it appears that the data (samplesToWrite) passed to FLAC__stream_encoder_process is always freed before the function due to the HeapBlock<int> temp which gets out of the if (bitsToShift > 0) scope.
I guess that using this code in release does not necessarily causes any problem, but in Debug, the freed Heap data is always filled with 0xfeeefeee… which probably explains the silent FLAC files I get as I only used it in Debug so far…


#9

Yikes! That’d certainly explain it! I was testing with a mac, which doesn’t overwrite the freed blocks, which must be why it worked for me…

Apologies for my “schoolboy error” there, and many thanks for spotting it - I’ll get a fix checked in imminently!


#10

You’re welcome

Thanks for the fast update…

Best