Project Nayuki


Simple FLAC implementation

This is my independent implementation FLAC, optimizing the code for clarity to a human reader. The decoder is implemented in about 300 lines of source code, and the encoder in ~200 lines. These can serve as a starting point for someone who wants to understand the FLAC file format down to the byte level, or build their own FLAC decoder/encoder tools. FLAC is a wonderful file format (e.g. open source, royalty-free, simple concepts) with widespread usage (e.g. supported on portable music players, files distributed on sharing networks), but I was disappointed when searching on the web I found a dearth of quality implementations other than the official C code.

FLAC has a substantially better specification document than all the other popular compressed audio file formats (e.g. MP3, AAC, Vorbis). However the details are incomplete in several areas such as mid-side coding, fixed prediction, linear predictive coding, and Rice coding. I had to read some existing codebases to cover the missing knowledge – mostly from the relatively short flac.js alternative implementation, and the rest from the long official reference code in C.

My decoder and encoder implementations here have a number of limitations for the sake of simplicity. Not many comments are included in the code because the hope is that the code should be self-explanatory by its brevity and by cross-referencing with the FLAC format specification. Only whole-byte sample depths are supported, namely 8, 16, 24, 32 bits (and not 20 bits for example). There is little error checking of reserved and invalid values in the input file – so many invalid FLAC files won’t be flagged by this decoder’s logic. For the decoder, if the input FLAC file is well-formed and the decoded audio data is less than 4 GiB, then the generated output should be correct. For the encoder, it only packages up the audio samples using verbatim encoding, which offers no compression at all (though the output FLAC file is perfectly legal); furthermore it tries to avoid filling in data fields that are not mandatory (such as the MD5 hash).

Source code

My simple FLAC decoder and encoder are offered with equal functionality in Java and Python. The Python code is about 20% shorter, but the Java version runs about 30× faster than the Python version.

Java (SE 7+)
  • Decoder application: SimpleDecodeFlacToWav.java
    Usage: java SimpleDecodeFlacToWav InFile.flac OutFile.wav

    The performance of this naive un-optimized implementation is surprisingly not bad. On my computer it takes about 3 seconds to decode a 5-minute FLAC file (CD audio) and write out the WAV file, so the speed achieved is about 100× real time.

  • Encoder application: SimpleEncodeWavToFlac.java
    Usage: java SimpleEncodeWavToFlac InFile.wav OutFile.flac

    This encoder produces valid FLAC files, but uses the non-compressing verbatim encoding, thus making the output FLAC file about 0.1% larger than the input WAV file. Exploration of the other encoding modes is left to more advanced encoder implementations.

  • (Bonus) Residue-only decoder: DecodeFlacResidueToWav.java
    Usage: java DecodeFlacResidueToWav InFile.flac OutFile.wav

    This shows the raw residue values that were encoded by FLAC, which are the less predictable parts of the signal that remain after stereo decorrelation (e.g. mid-side) and linear predictive coding (LPC) were performed. This hacked FLAC decoder skips the step of LPC restoration, skips the step of stereo restoration, mutes the fixed/LPC warmup (non-residue) samples, and mutes constant and verbatim subframes (which do not use any form of prediction). When listening to the FLAC residues of pop music, percussion instruments sound similar but vocals and tonal instruments are somewhat attenuated. When listening to residues of tonal instruments (such as a piano playing a couple of notes simultaneously), the audio becomes very quiet due to the excellent LPC predictions. It should be noted that a loud residue signal is associated with a high bit rate for the FLAC-compressed file, and vice versa.

Python
  • Decoder application: simple-decode-flac-to-wav.py
    Usage: python simple-decode-flac-to-wav.py InFile.flac OutFile.wav

    The Python code reads more easily than the Java code, due to: the lack of object types, lack of differentiation of integer widths, the use of list/generator comprehensions, and the lack of braces. But it comes with a performance penalty of being around 100× slower than the Java code (which is a typical slowdown figure for numeric processing in Python, e.g. see my Project Euler solutions benchmarks). Using the PyPy interpreter gives a 3× boost so that it is only 30× slower than Java. Either way, the Python code seems to be only good for education and study, but can’t be turned into a FLAC implementation for serious use.

  • Encoder application: simple-encode-wav-to-flac.py
    Usage: python simple-encode-wav-to-flac.py InFile.wav OutFile.flac

    This encoder produces valid FLAC files, but uses the non-compressing verbatim encoding, thus making the output FLAC file about 0.1% larger than the input WAV file. Exploration of the other encoding modes is left to more advanced encoder implementations. Unfortunately even though only verbatim mode is used, this Python code runs about as slowly as the Python decoder for the same audio length.

License: MIT (open source)