line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package MP3::TAG::ID3v1; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# reads ID3v1 and ID3v1.1 mp3-tags |
4
|
|
|
|
|
|
|
# writes ID3v1.1 mp3-tags |
5
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
3
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
28
|
|
7
|
1
|
|
|
1
|
|
6
|
use vars qw /@mp3_genres @winamp_genres $AUTOLOAD %ok_length/; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
1273
|
|
8
|
|
|
|
|
|
|
# allowed fields in ID3v1.1 and max length of this fields (expect for track and genre which are coded later) |
9
|
|
|
|
|
|
|
%ok_length = (song => 30, artist => 30, album => 30, comment => 28, track => 3, genre => 30, year=>4, genreID=>1); |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=pod |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 NAME |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
MP3::TAG::ID3v1 - Perl extension for reading / writing ID3v1 tags of mp3-files |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=head1 SYNOPSIS |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
MP3::TAG::ID3v2 is designed to be called from the MP3::Tag module. |
20
|
|
|
|
|
|
|
It then returns a ID3v2-tag-object, which can be used in a users |
21
|
|
|
|
|
|
|
program. |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
use MP3::TAG::ID3v1; |
24
|
|
|
|
|
|
|
$id3v1 = MP3::TAG::ID3v1->new($mp3obj); |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
C<$mp3obj> is a object from MP3::Tag. See according documentation. |
27
|
|
|
|
|
|
|
C<$tag> is undef when no tag is found in the C<$mp3obj>. |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
* Reading the tag |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
print " Song: " .$id3v1->song . "\n"; |
32
|
|
|
|
|
|
|
print " Artist: " .$id3v1->artist . "\n"; |
33
|
|
|
|
|
|
|
print " Album: " .$id3v1->album . "\n"; |
34
|
|
|
|
|
|
|
print "Comment: " .$id3v1->comment . "\n"; |
35
|
|
|
|
|
|
|
print " Year: " .$id3v1->year . "\n"; |
36
|
|
|
|
|
|
|
print " Genre: " .$id3v1->genre . "\n"; |
37
|
|
|
|
|
|
|
print " Track: " .$id3v1->track . "\n"; |
38
|
|
|
|
|
|
|
@tagdata = $mp3->all(); |
39
|
|
|
|
|
|
|
foreach (@tagdata) { |
40
|
|
|
|
|
|
|
print $_; |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
* Changing / Writing the tag |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
$id3v1->comment("This is only a Test Tag"); |
46
|
|
|
|
|
|
|
$id3v1->song("testing"); |
47
|
|
|
|
|
|
|
$id3v1->artist("Artest"); |
48
|
|
|
|
|
|
|
$id3v1->album("Test it"); |
49
|
|
|
|
|
|
|
$id3v1->year("1965"); |
50
|
|
|
|
|
|
|
$id3v1->track("5"); |
51
|
|
|
|
|
|
|
$id3v1->genre("Blues"); |
52
|
|
|
|
|
|
|
# or at once |
53
|
|
|
|
|
|
|
$id3v1->all("song title","artist","album","1900","comment",10,"Ska");# |
54
|
|
|
|
|
|
|
$id3v1->writeTag; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=head1 AUTHOR |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
Thomas Geffert, thg@users.sourceforge.net |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
=head1 DESCRIPTION |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=item new() |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
$id3v1 = MP3::TAG::ID3v1->new($mp3obj[, $create]); |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
Generally called from MP3::TAG, because a $mp3obj is needed. |
67
|
|
|
|
|
|
|
If $create is true, a new tag is created. Otherwise undef is |
68
|
|
|
|
|
|
|
returned, if now ID3v1 tag is found in the $mp3obj. |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=cut |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
# create a ID3v1 object |
73
|
|
|
|
|
|
|
sub new { |
74
|
2
|
|
|
2
|
1
|
4
|
my ($class, $mp3obj, $create) = @_; |
75
|
2
|
|
|
|
|
4
|
my $self={mp3=>$mp3obj}; |
76
|
2
|
|
|
|
|
2
|
my $buffer; |
77
|
|
|
|
|
|
|
|
78
|
2
|
50
|
33
|
|
|
6
|
if (defined $create && $create) { |
79
|
0
|
|
|
|
|
0
|
$self->{new} = 1; |
80
|
|
|
|
|
|
|
} else { |
81
|
2
|
|
|
|
|
6
|
$mp3obj->seek(-128,2); |
82
|
2
|
|
|
|
|
6
|
$mp3obj->read(\$buffer, 128); |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
2
|
50
|
33
|
|
|
11
|
if ($create || substr ($buffer,0,3) eq "TAG") { |
86
|
2
|
|
|
|
|
5
|
bless $self, $class; |
87
|
2
|
|
|
|
|
4
|
$self->readTag($buffer); |
88
|
|
|
|
|
|
|
|
89
|
2
|
|
|
|
|
7
|
return $self; |
90
|
|
|
|
|
|
|
} else { |
91
|
0
|
|
|
|
|
0
|
return undef; |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=pod |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=item song(), artist(), album(), year(), comment(), track(), genre() |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
$artist = $id3v1->artist; |
100
|
|
|
|
|
|
|
$artist = $id3v1->artist($artist); |
101
|
|
|
|
|
|
|
$album = $id3v1->album; |
102
|
|
|
|
|
|
|
$album = $id3v1->album($album); |
103
|
|
|
|
|
|
|
$year = $id3v1->year; |
104
|
|
|
|
|
|
|
$year = $id3v1->year($year); |
105
|
|
|
|
|
|
|
$comment = $id3v1->comment; |
106
|
|
|
|
|
|
|
$comment = $id3v1->comment($comment); |
107
|
|
|
|
|
|
|
$track = $id3v1->track; |
108
|
|
|
|
|
|
|
$track = $id3v1->track($track); |
109
|
|
|
|
|
|
|
$genre = $id3v1->genre; |
110
|
|
|
|
|
|
|
$genre = $id3v1->genre($genre); |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
Use these functions to retrieve the date of these fields, |
113
|
|
|
|
|
|
|
or to set the data. |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
$genre can be a string with the name of the genre, or a number |
116
|
|
|
|
|
|
|
describing the genre. |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=cut |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
sub AUTOLOAD { |
121
|
6
|
|
|
6
|
|
81
|
my $self = shift; |
122
|
6
|
|
|
|
|
8
|
my $attr = $AUTOLOAD; |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
# is it an allowed field |
125
|
6
|
|
|
|
|
23
|
$attr =~ s/.*:://; |
126
|
6
|
50
|
|
|
|
17
|
return unless $attr =~ /[^A-Z]/; |
127
|
6
|
50
|
|
|
|
15
|
warn "invalid field: ->$attr()" unless $ok_length{$attr}; |
128
|
|
|
|
|
|
|
|
129
|
6
|
100
|
|
|
|
21
|
if (my $new = shift) { |
130
|
2
|
|
|
|
|
8
|
$new =~ s/ *$//; |
131
|
2
|
|
|
|
|
4
|
$new = substr $new, 0, $ok_length{$attr}; |
132
|
2
|
50
|
|
|
|
5
|
if ($attr eq "genre") { |
133
|
0
|
0
|
|
|
|
0
|
if ($new =~ /^\d+$/) { |
134
|
0
|
|
|
|
|
0
|
$self->{genreID} = $new; |
135
|
|
|
|
|
|
|
} else { |
136
|
0
|
|
|
|
|
0
|
$self->{genreID} = genre2id($new); |
137
|
|
|
|
|
|
|
} |
138
|
0
|
|
|
|
|
0
|
$new = id2genre($self->{genreID}); |
139
|
|
|
|
|
|
|
} |
140
|
2
|
|
|
|
|
3
|
$self->{$attr}=$new; |
141
|
2
|
|
|
|
|
4
|
$self->{changed} = 1; |
142
|
|
|
|
|
|
|
} |
143
|
6
|
|
|
|
|
20
|
return $self->{$attr}; |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=pod |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=item all() |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
@tagdata = $id3v1->all; |
151
|
|
|
|
|
|
|
@tagdata = $id3v1->all($song, $artist, $album, $year, $comment, $track, $genre); |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
Returns all information of the tag in a list. |
154
|
|
|
|
|
|
|
You can use this sub also to set the data of the complete tag. |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
The order of the data is always song, artist, album, year, comment, track, and genre. |
157
|
|
|
|
|
|
|
genre has to be a string with the name of the genre, or a number identifying the genre. |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=cut |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
sub all { |
162
|
0
|
|
|
0
|
1
|
0
|
my $self=shift; |
163
|
0
|
0
|
|
|
|
0
|
if ($#_ == 6) { |
164
|
0
|
|
|
|
|
0
|
my $new; |
165
|
0
|
|
|
|
|
0
|
for (qw/song artist album year comment track genre/) { |
166
|
0
|
|
|
|
|
0
|
$new = shift; |
167
|
0
|
|
|
|
|
0
|
$new =~ s/ *$//; |
168
|
0
|
|
|
|
|
0
|
$new = substr $new, 0, $ok_length{$_}; |
169
|
0
|
|
|
|
|
0
|
$self->{$_}=$new; |
170
|
|
|
|
|
|
|
} |
171
|
0
|
0
|
|
|
|
0
|
if ($self->{genre} =~ /^\d+$/) { |
172
|
0
|
|
|
|
|
0
|
$self->{genreID} = $self->{genre}; |
173
|
|
|
|
|
|
|
} else { |
174
|
0
|
|
|
|
|
0
|
$self->{genreID} = genre2id($self->{genre}); |
175
|
|
|
|
|
|
|
} |
176
|
0
|
|
|
|
|
0
|
$self->{genre} = id2genre($self->{genreID}); |
177
|
0
|
|
|
|
|
0
|
$self->{changed} = 1; |
178
|
|
|
|
|
|
|
} |
179
|
0
|
|
|
|
|
0
|
return ($self->{song},$self->{artist},$self->{album}, |
180
|
|
|
|
|
|
|
$self->{year},$self->{genre}, |
181
|
|
|
|
|
|
|
$self->{track}, $self->{comment}); |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=pod |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=item writeTag() |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
$id3v1->writeTag; |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
Writes the ID3v1 tag to the file. |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=cut |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub writeTag { |
195
|
2
|
|
|
2
|
1
|
6
|
my $self = shift; |
196
|
2
|
50
|
33
|
|
|
10
|
return undef unless exists $self->{song} && exists $self->{changed}; |
197
|
2
|
|
|
|
|
13
|
my $data = pack("a30a30a30a4a28xCC",$self->{song},$self->{artist},$self->{album}, |
198
|
|
|
|
|
|
|
$self->{year}, $self->{comment}, $self->{track}, $self->{genreID}); |
199
|
2
|
|
|
|
|
3
|
my $mp3obj = $self->{mp3}; |
200
|
2
|
|
|
|
|
2
|
my $mp3tag; |
201
|
2
|
|
|
|
|
17
|
$mp3obj->close; |
202
|
2
|
50
|
|
|
|
6
|
if ($mp3obj->open("+<")) { |
203
|
2
|
|
|
|
|
6
|
$mp3obj->seek(-128,2); |
204
|
2
|
|
|
|
|
6
|
$mp3obj->read(\$mp3tag, 3); |
205
|
2
|
50
|
|
|
|
6
|
if ($mp3tag eq "TAG") { |
206
|
2
|
|
|
|
|
7
|
$mp3obj->write($data); |
207
|
|
|
|
|
|
|
} else { |
208
|
0
|
|
|
|
|
0
|
$mp3obj->seek(0,2); |
209
|
0
|
|
|
|
|
0
|
$mp3obj->write("TAG$data"); |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
} |
212
|
2
|
|
|
|
|
8
|
return 1; |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=pod |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=item removeTag() |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
$id3v1->removeTag; |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
Removes the ID3v1 tag from the file. |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=cut |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub removeTag { |
226
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
227
|
0
|
|
|
|
|
0
|
my $mp3obj = $self->{mp3}; |
228
|
0
|
|
|
|
|
0
|
my $mp3tag; |
229
|
0
|
|
|
|
|
0
|
$mp3obj->seek(-128,2); |
230
|
0
|
|
|
|
|
0
|
$mp3obj->read(\$mp3tag, 3); |
231
|
0
|
0
|
|
|
|
0
|
if ($mp3tag eq "TAG") { |
232
|
0
|
|
|
|
|
0
|
$mp3obj->close; |
233
|
0
|
0
|
|
|
|
0
|
if ($mp3obj->open("+<")) { |
234
|
0
|
|
|
|
|
0
|
$mp3obj->truncate(-128); |
235
|
0
|
|
|
|
|
0
|
$self->all("","","","","",0,255); |
236
|
0
|
|
|
|
|
0
|
$mp3obj->close; |
237
|
0
|
|
|
|
|
0
|
$self->{changed} = 1; |
238
|
0
|
|
|
|
|
0
|
return 1; |
239
|
|
|
|
|
|
|
} |
240
|
0
|
|
|
|
|
0
|
return -1; |
241
|
|
|
|
|
|
|
} |
242
|
0
|
|
|
|
|
0
|
return 0; |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=pod |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
=item genres() |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
@allgenres = $id3v1->genres; |
250
|
|
|
|
|
|
|
$genreName = $id3v1->genres($genreID); |
251
|
|
|
|
|
|
|
$genreID = $id3v1->genres($genreName); |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
Returns a list of all genres, or the according name or id to |
254
|
|
|
|
|
|
|
a given id or name. |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
=cut |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
sub genres { |
259
|
|
|
|
|
|
|
# return an array with all genres, of if a parameter is given, the according genre |
260
|
0
|
|
|
0
|
1
|
0
|
my $genre = shift; |
261
|
0
|
0
|
|
|
|
0
|
return \@winamp_genres unless defined $genre; |
262
|
0
|
0
|
|
|
|
0
|
return $winamp_genres[$genre] if $genre =~ /^\d+$/; |
263
|
0
|
|
|
|
|
0
|
my $r; |
264
|
0
|
|
|
|
|
0
|
foreach (@winamp_genres) { |
265
|
0
|
0
|
|
|
|
0
|
if ($_ eq $genre) { |
266
|
0
|
|
|
|
|
0
|
$r=$_; |
267
|
0
|
|
|
|
|
0
|
last; |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
} |
270
|
0
|
|
|
|
|
0
|
return $r; |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
################# |
274
|
|
|
|
|
|
|
## |
275
|
|
|
|
|
|
|
## internal subs |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# actually read the tag data |
278
|
|
|
|
|
|
|
sub readTag { |
279
|
2
|
|
|
2
|
0
|
4
|
my ($self, $buffer) = @_; |
280
|
2
|
|
|
|
|
5
|
my $mp3obj = $self->{mp3}; |
281
|
2
|
|
|
|
|
2
|
my $id3v1; |
282
|
|
|
|
|
|
|
|
283
|
2
|
50
|
|
|
|
5
|
if ($self->{new}) { |
284
|
0
|
|
|
|
|
0
|
($self->{song}, $self->{artist}, $self->{album}, $self->{year}, |
285
|
|
|
|
|
|
|
$self->{comment}, $self->{track}, $self->{genre}, $self->{genreID}) = ("","","","","",0,"",255); |
286
|
0
|
|
|
|
|
0
|
$self->{changed} = 1; |
287
|
|
|
|
|
|
|
} else { |
288
|
2
|
|
|
|
|
21
|
(undef, $self->{song}, $self->{artist}, $self->{album}, $self->{year}, |
289
|
|
|
|
|
|
|
$self->{comment}, $id3v1, $self->{track}, $self->{genreID}) = |
290
|
|
|
|
|
|
|
unpack ("a3Z30Z30Z30Z4Z28CCC", $buffer); |
291
|
|
|
|
|
|
|
|
292
|
2
|
50
|
|
|
|
7
|
if ($id3v1!=0) { # ID3v1 tag found: track is not valid, comment two chars longer |
293
|
0
|
|
|
|
|
0
|
$self->{comment} .= chr($id3v1); |
294
|
0
|
0
|
|
|
|
0
|
$self->{comment} .= chr($self->{track}) if $self->{track}!=32; |
295
|
0
|
|
|
|
|
0
|
$self->{track} = 0; |
296
|
|
|
|
|
|
|
}; |
297
|
2
|
|
|
|
|
8
|
$self->{genre} = id2genre($self->{genreID}); |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
# convert one byte id to genre name |
302
|
|
|
|
|
|
|
sub id2genre { |
303
|
2
|
|
|
2
|
0
|
3
|
my $id=shift; |
304
|
2
|
50
|
33
|
|
|
19
|
return "" unless defined $id && $id<$#winamp_genres; |
305
|
2
|
|
|
|
|
5
|
return $winamp_genres[$id]; |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
# convert genre name to one byte id |
309
|
|
|
|
|
|
|
sub genre2id { |
310
|
0
|
|
|
0
|
0
|
|
my $genre = shift; |
311
|
0
|
|
|
|
|
|
my $i=0; |
312
|
0
|
|
|
|
|
|
foreach (@winamp_genres) { |
313
|
0
|
0
|
|
|
|
|
if (uc $genre eq uc $_) { |
314
|
0
|
|
|
|
|
|
return $i; |
315
|
|
|
|
|
|
|
} |
316
|
0
|
|
|
|
|
|
$i++, |
317
|
|
|
|
|
|
|
} |
318
|
0
|
|
|
|
|
|
return 255; |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
# nothing to do for destroy |
322
|
0
|
|
|
0
|
|
|
sub DESTROY { |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
1; |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
######## define all the genres |
328
|
|
|
|
|
|
|
|
329
|
1
|
|
|
1
|
|
17
|
BEGIN { @mp3_genres = ( 'Blues', 'Classic Rock', 'Country', 'Dance', |
330
|
|
|
|
|
|
|
'Disco', 'Funk', 'Grunge', 'Hip-Hop', 'Jazz', 'Metal', 'New Age', |
331
|
|
|
|
|
|
|
'Oldies', 'Other', 'Pop', 'R&B', 'Rap', 'Reggae', 'Rock', 'Techno', |
332
|
|
|
|
|
|
|
'Industrial', 'Alternative', 'Ska', 'Death Metal', 'Pranks', |
333
|
|
|
|
|
|
|
'Soundtrack', 'Euro-Techno', 'Ambient', 'Trip-Hop', 'Vocal', |
334
|
|
|
|
|
|
|
'Jazz+Funk', 'Fusion', 'Trance', 'Classical', 'Instrumental', 'Acid', |
335
|
|
|
|
|
|
|
'House', 'Game', 'Sound Clip', 'Gospel', 'Noise', 'AlternRock', |
336
|
|
|
|
|
|
|
'Bass', 'Soul', 'Punk', 'Space', 'Meditative', 'Instrumental Pop', |
337
|
|
|
|
|
|
|
'Instrumental Rock', 'Ethnic', 'Gothic', 'Darkwave', |
338
|
|
|
|
|
|
|
'Techno-Industrial', 'Electronic', 'Pop-Folk', 'Eurodance', 'Dream', |
339
|
|
|
|
|
|
|
'Southern Rock', 'Comedy', 'Cult', 'Gangsta', 'Top 40', |
340
|
|
|
|
|
|
|
'Christian Rap', 'Pop/Funk', 'Jungle', 'Native American', 'Cabaret', 'New Wave', |
341
|
|
|
|
|
|
|
'Psychadelic', 'Rave', 'Showtunes', 'Trailer', 'Lo-Fi', 'Tribal', |
342
|
|
|
|
|
|
|
'Acid Punk', 'Acid Jazz', 'Polka', 'Retro', 'Musical', 'Rock & Roll', |
343
|
|
|
|
|
|
|
'Hard Rock', ); |
344
|
|
|
|
|
|
|
|
345
|
1
|
|
|
|
|
46
|
@winamp_genres = ( @mp3_genres, 'Folk', 'Folk-Rock', |
346
|
|
|
|
|
|
|
'National Folk', 'Swing', 'Fast Fusion', 'Bebob', 'Latin', 'Revival', |
347
|
|
|
|
|
|
|
'Celtic', 'Bluegrass', 'Avantgarde', 'Gothic Rock', |
348
|
|
|
|
|
|
|
'Progressive Rock', 'Psychedelic Rock', 'Symphonic Rock', |
349
|
|
|
|
|
|
|
'Slow Rock', 'Big Band', 'Chorus', 'Easy Listening', |
350
|
|
|
|
|
|
|
'Acoustic', 'Humour', 'Speech', 'Chanson', 'Opera', |
351
|
|
|
|
|
|
|
'Chamber Music', 'Sonata', 'Symphony', 'Booty Bass', 'Primus', |
352
|
|
|
|
|
|
|
'Porn Groove', 'Satire', 'Slow Jam', 'Club', 'Tango', 'Samba', |
353
|
|
|
|
|
|
|
'Folklore', 'Ballad', 'Power Ballad', 'Rhythmic Soul', |
354
|
|
|
|
|
|
|
'Freestyle', 'Duet', 'Punk Rock', 'Drum Solo', 'Acapella', |
355
|
|
|
|
|
|
|
'Euro-House', 'Dance Hall', ); |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
=pod |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
=head1 SEE ALSO |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
MP3::Tag, MP3::TAG::ID3v2 |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
ID3v1 standard - http://www.id3.org |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
=cut |