The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl -w

# Read .inf files from current directory, produce a leader of a cddb file
# on STDOUT (processable with `fdquery --i file' from Net::FreeDB2)

use strict;

my @inf;

for my $file (<*.inf>) {
  local *F;
  open F, $file or die;
  my @lines = <F>;
  close F or die;
  chomp @lines;
  my %line;
  for my $line (@lines) {
    next if $line =~ /^\s*#/;
    die unless $line =~ /^\s*(\S+)\s*=\s*(.*?)\s*$/;
    $line{lc $1} = $2;
  }
  die unless exists $line{tracknumber};
  $inf[$line{tracknumber}] = \%line;
}

for my $n (1..$#inf) {
  die "Missing track number $n" unless defined $inf[$n];
}

print <<EOP;
# xmcd
#
# Track frame offsets:
EOP

for my $n (1..$#inf) {
  my $start = $inf[$n]{trackstart} + 150;
  print "# $start\n";
}

my @length = map { $inf[$_]{tracklength} =~ /(\d+)/; $1 } 1..$#inf;
my $length = int (($inf[-1]{trackstart} + $length[-1] - $inf[1]{trackstart})/75 + 2);

#my $diskid = compute_discid ($inf[1]{trackstart} + 150, @length);
my $diskid = $inf[1]{cddb_discid};
$diskid =~ s/^0x//i;

print <<EOP;
#
# Disc length: $length seconds
#
# Revision: 5
# Submitted via: not submitted yet
DISCID=$diskid
EOP


# Usage:
#
#      my $id = compute_discid ($leader, @frames);
#
# "$leader" is the number of frames before track 1.
# "@frames" is the length in frames of each track on the disc.
# (A frame is 1/75th of a second.)
# Returns the disc ID as a string.

sub cddb_sum {
  # a number like 2344 becomes 2+3+4+4 (13).
  my ($n) = @_;
  my $ret = 0;
  while ($n > 0) {
    $ret += ($n % 10);
    $n /= 10;
  }
  return $ret;
}

sub compute_discid {
  my @frames = @_;

  my $tracks = $#frames + 1;
  my $n = 0;

  my @start_secs;
  my $i;

  for ($i = 0; $i < $tracks; $i++) {
    $start_secs[$i] = int ($frames[$i] / 75);
  }

  for ($i = 0; $i < $tracks-1; $i++) {
    $n = $n + cddb_sum ($start_secs[$i]);
  }

  my $t = $start_secs[$tracks-1] - $start_secs[0];

  my $id = ((($n % 0xFF) << 24) | ($t << 8) | $tracks-1);
  return sprintf ("%08x", $id);
}