changeset 3:74031379d3cb CDDB-STUFF_1_0

Initial revision
author darius
date Wed, 09 Aug 2000 02:18:47 +0000
parents 5cead4da1db9
children 3a7a8d8a070a
files cddb-id.c get_cdinfo.tcl gettracks.sh tracknamer.tcl
diffstat 4 files changed, 683 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cddb-id.c	Wed Aug 09 02:18:47 2000 +0000
@@ -0,0 +1,182 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sysexits.h>
+#include <fcntl.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/cdio.h>
+
+int cddb_sum(int n);
+unsigned long cddb_discid(int tot_trks, struct cd_toc_entry *cdtoc);
+void usage(void);
+
+int
+main(int argc, char **argv)
+{
+    int 			cd_fd, tot_tracks, i, machine, disc_length, tracknums;
+    unsigned long		disc_id;
+    struct ioc_toc_header	toc_head;
+    struct ioc_read_toc_entry	toc_entries_head;
+    struct cd_toc_entry		*toc_entries;
+    char			cd_path[256], ch;
+
+    /* Default CD path */
+    strcpy(cd_path, "/dev/cd0c");
+
+    /* Default to human readable */
+    machine = 0;
+
+    /* Default to no track number stuff */
+    tracknums = 0;
+
+    while ((ch = getopt(argc, argv, "f:mhn")) != -1) {
+	switch(ch) {
+	case 'f':
+	    if (strlen(optarg) > 255) {
+		warnx("Filename too long");
+		exit(EX_USAGE);
+	    }
+	    
+	    strcpy(cd_path, optarg);
+	    break;
+	    
+	case 'm':
+	    machine = 1;
+	    break;
+	    
+	case 'n':
+	    tracknums = 1;
+	    break;
+	    
+	case '?':
+	case 'h':
+	default:
+	    usage();
+	    break;
+	}
+    }
+    
+    if ((cd_fd = open(cd_path, O_RDWR)) == -1) {
+	warnx("Failed to open %s, reason: %s", cd_path, strerror(errno));
+	exit(EX_IOERR);
+    }
+
+    if (ioctl(cd_fd, CDIOREADTOCHEADER, &toc_head) == -1) {
+	warnx("Failed to get TOC header, reason: %s", strerror(errno));
+	exit(EX_UNAVAILABLE);
+    }
+    
+    tot_tracks = toc_head.ending_track - toc_head.starting_track + 1;
+
+    toc_entries = (struct cd_toc_entry *)malloc(sizeof(struct cd_toc_entry) * (tot_tracks + 1));
+    if (toc_entries == NULL) {
+	warnx("Couldn't allocate memeory for TOC entries");
+	exit(EX_UNAVAILABLE);
+    }
+    
+    toc_entries_head.data = toc_entries;
+    toc_entries_head.data_len = sizeof(struct cd_toc_entry) * (tot_tracks + 1);
+    toc_entries_head.starting_track = 0;
+    toc_entries_head.address_format = CD_MSF_FORMAT;
+
+    if (ioctl(cd_fd, CDIOREADTOCENTRYS, &toc_entries_head) == -1) {
+	warnx("Failed to get TOC entries, reason: %s\n", strerror(errno));
+	exit(EX_UNAVAILABLE);
+    }
+    
+    if (tracknums) {
+	for (i = 1; i <= tot_tracks; i++)
+	    if (!(toc_entries[i].control & 4))
+	        printf("%d ", i);
+	
+	printf("\n");
+	
+	exit(0);
+    }
+    
+    disc_id = cddb_discid(tot_tracks, toc_entries);
+    disc_length = (toc_entries[tot_tracks].addr.msf.minute * 60) +
+	(toc_entries[tot_tracks].addr.msf.second);
+
+    if (machine == 0) {
+	printf("Start track = %d, end track = %d, length = %d\n", toc_head.starting_track,
+	       toc_head.ending_track, toc_head.len);
+	printf("Disc ID is %08x\n", disc_id);
+	printf("Length is %d seconds\n", disc_length);
+    } else {
+	printf("%08x", disc_id);
+    }
+    
+    for (i = 0; i < tot_tracks; i++) {
+	if (machine == 0) {
+	    printf("Track %d, Minute = %d, Second = %d, Frame = %d, Type = %s, Offset = %d\n", 
+		   toc_entries[i].track, toc_entries[i].addr.msf.minute,
+		   toc_entries[i].addr.msf.second, toc_entries[i].addr.msf.frame,
+		   (toc_entries[i].control & 4) ? "data" : "audio",
+		   (toc_entries[i].addr.msf.minute * 60 * 75) +
+		   (toc_entries[i].addr.msf.second * 75) +
+		   toc_entries[i].addr.msf.frame);
+	} else {
+	    printf(" %d", (toc_entries[i].addr.msf.minute * 60 * 75) +
+		   (toc_entries[i].addr.msf.second * 75) +
+		   toc_entries[i].addr.msf.frame);
+	}
+
+    }
+
+    if (machine == 1) {
+	printf(" %d\n", disc_length);
+    }
+}
+    
+int
+cddb_sum(int n)
+{
+        int     ret;
+
+	/* For backward compatibility this algorithm must not change */
+
+	ret = 0;
+
+	while (n > 0) {
+		ret = ret + (n % 10);
+		n = n / 10;
+	}
+
+	return (ret);
+}
+
+unsigned long
+cddb_discid(int tot_trks, struct cd_toc_entry *cdtoc)
+{
+        int     i,
+		t = 0,
+		n = 0;
+
+	/* For backward compatibility this algorithm must not change */
+
+	i = 0;
+
+	while (i < tot_trks) {
+		n = n + cddb_sum((cdtoc[i].addr.msf.minute * 60)
+		      + cdtoc[i].addr.msf.second);
+		i++;
+	}
+	t = ((cdtoc[tot_trks].addr.msf.minute * 60) +
+	      cdtoc[tot_trks].addr.msf.second) -
+	    ((cdtoc[0].addr.msf.minute * 60) +
+	      cdtoc[0].addr.msf.second);
+
+	return ((n % 0xff) << 24 | t << 8 | tot_trks);
+}
+
+void
+usage(void)
+{
+    printf("Usage:\n");
+    printf("cddb-id [-f <cd-dev>] [-m]\n");
+    printf("<cd-dev> is the cd device to use (Default: /dev/cd0c)\n");
+    printf("-m causes machine readable output\n");
+    exit(EX_USAGE);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/get_cdinfo.tcl	Wed Aug 09 02:18:47 2000 +0000
@@ -0,0 +1,169 @@
+#!/bin/sh
+# tcl magic \
+exec tclsh8.0 $0 $*
+
+#
+# This software is copyright Daniel O'Connor (darius@dons.net.au) 1998, 1999
+#
+# This software is release under the GNU Public License Version 2.
+# A copy of this licence must be distributed with this software.
+#
+
+proc main {} {
+    global argv0 argv tracks auto_path;
+
+    lappend auto_path ".";
+
+    if { [ llength $argv ] < 4 } {
+	puts stderr "Bad usage";
+	puts stderr "$argv0 <outfile> <discid> \[ <tracks> ... \] <disclen>";
+	exit 1;
+    }
+    set outfile [ lindex $argv 0 ];
+    set discid [ lindex $argv 1 ];
+    set trackoffs [ lrange $argv 2 [ expr [ llength $argv ] - 2 ] ];
+    set disclen [ lindex $argv end ];
+
+    if { $outfile == "-" } {
+	set wfh stdout;
+    } else {
+	set wfh [ open $outfile "w" ];
+    }
+
+    set fh [ socket cddb.cddb.com 8880 ];
+
+    # Greeting from server
+    #puts [ gets $fh ];
+    gets $fh;
+
+    puts $fh "CDDB HELLO [ exec id -u -n ] [ exec hostname ] TclMangler 0.1";
+    flush $fh
+
+    # Hello message
+    #puts [ gets $fh ];
+    gets $fh;
+
+    puts $fh "CDDB QUERY $discid [ llength $trackoffs ] $trackoffs $disclen"
+    flush $fh 
+
+    set line [ gets $fh ];
+    if { [ regexp {([0-9][0-9][0-9]) (.*)} $line a rtn rest ] } {
+	switch -- $rtn {
+	    "200" {
+		if { [ regexp {([a-z]*) ([0-9a-f]*) (.*)} $rest a cat discid name ] } {
+		    puts stderr "Matched CD called $name in category $cat";
+		} else {
+		    puts stderr "Couldn't parse line with code 200 '$rest'";
+		    exit 1;
+		}
+	    }
+
+	    "202" {
+		puts stderr "No such CD found.. generating dummy file";
+		puts $wfh "# xmcd CD database file
+# Copyright (C) 1993-1999 CDDB, Inc.
+#
+# Track frame offsets:";
+		foreach t $trackoffs {
+		    puts $wfh "#\t$t";
+		}
+		puts $wfh "#
+# Disc length: $disclen seconds
+#
+# Revision: 1
+# Submitted via: Tcl Mangler 0.1 - Copyright (c) 1999 Daniel O'Connor
+#
+DISCID=$discid
+DTITLE=";
+		set i 0;
+		foreach t $trackoffs {
+		    puts $wfh "TTITLE$i=";
+		    incr i
+		}
+
+		exit;
+	    }
+
+	    "211" {
+		set tot 0;
+		set matches "";
+
+		while { 1 } {
+		    set line [ gets $fh ];
+		    if { $line == "." } {
+			break;
+		    }
+
+		    if { [ regexp {^([a-z]*) ([0-9a-f]*) (.*)} $line a cat discid name ] } {
+			puts stderr "[ expr $tot + 1 ]) Matched CD called $name in category $cat";
+			lappend matches [ list $cat $discid $name ];
+			incr tot;
+		    } else {
+			puts stderr "Couldn't parse line after code 210 - '$line'";
+			exit 1;
+		    }
+		}
+		
+		if { $tot == 0 } {
+		    puts stderr "No matches found for 210?";
+		    exit 1;
+		}
+
+		if { $tot == 1 } {
+		    set num 0;
+		} else {
+		    puts stderr "Please enter the number which corresponds to the correct entry";
+		    while { 1 } {
+			set num [ gets stdin ];
+			if { ($num >= 1) && ($num <= $tot ) } {
+			    break;
+			}
+			puts stderr "Sorry, that number is invalid, please try again";
+		    }
+
+		    set cat [ lindex [ lindex $matches [ expr $num - 1 ] ] 0 ];
+		    set discid [ lindex [ lindex $matches [ expr $num - 1 ] ] 1 ];
+		    set name [ lindex [ lindex $matches [ expr $num - 1 ] ] 2 ];
+		}
+	    }
+
+	    "501" {
+		puts stderr"Invalid disc ID $discid";
+		exit 1;
+	    }
+
+	    default {
+		puts stderr "Couldn't parse '$line'";
+		exit 1;
+	    }
+	}
+    }
+
+    puts $fh "CDDB READ $cat $discid"
+    flush $fh
+    
+    gets $fh line;
+
+    if { [ regexp {([0-9][0-9][0-9]) (.*)} $line a rtn rest ] } {
+	if { $rtn != "210" } {
+	    puts stderr "Bad error from CDDB READ command ($line)"
+	    exit 1;
+	}
+    } else {
+	puts stderr "Couldn't parse $line";
+	exit 1;
+    }
+
+    while { 1 } {
+	set line [ gets $fh ];
+	if { $line == "." } {
+	    break;
+	}
+	
+	puts $wfh $line;
+    }
+
+    close $fh;
+}
+
+main;
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gettracks.sh	Wed Aug 09 02:18:47 2000 +0000
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+cddev=/dev/acd0c
+root=`dirname $0`
+if [ $# -eq 0 ]; then
+  tracks=`$root/cddb-id -f $cddev -n`
+else
+  tracks=$*
+fi
+
+echo Ripping tracks $tracks
+
+ripper="cdd -t \$num -"
+comp="lame -x -b 192 - -"
+#comp="gogo -silent -offset 0 -b 192 stdin"
+
+for t in $tracks ; do
+  num=`printf %02d $t`
+  name=`printf track_%s.mp3 $num`
+  echo Ripping $num to $name
+  eval $ripper 2>> rip.log | sox -t cdr - -t wav - | $comp > $name
+  if [ $? -ne 0 ]; then
+    echo "Failed!"
+    exit 1
+  fi
+done
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tracknamer.tcl	Wed Aug 09 02:18:47 2000 +0000
@@ -0,0 +1,305 @@
+#!/bin/sh
+# tcl magic \
+exec tclsh8.0 $0 $*
+
+#
+# This software is copyright Daniel O'Connor (darius@dons.net.au) 1998, 1999
+#
+# This software is release under the GNU Public License Version 2.
+# A copy of this licence must be distributed with this software.
+#
+
+proc edit_tracks {} {
+    global tracks state;
+    
+#    if { [ catch {loadlibs [ list "X11" "tk80" ]} msg] } {
+#	log "Failed to load library files - $msg";
+#	exit 1;
+#    }
+
+    set tracks(tmp:albumartist) $tracks(albumartist);
+    set tracks(tmp:albumname) $tracks(albumname);
+    for { set i 1 } { $i <= $tracks(number) } { incr i } {
+	set tracks(tmp:artist:$i) $tracks(artist:$i);
+	set tracks(tmp:title:$i) $tracks(title:$i);
+    }
+
+    # create the toplevel
+    eval destroy [winfo child .];
+    wm title . "Track Edit"
+
+    # Let's have a menubar
+    frame .menubar -relief raised -bd 2
+    pack .menubar -side top -fill x
+
+    # Add the File menu
+    menubutton .menubar.file -text "File" -menu .menubar.file.m -underline 0;
+    menu .menubar.file.m -tearoff 0;
+    .menubar.file.m add command -label " Fill Down" -command "fill_down" \
+	-underline 2 -accelerator "Ctrl-d";
+    .menubar.file.m add command -label " Revert   " -command "revert" \
+	-underline 2 -accelerator "Ctrl-r";
+    .menubar.file.m add command -label " Swap     " -command "swap" \
+	-underline 2
+    .menubar.file.m add separator;
+    .menubar.file.m add command -label " Save     " -command "save_names" \
+	-underline 2 -accelerator "Ctrl-s";
+    .menubar.file.m add command -label " Exit     " -command "namer_exit" \
+	-underline 2 -accelerator "Ctrl-q";
+
+    pack .menubar.file -side left;
+
+    # Top frame for entry widgets
+    frame .top -relief raised -bd 1
+    pack .top -side top -fill both
+    # Bottom frame for button
+    frame .bot -relief raised -bd 1
+    pack .bot -side top -fill both
+
+    frame .top.disctitle;
+    pack .top.disctitle;
+    label .top.disctitle.label -text "Disc Title";
+    entry .top.disctitle.entry -width 80 -relief sunken -textvariable tracks(tmp:albumname);
+    pack .top.disctitle.label .top.disctitle.entry -side left;
+    frame .top.discartist;
+    pack .top.discartist;
+    label .top.discartist.label -text "Disc Artist";
+    entry .top.discartist.entry -width 80 -relief sunken -textvariable tracks(tmp:albumartist);
+    pack .top.discartist.label .top.discartist.entry -side left;
+
+    label .top.label -text "Artist/Title";
+    pack .top.label;
+
+    add_entries .top
+
+    button .bot.revert -text Save -command save_names;
+    button .bot.save -text Revert -command revert;
+    pack .bot.revert .bot.save -side left;
+
+    bind all <Control-q> {namer_exit}
+    bind all <Control-s> {save_names}
+    bind all <Control-d> {fill_down}
+    bind all <Control-r> {revert}
+    update;
+
+    vwait state(exitnow);
+    destroy .
+    catch {update};
+}
+
+
+proc swap {} {
+    global tracks;
+    
+    for { set i 1 } { $i <= $tracks(number) } { incr i } {
+	set tmp $tracks(tmp:title:$i);
+	set tracks(tmp:title:$i) $tracks(tmp:artist:$i);
+	set tracks(tmp:artist:$i) $tmp;
+    }
+}
+
+proc fill_down {} {
+    global tracks;
+
+    for { set i 2 } { $i <= $tracks(number) } { incr i } {
+	set tracks(tmp:artist:$i) $tracks(tmp:artist:1);
+    }
+}
+
+proc revert {} {
+    global tracks;
+
+    set tracks(tmp:albumname) $tracks(albumname);
+    set tracks(tmp:albumartist) $tracks(albumartist);
+
+    for { set i 1 } { $i <= $tracks(number) } { incr i } {
+	set tracks(tmp:artist:$i) $tracks(artist:$i);
+	set tracks(tmp:title:$i) $tracks(title:$i);
+    }
+}
+
+proc add_entries { parent } {
+    global tracks;
+    
+    for { set i 1 } { $i <= $tracks(number) } { incr i } {
+	frame $parent.fr_track:$i;
+	pack $parent.fr_track:$i -side top;
+	
+	label $parent.fr_track:$i.label -text "Track $i:";
+	entry $parent.fr_track:$i.ar_entry -width 40 -relief sunken -textvariable tracks(tmp:artist:$i);
+	entry $parent.fr_track:$i.ti_entry -width 40 -relief sunken -textvariable tracks(tmp:title:$i);
+	pack $parent.fr_track:$i.label $parent.fr_track:$i.ar_entry $parent.fr_track:$i.ti_entry -side left;
+	
+#	log "Title $i";
+    }
+}
+proc save_names {} {
+    global tracks;
+
+    set tracks(albumname) $tracks(tmp:albumname);
+    set $tracks(albumartist) tracks(tmp:albumartist);
+
+    for { set i 1 } { $i <= $tracks(number) } { incr i } {
+	set tracks(artist:$i) $tracks(tmp:artist:$i);
+	set tracks(title:$i) $tracks(tmp:title:$i);
+    }
+
+    set tracks(updated) 1;
+#    print_info;
+
+}
+
+proc print_info {} {
+    global tracks;
+
+    puts "Title: $tracks(albumname)";
+    puts "Artist: $tracks(albumartist)";
+
+    for { set i 1 } { $i <= $tracks(number) } { incr i } {
+	puts "Track $i: $tracks(artist:$i) - $tracks(title:$i)";
+    }
+}
+proc namer_exit {} {
+    global state;
+
+#    log "Bye";
+#    print_info;
+    set state(exitnow) 1;
+}
+
+##################################################################
+# Load a list of libraries.
+# Takes a list of the form { "foo" "bar" } to look for
+# libfoo.so.n.m and libbar.so.n.m.
+# Also looks at the LD_LIBRARY_PATH variable for extra places to look
+#
+proc loadlibs {liblist} {
+    global env;
+    
+    set file [open {|/sbin/ldconfig -r} r]
+    while { ! [eof $file] } {
+	if { [ regexp {[0-9]+:-l(.*) => (.*)/lib(.*)\.so\.(.*)} [gets $file] a b c d e ] == 0 } {
+	    continue;
+	}
+	
+	# List of partially processed libs
+	# eg '/usr/local/lib' 'tiff34' '1.0'
+	if { [ regexp {(.*)\.(.*)} $e f g h ] == 0 } {
+	    set maj $e;
+	    set min 0;
+	} else {
+	    set maj $g;
+	    set min $h;
+	}
+	set tmp [ list $c $d $maj $min ];
+#	puts "ldconfig - $tmp";
+	lappend all_list $tmp;
+    }
+
+    close $file;
+
+    if { [ info exists env(LD_LIBRARY_PATH) ] == 1} {
+	set ld_path [ split $env(LD_LIBRARY_PATH) ":"];
+	
+	foreach dir $ld_path {
+	    set found [glob -nocomplain -- "$dir/lib*.so.*"];
+	    if { $found != "" } {
+		foreach foo $found {
+		    if { [ regexp {(.*)/lib(.*)\.so\.(.*)} $foo a b c d ] == 0 } {
+			continue;
+		    }
+
+		    if { [ regexp {(.*)\.(.*)} $d e f g ] == 0 } {
+			set maj $d;
+			set min 0;
+		    } else {
+			set maj $f;
+			set min $g;
+		    }
+		    set tmp [ list $b $c $maj $min ];
+#		    puts "LD_LIB - $tmp";
+		    lappend all_list $tmp;
+		}
+	    }
+	}
+    }
+
+    set libs_to_load "";
+
+    foreach lib $liblist {
+	set found_lib "";
+	set found_maj 0;
+	set found_min 0;
+
+	foreach line $all_list {
+	    # Path
+	    set b [ lindex $line 0 ];
+	    # Lib name
+	    set e [ lindex $line 1 ];
+	    # Major
+	    set c [ lindex $line 2 ];
+	    # Minor
+	    set d [ lindex $line 3 ];
+	    if { ($e == $lib) && (($c > $found_maj) || (($c == $found_maj) && ($d > $found_min))) } {
+		set found_maj $c;
+		set found_min $d;
+		set found_lib $e;
+		set found_path $b;
+#		puts "Found $found_lib ($found_maj.$found_min)";
+	    }
+	}
+
+	if { $found_lib != "" } {
+	    lappend libs_to_load [ list $found_lib $found_path $found_maj $found_min ];
+	} else {
+	    error "Unable to find library for $lib";
+	}
+    }
+
+    set loaded_OK "";
+
+    foreach lib $libs_to_load {
+	set libname [ lindex $lib 0 ];
+	set libpath [ lindex $lib 1 ];
+	set libmaj [ lindex $lib 2 ];
+	set libmin [ lindex $lib 3 ];
+	# Try no extension for ELF
+	if { $libmin == 0 } {
+	    if { [ file exists $libpath/lib$libname.so.$libmaj ] } {
+		set loadname $libpath/lib$libname.so.$libmaj
+	    } else {
+		set loadname $libpath/lib$libname.so.$libmaj.$libmin
+	    }
+	} else {
+	    set loadname $libpath/lib$libname.so.$libmaj.$libmin
+	}
+	if { [catch {load $loadname} msg ] } {
+	    # Ignore the error if it's because it couldn't find the procedure - needed for X11
+	    if { [regexp -nocase .*couldn\'t\ find\ procedure.* $msg ] == 0 } {
+		error "Warning: Couldn't load $lib because $msg";
+	    } else {
+		lappend loaded_OK $libname;
+	    }
+	} else {
+	    lappend loaded_OK $lib;
+	}
+    }
+
+    return $loaded_OK;
+}
+
+proc log {format args} {
+    # Extract the calling function's name
+    set fname [lindex [info level -1] 0];
+
+    # Evaluate the supplied format string and arguments
+    if {[catch {set csm [eval format {$format} $args]} msg]} {
+        set csm "bad log message. format='$format' args='$args'";
+    }
+
+    # Emit the message
+    puts stderr "[clock format [clock seconds] -format {%y/%m/%d %H:%M:%S} -gmt yes]:$fname: $csm";
+    flush stderr;
+}
+
+