xref: /plan9/sys/src/games/mp3enc/id3tag.c (revision 8f5875f3e9b20916b4c52ad4336922bc8653eb7b)
1 /*
2  * id3tag.c -- Write ID3 version 1 and 2 tags.
3  *
4  * Copyright (C) 2000 Don Melton.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19  */
20 
21 /*
22  * HISTORY: This source file is part of LAME (see http://www.mp3dev.org/mp3/)
23  * and was originally adapted by Conrad Sanderson <c.sanderson@me.gu.edu.au>
24  * from mp3info by Ricardo Cerqueira <rmc@rccn.net> to write only ID3 version 1
25  * tags.  Don Melton <don@blivet.com> COMPLETELY rewrote it to support version
26  * 2 tags and be more conformant to other standards while remaining flexible.
27  *
28  * NOTE: See http://id3.org/ for more information about ID3 tag formats.
29  */
30 
31 /* $Id: id3tag.c,v 1.18 2001/01/15 15:16:09 aleidinger Exp $ */
32 
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
36 
37 #ifdef STDC_HEADERS
38 # include <stddef.h>
39 # include <stdlib.h>
40 # include <string.h>
41 #else
42 # ifndef HAVE_STRCHR
43 #  define strchr index
44 #  define strrchr rindex
45 # endif
46 char *strchr (), *strrchr ();
47 # ifndef HAVE_MEMCPY
48 #  define memcpy(d, s, n) bcopy ((s), (d), (n))
49 #  define memmove(d, s, n) bcopy ((s), (d), (n))
50 # endif
51 #endif
52 
53 #include "lame.h"
54 #include "id3tag.h"
55 #include "util.h"
56 #include "bitstream.h"
57 
58 #ifdef WITH_DMALLOC
59 #include <dmalloc.h>
60 #endif
61 
62 static const char *const genre_names[] =
63 {
64     /*
65      * NOTE: The spelling of these genre names is identical to those found in
66      * Winamp and mp3info.
67      */
68     "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge",
69     "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B",
70     "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska",
71     "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop",
72     "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
73     "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "Alt. Rock",
74     "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
75     "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial",
76     "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy",
77     "Cult", "Gangsta Rap", "Top 40", "Christian Rap", "Pop/Funk", "Jungle",
78     "Native American", "Cabaret", "New Wave", "Psychedelic", "Rave",
79     "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz",
80     "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk",
81     "Folk/Rock", "National Folk", "Swing", "Fast-Fusion", "Bebob", "Latin",
82     "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock",
83     "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock",
84     "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech",
85     "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass",
86     "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
87     "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet",
88     "Punk Rock", "Drum Solo", "A Cappella", "Euro-House", "Dance Hall",
89     "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie",
90     "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta Rap",
91     "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian",
92     "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop",
93     "Synthpop"
94 };
95 
96 #define GENRE_NAME_COUNT \
97     ((int)(sizeof genre_names / sizeof (const char *const)))
98 
99 static const int genre_alpha_map [] = {
100     123, 34, 74, 73, 99, 20, 40, 26, 145, 90, 116, 41, 135, 85, 96, 138, 89, 0,
101     107, 132, 65, 88, 104, 102, 97, 136, 61, 141, 32, 1, 112, 128, 57, 140, 2,
102     139, 58, 3, 125, 50, 22, 4, 55, 127, 122, 120, 98, 52, 48, 54, 124, 25, 84,
103     80, 115, 81, 119, 5, 30, 36, 59, 126, 38, 49, 91, 6, 129, 79, 137, 7, 35,
104     100, 131, 19, 33, 46, 47, 8, 29, 146, 63, 86, 71, 45, 142, 9, 77, 82, 64,
105     133, 10, 66, 39, 11, 103, 12, 75, 134, 13, 53, 62, 109, 117, 23, 108, 92,
106     67, 93, 43, 121, 15, 68, 14, 16, 76, 87, 118, 17, 78, 143, 114, 110, 69, 21,
107     111, 95, 105, 42, 37, 24, 56, 44, 101, 83, 94, 106, 147, 113, 18, 51, 130,
108     144, 60, 70, 31, 72, 27, 28
109 };
110 
111 #define GENRE_ALPHA_COUNT ((int)(sizeof genre_alpha_map / sizeof (int)))
112 
113 void
id3tag_genre_list(void (* handler)(int,const char *,void *),void * cookie)114 id3tag_genre_list(void (*handler)(int, const char *, void *), void *cookie)
115 {
116     if (handler) {
117         int i;
118         for (i = 0; i < GENRE_NAME_COUNT; ++i) {
119             if (i < GENRE_ALPHA_COUNT) {
120                 int j = genre_alpha_map[i];
121                 handler(j, genre_names[j], cookie);
122             }
123         }
124     }
125 }
126 
127 #define GENRE_NUM_UNKNOWN 255
128 
129 void
id3tag_init(lame_global_flags * gfp)130 id3tag_init(lame_global_flags *gfp)
131 {
132     lame_internal_flags *gfc = gfp->internal_flags;
133     memset(&gfc->tag_spec, 0, sizeof gfc->tag_spec);
134     gfc->tag_spec.genre = GENRE_NUM_UNKNOWN;
135 }
136 
137 #define CHANGED_FLAG    (1U << 0)
138 #define ADD_V2_FLAG     (1U << 1)
139 #define V1_ONLY_FLAG    (1U << 2)
140 #define V2_ONLY_FLAG    (1U << 3)
141 #define SPACE_V1_FLAG   (1U << 4)
142 #define PAD_V2_FLAG     (1U << 5)
143 
144 void
id3tag_add_v2(lame_global_flags * gfp)145 id3tag_add_v2(lame_global_flags *gfp)
146 {
147     lame_internal_flags *gfc = gfp->internal_flags;
148     gfc->tag_spec.flags &= ~V1_ONLY_FLAG;
149     gfc->tag_spec.flags |= ADD_V2_FLAG;
150 }
151 
152 void
id3tag_v1_only(lame_global_flags * gfp)153 id3tag_v1_only(lame_global_flags *gfp)
154 {
155     lame_internal_flags *gfc = gfp->internal_flags;
156     gfc->tag_spec.flags &= ~(ADD_V2_FLAG | V2_ONLY_FLAG);
157     gfc->tag_spec.flags |= V1_ONLY_FLAG;
158 }
159 
160 void
id3tag_v2_only(lame_global_flags * gfp)161 id3tag_v2_only(lame_global_flags *gfp)
162 {
163     lame_internal_flags *gfc = gfp->internal_flags;
164     gfc->tag_spec.flags &= ~V1_ONLY_FLAG;
165     gfc->tag_spec.flags |= V2_ONLY_FLAG;
166 }
167 
168 void
id3tag_space_v1(lame_global_flags * gfp)169 id3tag_space_v1(lame_global_flags *gfp)
170 {
171     lame_internal_flags *gfc = gfp->internal_flags;
172     gfc->tag_spec.flags &= ~V2_ONLY_FLAG;
173     gfc->tag_spec.flags |= SPACE_V1_FLAG;
174 }
175 
176 void
id3tag_pad_v2(lame_global_flags * gfp)177 id3tag_pad_v2(lame_global_flags *gfp)
178 {
179     lame_internal_flags *gfc = gfp->internal_flags;
180     gfc->tag_spec.flags &= ~V1_ONLY_FLAG;
181     gfc->tag_spec.flags |= PAD_V2_FLAG;
182 }
183 
184 void
id3tag_set_title(lame_global_flags * gfp,const char * title)185 id3tag_set_title(lame_global_flags *gfp, const char *title)
186 {
187     lame_internal_flags *gfc = gfp->internal_flags;
188     if (title && *title) {
189         gfc->tag_spec.title = title;
190         gfc->tag_spec.flags |= CHANGED_FLAG;
191     }
192 }
193 
194 void
id3tag_set_artist(lame_global_flags * gfp,const char * artist)195 id3tag_set_artist(lame_global_flags *gfp, const char *artist)
196 {
197     lame_internal_flags *gfc = gfp->internal_flags;
198     if (artist && *artist) {
199         gfc->tag_spec.artist = artist;
200         gfc->tag_spec.flags |= CHANGED_FLAG;
201     }
202 }
203 
204 void
id3tag_set_album(lame_global_flags * gfp,const char * album)205 id3tag_set_album(lame_global_flags *gfp, const char *album)
206 {
207     lame_internal_flags *gfc = gfp->internal_flags;
208     if (album && *album) {
209         gfc->tag_spec.album = album;
210         gfc->tag_spec.flags |= CHANGED_FLAG;
211     }
212 }
213 
214 void
id3tag_set_year(lame_global_flags * gfp,const char * year)215 id3tag_set_year(lame_global_flags *gfp, const char *year)
216 {
217     lame_internal_flags *gfc = gfp->internal_flags;
218     if (year && *year) {
219         int num = atoi(year);
220         if (num < 0) {
221             num = 0;
222         }
223         /* limit a year to 4 digits so it fits in a version 1 tag */
224         if (num > 9999) {
225             num = 9999;
226         }
227         if (num) {
228             gfc->tag_spec.year = num;
229             gfc->tag_spec.flags |= CHANGED_FLAG;
230         }
231     }
232 }
233 
234 void
id3tag_set_comment(lame_global_flags * gfp,const char * comment)235 id3tag_set_comment(lame_global_flags *gfp, const char *comment)
236 {
237     lame_internal_flags *gfc = gfp->internal_flags;
238     if (comment && *comment) {
239         gfc->tag_spec.comment = comment;
240         gfc->tag_spec.flags |= CHANGED_FLAG;
241     }
242 }
243 
244 void
id3tag_set_track(lame_global_flags * gfp,const char * track)245 id3tag_set_track(lame_global_flags *gfp, const char *track)
246 {
247     lame_internal_flags *gfc = gfp->internal_flags;
248     if (track && *track) {
249         int num = atoi(track);
250         if (num < 0) {
251             num = 0;
252         }
253         /* limit a track to 255 so it fits in a version 1 tag even though CD
254          * audio doesn't allow more than 99 tracks */
255         if (num > 255) {
256             num = 255;
257         }
258         if (num) {
259             gfc->tag_spec.track = num;
260             gfc->tag_spec.flags |= CHANGED_FLAG;
261         }
262     }
263 }
264 
265 /* would use real "strcasecmp" but it isn't portable */
266 static int
local_strcasecmp(const char * s1,const char * s2)267 local_strcasecmp(const char *s1, const char *s2)
268 {
269     unsigned char c1;
270     unsigned char c2;
271     do {
272         c1 = tolower(*s1);
273         c2 = tolower(*s2);
274         if (!c1) {
275             break;
276         }
277         ++s1;
278         ++s2;
279     } while (c1 == c2);
280     return c1 - c2;
281 }
282 
283 int
id3tag_set_genre(lame_global_flags * gfp,const char * genre)284 id3tag_set_genre(lame_global_flags *gfp, const char *genre)
285 {
286     lame_internal_flags *gfc = gfp->internal_flags;
287     if (genre && *genre) {
288         char *str;
289         int num = strtol(genre, &str, 10);
290         /* is the input a string or a valid number? */
291         if (*str) {
292             int i;
293             for (i = 0; i < GENRE_NAME_COUNT; ++i) {
294                 if (!local_strcasecmp(genre, genre_names[i])) {
295                     num = i;
296                     break;
297                 }
298             }
299             if (i == GENRE_NAME_COUNT) {
300                 return -1;
301             }
302         } else if ((num < 0) || (num >= GENRE_NAME_COUNT)) {
303             return -1;
304         }
305         gfc->tag_spec.genre = num;
306         gfc->tag_spec.flags |= CHANGED_FLAG;
307     }
308     return 0;
309 }
310 
311 static unsigned char *
set_4_byte_value(unsigned char * bytes,unsigned long value)312 set_4_byte_value(unsigned char *bytes, unsigned long value)
313 {
314     int index;
315     for (index = 3; index >= 0; --index) {
316         bytes[index] = value & 0xfful;
317         value >>= 8;
318     }
319     return bytes + 4;
320 }
321 
322 #define FRAME_ID(a, b, c, d) \
323     ( ((unsigned long)(a) << 24) \
324     | ((unsigned long)(b) << 16) \
325     | ((unsigned long)(c) <<  8) \
326     | ((unsigned long)(d) <<  0) )
327 #define TITLE_FRAME_ID FRAME_ID('T', 'I', 'T', '2')
328 #define ARTIST_FRAME_ID FRAME_ID('T', 'P', 'E', '1')
329 #define ALBUM_FRAME_ID FRAME_ID('T', 'A', 'L', 'B')
330 #define YEAR_FRAME_ID FRAME_ID('T', 'Y', 'E', 'R')
331 #define COMMENT_FRAME_ID FRAME_ID('C', 'O', 'M', 'M')
332 #define TRACK_FRAME_ID FRAME_ID('T', 'R', 'C', 'K')
333 #define GENRE_FRAME_ID FRAME_ID('T', 'C', 'O', 'N')
334 
335 static unsigned char *
set_frame(unsigned char * frame,unsigned long id,const char * text,size_t length)336 set_frame(unsigned char *frame, unsigned long id, const char *text,
337     size_t length)
338 {
339     if (length) {
340         frame = set_4_byte_value(frame, id);
341         /* Set frame size = total size - header size.  Frame header and field
342          * bytes include 2-byte header flags, 1 encoding descriptor byte, and
343          * for comment frames: 3-byte language descriptor and 1 content
344          * descriptor byte */
345         frame = set_4_byte_value(frame, ((id == COMMENT_FRAME_ID) ? 5 : 1)
346                 + length);
347         /* clear 2-byte header flags */
348         *frame++ = 0;
349         *frame++ = 0;
350         /* clear 1 encoding descriptor byte to indicate ISO-8859-1 format */
351         *frame++ = 0;
352         if (id == COMMENT_FRAME_ID) {
353             /* use id3lib-compatible bogus language descriptor */
354             *frame++ = 'X';
355             *frame++ = 'X';
356             *frame++ = 'X';
357             /* clear 1 byte to make content descriptor empty string */
358             *frame++ = 0;
359         }
360         while (length--) {
361             *frame++ = *text++;
362         }
363     }
364     return frame;
365 }
366 
367 int
id3tag_write_v2(lame_global_flags * gfp)368 id3tag_write_v2(lame_global_flags *gfp)
369 {
370     lame_internal_flags *gfc = gfp->internal_flags;
371     if ((gfc->tag_spec.flags & CHANGED_FLAG)
372             && !(gfc->tag_spec.flags & V1_ONLY_FLAG)) {
373         /* calculate length of four fields which may not fit in verion 1 tag */
374         size_t title_length = gfc->tag_spec.title
375             ? strlen(gfc->tag_spec.title) : 0;
376         size_t artist_length = gfc->tag_spec.artist
377             ? strlen(gfc->tag_spec.artist) : 0;
378         size_t album_length = gfc->tag_spec.album
379             ? strlen(gfc->tag_spec.album) : 0;
380         size_t comment_length = gfc->tag_spec.comment
381             ? strlen(gfc->tag_spec.comment) : 0;
382         /* write tag if explicitly requested or if fields overflow */
383         if ((gfc->tag_spec.flags & (ADD_V2_FLAG | V2_ONLY_FLAG))
384                 || (title_length > 30)
385                 || (artist_length > 30) || (album_length > 30)
386                 || (comment_length > 30)
387                 || (gfc->tag_spec.track && (comment_length > 28))) {
388             size_t tag_size;
389             char year[5];
390             size_t year_length;
391             char track[3];
392             size_t track_length;
393             char genre[6];
394             size_t genre_length;
395             unsigned char *tag;
396             unsigned char *p;
397             size_t adjusted_tag_size;
398             unsigned int index;
399             /* calulate size of tag starting with 10-byte tag header */
400             tag_size = 10;
401             if (title_length) {
402                 /* add 10-byte frame header, 1 encoding descriptor byte ... */
403                 tag_size += 11 + title_length;
404             }
405             if (artist_length) {
406                 tag_size += 11 + artist_length;
407             }
408             if (album_length) {
409                 tag_size += 11 + album_length;
410             }
411             if (gfc->tag_spec.year) {
412                 year_length = sprintf(year, "%d", gfc->tag_spec.year);
413                 tag_size += 11 + year_length;
414             } else {
415                 year_length = 0;
416             }
417             if (comment_length) {
418                 /* add 10-byte frame header, 1 encoding descriptor byte,
419                  * 3-byte language descriptor, 1 content descriptor byte ... */
420                 tag_size += 15 + comment_length;
421             }
422             if (gfc->tag_spec.track) {
423                 track_length = sprintf(track, "%d", gfc->tag_spec.track);
424                 tag_size += 11 + track_length;
425             } else {
426                 track_length = 0;
427             }
428             if (gfc->tag_spec.genre != GENRE_NUM_UNKNOWN) {
429                 genre_length = sprintf(genre, "(%d)", gfc->tag_spec.genre);
430                 tag_size += 11 + genre_length;
431             } else {
432                 genre_length = 0;
433             }
434             if (gfc->tag_spec.flags & PAD_V2_FLAG) {
435                 /* add 128 bytes of padding */
436                 tag_size += 128;
437             }
438             tag = (unsigned char *)malloc(tag_size);
439             if (!tag) {
440                 return -1;
441             }
442             p = tag;
443             /* set tag header starting with file identifier */
444             *p++ = 'I'; *p++ = 'D'; *p++ = '3';
445             /* set version number word */
446             *p++ = 3; *p++ = 0;
447             /* clear flags byte */
448             *p++ = 0;
449             /* calculate and set tag size = total size - header size */
450             adjusted_tag_size = tag_size - 10;
451             /* encode adjusted size into four bytes where most significant
452              * bit is clear in each byte, for 28-bit total */
453             *p++ = (adjusted_tag_size >> 21) & 0x7fu;
454             *p++ = (adjusted_tag_size >> 14) & 0x7fu;
455             *p++ = (adjusted_tag_size >> 7) & 0x7fu;
456             *p++ = adjusted_tag_size & 0x7fu;
457 
458             /*
459              * NOTE: The remainder of the tag (frames and padding, if any)
460              * are not "unsynchronized" to prevent false MPEG audio headers
461              * from appearing in the bitstream.  Why?  Well, most players
462              * and utilities know how to skip the ID3 version 2 tag by now
463              * even if they don't read its contents, and it's actually
464              * very unlikely that such a false "sync" pattern would occur
465              * in just the simple text frames added here.
466              */
467 
468             /* set each frame in tag */
469             p = set_frame(p, TITLE_FRAME_ID, gfc->tag_spec.title, title_length);
470             p = set_frame(p, ARTIST_FRAME_ID, gfc->tag_spec.artist,
471                     artist_length);
472             p = set_frame(p, ALBUM_FRAME_ID, gfc->tag_spec.album, album_length);
473             p = set_frame(p, YEAR_FRAME_ID, year, year_length);
474             p = set_frame(p, COMMENT_FRAME_ID, gfc->tag_spec.comment,
475                     comment_length);
476             p = set_frame(p, TRACK_FRAME_ID, track, track_length);
477             p = set_frame(p, GENRE_FRAME_ID, genre, genre_length);
478             /* clear any padding bytes */
479             memset(p, 0, tag_size - (p - tag));
480             /* write tag directly into bitstream at current position */
481             for (index = 0; index < tag_size; ++index) {
482                 add_dummy_byte(gfp, tag[index]);
483             }
484             free(tag);
485             return tag_size;
486         }
487     }
488     return 0;
489 }
490 
491 static unsigned char *
set_text_field(unsigned char * field,const char * text,size_t size,int pad)492 set_text_field(unsigned char *field, const char *text, size_t size, int pad)
493 {
494     while (size--) {
495         if (text && *text) {
496             *field++ = *text++;
497         } else {
498             *field++ = pad;
499         }
500     }
501     return field;
502 }
503 
504 int
id3tag_write_v1(lame_global_flags * gfp)505 id3tag_write_v1(lame_global_flags *gfp)
506 {
507     lame_internal_flags *gfc = gfp->internal_flags;
508     if ((gfc->tag_spec.flags & CHANGED_FLAG)
509             && !(gfc->tag_spec.flags & V2_ONLY_FLAG)) {
510         unsigned char tag[128];
511         unsigned char *p = tag;
512         int pad = (gfc->tag_spec.flags & SPACE_V1_FLAG) ? ' ' : 0;
513         char year[5];
514         unsigned int index;
515         /* set tag identifier */
516         *p++ = 'T'; *p++ = 'A'; *p++ = 'G';
517         /* set each field in tag */
518         p = set_text_field(p, gfc->tag_spec.title, 30, pad);
519         p = set_text_field(p, gfc->tag_spec.artist, 30, pad);
520         p = set_text_field(p, gfc->tag_spec.album, 30, pad);
521         sprintf(year, "%d", gfc->tag_spec.year);
522         p = set_text_field(p, gfc->tag_spec.year ? year : NULL, 4, pad);
523         /* limit comment field to 28 bytes if a track is specified */
524         p = set_text_field(p, gfc->tag_spec.comment, gfc->tag_spec.track
525                 ? 28 : 30, pad);
526         if (gfc->tag_spec.track) {
527             /* clear the next byte to indicate a version 1.1 tag */
528             *p++ = 0;
529             *p++ = gfc->tag_spec.track;
530         }
531         *p++ = gfc->tag_spec.genre;
532         /* write tag directly into bitstream at current position */
533         for (index = 0; index < 128; ++index) {
534             add_dummy_byte(gfp, tag[index]);
535         }
536         return 128;
537     }
538     return 0;
539 }
540