summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2005-07-05 22:02:59 +0000
committerDaniel Stenberg <daniel@haxx.se>2005-07-05 22:02:59 +0000
commit5081182fe13f1158d41138b79985dff8b0632ca1 (patch)
tree32814e966e0c1cc7af52b123477dd1804c41fe44 /tools
parent2e9ce4ee475d57d2838a6a0dfb5d37c4c7992a3c (diff)
downloadrockbox-5081182fe13f1158d41138b79985dff8b0632ca1.tar.gz
rockbox-5081182fe13f1158d41138b79985dff8b0632ca1.zip
Added CRC32 of the compressed song data, since that is what the format wants.
This is only added for mp3 yet as I didn't figure out how to get the index to the compressed vorbis off ogg files just yet. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7033 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'tools')
-rwxr-xr-xtools/songdb.pl317
1 files changed, 95 insertions, 222 deletions
diff --git a/tools/songdb.pl b/tools/songdb.pl
index 202ab06401..589267b632 100755
--- a/tools/songdb.pl
+++ b/tools/songdb.pl
@@ -84,7 +84,7 @@ sub get_oggtag {
84 84
85 my $ogg = vorbiscomm->new($fn); 85 my $ogg = vorbiscomm->new($fn);
86 86
87 $ogg->load; 87 my $h= $ogg->load;
88 88
89 # Convert this format into the same format used by the id3 parser hash 89 # Convert this format into the same format used by the id3 parser hash
90 90
@@ -100,7 +100,6 @@ sub get_oggtag {
100 $n = 'ALBUM'; 100 $n = 'ALBUM';
101 } 101 }
102 $hash{$n}=$cmmt if($n); 102 $hash{$n}=$cmmt if($n);
103 # print $k, '=', $cmmt, "\n";
104 } 103 }
105 } 104 }
106 105
@@ -147,6 +146,88 @@ sub extractdirs {
147 return @dirs; 146 return @dirs;
148} 147}
149 148
149# CRC32 32KB of data (use less if there isn't 32KB available)
150
151sub crc32 {
152 my ($filename, $index) = @_;
153
154 my $len = 32*1024;
155
156 if(!open(FILE, "<$filename")) {
157 print "failed to open \"$filename\" $!\n";
158 return -2;
159 }
160
161 # read $data from index $index to $buffer from the file, may return fewer
162 # bytes when dealing with a very small file.
163 #
164 # TODO: make sure we don't include a trailer with metadata when doing this.
165 # Like a id3v1 tag.
166 my $nread = sysread FILE, $buffer, $len, $index;
167
168 close(FILE);
169
170 my @crc_table =
171 ( # CRC32 lookup table for polynomial 0x04C11DB7
172 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
173 0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
174 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, 0x4C11DB70, 0x48D0C6C7,
175 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75,
176 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3,
177 0x709F7B7A, 0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
178 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58, 0xBAEA46EF,
179 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D,
180 0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB,
181 0xCEB42022, 0xCA753D95, 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1,
182 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
183 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072,
184 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4,
185 0x0808D07D, 0x0CC9CDCA, 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE,
186 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08,
187 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
188 0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC,
189 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6,
190 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, 0xE0B41DE7, 0xE4750050,
191 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2,
192 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
193 0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637,
194 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1,
195 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53,
196 0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5,
197 0x3F9B762C, 0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
198 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E, 0xF5EE4BB9,
199 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B,
200 0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD,
201 0xCDA1F604, 0xC960EBB3, 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7,
202 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
203 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3,
204 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2,
205 0x470CDD2B, 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8,
206 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E,
207 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
208 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A,
209 0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0,
210 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, 0xE3A1CBC1, 0xE760D676,
211 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4,
212 0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
213 0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668,
214 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
215 );
216
217 my $crc = 0xffffffff;
218 for ($i = 0; $i < $nread; $i++) {
219 # get the numeric for the byte of the $i index
220 $buf = ord(substr($buffer, $i, 1));
221
222 $crc = ($crc << 8) ^ $crc_table[(($crc >> 24) ^ $buf) & 0xFF];
223
224 # printf("%08x\n", $crc);
225 }
226
227 return $crc;
228
229}
230
150sub singlefile { 231sub singlefile {
151 my ($file) = @_; 232 my ($file) = @_;
152 my $hash; 233 my $hash;
@@ -156,6 +237,10 @@ sub singlefile {
156 } 237 }
157 else { 238 else {
158 $hash = get_mp3tag($file); 239 $hash = get_mp3tag($file);
240
241 my $info = get_mp3info($file);
242
243 $hash->{FILECRC} = crc32($file, $info->{headersize});
159 } 244 }
160 245
161 return $hash; # a hash reference 246 return $hash; # a hash reference
@@ -626,9 +711,10 @@ if ($db) {
626 my $str = $f."\x00" x ($maxfilelen- length($f)); 711 my $str = $f."\x00" x ($maxfilelen- length($f));
627 my $id3 = $entries{$f}; 712 my $id3 = $entries{$f};
628 print DB $str; 713 print DB $str;
629 dumpint(0); # TODO: add hashing; 0 for now. 714 #print STDERR "CRC: ".."\n";
630 dumpint($id3->{'songoffset'}); 715 dumpint($id3->{'FILECRC'}); # CRC32 of the song data
631 dumpint(-1); 716 dumpint($id3->{'songoffset'}); # offset to song data
717 dumpint(-1); # what's this for?
632 } 718 }
633 719
634 close(DB); 720 close(DB);
@@ -837,223 +923,6 @@ sub use_winamp_genres {
837 923
838=pod 924=pod
839 925
840=item remove_mp3tag (FILE [, VERSION, BUFFER])
841
842Can remove ID3v1 or ID3v2 tags. VERSION should be C<1> for ID3v1,
843C<2> for ID3v2, and C<ALL> for both.
844
845For ID3v1, removes last 128 bytes from file if those last 128 bytes begin
846with the text 'TAG'. File will be 128 bytes shorter.
847
848For ID3v2, removes ID3v2 tag. Because an ID3v2 tag is at the
849beginning of the file, we rewrite the file after removing the tag data.
850The buffer for rewriting the file is 4MB. BUFFER (in bytes) ca
851change the buffer size.
852
853Returns the number of bytes removed, or -1 if no tag removed,
854or undef if there is an error.
855
856=cut
857
858sub remove_mp3tag {
859 my($file, $version, $buf) = @_;
860 my($fh, $return);
861
862 $buf ||= 4096*1024; # the bigger the faster
863 $version ||= 1;
864
865 if (not (defined $file && $file ne '')) {
866 $@ = "No file specified";
867 return undef;
868 }
869
870 if (not -s $file) {
871 $@ = "File is empty";
872 return undef;
873 }
874
875 if (ref $file) { # filehandle passed
876 $fh = $file;
877 } else {
878 $fh = gensym;
879 if (not open $fh, "+< $file\0") {
880 $@ = "Can't open $file: $!";
881 return undef;
882 }
883 }
884
885 binmode $fh;
886
887 if ($version eq 1 || $version eq 'ALL') {
888 seek $fh, -128, 2;
889 my $tell = tell $fh;
890 if (<$fh> =~ /^TAG/) {
891 truncate $fh, $tell or warn "Can't truncate '$file': $!";
892 $return += 128;
893 }
894 }
895
896 if ($version eq 2 || $version eq 'ALL') {
897 my $h = _get_v2head($fh);
898 if ($h) {
899 local $\;
900 seek $fh, 0, 2;
901 my $eof = tell $fh;
902 my $off = $h->{tag_size};
903
904 while ($off < $eof) {
905 seek $fh, $off, 0;
906 read $fh, my($bytes), $buf;
907 seek $fh, $off - $h->{tag_size}, 0;
908 print $fh $bytes;
909 $off += $buf;
910 }
911
912 truncate $fh, $eof - $h->{tag_size}
913 or warn "Can't truncate '$file': $!";
914 $return += $h->{tag_size};
915 }
916 }
917
918 _close($file, $fh);
919
920 return $return || -1;
921}
922
923
924=pod
925
926=item set_mp3tag (FILE, TITLE, ARTIST, ALBUM, YEAR, COMMENT, GENRE [, TRACKNUM])
927
928=item set_mp3tag (FILE, $HASHREF)
929
930Adds/changes tag information in an MP3 audio file. Will clobber
931any existing information in file.
932
933Fields are TITLE, ARTIST, ALBUM, YEAR, COMMENT, GENRE. All fields have
934a 30-byte limit, except for YEAR, which has a four-byte limit, and GENRE,
935which is one byte in the file. The GENRE passed in the function is a
936case-insensitive text string representing a genre found in C<@mp3_genres>.
937
938Will accept either a list of values, or a hashref of the type
939returned by C<get_mp3tag>.
940
941If TRACKNUM is present (for ID3v1.1), then the COMMENT field can only be
94228 bytes.
943
944ID3v2 support may come eventually. Note that if you set a tag on a file
945with ID3v2, the set tag will be for ID3v1[.1] only, and if you call
946C<get_mp3_tag> on the file, it will show you the (unchanged) ID3v2 tags,
947unless you specify ID3v1.
948
949=cut
950
951sub set_mp3tag {
952 my($file, $title, $artist, $album, $year, $comment, $genre, $tracknum) = @_;
953 my(%info, $oldfh, $ref, $fh);
954 local %v1_tag_fields = %v1_tag_fields;
955
956 # set each to '' if undef
957 for ($title, $artist, $album, $year, $comment, $tracknum, $genre,
958 (@info{@v1_tag_names}))
959 {$_ = defined() ? $_ : ''}
960
961 ($ref) = (overload::StrVal($title) =~ /^(?:.*\=)?([^=]*)\((?:[^\(]*)\)$/)
962 if ref $title;
963 # populate data to hashref if hashref is not passed
964 if (!$ref) {
965 (@info{@v1_tag_names}) =
966 ($title, $artist, $album, $year, $comment, $tracknum, $genre);
967
968 # put data from hashref into hashref if hashref is passed
969 } elsif ($ref eq 'HASH') {
970 %info = %$title;
971
972 # return otherwise
973 } else {
974 warn(<<'EOT');
975Usage: set_mp3tag (FILE, TITLE, ARTIST, ALBUM, YEAR, COMMENT, GENRE [, TRACKNUM])
976 set_mp3tag (FILE, $HASHREF)
977EOT
978 return undef;
979 }
980
981 if (not (defined $file && $file ne '')) {
982 $@ = "No file specified";
983 return undef;
984 }
985
986 if (not -s $file) {
987 $@ = "File is empty";
988 return undef;
989 }
990
991 # comment field length 28 if ID3v1.1
992 $v1_tag_fields{COMMENT} = 28 if $info{TRACKNUM};
993
994
995 # only if -w is on
996 if ($^W) {
997 # warn if fields too long
998 foreach my $field (keys %v1_tag_fields) {
999 $info{$field} = '' unless defined $info{$field};
1000 if (length($info{$field}) > $v1_tag_fields{$field}) {
1001 warn "Data too long for field $field: truncated to " .
1002 "$v1_tag_fields{$field}";
1003 }
1004 }
1005
1006 if ($info{GENRE}) {
1007 warn "Genre `$info{GENRE}' does not exist\n"
1008 unless exists $mp3_genres{$info{GENRE}};
1009 }
1010 }
1011
1012 if ($info{TRACKNUM}) {
1013 $info{TRACKNUM} =~ s/^(\d+)\/(\d+)$/$1/;
1014 unless ($info{TRACKNUM} =~ /^\d+$/ &&
1015 $info{TRACKNUM} > 0 && $info{TRACKNUM} < 256) {
1016 warn "Tracknum `$info{TRACKNUM}' must be an integer " .
1017 "from 1 and 255\n" if $^W;
1018 $info{TRACKNUM} = '';
1019 }
1020 }
1021
1022 if (ref $file) { # filehandle passed
1023 $fh = $file;
1024 } else {
1025 $fh = gensym;
1026 if (not open $fh, "+< $file\0") {
1027 $@ = "Can't open $file: $!";
1028 return undef;
1029 }
1030 }
1031
1032 binmode $fh;
1033 $oldfh = select $fh;
1034 seek $fh, -128, 2;
1035 # go to end of file if no tag, beginning of file if tag
1036 seek $fh, (<$fh> =~ /^TAG/ ? -128 : 0), 2;
1037
1038 # get genre value
1039 $info{GENRE} = $info{GENRE} && exists $mp3_genres{$info{GENRE}} ?
1040 $mp3_genres{$info{GENRE}} : 255; # some default genre
1041
1042 local $\;
1043 # print TAG to file
1044 if ($info{TRACKNUM}) {
1045 print pack "a3a30a30a30a4a28xCC", 'TAG', @info{@v1_tag_names};
1046 } else {
1047 print pack "a3a30a30a30a4a30C", 'TAG', @info{@v1_tag_names[0..4, 6]};
1048 }
1049
1050 select $oldfh;
1051
1052 _close($file, $fh);
1053
1054 return 1;
1055}
1056
1057=pod 926=pod
1058 927
1059=item get_mp3tag (FILE [, VERSION, RAW_V2]) 928=item get_mp3tag (FILE [, VERSION, RAW_V2])
@@ -1402,6 +1271,8 @@ sub get_mp3info {
1402 1271
1403 my $vbr = _get_vbr($fh, $h, \$off); 1272 my $vbr = _get_vbr($fh, $h, \$off);
1404 1273
1274 $h->{headersize}=$off; # data size prepending the actual mp3 data
1275
1405 seek $fh, 0, 2; 1276 seek $fh, 0, 2;
1406 $eof = tell $fh; 1277 $eof = tell $fh;
1407 seek $fh, -128, 2; 1278 seek $fh, -128, 2;
@@ -1459,6 +1330,8 @@ sub _get_info {
1459 $i->{FRAME_LENGTH} = int($h->{size} / $i->{FRAMES}) if $i->{FRAMES}; 1330 $i->{FRAME_LENGTH} = int($h->{size} / $i->{FRAMES}) if $i->{FRAMES};
1460 $i->{FREQUENCY} = $frequency_tbl[3 * $h->{IDR} + $h->{sampling_freq}]; 1331 $i->{FREQUENCY} = $frequency_tbl[3 * $h->{IDR} + $h->{sampling_freq}];
1461 1332
1333 $i->{headersize} = $h->{headersize};
1334
1462 return $i; 1335 return $i;
1463} 1336}
1464 1337