From e30c11a0d1ba271fd2210a3024d5e32fa3b8480a Mon Sep 17 00:00:00 2001 From: Steve Youngs Date: Sun, 19 Jun 2011 11:56:46 +1000 Subject: [PATCH] Initial import from tla repo Signed-off-by: Steve Youngs --- build.sh | 109 +++++++ zcdrip.in | 868 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ zdiscid.c | 161 ++++++++++ 3 files changed, 1138 insertions(+) create mode 100755 build.sh create mode 100644 zcdrip.in create mode 100644 zdiscid.c diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..046d2d5 --- /dev/null +++ b/build.sh @@ -0,0 +1,109 @@ +#!/bin/zsh + +## Copyright (C) 2006, 2007 Steve Youngs + +## Author: Steve Youngs +## Maintainer: Steve Youngs +## Created: <2006-08-16> + +## This file is part of zcdrip + +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions +## are met: +## +## 1. Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## +## 2. Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## +## 3. Neither the name of the author nor the names of any contributors +## may be used to endorse or promote products derived from this +## software without specific prior written permission. +## +## THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR +## IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +## WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +## DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +## FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES# LOSS OF USE, DATA, OR PROFITS# OR +## BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +## WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +## OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +## IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +### Commentary: +## +## Because I suck at writing makefiles + +### Code: +clean () +{ + rm -vf zcdrip ecdrip zdiscid +} + +all () +{ + clean + sub=@VERSION@ + rep=$(tla logs --full|tail -n1) + zmodload -i zsh/mapfile + gcc -Wall -o zdiscid zdiscid.c + mapfile[zcdrip]=${mapfile[zcdrip.in]/$sub/$rep} + chmod -v 755 zcdrip +} + +eshell () +{ + [[ -f zcdrip && -f zdiscid ]] || all + ln -svf zcdrip ecdrip +} + +target=${target:-/usr/local/bin} +INSTALL=${INSTALL:-install} + +_install () +{ + [[ -f zcdrip && -f zdiscid ]] || all + + $INSTALL -vd $target + $INSTALL -v zcdrip zdiscid $target + [[ -f ecdrip ]] && $INSTALL -v ecdrip $target +} + +ourname=${0##/} +help () +{ + cat< +## Maintainer: Steve Youngs +## Created: <2006-08-08> +## Time-stamp: + +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions +## are met: +## +## 1. Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## +## 2. Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## +## 3. Neither the name of the author nor the names of any contributors +## may be used to endorse or promote products derived from this +## software without specific prior written permission. +## +## THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR +## IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +## WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +## DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +## FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES# LOSS OF USE, DATA, OR PROFITS# OR +## BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +## WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +## OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +## IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +### Commentary: +## +## Ease the process of ripping audio CDs to .mp3 or .ogg. See +## help (zcdrip -h) for full details. +## + +### Todo: +## +## o Partial album ripping. Specify track numbers or a range of +## track numbers to only rip/encode those tracks. +## +## o Ripping from music DVDs +## + +### Bugs: +## +## Bugs? What bugs? Seriously though, if you find any, let me +## know. +## + +# Debug +[[ -n $DEBUG ]] && set -x; zdebug=${TMPPREFIX}/zdebug + +### Code: +ourname=${0##*/} + +# Version info. +VERSION=@VERSION@ +COPYRIGHT="Copyright (C) 2006 - 2008 Steve Youngs " + +version_str="${ourname}: ${VERSION} +${COPYRIGHT}" + +_version () { echo $version_str } + +# Help +usage () +{ + # If you use eshell you will have a problem displaying this help. + # This is the only part of the script that eshell has a problem + # with, but if you really want to be able to view this help in + # eshell, create a symlink and call it `ecdrip'. + + [[ ${LINES} -lt 70 && $TERM != dumb ]] && _doc=${PAGER:-less} || _doc=cat + [[ $ourname == ecdrip ]] && _doc=cat + $_doc<, $ourname will + be called with "set -x". + + "set -x" spams your stdout with a _LOT_ of messages, it would most + likely pay you to redirect stdout/stderr to a file. + +${COPYRIGHT} + +EOF +} + +# Convert song title to something resembling a sane filename... no +# whitespace, no punctuation, etc. Also adds .ogg/.mp3 extension. +fnamefix () +{ + local psub="[[:cntrl:],\*\?\`';/\\\\\"]" + local prep="" + local wsub="[[:space:][:blank:]]" + local wrep="_" + + setopt extendedglob + + for (( i=1; i<=$tracks; ++i )); do + tf=$filename[$i] + tf=${tf//\\t/ } + tf=${tf//${~psub}/$prep} + tf=${tf//[ ]##/ } + tf=${tf//${~wsub}/$wrep} + filename[$i]=$tf.$prepargs[1] + done +} + +### freedb magic +_freedb_login () +{ + local args + if [[ -z $1 ]]; then + print invalid args >&2 + return 1 + fi + + args="$@" + # login + tcp_send "cddb hello $args" + tcp_expect -T 10 -s $ourname "*Hello and welcome*" + if [[ $? -eq 2 ]]; then + print Timeout waiting for cddb server >&2 + exit 4 + fi + # set protocol level + tcp_send "proto 6" + tcp_expect -T 10 -s $ourname "*CDDB protocol*" + if [[ $? -eq 2 ]]; then + print Timeout waiting for cddb server >&2 + exit 4 + fi + return 0 +} + +_parse_cddb () +{ + local various=yes + art=$(grep DTITLE $zlog|cut -d= -f2|cut -d/ -f1|sed '1!d') + art=${art/%[[:space:]]/} + art=${art//'&'/'\&'} + + # Possibly override. + art=${ARTIST:-$art} + + # Artist + if [[ "$art" != "Various Artists" && "$art" != "Various" ]]; then + various=no + fi + + # Album, year, genre, number or tracks + album=$(grep DTITLE $zlog|cut -d= -f2|cut -d/ -f2) + album=${album/#[[:space:]]/} + album=${album//[[:cntrl:]]/} + year=$(grep DYEAR $zlog|cut -d= -f2) + year=${year//[[:cntrl:]]/} + genre=$(grep DGENRE $zlog|cut -d= -f2) + genre=${genre//[[:cntrl:]]/} + tracks=$zid[2] + + # Possibly override album, year, genre + album=${ALBUM:-$album} + year=${YEAR:-$year} + genre=${GENRE:-$genre} + + # print what we got when we're debugging + if [[ -n $DEBUG ]]; then + printf "Artist: %s\nAlbum: %s\nYear: %s\nGenre: %s\nNum Tracks: %s\n" \ + $art $album $year $genre $tracks > $zdebug + printf "Various: %s\n" $various >> $zdebug + echo --- Titles --- >> $zdebug + grep TTITLE $zlog >> $zdebug + fi + + # create an rcfile + if [[ $various == yes || -n $(grep TTITLE $zlog|grep $art) ]]; then + grep TTITLE $zlog|cut -d= -f2|sed 's@ [-/] @|@' > $rcfile + else + grep TTITLE $zlog|cut -d= -f2 > $rcfile + sed -i "s@^@${art}|@g" $rcfile + fi + +} + +_freedb_read () +{ + if [[ -z $1 ]]; then + print invalid args >&2 + return 1 + fi + + tcp_send "cddb read $1 $2" + tcp_expect -T 25 -s $ourname "*PLAYORDER*" + if [[ $? -eq 2 ]]; then + print Timeout waiting for cddb server >&2 + exit 4 + fi + + _parse_cddb + +} + +_freedb_query () +{ + if [[ -z $1 ]]; then + print invalid args >&2 + return 1 + fi + + tcp_send "cddb query $zid" + tcp_expect -T 10 -p idx -s $ourname "*No match for disc ID*" \ + "<-\[$ourname\] 200*" "<-\[$ourname\] .*" + if [[ $? -eq 2 ]]; then + print Timeout waiting for cddb server >&2 + exit 4 + fi + case $idx in + (1) + print No entry listed for disc: $zid[1] >&2 + print You will have to do this disc manually >&2 + exit 4 + ;; + (2) + category=$TCP_LINE + category=${category/*200 /} + category=${category/ $zid[1]*/} + _freedb_read $category $zid[1] + ;; + (3) + echo Multiple entries found... + echo + tmulti=(${(ps:\r:)${tcp_expect_lines}}) + [[ $tmulti[1] == *inexact* ]] && exact=no + tmulti[1]=${tmulti[1]:#${tmulti[1]}} + multi=($tmulti) + for (( i=1; i<${#multi}; ++i )); do + multi[$i]=${multi[$i]/<-\[$ourname\] /} + printf "\t[%s]%s\n" $i $multi[$i] + done + echo + echo -n "Which CDDB entry (q to quit): " + read choice + case $choice in + ([qQ]) do_offline; exit 0 ;; + ([^[:digit:]]) + print Invalid response >&2 + do_offline + exit 2 + ;; + ([[:digit:]]) + category=$multi[$choice] + if [[ $exact == no ]]; then + tcategory=(${(ps: :)category}) + _freedb_read $tcategory[1,2] + else + category=${category/ $zid[1]*/} + _freedb_read $category $zid[1] + fi + ;; + (*) + print Unknown error >&2 + do_offline + exit 2 + ;; + esac + ;; + (*) print Unknown error >&2 ;; + esac +} + +do_online () +{ + autoload -U tcp_open + autoload -U tcp_log + [[ -n $DEBUG ]] || TCP_SILENT=nodebugging + + zcddb=${zcddb:-freedb.freedb.org} + port=8880 + zuser=${zuser:-$USER} + zhost=${zhost:-$HOST} + proto=6 + zlog=${TMPPREFIX}/zcdrip.log + + # open the log and connect + tcp_log $zlog + tcp_open $zcddb $port $ourname + tcp_expect -T 10 -s $ourname "<-\[$ourname\] 201*ready*" + if [[ $? -eq 2 ]]; then + print Timeout waiting for cddb server >&2 + exit 4 + else + _freedb_login $zuser $zhost $ourname $VERSION + fi + + # query cddb server to find out if the CD is listed + _freedb_query $zid + +} + +# Close tcp connection +do_offline () +{ + tcp_close $ourname + tcp_log -c +} + +# Tidy up if not debugging +cleanup () +{ + rm -f $zlog $rcfile $zdebug + unset ARTIST ALBUM YEAR GENRE +} + +# convert album/artist name into a sane filename for output dir +_album_to_dir () +{ + local talbum=$album + local tart=$art + local psub="[[:cntrl:],\`';/\\\\\"]" + local prep="" + local wsub="[[:space:][:blank:]]" + local wrep="_" + + setopt extendedglob + + talbum=${talbum//\\t/ } + talbum=${talbum//${~psub}/$prep} + talbum=${talbum//[ ]##/ } + talbum=${talbum//${~wsub}/$wrep} + + tart=${tart//\\t/ } + tart=${tart//${~psub}/$prep} + tart=${tart//[ ]##/ } + tart=${tart//${~wsub}/$wrep} + + # Various Artists is sometimes "Various" and other times "Various + # Artists", we'll call them all "Various_Artists". + if [[ "${tart}" == "Various" ]]; then + tart=Various_Artists + fi + + dir=$(pwd)/${tart}/${talbum} + [[ -d ${dir} ]] || mkdir -p ${dir} + [[ $keep_flac == yes ]] && fdir=${dir}/flac; mkdir -p ${fdir} +} + + +# Store song titles, artist, and album names. +prep () +{ + zid=($(zdiscid)) + tracks=$zid[2] + + [[ -d ${TMPPREFIX} ]] || mkdir -p ${TMPPREFIX} + + if [[ $online == yes ]]; then + do_online + do_offline + fi + + typeset -A artist + typeset -A song + typeset -A filename + + if [[ $zedit == yes && -n $rcfile ]]; then + _zedit=${EDITOR:-vi} + cat>$rcfile</dev/null || genre=Other + + for (( i=1; i<=$tracks; ++i )); do + echo MP3-Ripping: $song[$i], by: $artist[$i], to: $filename[$i] + cdparanoia -X $i $wavfile + if [[ -f $wavfile ]]; then + if [[ $keep_flac == yes ]]; then + flacfile=${filename[$i]/%mp3/flac} + flacenc ${flacfile} ${wavfile} $song[$i] $artist[$i] $album \ + $year $genre $i $zcomment + flactomp3 ${flacfile} ${dir}/$filename[$i] + else + lame -h --tt $song[$i] --ta $artist[$i] --tl $album \ + --ty $year --tg $genre --tc $zcomment $wavfile \ + --tn $i ${dir}/$filename[$i] + fi + fi + [[ -f $wavfile ]] && rm -f $wavfile + done +} + +# Encode to OGG Vorbis +oggrip () +{ + for (( i=1; i<=$tracks; ++i )); do + echo OGG-Ripping: $song[$i], by: $artist[$i], to: $filename[$i] + cdparanoia -X $i $wavfile + if [[ -f $wavfile ]]; then + if [[ $keep_flac == yes ]]; then + flacfile=${filename[$i]/%ogg/flac} + flacenc ${flacfile} ${wavfile} $song[$i] $artist[$i] $album \ + $year $genre $i $zcomment + oggenc -q3 -o ${dir}/$filename[$i] ${fdir}/$flacfile + else + oggenc -q3 -o ${dir}/$filename[$i] -t $song[$i] -a $artist[$i] \ + -l $album -d $year -G $genre -c "comment=$zcomment" \ + -N $i $wavfile + rm $wavfile + fi + fi + done +} + +# Make sure we have everything we need. +# This might be a little over the top, but I don't see any point in +# checking for `oggenc' if you are encoding to MP3, likewise, there's +# no point in checking for `lame' if you are encoding to Ogg Vorbis. +chkreqs () +{ + reqs=(cdparanoia lame oggenc flac) + whence -w $reqs[1] 1>/dev/null + if [[ $? -gt 0 ]]; then + echo $ourname: error: Missing $reqs[1] >&2 + rv=3 + fi + case $atype in + (mp3) + whence -w $reqs[2] 1>/dev/null + if [[ $? -gt 0 ]]; then + echo $ourname: error: Missing $reqs[2] >&2 + rv=3 + fi + ;; + (ogg) + whence -w $reqs[3] 1>/dev/null + if [[ $? -gt 0 ]]; then + echo $ourname: error: Missing $reqs[3] >&2 + rv=3 + fi + ;; + esac + if [[ $keep_flac == yes ]]; then + whence -w $reqs[4] 1>/dev/null + if [[ $? -gt 0 ]]; then + echo $ourname: error: Missing $reqs[4] >&2 + rv=3 + fi + fi + if [[ $rv -eq 3 ]]; then + exit $rv + else + return 0 + fi +} + + +# Command line parsing +args=mofihVO-:r:a:s:t:e:d: +flavour=0 +rc=0 +interactive=no +rcfile=" " +zedit=" " + +while getopts $args opts; do + case $opts in + (-) + case $OPTARG in + (mp3) atype=mp3; (( ++flavour )) ;; + (ogg) atype=ogg; (( ++flavour )) ;; + (edit_rcfile?*) + rcfile=${OPTARG/edit_rcfile=/} + (( ++rc )) + zedit=yes + ;; + (flac_copy) keep_flac=yes ;; + (type?*) atype=${OPTARG/type=/}; (( ++flavour )) ;; + (interactive) interactive=yes; (( ++rc )) ;; + (online) online=yes; (( ++rc )); rcfile=${TMPPREFIX}/zrcfile ;; + (rcfile?*) rcfile=${OPTARG/rcfile=/}; (( ++rc )) ;; + (album?*) album=${OPTARG/album=/} ;; + (sameartist?*) art=${OPTARG/sameartist=/} ;; + (dir?*) dir=${OPTARG/dir=/} ;; + (version) _version; exit 0 ;; + (help) cmd=usage; rv=0 ;; + (*) + echo $ourname: error: bad option: --$OPTARG >&2 + exit 2 + ;; + esac + ;; + (i) interactive=yes; (( ++rc )) ;; + (O) online=yes; (( ++rc )); rcfile=${TMPPREFIX}/zrcfile ;; + (m) atype=mp3; (( ++flavour )) ;; + (o) atype=ogg; (( ++flavour )) ;; + (e) rcfile=$OPTARG; (( ++rc )); zedit=yes ;; + (f) keep_flac=yes ;; + (r) rcfile=$OPTARG; (( ++rc )) ;; + (a) album=$OPTARG ;; + (s) art=$OPTARG ;; + (t) atype=$OPTARG; (( ++flavour )) ;; + (d) dir=$OPTARG ;; + (V) _version; exit 0 ;; + (h) cmd=usage; rv=0 ;; + (*) rv=2 ;; + esac +done +shift $(( $OPTIND - 1 )) + +if [[ $cmd != usage ]]; then + case $flavour in + (0) + echo $ourname: error: no audio format specified >&2 + if [[ $rc -ne 1 ]]; then + echo $ourname: error: improper use of interactice/rcfile option >&2 + fi + rv=2 + ;; + (1) + if [[ $rc -ne 1 ]]; then + echo $ourname: error: improper use of interactive/rcfile option >&2 + rv=2 + else + typeset -A prepargs + prepargs=(1 $atype 2 $interactive 3 $rcfile 4 $zedit) + chkreqs + prep $prepargs + fi + ;; + (*) + echo $ourname: error: multiple or invalid audio formats specified >&2 + if [[ $rc -ne 1 ]]; then + echo $ourname: error: improper use of interactice/rcfile option >&2 + fi + rv=2 + ;; + esac +else + usage +fi + +exit $rv + +### zcdrip ends here diff --git a/zdiscid.c b/zdiscid.c new file mode 100644 index 0000000..60158a3 --- /dev/null +++ b/zdiscid.c @@ -0,0 +1,161 @@ +/* zdiscid.c -- Print the CDDB disc ID for an audio CD */ + +/* + * Copyright (C) 2006, 2007 Steve Youngs + */ + +/* + * Author: Steve Youngs + * Maintainer: Steve Youngs + * Created: <2006-08-13> + */ + +/* + * This file is part of zcdrip. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + + * 3. Neither the name of the author nor the names of any contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Commentary: + * + * Print the CDDB disc ID for an audio CD. + */ + +/* Code: */ +#include +#include +#include +#include +#include + +#define FAILURE_NOCD -1 + +struct toc { + int min, sec, frame; +} cdtoc[100]; + +int read_toc(); +int cddb_sum(int); +unsigned long get_cddb_id(int); + +int +read_toc() +{ + int drive = open("/dev/cdrom", O_RDONLY | O_NONBLOCK); + struct cdrom_tochdr tochdr; + struct cdrom_tocentry tocentry; + int i; + + if (ioctl(drive, CDROMREADTOCHDR, &tochdr) != 0) { + fprintf(stderr, "No disc in drive\n"); + close(drive); + return FAILURE_NOCD; + } + + for (i = tochdr.cdth_trk0; i <= tochdr.cdth_trk1; i++) { + tocentry.cdte_track = i; + tocentry.cdte_format = CDROM_MSF; + ioctl(drive, CDROMREADTOCENTRY, &tocentry); + cdtoc[i-1].min = tocentry.cdte_addr.msf.minute; + cdtoc[i-1].sec = tocentry.cdte_addr.msf.second; + cdtoc[i-1].frame = tocentry.cdte_addr.msf.frame; + cdtoc[i-1].frame += cdtoc[i-1].min * 60 * 75; + cdtoc[i-1].frame += cdtoc[i-1].sec * 75; + } + tocentry.cdte_track = 0xAA; + tocentry.cdte_format = CDROM_MSF; + ioctl(drive, CDROMREADTOCENTRY, &tocentry); + cdtoc[tochdr.cdth_trk1].min = tocentry.cdte_addr.msf.minute; + cdtoc[tochdr.cdth_trk1].sec = tocentry.cdte_addr.msf.second; + cdtoc[tochdr.cdth_trk1].frame = tocentry.cdte_addr.msf.frame; + cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].min * 60 * 75; + cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].sec * 75; + close(drive); + return tochdr.cdth_trk1; +} + +int +cddb_sum(int n) +{ + int ret = 0; + + while (n > 0) { + ret = ret + (n % 10); + n = n / 10; + } + + return ret; +} + +unsigned long +get_cddb_id(int ntrks) +{ + int i, t, n; + + i = t = n = 0; + + while (i < ntrks) { + n = n + cddb_sum((cdtoc[i].min * 60) + cdtoc[i].sec); + i++; + } + + t = ((cdtoc[ntrks].min * 60) + cdtoc[ntrks].sec) - + ((cdtoc[0].min * 60) + cdtoc[0].sec); + + return ((n % 0xff) << 24 | t << 8 | ntrks); +} + +int +main(int argc, char **argv) +{ + int ntrks, i; + + ntrks = read_toc(); + + switch (ntrks) { + case 0: + case 1: + fprintf(stderr, "Disc is not an audio CD\n"); + return 1; + case -1: + return ntrks; + default: + break; + } + + printf("%08lx %d", get_cddb_id(ntrks), ntrks); + for (i = 0; i < ntrks; i++) { + printf(" %d", cdtoc[i].frame); + } + printf(" %d\n", (cdtoc[ntrks].frame) / 75); + return 0; +} + +/* zdiscid.c ends here */ + -- 2.25.1