diff --git a/example/cdtext.c b/example/cdtext.c index df17f4d7..1d50f89d 100644 --- a/example/cdtext.c +++ b/example/cdtext.c @@ -1,5 +1,6 @@ /* - Copyright (C) 2004, 2005, 2006, 2008, 2009 Rocky Bernstein + Copyright (C) 2004, 2005, 2006, 2008, 2009, 2011 + Rocky Bernstein This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,7 +32,7 @@ static void print_cdtext_track_info(CdIo_t *p_cdio, track_t i_track, const char *psz_msg) { - const cdtext_t *cdtext = cdio_get_cdtext(p_cdio, 0); + const cdtext_t *cdtext = cdio_get_cdtext(p_cdio, i_track); if (NULL != cdtext) { cdtext_field_t i; diff --git a/lib/driver/cdtext.c b/lib/driver/cdtext.c index e2b3b2b4..d5342707 100644 --- a/lib/driver/cdtext.c +++ b/lib/driver/cdtext.c @@ -1,7 +1,5 @@ /* - $Id: cdtext.c,v 1.7 2008/06/16 22:41:44 flameeyes Exp $ - - Copyright (C) 2004, 2005, 2008 Rocky Bernstein + Copyright (C) 2004, 2005, 2008, 2011 Rocky Bernstein toc reading routine adapted from cuetools Copyright (C) 2003 Svend Sanjay Sorensen @@ -35,6 +33,7 @@ #include #endif +#include /*! Note: the order and number items (except CDTEXT_INVALID) should match the cdtext_field_t enumeration. */ @@ -55,6 +54,37 @@ static const char cdtext_keywords[][16] = "UPC_EAN", }; +static const char cdtext_genre[][30] = +{ + "Not Used", + "Not Defined", + "Adult Contemporary", + "Alternative Rock", + "Childrens Music", + "Classical", + "Contemporary Christian", + "Country", + "Dance", + "Easy Listening", + "Erotic", + "Folk", + "Gospel", + "Hip Hop", + "Jazz", + "Latin", + "Musical", + "New Age", + "Opera", + "Operetta", + "Pop Music", + "Rap", + "Reggae", + "Rock Music", + "Rhythm & Blues", + "Sound Effects", + "Spoken Word", + "World Music" +} ; /*! Return string representation of the enum values above */ const char * @@ -126,10 +156,10 @@ cdtext_is_keyword (const char *key) char *item; item = bsearch(key, - cdtext_keywords, 12, - sizeof (char *), - (int (*)(const void *, const void *)) - strcmp); + cdtext_keywords, 12, + sizeof (char *), + (int (*)(const void *, const void *)) + strcmp); return (NULL != item) ? 0 : 1; #else unsigned int i; @@ -162,8 +192,8 @@ cdtext_set (cdtext_field_t key, const char *p_value, cdtext_t *p_cdtext) */ bool cdtext_data_init(void *p_user_data, track_t i_first_track, - unsigned char *wdata, int i_data, - set_cdtext_field_fn_t set_cdtext_field_fn) + unsigned char *wdata, int i_data, + set_cdtext_field_fn_t set_cdtext_field_fn) { CDText_data_t *p_data; int i = -1; @@ -172,29 +202,17 @@ cdtext_data_init(void *p_user_data, track_t i_first_track, int idx; int i_track; bool b_ret = false; - char block = 0; + char block = 0; + char encoding[16]; + CDText_blocksize_t p_blocksize; memset( buffer, 0x00, sizeof(buffer) ); idx = 0; - p_data = (CDText_data_t *) (&wdata[4]); + bzero(encoding,16); + bzero(&p_blocksize, sizeof(CDText_blocksize_t)); - /* For reasons I don't understand - incorrect CDROM TOC reading? - we are off sometimes by 4. - */ - /* - * Leon Lohse: can anybody confirm this problem? - * - if( (p_data->type < 0x80) || (p_data->type > 0x85) - || (p_data->block == 0) ) { - CDText_data_t *p_data_test = (CDText_data_t *) (&wdata[8]); - if( (p_data_test->type >= 0x80) - && (p_data_test->type <= 0x85) && (p_data_test->block == 0) ) { - p_data = p_data_test; - i_data -= 4; - } - } - */ + p_data = (CDText_data_t *) (&wdata[4]); for( ; i_data > 0; i_data -= sizeof(CDText_data_t), p_data++ ) { @@ -206,69 +224,135 @@ cdtext_data_init(void *p_user_data, track_t i_first_track, } #endif - /* we should increment i here and not just when we get a char string */ - if( p_data->seq != ++i || p_data->block != block ) break; + if ( p_data->seq != ++i || p_data->block != block ) break; /* only handle character packs */ - if( ((p_data->type >= 0x80) && (p_data->type <= 0x85)) || + if ( ((p_data->type >= 0x80) && (p_data->type <= 0x86)) || (p_data->type == 0x8E)) { i_track = p_data->i_track; - /* can we somehow use p_data->characterPosition to make this simpler? */ for( j=0; j < CDIO_CDTEXT_MAX_TEXT_DATA; (p_data->bDBC ? j+=2 : j++) ) { - if( p_data->text[j] == 0x00 && (!p_data->bDBC || p_data->text[j+1] == 0x00)) { - - /* omit empty strings */ - if((buffer[0] != 0x00) && (!p_data->bDBC || buffer[1] != 0x00)) { + if( p_data->text[j] == 0x00 && (!p_data->bDBC || p_data->text[j+1] == 0x00)) { + + /* omit empty strings */ + if((buffer[0] != 0x00) && (!p_data->bDBC || buffer[1] != 0x00)) { + switch( p_data->type) { + case CDIO_CDTEXT_TITLE: + SET_CDTEXT_FIELD(CDTEXT_TITLE); + break; + case CDIO_CDTEXT_PERFORMER: + SET_CDTEXT_FIELD(CDTEXT_PERFORMER); + break; + case CDIO_CDTEXT_SONGWRITER: + SET_CDTEXT_FIELD(CDTEXT_SONGWRITER); + break; + case CDIO_CDTEXT_COMPOSER: + SET_CDTEXT_FIELD(CDTEXT_COMPOSER); + break; + case CDIO_CDTEXT_ARRANGER: + SET_CDTEXT_FIELD(CDTEXT_ARRANGER); + break; + case CDIO_CDTEXT_MESSAGE: + SET_CDTEXT_FIELD(CDTEXT_MESSAGE); + break; + case CDIO_CDTEXT_DISCID: + if(i_track == 0) { + SET_CDTEXT_FIELD(CDTEXT_DISCID); + } + break; + case CDIO_CDTEXT_UPC: + if(i_track == 0) { + SET_CDTEXT_FIELD(CDTEXT_UPC_EAN); + } + else { + SET_CDTEXT_FIELD(CDTEXT_ISRC); + } + break; + } + + b_ret = true; + i_track++; + idx = 0; + } + } else { + buffer[idx++] = p_data->text[j]; + if(p_data->bDBC) + buffer[idx++] = p_data->text[j+1]; + } - bool b_field_set=true; - switch( p_data->type) { - case CDIO_CDTEXT_TITLE: - SET_CDTEXT_FIELD(CDTEXT_TITLE); - break; - case CDIO_CDTEXT_PERFORMER: - SET_CDTEXT_FIELD(CDTEXT_PERFORMER); - break; - case CDIO_CDTEXT_SONGWRITER: - SET_CDTEXT_FIELD(CDTEXT_SONGWRITER); - break; - case CDIO_CDTEXT_COMPOSER: - SET_CDTEXT_FIELD(CDTEXT_COMPOSER); - break; - case CDIO_CDTEXT_ARRANGER: - SET_CDTEXT_FIELD(CDTEXT_ARRANGER); - break; - case CDIO_CDTEXT_MESSAGE: - SET_CDTEXT_FIELD(CDTEXT_MESSAGE); - break; - case CDIO_CDTEXT_UPC: - if(i_track == 0) { - SET_CDTEXT_FIELD(CDTEXT_UPC_EAN); - } - else { - SET_CDTEXT_FIELD(CDTEXT_ISRC); - } - break; - default : b_field_set = false; - } - if (b_field_set) { - b_ret = true; - i_track++; - idx = 0; - } - } - } else { - buffer[idx++] = p_data->text[j]; - if(p_data->bDBC) - buffer[idx++] = p_data->text[j+1]; - } buffer[idx] = 0x00; - if(p_data->bDBC) - buffer[idx+1] = 0x00; + if(p_data->bDBC) + buffer[idx+1] = 0x00; + } + } else { + /* not a character pack */ + if (p_data->type == CDIO_CDTEXT_GENRE) { + i_track = p_data->i_track; + /* seems like it is a uint_16 in the first 2 bytes */ + if((p_data->text[0] << 8) + p_data->text[1] != CDIO_CDTEXT_GENRE_UNUSED) { + sprintf(buffer,"%s",cdtext_genre[(p_data->text[0] << 8) + p_data->text[1]]); + SET_CDTEXT_FIELD(CDTEXT_GENRE); + } +#ifdef _DEBUG_CDTEXT + printf("GENRE information present: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + p_data->text[0],p_data->text[1],p_data->text[2],p_data->text[3], + p_data->text[4],p_data->text[5],p_data->text[6],p_data->text[7], + p_data->text[8],p_data->text[9],p_data->text[10],p_data->text[11]); +#endif + } + + if(p_data->type == CDIO_CDTEXT_TOC) { +#ifdef _DEBUG_CDTEXT + printf("TOC information present: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + p_data->text[0],p_data->text[1],p_data->text[2],p_data->text[3], + p_data->text[4],p_data->text[5],p_data->text[6],p_data->text[7], + p_data->text[8],p_data->text[9],p_data->text[10],p_data->text[11]); +#endif + } + + if (p_data->type == CDIO_CDTEXT_TOC2) { +#ifdef _DEBUG_CDTEXT + printf("TOC2 information present: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + p_data->text[0],p_data->text[1],p_data->text[2],p_data->text[3], + p_data->text[4],p_data->text[5],p_data->text[6],p_data->text[7], + p_data->text[8],p_data->text[9],p_data->text[10],p_data->text[11]); +#endif + } + + /* i got this info from cdrtools' cdda2wav; all the tests i ran so far were successful */ + if (p_data->type == CDIO_CDTEXT_BLOCKSIZE) { + /* i_track is the pack element number in this case */ + switch(p_data->i_track){ + case 0: + memcpy((char*)&p_blocksize,p_data->text,0x0c); + break; + case 1: + memcpy(((char*)&p_blocksize)+0x0c,p_data->text,0x0c); + break; + case 2: + memcpy(((char*)&p_blocksize)+0x18,p_data->text,0x0c); + break; + } } } } + + if (p_blocksize.packcount[15] >= 3) { + /* BLOCKSIZE packs present */ + switch (p_blocksize.charcode){ + case CDIO_CDTEXT_CHARCODE_ISO_8859_1: + sprintf(encoding,"ISO-8859-1"); + break; + case CDIO_CDTEXT_CHARCODE_ASCII: + sprintf(encoding,"ASCII"); + break; + case CDIO_CDTEXT_CHARCODE_KANJI: + sprintf(encoding,"Shift-JIS"); + break; + } + + } + return b_ret; } - diff --git a/lib/driver/cdtext_private.h b/lib/driver/cdtext_private.h index 56b0e626..02f338e4 100644 --- a/lib/driver/cdtext_private.h +++ b/lib/driver/cdtext_private.h @@ -1,7 +1,5 @@ /* - $Id: cdtext_private.h,v 1.3 2008/04/22 15:29:11 karl Exp $ - - Copyright (C) 2004, 2005, 2008 Rocky Bernstein + Copyright (C) 2004, 2005, 2008, 2011 Rocky Bernstein This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,7 +26,7 @@ to be helpful in debuggers where wants just to refer to the ISO_*_ names and get something. */ -extern enum cdtext_enum1_s { +extern const enum cdtext_enum1_s { CDIO_CDTEXT_MAX_PACK_DATA = 255, CDIO_CDTEXT_MAX_TEXT_DATA = 12, CDIO_CDTEXT_TITLE = 0x80, @@ -45,13 +43,91 @@ extern enum cdtext_enum1_s { CDIO_CDTEXT_BLOCKSIZE = 0x8F } cdtext_enums1; + +/*! + * CD-Text Genre Codes + */ +extern const enum cdtext_genre_enum_s { + CDIO_CDTEXT_GENRE_UNUSED = 0, /**< not used */ + CDIO_CDTEXT_GENRE_UNDEFINED = 1, /**< not defined */ + CDIO_CDTEXT_GENRE_ADULT_CONTEMP = 2, /**< Adult Contemporary */ + CDIO_CDTEXT_GENRE_ALT_ROCK = 3, /**< Alternative Rock */ + CDIO_CDTEXT_GENRE_CHILDRENS = 4, /**< Childrens Music */ + CDIO_CDTEXT_GENRE_CLASSIC = 5, /**< Classical */ + CDIO_CDTEXT_GENRE_CHRIST_CONTEMP = 6, /**< Contemporary Christian */ + CDIO_CDTEXT_GENRE_COUNTRY = 7, /**< Country */ + CDIO_CDTEXT_GENRE_DANCE = 8, /**< Dance */ + CDIO_CDTEXT_GENRE_EASY_LISTENING = 9, /**< Easy Listening */ + CDIO_CDTEXT_GENRE_EROTIC = 10, /**< Erotic */ + CDIO_CDTEXT_GENRE_FOLK = 11, /**< Folk */ + CDIO_CDTEXT_GENRE_GOSPEL = 12, /**< Gospel */ + CDIO_CDTEXT_GENRE_HIPHOP = 13, /**< Hip Hop */ + CDIO_CDTEXT_GENRE_JAZZ = 14, /**< Jazz */ + CDIO_CDTEXT_GENRE_LATIN = 15, /**< Latin */ + CDIO_CDTEXT_GENRE_MUSICAL = 16, /**< Musical */ + CDIO_CDTEXT_GENRE_NEWAGE = 17, /**< New Age */ + CDIO_CDTEXT_GENRE_OPERA = 18, /**< Opera */ + CDIO_CDTEXT_GENRE_OPERETTA = 19, /**< Operetta */ + CDIO_CDTEXT_GENRE_POP = 20, /**< Pop Music */ + CDIO_CDTEXT_GENRE_RAP = 21, /**< RAP */ + CDIO_CDTEXT_GENRE_REGGAE = 22, /**< Reggae */ + CDIO_CDTEXT_GENRE_ROCK = 23, /**< Rock Music */ + CDIO_CDTEXT_GENRE_RYTHMANDBLUES = 24, /**< Rhythm & Blues */ + CDIO_CDTEXT_GENRE_SOUNDEFFECTS = 25, /**< Sound Effects */ + CDIO_CDTEXT_GENRE_SOUNDTRACK = 26, /**< Soundtrack */ + CDIO_CDTEXT_GENRE_SPOKEN_WORD = 27, /**< Spoken Word */ + CDIO_CDTEXT_GENRE_WORLD_MUSIC = 28 /**< World Music */ +} cdtext_genre_enum; + +/*! + * CD-Text character codes + */ +extern const enum cdtext_charcode_enum_s { + CDIO_CDTEXT_CHARCODE_ISO_8859_1 = 0x00, /**< ISO-8859-1 */ + CDIO_CDTEXT_CHARCODE_ASCII = 0x01, /**< ASCII - 7 bit */ + CDIO_CDTEXT_CHARCODE_KANJI = 0x80, /**< Music Shift-JIS Kanji - + double byte */ + CDIO_CDTEXT_CHARCODE_KOREAN = 0x81, /**< Korean */ + CDIO_CDTEXT_CHARCODE_CHINESE = 0x82, /**< Mandarin Chinese */ + CDIO_CDTEXT_CHARCODE_UNDEFINED = 0xFF, /**< everything else */ +} cdtext_charcode_enum; + +/*! + * The language code is encoded as specified in ANNEX 1 to part 5 of EBU + * Tech 32 58 -E (1991). + */ +extern const enum cdtext_lang_enum_s +{ + CDIO_CDTEXT_LANG_CZECH = 0x06, + CDIO_CDTEXT_LANG_DANISH = 0x07, + CDIO_CDTEXT_LANG_GERMAN = 0x08, + CDIO_CDTEXT_LANG_ENGLISH = 0x09, + CDIO_CDTEXT_LANG_SPANISH = 0x0A, + CDIO_CDTEXT_LANG_FRENCH = 0x0F, + CDIO_CDTEXT_LANG_ITALIAN = 0x15, + CDIO_CDTEXT_LANG_HUNGARIAN = 0x1b, + CDIO_CDTEXT_LANG_DUTCH = 0x1d, + CDIO_CDTEXT_LANG_NORWEGIAN = 0x1e, + CDIO_CDTEXT_LANG_POLISH = 0x20, + CDIO_CDTEXT_LANG_PORTUGUESE = 0x21, + CDIO_CDTEXT_LANG_SLOVENE = 0x26, + CDIO_CDTEXT_LANG_FINNISH = 0x27, + CDIO_CDTEXT_LANG_SWEDISH = 0x28, + CDIO_CDTEXT_LANG_RUSSIAN = 0x56, + CDIO_CDTEXT_LANG_KOREAN = 0x65, + CDIO_CDTEXT_LANG_JAPANESE = 0x69, + CDIO_CDTEXT_LANG_GREEK = 0x70, + CDIO_CDTEXT_LANG_CHINESE = 0x75, +} cdtext_lang_enum; + + #define CDIO_CDTEXT_MAX_PACK_DATA 255 #define CDIO_CDTEXT_MAX_TEXT_DATA 12 /* From table J.2 - Pack Type Indicator Definitions from Working Draft NCITS XXX T10/1364-D Revision 10G. November 12, 2001. */ -/* Title of Alubm name (ID=0) or Track Titles (ID != 0) */ +/* Title of Album name (ID=0) or Track Titles (ID != 0) */ #define CDIO_CDTEXT_TITLE 0x80 /* Name(s) of the performer(s) in ASCII */ @@ -99,13 +175,13 @@ struct CDText_data track_t i_track; uint8_t seq; #ifdef WORDS_BIGENDIAN - uint8_t bDBC: 1; /* double byte character */ + uint8_t bDBC: 1; /* double byte character */ uint8_t block: 3; /* block number 0..7 */ uint8_t characterPosition:4; /* character position */ #else uint8_t characterPosition:4; /* character position */ - uint8_t block :3; /* block number 0..7 */ - uint8_t bDBC :1; /* double byte character */ + uint8_t block :3; /* block number 0..7 */ + uint8_t bDBC :1; /* double byte character */ #endif char text[CDIO_CDTEXT_MAX_TEXT_DATA]; uint8_t crc[2]; @@ -113,6 +189,25 @@ struct CDText_data PRAGMA_END_PACKED +/* + * content of BLOCKSIZE packs + */ +typedef struct CDText_blocksize +{ + uint8_t charcode; /* character code */ + uint8_t i_firstTrack; /* first track number */ + uint8_t i_lastTrack; /* last track number */ + uint8_t copyright; /* cd-text information copyright byte */ + uint8_t packcount[16];/* number of packs of each type + * 0 TITLE; 1 PERFORMER; 2 SONGWRITER; 3 COMPOSER; + * 4 ARRANGER; 5 MESSAGE; 6 DISCID; 7 GENRE; + * 8 TOC; 9 TOC2; 10-12 RESERVED; 13 CLOSED; + * 14 UPC_ISRC; 15 BLOCKSIZE */ + uint8_t lastseq[8]; /* last sequence for block 0..7 */ + uint8_t langcode[8]; /* language code for block 0..7 */ +} CDText_blocksize_t; + + typedef struct CDText_data CDText_data_t; typedef void (*set_cdtext_field_fn_t) (void *user_data, track_t i_track,