i18n of time/date setting menu
[kugel-rb.git] / firmware / id3.c
blob54f0f970c12d195b6704d328bdc235c12c0ddd13
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Daniel Stenberg
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
21 * Parts of this code has been stolen from the Ample project and was written
22 * by David Härdeman. It has since been extended and enhanced pretty much by
23 * all sorts of friendly Rockbox people.
25 * A nice reference for MPEG header info:
26 * http://rockbox.haxx.se/docs/mpeghdr.html
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <stdbool.h>
35 #include "file.h"
36 #include "debug.h"
37 #include "atoi.h"
39 #include "id3.h"
41 #define UNSYNC(b0,b1,b2,b3) (((b0 & 0x7F) << (3*7)) | \
42 ((b1 & 0x7F) << (2*7)) | \
43 ((b2 & 0x7F) << (1*7)) | \
44 ((b3 & 0x7F) << (0*7)))
46 #define BYTES2INT(b0,b1,b2,b3) (((b0 & 0xFF) << (3*8)) | \
47 ((b1 & 0xFF) << (2*8)) | \
48 ((b2 & 0xFF) << (1*8)) | \
49 ((b3 & 0xFF) << (0*8)))
51 /* Table of bitrates for MP3 files, all values in kilo.
52 * Indexed by version, layer and value of bit 15-12 in header.
54 const int bitrate_table[2][3][16] =
57 {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},
58 {0,32,48,56, 64,80, 96, 112,128,160,192,224,256,320,384,0},
59 {0,32,40,48, 56,64, 80, 96, 112,128,160,192,224,256,320,0}
62 {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,0},
63 {0, 8,16,24,32,40,48, 56, 64, 80, 96,112,128,144,160,0},
64 {0, 8,16,24,32,40,48, 56, 64, 80, 96,112,128,144,160,0}
68 /* Table of samples per frame for MP3 files.
69 * Indexed by layer. Multiplied with 1000.
71 const int bs[4] = {0, 384000, 1152000, 1152000};
73 /* Table of sample frequency for MP3 files.
74 * Indexed by version and layer.
76 const int freqtab[][4] =
78 {11025, 12000, 8000, 0}, /* MPEG version 2.5 */
79 {44100, 48000, 32000, 0}, /* MPEG Version 1 */
80 {22050, 24000, 16000, 0}, /* MPEG version 2 */
83 #define UNICODE_BOM_1 0xfffe
84 #define UNICODE_BOM_2 0xfeff
86 /* Checks to see if the passed in string is a 16-bit wide Unicode v2
87 string. If it is, we attempt to convert it to a 8-bit ASCII string
88 (for valid 8-bit ASCII characters). If it's not unicode, we leave
89 it alone. At some point we should fully support unicode strings */
90 static int unicode_munge(char** string, int *len) {
91 int tmp;
92 bool le = false;
93 int i;
94 char *str = *string;
95 char *outstr = *string;
97 if(str[0] > 0x03) {
98 /* Plain old string */
99 return 0;
102 /* Type 0x00 is ordinary ISO 8859-1 */
103 if(str[0] == 0x00) {
104 (*len)--;
105 (*string)++; /* Skip the encoding type byte */
106 return 0;
109 /* Unicode with or without BOM */
110 if(str[0] == 0x01 || str[0] == 0x02) {
111 str++;
112 tmp = BYTES2INT(0, 0, str[1], str[2]);
114 if(tmp == UNICODE_BOM_2) { /* Little endian? */
115 le = true;
116 str += 2;
119 if(tmp == UNICODE_BOM_1) /* Big endian? */
120 str += 2;
122 i = 0;
124 do {
125 if(le) {
126 if(str[1])
127 outstr[i++] = '.';
128 else
129 outstr[i++] = str[0];
130 } else {
131 if(str[0])
132 outstr[i++] = '.';
133 else
134 outstr[i++] = str[1];
136 } while(str[0] || str[1]);
138 *len = i;
139 (*string)++; /* Skip the encoding type byte */
140 return 0;
143 /* If we come here, the string was of an unsupported type */
144 *len = 1;
145 outstr[0] = 0;
146 return -1;
150 * Removes trailing spaces from a string.
152 * Arguments: buffer - the string to process
154 * Returns: void
156 static void
157 stripspaces(char *buffer)
159 int i = 0;
160 while(*(buffer + i) != '\0')
161 i++;
163 for(;i >= 0; i--) {
164 if(*(buffer + i) == ' ')
165 *(buffer + i) = '\0';
166 else if(*(buffer + i) == '\0')
167 continue;
168 else
169 break;
174 * Sets the title of an MP3 entry based on its ID3v1 tag.
176 * Arguments: file - the MP3 file to scen for a ID3v1 tag
177 * entry - the entry to set the title in
179 * Returns: true if a title was found and created, else false
181 static bool setid3v1title(int fd, struct mp3entry *entry)
183 unsigned char buffer[31];
184 int offsets[4] = {-95,-65,-125,-31};
185 int i;
187 for (i=0;i<4;i++) {
188 if (-1 == lseek(fd, offsets[i], SEEK_END))
189 return false;
191 buffer[30]=0;
192 read(fd, buffer, 30);
193 stripspaces(buffer);
195 if (buffer[0] || i == 3) {
196 switch(i) {
197 case 0:
198 strcpy(entry->id3v1buf[0], buffer);
199 entry->artist = entry->id3v1buf[0];
200 break;
201 case 1:
202 strcpy(entry->id3v1buf[1], buffer);
203 entry->album = entry->id3v1buf[1];
204 break;
205 case 2:
206 strcpy(entry->id3v1buf[2], buffer);
207 entry->title = entry->id3v1buf[2];
208 break;
209 case 3:
210 /* id3v1.1 uses last two bytes of comment field for track
211 number: first must be 0 and second is track num */
212 if (buffer[28] == 0)
213 entry->tracknum = buffer[29];
214 break;
219 return true;
224 * Sets the title of an MP3 entry based on its ID3v2 tag.
226 * Arguments: file - the MP3 file to scen for a ID3v2 tag
227 * entry - the entry to set the title in
229 * Returns: true if a title was found and created, else false
231 static void setid3v2title(int fd, struct mp3entry *entry)
233 int minframesize;
234 int size;
235 int readsize = 0, headerlen;
236 char *title = NULL;
237 char *artist = NULL;
238 char *album = NULL;
239 char *tracknum = NULL;
240 char header[10];
241 unsigned short int version;
242 int titlen=0, artistn=0, albumn=0, tracknumn=0;
243 char *buffer = entry->id3v2buf;
245 /* 10 = headerlength */
246 if(entry->id3v2len < 10)
247 return;
249 /* Check version */
250 lseek(fd, 0, SEEK_SET);
251 if(10 != read(fd, header, 10))
252 return;
254 version = (unsigned short int)header[3];
256 /* Read all frames in the tag */
257 size = entry->id3v2len - 10;
259 if(size >= (int)sizeof(entry->id3v2buf))
260 size = sizeof(entry->id3v2buf)-1;
262 if(size != read(fd, buffer, size))
263 return;
265 *(buffer + size) = '\0';
267 /* Set minimum frame size according to ID3v2 version */
268 if(version > 2)
269 minframesize = 12;
270 else
271 minframesize = 8;
274 * We must have at least minframesize bytes left for the
275 * remaining frames to be interesting
277 while(size - readsize > minframesize) {
279 /* Read frame header and check length */
280 if(version > 2) {
281 memcpy(header, (buffer + readsize), 10);
282 readsize += 10;
283 if (version > 3) {
284 headerlen = UNSYNC(header[4], header[5],
285 header[6], header[7]);
286 } else {
287 /* version .3 files don't use synchsafe ints for
288 * size */
289 headerlen = BYTES2INT(header[4], header[5],
290 header[6], header[7]);
292 } else {
293 memcpy(header, (buffer + readsize), 6);
294 readsize += 6;
295 headerlen = (header[3] << 16) +
296 (header[4] << 8) +
297 (header[5]);
300 /* Get only the part of the header that is within our buffer */
301 if(headerlen > (size-readsize))
302 headerlen = (size - readsize);
304 /* Check for certain frame headers */
305 if(!strncmp(header, "TPE1", strlen("TPE1")) ||
306 !strncmp(header, "TP1", strlen("TP1"))) {
307 readsize++;
308 headerlen--;
309 artist = buffer + readsize;
310 artistn = headerlen;
311 unicode_munge(&artist, &artistn);
313 else if(!strncmp(header, "TIT2", strlen("TIT2")) ||
314 !strncmp(header, "TT2", strlen("TT2"))) {
315 readsize++;
316 headerlen--;
317 title = buffer + readsize;
318 titlen = headerlen;
319 unicode_munge(&title, &titlen);
321 else if(!strncmp(header, "TALB", strlen("TALB"))) {
322 readsize++;
323 headerlen--;
324 album = buffer + readsize;
325 albumn = headerlen;
326 unicode_munge(&album, &albumn);
328 else if(!strncmp(header, "TRCK", strlen("TRCK"))) {
329 readsize++;
330 headerlen--;
331 tracknum = buffer + readsize;
332 tracknumn = headerlen;
333 unicode_munge(&tracknum, &tracknumn);
336 readsize += headerlen;
339 if(artist) {
340 entry->artist = artist;
341 artist[artistn]=0;
344 if(title) {
345 entry->title = title;
346 title[titlen]=0;
349 if(album) {
350 entry->album = album;
351 album[albumn]=0;
354 if(tracknum) {
355 tracknum[tracknumn] = 0;
356 entry->tracknum = atoi(tracknum);
361 * Calculates the size of the ID3v2 tag.
363 * Arguments: file - the file to search for a tag.
365 * Returns: the size of the tag or 0 if none was found
367 static int getid3v2len(int fd)
369 char buf[6];
370 int offset;
372 /* Make sure file has a ID3 tag */
373 if((-1 == lseek(fd, 0, SEEK_SET)) ||
374 (read(fd, buf, 6) != 6) ||
375 (strncmp(buf, "ID3", strlen("ID3")) != 0))
376 offset = 0;
378 /* Now check what the ID3v2 size field says */
379 else if(read(fd, buf, 4) != 4)
380 offset = 0;
381 else
382 offset = UNSYNC(buf[0], buf[1], buf[2], buf[3]) + 10;
384 return offset;
387 static int getfilesize(int fd)
389 int size;
391 /* seek to the end of it */
392 size = lseek(fd, 0, SEEK_END);
393 if(-1 == size)
394 return 0; /* unknown */
396 return size;
400 * Calculates the size of the ID3v1 tag.
402 * Arguments: file - the file to search for a tag.
404 * Returns: the size of the tag or 0 if none was found
406 static int getid3v1len(int fd)
408 char buf[3];
409 int offset;
411 /* Check if we find "TAG" 128 bytes from EOF */
412 if((lseek(fd, -128, SEEK_END) == -1) ||
413 (read(fd, buf, 3) != 3) ||
414 (strncmp(buf, "TAG", 3) != 0))
415 offset = 0;
416 else
417 offset = 128;
419 return offset;
422 /* check if 'head' is a valid mp3 frame header */
423 static bool mp3frameheader(unsigned long head)
425 if ((head & 0xffe00000) != 0xffe00000) /* bad sync? */
426 return false;
427 if (!((head >> 17) & 3)) /* no layer? */
428 return false;
429 if (((head >> 12) & 0xf) == 0xf) /* bad bitrate? */
430 return false;
431 if (!((head >> 12) & 0xf)) /* no bitrate? */
432 return false;
433 if (((head >> 10) & 0x3) == 0x3) /* bad sample rate? */
434 return false;
435 if (((head >> 19) & 1) == 1 &&
436 ((head >> 17) & 3) == 3 &&
437 ((head >> 16) & 1) == 1)
438 return false;
439 if ((head & 0xffff0000) == 0xfffe0000)
440 return false;
442 return true;
446 * Calculates the length (in milliseconds) of an MP3 file.
448 * Modified to only use integers.
450 * Arguments: file - the file to calculate the length upon
451 * entry - the entry to update with the length
453 * Returns: the song length in milliseconds,
454 * 0 means that it couldn't be calculated
456 static int getsonglength(int fd, struct mp3entry *entry)
458 unsigned int filetime = 0;
459 unsigned long header=0;
460 unsigned char tmp;
461 unsigned char frame[156];
462 unsigned char* xing;
464 enum {
465 MPEG_VERSION2_5,
466 MPEG_VERSION1,
467 MPEG_VERSION2
468 } version;
469 int layer;
470 int bitindex;
471 int bitrate;
472 int freqindex;
473 int frequency;
474 int chmode;
475 int bytecount;
476 int bytelimit;
477 int bittable; /* which bitrate table to use */
478 bool header_found = false;
480 long bpf;
481 long tpf;
483 /* Start searching after ID3v2 header */
484 if(-1 == lseek(fd, entry->id3v2len, SEEK_SET))
485 return 0;
487 /* Fill up header with first 24 bits */
488 for(version = 0; version < 3; version++) {
489 header <<= 8;
490 if(!read(fd, &tmp, 1))
491 return 0;
492 header |= tmp;
495 /* Loop trough file until we find a frame header */
496 bytecount = entry->id3v2len - 1;
497 bytelimit = entry->id3v2len + 0x20000;
498 restart:
499 do {
500 header <<= 8;
501 if(!read(fd, &tmp, 1))
502 return 0;
503 header |= tmp;
505 /* Quit if we haven't found a valid header within 128K */
506 bytecount++;
507 if(bytecount > bytelimit)
508 return 0;
509 } while(!mp3frameheader(header));
512 * Some files are filled with garbage in the beginning,
513 * if the bitrate index of the header is binary 1111
514 * that is a good indicator
516 if((header & 0xF000) == 0xF000)
517 goto restart;
519 /* MPEG Audio Version */
520 switch((header & 0x180000) >> 19) {
521 case 0:
522 /* MPEG version 2.5 is not an official standard */
523 version = MPEG_VERSION2_5;
524 bittable = MPEG_VERSION2; /* use the V2 bit rate table */
525 break;
527 case 2:
528 /* MPEG version 2 (ISO/IEC 13818-3) */
529 version = MPEG_VERSION2;
530 bittable = MPEG_VERSION2;
531 break;
533 case 3:
534 /* MPEG version 1 (ISO/IEC 11172-3) */
535 version = MPEG_VERSION1;
536 bittable = MPEG_VERSION1;
537 break;
538 default:
539 goto restart;
542 /* Layer */
543 switch((header & 0x060000) >> 17) {
544 case 1:
545 layer = 3;
546 break;
547 case 2:
548 layer = 2;
549 break;
550 case 3:
551 layer = 1;
552 break;
553 default:
554 goto restart;
557 /* Bitrate */
558 bitindex = (header & 0xF000) >> 12;
559 bitrate = bitrate_table[bittable-1][layer-1][bitindex];
560 if(bitrate == 0)
561 goto restart;
563 /* Sampling frequency */
564 freqindex = (header & 0x0C00) >> 10;
565 frequency = freqtab[version][freqindex];
566 if(frequency == 0)
567 goto restart;
569 #ifdef DEBUG_VERBOSE
570 DEBUGF( "Version %i, lay %i, biti %i, bitr %i, freqi %i, freq %i, chmode %d\n",
571 version, layer, bitindex, bitrate, freqindex, frequency, chmode);
572 #endif
573 entry->version = version;
574 entry->layer = layer;
575 entry->frequency = frequency;
577 /* Calculate bytes per frame, calculation depends on layer */
578 switch(layer) {
579 case 1:
580 bpf = bitrate_table[bittable - 1][layer - 1][bitindex];
581 bpf *= 48000;
582 bpf /= freqtab[version][freqindex] << (bittable - 1);
583 break;
584 case 2:
585 case 3:
586 bpf = bitrate_table[bittable - 1][layer - 1][bitindex];
587 bpf *= 144000;
588 bpf /= freqtab[version][freqindex] << (bittable - 1);
589 break;
590 default:
591 bpf = 1;
594 /* Calculate time per frame */
595 tpf = bs[layer] / (freqtab[version][freqindex] << (bittable - 1));
597 entry->bpf = bpf;
598 entry->tpf = tpf;
600 /* OK, we have found a frame. Let's see if it has a Xing header */
601 if(read(fd, frame, sizeof frame) < 0)
602 return -1;
604 /* Channel mode (stereo/mono) */
605 chmode = (header & 0xc0) >> 6;
607 /* calculate position of Xing VBR header */
608 if ( version == 1 ) {
609 if ( chmode == 3 ) /* mono */
610 xing = frame + 17;
611 else
612 xing = frame + 32;
614 else {
615 if ( chmode == 3 ) /* mono */
616 xing = frame + 9;
617 else
618 xing = frame + 17;
621 if (xing[0] == 'X' &&
622 xing[1] == 'i' &&
623 xing[2] == 'n' &&
624 xing[3] == 'g')
626 int i = 8; /* Where to start parsing info */
628 /* Yes, it is a VBR file */
629 entry->vbr = true;
630 entry->vbrflags = xing[7];
632 if (entry->vbrflags & VBR_FRAMES_FLAG) /* Is the frame count there? */
634 int framecount = (xing[i] << 24) | (xing[i+1] << 16) |
635 (xing[i+2] << 8) | xing[i+3];
637 filetime = framecount * tpf;
638 i += 4;
641 if (entry->vbrflags & VBR_BYTES_FLAG) /* is byte count there? */
643 int bytecount = (xing[i] << 24) | (xing[i+1] << 16) |
644 (xing[i+2] << 8) | xing[i+3];
646 bitrate = bytecount * 8 / filetime;
647 i += 4;
650 if (entry->vbrflags & VBR_TOC_FLAG) /* is table-of-contents there? */
652 memcpy( entry->toc, xing+i, 100 );
655 /* Make sure we skip this frame in playback */
656 bytecount += bpf;
658 header_found = true;
661 if (xing[0] == 'V' &&
662 xing[1] == 'B' &&
663 xing[2] == 'R' &&
664 xing[3] == 'I')
666 int framecount;
667 int bytecount;
669 /* Yes, it is a FhG VBR file */
670 entry->vbr = true;
671 entry->vbrflags = 0;
673 bytecount = (xing[10] << 24) | (xing[11] << 16) |
674 (xing[12] << 8) | xing[13];
676 framecount = (xing[14] << 24) | (xing[15] << 16) |
677 (xing[16] << 8) | xing[17];
679 filetime = framecount * tpf;
680 bitrate = bytecount * 8 / filetime;
682 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
684 /* Make sure we skip this frame in playback */
685 bytecount += bpf;
687 header_found = true;
690 /* Is it a LAME Info frame? */
691 if (xing[0] == 'I' &&
692 xing[1] == 'n' &&
693 xing[2] == 'f' &&
694 xing[3] == 'o')
696 /* Make sure we skip this frame in playback */
697 bytecount += bpf;
699 header_found = true;
703 entry->bitrate = bitrate;
705 /* If the file time hasn't been established, this may be a fixed
706 rate MP3, so just use the default formula */
707 if(filetime == 0)
710 * Now song length is
711 * ((filesize)/(bytes per frame))*(time per frame)
713 filetime = entry->filesize/bpf*tpf;
716 DEBUGF("Old ID3V2 length: %x\n", entry->id3v2len);
717 /* Adjust the tag length only if there is a tag present */
718 if(entry->id3v2len || header_found)
719 entry->id3v2len = bytecount;
720 DEBUGF("New ID3V2 length: %x\n", bytecount);
722 return filetime;
727 * Checks all relevant information (such as ID3v1 tag, ID3v2 tag, length etc)
728 * about an MP3 file and updates it's entry accordingly.
730 * Arguments: entry - the entry to check and update with the new information
732 * Returns: void
734 bool mp3info(struct mp3entry *entry, char *filename)
736 int fd;
737 fd = open(filename, O_RDONLY);
738 if(-1 == fd)
739 return true;
741 memset(entry, 0, sizeof(struct mp3entry));
743 strncpy(entry->path, filename, sizeof(entry->path));
745 entry->title = NULL;
746 entry->filesize = getfilesize(fd);
747 entry->id3v2len = getid3v2len(fd);
748 entry->tracknum = 0;
750 if (entry->id3v2len)
751 setid3v2title(fd, entry);
752 entry->length = getsonglength(fd, entry);
754 entry->id3v1len = getid3v1len(fd);
755 if(entry->id3v1len && !entry->title)
756 setid3v1title(fd, entry);
758 close(fd);
760 if(!entry->length || (entry->filesize < 8 ))
761 /* no song length or less than 8 bytes is hereby considered to be an
762 invalid mp3 and won't be played by us! */
763 return true;
765 return false;
768 #ifdef DEBUG_STANDALONE
770 char *secs2str(int ms)
772 static char buffer[32];
773 int secs = ms/1000;
774 ms %= 1000;
775 snprintf(buffer, sizeof(buffer), "%d:%02d.%d", secs/60, secs%60, ms/100);
776 return buffer;
779 int main(int argc, char **argv)
781 int i;
782 for(i=1; i<argc; i++) {
783 struct mp3entry mp3;
784 if(mp3info(&mp3, argv[i])) {
785 printf("Failed to get %s\n", argv[i]);
786 return 0;
789 printf("****** File: %s\n"
790 " Title: %s\n"
791 " Artist: %s\n"
792 " Album: %s\n"
793 " Length: %s / %d s\n"
794 " Bitrate: %d\n"
795 " Frequency: %d\n",
796 argv[i],
797 mp3.title?mp3.title:"<blank>",
798 mp3.artist?mp3.artist:"<blank>",
799 mp3.album?mp3.album:"<blank>",
800 secs2str(mp3.length),
801 mp3.length/1000,
802 mp3.bitrate,
803 mp3.frequency);
806 return 0;
809 #endif
811 /* -----------------------------------------------------------------
812 * local variables:
813 * eval: (load-file "rockbox-mode.el")
814 * end: