#!/usr/bin/perl

# musicgraph.pl v. 2004-01-16 by Charlie <perl@rheme.net>:
# graph the lengths of stuff in your iTunes Music Library
# with gnuplot using something X11ish (e.g. AquaTerm or X11).

# I made this 'cause I was curious about various flippant
# phrases like "ordinary three-minute pop song" or whatever,
# and I'd heard that many radio stations won't play anything
# over 4m, and that people carefully edit to just under that.
# This seem pretty likely; my resonably big and diverse
# library has a non-spoken-word mean of 3:59 (no, really),
# a mode in the 3:48 +/- 3s group, and a median of 3:57.
# The curve is even a little convex to the left of 4:00, and
# a little concave to the right of it. Still, the graph
# is quite spiky, and my music selection is not all /that/
# large (or typical). I'd be interested to hear what other
# people get. Oh, hey, check for spikes on the other minute
# marks. I may be imagining them, and I'm not sure why
# they'd be there: are people in studios just rounding stuff
# off? When they have a 4:52 track, do they insert silence
# to make it even, or what? More likely it's just chance.

# Bugs:
# + The plot tickmarks are not necessarily accurate.
# + If $max is unset, it should graph all songs, not none.
# + (Your bug here.)

open Library, "$ENV{HOME}/Music/iTunes/iTunes Music Library.xml"
	or die "I can't find iTunes' library.\n";

open Plotter, "|gnuplot -persist - 2>/dev/null"
# Redirection hides the annoying interactivity-assuming prompt.
# "-persist" is not necessary under AquaTerm. Not sure why not.
	or die "I can't find gnuplot.\n";

# $step is the sample width for song lengths (in ms);
# make it a multiple of 6 for convenient tickmarks.
$step = 6000; $gnuplotargs = "with steps";
# Or, if you like your graphs to look as though they've
# been through a rock-tumbler, snack your eyes on:
#$step = 600; $gnuplotargs = "smooth bezier";

$max = 600000; # ignore songs longer than this many ms

while (<Library>) {
	(/^\W*\<key\>Total Time\<\/key\>\<integer\>(\d+)\<\/integer\>$/)
	# $1 is now the length of some song in ms.
		# Increment the length's point on the array:
		# (I mentioned the array, right?)
		&& ($1 < $max) && ($bell[int($1/$step)]++);
		# If you're a nerd and want to see /all/ your songs, use:
		#&& ($bell[int($1/$step)]++); ($1 > $max) && ($max = $1);
		# ... you nerd.
}

print Plotter "plot '-' $gnuplotargs\n";
while ($i < $max/$step) {
	print Plotter ($bell[$i++]+0) . "\n";
}
close Plotter; # Otherwise it leaves a zombie prompt.
