1#!/usr/bin/perl -w 2# Copyright 2002 by Heiko Ei�feldt (Eissfeldt) 3use strict; 4use integer; 5 6# read all .inf files and generate the binary cdtext block 7# for cdrecord. 8 9my @results; 10 11sub fill_packet 12{ 13 my $ID = shift; 14 my $track = shift; 15 my $seq_nr = shift; 16 my $charpos = shift; 17 my $text = shift; 18 my $todo = shift; 19 20 return if (!defined($$text)); 21 22 my @packet = (); 23 push @packet, chr($ID); # track title, performer, ... 24 push @packet, chr($$track); 25 push @packet, chr($$seq_nr); 26 $$charpos = 15 if ($$charpos > 15); 27 push @packet, chr($$charpos); 28 29 my $cp = 0; 30 my $tracks_inp = 0; 31 while (length($$text) + 1 < 12 - $cp) { 32 push @packet, split(//, $$text); 33 push @packet, chr(0); 34 $cp += length($$text) + 1; 35 $$charpos = 0; 36 $tracks_inp++; 37 38 $$text = shift @$todo; 39 if ($#$todo < 1 && (!defined($$text) || $$text eq "") ) { 40 push @packet, (chr(0)) x (12 - $cp); 41 $$seq_nr++; 42 print_packet(@packet); 43 return; 44 } 45 $$text = "" if (!defined($$text)); 46 $$track++; 47 } 48 49 # packet gets full 50 my $left = 12 - $cp; 51 if ($left > length($$text)) { 52 # title fits into packet 53 push @packet, split(//, $$text); 54 push @packet, chr(0); 55 $tracks_inp++; 56 print_packet(@packet); 57 58 $$charpos = 0; 59 $$text = shift @$todo; 60 unless ((!defined($$text) || $$text eq "") && $#$todo < 1) { $$track++; } 61 $$seq_nr++; 62 } else { 63 # print current packet and more if more entries are present 64 push @packet, split(//, substr($$text, 0, $left)); 65 print_packet(@packet); 66 67 $$text = substr($$text, $left); 68 $$charpos += $left; 69 $$seq_nr++; 70 } 71} 72 73my @crctab =( 74 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 75 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 76 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 77 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 78 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 79 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 80 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 81 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 82 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 83 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 84 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 85 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 86 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 87 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 88 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 89 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 90 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 91 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 92 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 93 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 94 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 95 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 96 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 97 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 98 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 99 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 100 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 101 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 102 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 103 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 104 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 105 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, 106); 107 108sub add_crc 109{ 110 # crc with polynomial: x^16 + x^12 + x^5 + 1 111 # 1,0001,0000,0010,0001 112 my $packref = shift; 113 my $crc = 0; 114 115 foreach (@$packref) { 116 $crc = ($crc << 8) ^ $crctab[ 117 ( ($crc >> (16-8)) ^ ord($_) ) & 0xff 118 ]; 119 $crc &= 0xffff; 120 } 121 $$packref[16] = chr((($crc >> 8) & 0xff) ^ 0xff); 122 $$packref[17] = chr(($crc & 0xff) ^ 0xff); 123} 124 125sub print_packet 126{ 127 return if ($#_ < 1); 128 my @packet = (@_); 129 add_crc(\@packet); 130 if ($packet[0] ne chr(0x8f)) { 131 printf STDERR ("%02x "x4 ." "."%c "x12 ." "."%02x "x2), map( defined($_) ? ord($_) : "___undef", @packet ); 132 } else { 133 printf STDERR ("%02x "x4 ." "."%02x "x12 ." "."%02x "x2), map( defined($_) ? ord($_) : "___undef", @packet ); 134 } 135 printf STDERR "\n"; 136 push @results, @packet; 137} 138 139my $defaultperformer = $ARGV[0] || die "usage: ", $^X, " defaultperformer_name\n"; 140my $prefix = $ARGV[1] || "audio"; 141@ARGV = glob("${prefix}_??.inf"); 142my @albumtitles; 143my @tracktitles; 144my @performers; 145my $ISRC; 146my @ISRCs; 147my $MCN; 148 149my $performer; 150while (<>) { 151 if (/^Performer=\s+'(.*?)'$/) { 152 $performer = $1; 153 } 154 if (/^Albumtitle=\s+'(.*?)'$/) { 155 push @albumtitles, $1; 156 } 157 if (/^Tracktitle=\s+'(.*?)'$/) { 158 push @tracktitles, $1; 159 } 160 if (/^ISRC=\s+(\S+?)$/) { 161 $ISRC = $1; 162 } 163 if (/^MCN=\s+(\S+?)$/) { 164 $MCN = $1; 165 } 166 if (eof) { 167 close ARGV; 168 $performer = $defaultperformer if (!defined($performer)); 169 push @performers, $performer; 170 $performer = undef; 171 push @ISRCs, $ISRC; 172 $ISRC = undef; 173 } 174} 175 176# 177my $seq_nr = 0; 178 179my @todo; 180my $text; 181my $track; 182my $charpos; 183 184# build cdtext packets 185 186# build track titles 187@todo = ($albumtitles[0], @tracktitles); 188$text = shift @todo; 189$track = 0; 190$charpos = 0; 191 192while ($#todo > 1 || defined($text)) { 193 fill_packet(0x80, \$track, \$seq_nr, \$charpos, \$text, \@todo); 194} 195 196my $trackpacks = $seq_nr; # store for later reference 197my $last_track = $track; 198 199# build performer entries 200#@todo = ($performer) x (1 + scalar(@tracktitles)); 201@todo = ($defaultperformer, @performers); 202$text = shift @todo; 203$track = 0; 204$charpos = 0; 205 206while ($#todo > 1 || defined($text)) { 207 fill_packet(0x81, \$track, \$seq_nr, \$charpos, \$text, \@todo); 208} 209 210my $perfpacks = $seq_nr - $trackpacks; # store for later reference 211 212# build ISRC entries 213@todo = ($MCN, @ISRCs); 214$text = shift @todo; 215$track = 0; 216$charpos = 0; 217 218while ($#todo > 1 || defined($text)) { 219 $text = "" if (!defined($text)); 220 fill_packet(0x8e, \$track, \$seq_nr, \$charpos, \$text, \@todo); 221} 222 223my $isrcpacks = $seq_nr - $trackpacks - $perfpacks; # store for later reference 224 225# build size information blocks 226my $size1 = chr(0) . chr(1) . chr($last_track) . chr(0) 227 . chr($trackpacks) . chr($perfpacks) . chr(0) x 5; 228my $size2 = chr(0) x 6 . chr($isrcpacks) . chr(3) . chr($seq_nr+2) . chr(0) x 2; 229my $size3 = chr(0) x 4 . chr(9); # hard coded language 09 = english 230@todo = ($size1, $size2, $size3); 231$text = shift @todo; 232$track = 0; 233$charpos = 0; 234 235while ((defined($text) && $text ne "") ) { 236 fill_packet(0x8f, \$track, \$seq_nr, \$charpos, \$text, \@todo); 237} 238 239# write out the results 240my $size = @results + 2; 241print chr($size >> 8), chr($size & 0xff), chr(0), chr(0), @results; 242