Welcome Guest ( Log In | Register )

FLAC bitrate histogram (shell script)
post Nov 25 2012, 04:39
Post #1

Group: Members (Donating)
Posts: 1985
Joined: 4-January 04
From: Austin, TX
Member No.: 10933

QUOTE (greynol @ Nov 23 2012, 17:58) *
In the meantime, does anyone know of a program that displays a histogram of bitrates from flac and hopefully some of the other more popular lossless formats?

No, but I vaguely recall wanting precisely this sort of information before. It's a holiday weekend, and I was bored, so I OCD'd out and hacked this together. Obviously, this probably requires a Unix system of some sort.


set -e

if [ ! -f "$1" -o $# != "2" ]; then
    echo "Usage: $0 <flac> <histogram-png>" >&2
    exit 1

FLAC_FILE=`basename "$FLAC_PATH"`
# uncomment this to autodect
#HISTOGRAM=`sed -e 's/\(.*\)\.flac/histogram-\1\.png/' <<< "$FLAC_FILE"`

read minblk maxblk origminframe origmaxframe channels bps rate <<< \
    `metaflac --show-min-blocksize --show-max-blocksize \
    --show-min-framesize --show-max-framesize \
    --show-channels --show-bps --show-sample-rate "$FLAC_PATH"`

# $blocksize is as reported by metaflac. Must be constant for entire file
if [ "$minblk" != "$maxblk" ]; then
    echo "ERROR: min/max blocksizes differ ($minblk, $maxblk)." >&2
    exit 1

# $rawblocksize: uncompressed size of block, in bits, including all channels

# Analyze FLAC, extract "bits=" property of each frame
flac -sa "$FLAC_PATH" -o- \
    | grep "blocksize=$BLOCKSIZE" \
    | sed -e 's/.*bits=\([0-9]*\).*/\1/' \
    >& $BITS_ORIG

# The "actual" minimum/maximum frame sizes appear to be outliers; e.g. for one
# FLAC with average frame size of roughly 70kb, the very first frame was 203kb
# and was nearly 2x the size of the next largest frame; the 2nd and 3rd frame
# were 112 bits long and were 135x smaller than the next smallest frame. For the
# sake of the histogram, drop those out.

echo "Dropping min frame size $(($origminframe*8))" \
    "and first frame size `head -1 $BITS_ORIG`."

tail -n +2 $BITS_ORIG | grep -v "^$(($origminframe*8))$" > $BITS
#cat $BITS_ORIG > $BITS # uncomment this to include min/max frame sizes

read minframesize maxframesize <<< \
    `awk -e 'BEGIN { max=0; min=999999; } min > $0 {min=$0} \
    max < $0 {max=$0} END { print min " " max }' \
    < $BITS`

gnuplot <<EOF
binwidth=25 # in kbits/s

set xlabel "Frame effective bitrate (kbps)"
set ylabel "frequency (frames)"
set xrange [$minbits:$maxbits]

# comment this out to display gnuplot window instead of writing to png
set term png size 500, 300 font "DejaVu Sans,8"
set output "$HISTOGRAM"

set yrange [0.0:]
plot "$BITS" using (bin(\$1/(1.e3*$blocksize/$rate),binwidth)):(1.0) title "$FLAC_FILE" smooth freq with boxes

# if commenting out above png output lines, uncomment this
# pause mouse

echo "Done, output in $HISTOGRAM"

Sample output...

Tame Impala, "Elephant":

Merzbow, "I Lead You Towards Glorious Times":

Autechre & Hafler Trio, "o":

I'm not aware of any way to get this sort of information from a format-independent utility like sox. Which is unfortunate.

This post has been edited by Axon: Nov 25 2012, 04:48
Go to the top of the page
+Quote Post

Posts in this topic

Reply to this topicStart new topic
1 User(s) are reading this topic (1 Guests and 0 Anonymous Users)
0 Members:


RSS Lo-Fi Version Time is now: 9th October 2015 - 08:34