All pastes #886739 Raw Edit

Stuff

public text v1 · immutable
#886739 ·published 2008-01-31 21:55 UTC
rendered paste body
#!/usr/bin/perl
###############################################################################
#                                                                             #
#                                  ARFlac.pl                                  #
#                                                                             # 
#               KitchenStaff (Kitchen.Staff.Supervisor@gmail.com)             #
#                                                                             #
# Many thanks to Mr. Spoon for his kind permission to use the AccurateRip     #
# technology and database.  Access to AccurateRip is regulated, see           #
# http://www.accuraterip.com/3rdparty-access.htm for details.                 #
#                                                                             #
# Original ARCue script by Christopher Key <cjk32@cam.ac.uk>                  #
#                                                                             #
# This script allows the usage of AccurateRip's extensive track checksum      #
# database to verify the accuracy of directories of flac files. To use,       #
# simply run:                                                                 #
#                                                                             #
# ARFlac.pl Flacdir1 Flacdir2 etc...                                          #
#                                                                             #
# OMGoptimized by infi/08                                                     #
#                                                                             #
###############################################################################
use Inline C;
use strict;
use LWP;
use Carp;
use Proc::ParallelLoop;
my $numcores = 2;
my $lwpUserAgent = LWP::UserAgent->new;

foreach my $flacDir (@ARGV) {
     # Get the list of flac files from the directory
     print $flacDir . ":";
     
     opendir CURDIR, $flacDir;
     my @flaclist = readdir CURDIR;
     closedir CURDIR;
     
     my @filelist = grep {/flac$/i} @flaclist;
     @filelist = sort @filelist;
     
     # We need track offsets in 'frames'
     # can get these from metaflac
     my (@trackOffsets,@trackLengths);
     my $tn=0;
     my $tmpl=0;
     foreach my $fl (@filelist) {
     
          $tmpl = `metaflac --show-total-samples "$flacDir/$fl"`;
          $trackLengths[$tn] = $tmpl/588;
          $tn++;
     }
     
     my $trackCount = $tn;
     my $curoff = 0;
     $trackOffsets[0] = 0;
     for ($tmpl = 1; $tmpl <= $trackCount; $tmpl++) {
          $curoff += $trackLengths[$tmpl-1];
          $trackOffsets[$tmpl] = $curoff;
     }
    # Calculate the three disc ids used by AR
    my ($discId1, $discId2, $cddbDiscId) = (0, 0, 0);
    {
        use integer;
        for (my $trackNo = 0; $trackNo <= $trackCount; $trackNo++) {
            my $trackOffset = $trackOffsets[$trackNo];
            $discId1 += $trackOffset;
            $discId2 += ($trackOffset ? $trackOffset : 1) * ($trackNo + 1);
            if ($trackNo < $trackCount) {
                $cddbDiscId = $cddbDiscId + sumDigits(int($trackOffset/75) + 2);
            }
        }
        $cddbDiscId = (($cddbDiscId % 255) << 24) + ((int($trackOffsets[$trackCount]/75) - int($trackOffsets[0]/75)) << 8) + $trackCount;
        $discId1 &= 0xFFFFFFFF;
        $discId2 &= 0xFFFFFFFF;
        $cddbDiscId &= 0xFFFFFFFF;
    }
  print "\nChecking AccurateRip database\n\n";
    # See if we can find the disc in the database
    my $arUrl = sprintf("http://www.accuraterip.com/accuraterip/%.1x/%.1x/%.1x/dBAR-%.3d-%.8x-%.8x-%.8x.bin", 
        $discId1 & 0xF, $discId1>>4 & 0xF, $discId1>>8 & 0xF, $trackCount, $discId1, $discId2, $cddbDiscId);
    my $arDiscNotInDb = 0;
    my $arNetworkFailed = 0;
    my $response = $lwpUserAgent->get($arUrl);
    
    if (!$response->is_success) {
        if ($response->status_line =~ m/^404/) {
            $arDiscNotInDb = 1;
        }else{
            $arNetworkFailed = $response->status_line;
        }
    }
    # Extract CRCs from response data
    my $arCrcCount = 0;
    my @arTrackConfidences = ();
    my @arTrackCRCs = ();
    if (!($arDiscNotInDb || $arNetworkFailed)) {
        my $arCrcData = $response->content;
        my $ptr = 0;
        while ($ptr < length($arCrcData)) {
            my ($chunkTrackCount, $chunkDiscId1, $chunkDiscId2, $chunkCddbDiscId);
            # Force perl to interpret these values as signed integers
            {
                use integer;
                $chunkTrackCount = unpack("c",substr($arCrcData,$ptr,1));
                $chunkDiscId1 = unpack("V",substr($arCrcData,$ptr+1,4)) + 0;
                $chunkDiscId2 = unpack("V",substr($arCrcData,$ptr+5,4)) + 0;
                $chunkCddbDiscId = unpack("V",substr($arCrcData,$ptr+9,4)) + 0;
            }
            $ptr +=13;
            if ( $chunkTrackCount != $trackCount
                || $chunkDiscId1 != $discId1
                || $chunkDiscId2 != $discId2
                || $chunkCddbDiscId != $cddbDiscId ) {
                croak("Track count or Disc IDs don't match.");
            }
            # How if it flagged that a track is not in the database?
            for (my $track = 0; $track < $trackCount; $track++) {
                my ($trackConfidence, $trackCrc);
                # Force perl to interpret these values as signed integers
                {
                    use integer;
                    $trackConfidence = unpack("c",substr($arCrcData,$ptr,1));
                    $trackCrc = unpack("V",substr($arCrcData,$ptr+1,4)) + 0;
                    $ptr += 9;
                }
                if ($arCrcCount == 0){
                    $arTrackConfidences[$track] = [];
                    $arTrackCRCs[$track] = [];
                }
                $arTrackConfidences[$track]->[$arCrcCount] = $trackConfidence;
                $arTrackCRCs[$track]->[$arCrcCount] = $trackCrc;
            }
            $arCrcCount++;
        }
    }
    
    printf "Track\tRipping Status\t\t[Disc ID: %08x-%08x]\n", $discId1, $cddbDiscId;
    # Calculate a CRC for each track
    my $errLevel = 0;
    # Calculate a CRC for each track
    my @trackCRCs = ();
    my $FH;
    my ($accuratelyRipped, $notAccuratelyRipped, $notInDatabase) = (0, 0, 0);
    #for (my $trackNo = 0; $trackNo < $trackCount; $trackNo++) {
    { my $trackNo = 0; pardo sub{ $trackNo < $trackCount }, sub { $trackNo++ }, sub {
         # Open a pipe to flac decode
         open($FH, "flac -d -c -f --force-raw-format --totally-silent --endian=little --sign=signed \"$flacDir/$filelist[$trackNo]\" |");
         binmode $FH;
         
        my ($frame, $CRC);
        $CRC = 0;
        for (my $frameNo = 0; $frameNo < $trackLengths[$trackNo]; $frameNo++) {
            if (read($FH, $frame, 2352) != 2352) { croak ("read failed.") };
            {
                use integer;
                $CRC += C_processFrame($frame, $frameNo, $trackLengths[$trackNo], $trackNo == 0, $trackNo == $trackCount - 1);
            }
        }
        
        close($FH);
        {
            use integer;
            $trackCRCs[$trackNo] = $CRC & 0xFFFFFFFF;
        }
        if ($arDiscNotInDb) {
            printf " %d\tTrack not present in database.    [%08x]\n", 
                $trackNo + 1, $trackCRCs[$trackNo];
             $notInDatabase++;
        }   elsif ($arNetworkFailed) {
            printf " %d\t    [%08x]\n", 
                $trackNo + 1, $trackCRCs[$trackNo];
        } else {
            my $foundCrc = 0;
            my $foundCrcMatch = 0;
            for (my $arCrcNo=0; $arCrcNo < $arCrcCount; $arCrcNo++) {
                if ($arTrackConfidences[$trackNo]->[$arCrcNo] != 0){
                    $foundCrc = 1;
                    if ($arTrackCRCs[$trackNo]->[$arCrcNo] == $trackCRCs[$trackNo]) {
                        printf " %d\tAccurately Ripped    (confidence %d)     [%08x]\n", 
                            $trackNo + 1, $arTrackConfidences[$trackNo]->[$arCrcNo], $arTrackCRCs[$trackNo]->[$arCrcNo];
                        $accuratelyRipped++;
                        $foundCrcMatch = 1;
                        last;
                    }
                }
            }
            if (!$foundCrc) {
                    printf " %d\tTrack not present in database.    [%08x]\n", 
                    $trackNo + 1, $trackCRCs[$trackNo];
                $notInDatabase++;
            }elsif (!$foundCrcMatch) {
                printf " %d\t** Rip not accurate **   (confidence %d)     [%08x] [%08x]\n", 
                    $trackNo + 1, $arTrackConfidences[$trackNo]->[0], $arTrackCRCs[$trackNo]->[0], $trackCRCs[$trackNo];
                $notAccuratelyRipped++;
            }
        }
    #}
	}, { "Max_Workers" => $numcores } ; }  
    if ($arDiscNotInDb) {
            print "Disc not present in AccurateRip database.\n";
            $errLevel = 2;
    } elsif ($arNetworkFailed) {
            print "Failed to get $arUrl : " . $arNetworkFailed . "\n";
            $errLevel = 3;
#   } elsif ($accuratelyRipped == $trackCount) {
#       print "All Tracks Accurately Ripped.\n";
#   } else {
#       if ($notAccuratelyRipped >= 3) {
#            print "Your CD disc is possibly a different pressing to the one(s) stored in AccurateRip.\n"
#       }
#
#       printf "Track(s) Accurately Ripped: %d\n", $accuratelyRipped;
#       printf "**** Track(s) Not Ripped Accurately: %d ****\n", $notAccuratelyRipped;
#       printf "Track(s) Not in Database: %d\n", $notInDatabase;
#
#       $errLevel = 1;
    }
    print "\n\n\n";
}
sub processFrame {
    use integer;
    my ($frame, $frameNo, $trackLength, $firstTrack, $lastTrack) = @_;
    if ($firstTrack && $frameNo<4) {
        return 0;
    } elsif ($lastTrack && $trackLength - $frameNo < 6) {
        return 0;
    } elsif ($firstTrack && $frameNo == 4) {
        my $sample = unpack("V", substr($frame,2348,4));
        return ($sample * 588 * 5);
    } else {
        my $CRC = 0;
        my $frameOffset = $frameNo * 588;
        foreach (unpack("V588", $frame)) {
            $CRC += $_ * (++$frameOffset);
        }
        return $CRC;
    }
}
sub sumDigits {
    my $n = shift;
    my $r = 0;
    while ($n > 0) {
        $r = $r + ($n % 10);
        $n = int($n / 10);
    }
    return $r;
}

__END__
__C__
int C_processFrame(char *frame, int frameno, int tracklen, int first, int last)
{
    unsigned int i, frameoffset, crc = 0, sample = 0;

    if( first && frameno < 4 )
    {
        return 0;
    }
    else if( last && ( tracklen - frameno < 6 ) )
    {
        return 0;
    }
    else if( first && frameno == 4 )
    {
        sample = *(unsigned int *)(frame + 2348);
        return sample * 588 * 5;
    }
    else
    {
        frameoffset = frameno * 588;
        for(i=0; i<588; i++) {
            sample = *(unsigned int *)( frame + (i * 4) );
            crc += sample * (++frameoffset);
        }
        return crc;
    }
}