#!/usr/bin/perl -w
# Read a file (from STDIN) created via (e.g.)
# readcd2 -fulltoc dev=0,1,0 -f=audio_cd
# , produce a leader of a cddb file on STDOUT
# (processable with `fdquery --i file' from Net::FreeDB2, or cddb2cddb)
use strict;
use MP3::Tag;
my $round_offset = 0; # Rounding down gives better match to initial size...
binmode STDIN;
my $in = do { local $/; <STDIN> };
my $s = 2 + unpack 'n', $in;
my $s1 = length $in;
die "TOC size mismatch: header=$s, actual=$s1" unless $s == $s1;
my %chunks = unpack 'x4 (x3 C x4 a3)*', $in;
sub msf2_sector {
my ($m,$s,$f) = unpack 'CCC', shift;
$f + 75*($s + 60*$m) # Apparently, already shifted by 150
}
my @tracks = sort {$a <=> $b} grep $_ <= 99, keys %chunks;
die "Gaps in tracks (@tracks)" unless @tracks == $tracks[-1] and $tracks[0] == 1;
my @sect = map msf2_sector($_), @chunks{@tracks, 0xa2}; # 0xa2 is leadout
#print "$_\n" for @sect;
#exit;
my @l = map $sect[$_] - $sect[$_ - 1], 1..$#sect;
print <<EOP;
# xmcd
#
# Track frame offsets:
EOP
for my $start (@sect[0..$#sect - 1]) {
print "# $start\n";
}
my $length = int ($sect[-1]/75);
my $diskid = compute_discid_my (@sect);
$diskid =~ s/^0x//i;
print <<EOP;
#
# Disc length: $length seconds
#
# Revision: 5
# Submitted via: not submitted yet
DISCID=$diskid
EOP
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 {
my @sect = @_;
my @secs = map int($_/75), @sect; # cdda2wav rounds down
my $n = 0;
$n += cddb_sum($_) for @secs[0 .. $#secs - 1]; # Skip leadout
my $t = $secs[-1] - $secs[0];
return sprintf '%08x', (($n % 0xFF) << 24) | ($t << 8) | (@secs - 1);
}