Index: apps/metadata/mp4.c =================================================================== --- apps/metadata/mp4.c (Revision 17647) +++ apps/metadata/mp4.c (Arbeitskopie) @@ -61,6 +61,10 @@ #define MP4_mp4a MP4_ID('m', 'p', '4', 'a') #define MP4_mp42 MP4_ID('m', 'p', '4', '2') #define MP4_qt MP4_ID('q', 't', ' ', ' ') +#define MP4_soaa MP4_ID('s', 'o', 'a', 'a') +#define MP4_soal MP4_ID('s', 'o', 'a', 'l') +#define MP4_soar MP4_ID('s', 'o', 'a', 'r') +#define MP4_sonm MP4_ID('s', 'o', 'n', 'm') #define MP4_soun MP4_ID('s', 'o', 'u', 'n') #define MP4_stbl MP4_ID('s', 't', 'b', 'l') #define MP4_stsd MP4_ID('s', 't', 's', 'd') @@ -451,6 +455,26 @@ } break; + case MP4_soaa: + read_mp4_tag_string(fd, size, &buffer, &buffer_left, + &id3->albumartistsort); + break; + + case MP4_soal: + read_mp4_tag_string(fd, size, &buffer, &buffer_left, + &id3->albumsort); + break; + + case MP4_soar: + read_mp4_tag_string(fd, size, &buffer, &buffer_left, + &id3->artistsort); + break; + + case MP4_sonm: + read_mp4_tag_string(fd, size, &buffer, &buffer_left, + &id3->titlesort); + break; + case MP4_extra: { char tag_name[TAG_NAME_LENGTH]; Index: apps/metadata/metadata_common.c =================================================================== --- apps/metadata/metadata_common.c (Revision 17647) +++ apps/metadata/metadata_common.c (Arbeitskopie) @@ -291,6 +291,22 @@ { p = &(id3->grouping); } + else if (strcasecmp(name, "artistsort") == 0) + { + p = &(id3->artistsort); + } + else if (strcasecmp(name, "albumartistsort") == 0) + { + p = &(id3->albumartistsort); + } + else if (strcasecmp(name, "albumsort") == 0) + { + p = &(id3->albumsort); + } + else if (strcasecmp(name, "titlesort") == 0) + { + p = &(id3->titlesort); + } else { len = parse_replaygain(name, value, id3, buf, buf_remaining); Index: apps/tagcache.c =================================================================== --- apps/tagcache.c (Revision 17647) +++ apps/tagcache.c (Arbeitskopie) @@ -61,6 +61,7 @@ #include "thread.h" #include "kernel.h" #include "system.h" +#include "debug.h" #include "logf.h" #include "string.h" #include "usb.h" @@ -109,11 +110,15 @@ /* Tags we want to get sorted (loaded to the tempbuf). */ static const int sorted_tags[] = { tag_artist, tag_album, tag_genre, - tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_title }; + tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_title, + tag_titlesort, tag_albumsort, tag_artistsort, tag_albumartistsort +}; /* Uniqued tags (we can use these tags with filters and conditional clauses). */ static const int unique_tags[] = { tag_artist, tag_album, tag_genre, - tag_composer, tag_comment, tag_albumartist, tag_grouping }; + tag_composer, tag_comment, tag_albumartist, tag_grouping, + tag_albumsort, tag_artistsort, tag_albumartistsort +}; /* Numeric tags (we can use these tags with conditional clauses). */ static const int numeric_tags[] = { tag_year, tag_discnumber, @@ -125,9 +130,11 @@ /* String presentation of the tags defined in tagcache.h. Must be in correct order! */ static const char *tags_str[] = { "artist", "album", "genre", "title", - "filename", "composer", "comment", "albumartist", "grouping", "year", - "discnumber", "tracknumber", "bitrate", "length", "playcount", "rating", - "playtime", "lastplayed", "commitid", "mtime" }; + "filename", "composer", "comment", "albumartist", "grouping", + "titlesortorder", "albumsortorder", "performersortorder", + "albumartistsortorder", "year", "discnumber", "tracknumber", + "bitrate", "length", "playcount", "rating", "playtime", + "lastplayed", "commitid", "mtime" }; /* Status information of the tagcache. */ static struct tagcache_stat tc_stat; @@ -1588,6 +1595,11 @@ id3->albumartist = get_tag_string(entry, tag_albumartist); id3->grouping = get_tag_string(entry, tag_grouping); + id3->titlesort = get_tag_string(entry, tag_titlesort); + id3->albumsort = get_tag_string(entry, tag_albumsort); + id3->artistsort = get_tag_string(entry, tag_artistsort); + id3->albumartistsort = get_tag_string(entry, tag_albumartistsort); + id3->playcount = get_tag_numeric(entry, tag_playcount); id3->rating = get_tag_numeric(entry, tag_rating); id3->lastplayed = get_tag_numeric(entry, tag_lastplayed); @@ -1633,12 +1645,14 @@ return length + 1; } -#define ADD_TAG(entry,tag,data) \ - /* Adding tag */ \ - entry.tag_offset[tag] = offset; \ - entry.tag_length[tag] = check_if_empty(data); \ - offset += entry.tag_length[tag] - +static int add_tag(int offset, struct temp_file_entry *entry, int tag, + char **data) +{ + entry->tag_offset[tag] = offset; + entry->tag_length[tag] = check_if_empty(data); + return entry->tag_length[tag]; +} + static void add_tagcache(char *path, unsigned long mtime #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) ,const struct dirent *dc @@ -1655,7 +1669,8 @@ int path_length = strlen(path); bool has_albumartist; bool has_grouping; - + bool have_titlesort, have_albumsort, have_artistsort, + have_albumartistsort; if (cachefd < 0) return ; @@ -1771,34 +1786,64 @@ entry.tag_offset[tag_mtime] = mtime; /* String tags. */ - has_albumartist = id3.albumartist != NULL - && strlen(id3.albumartist) > 0; - has_grouping = id3.grouping != NULL - && strlen(id3.grouping) > 0; + has_albumartist = id3.albumartist != NULL && + strlen(id3.albumartist) > 0; + has_grouping = id3.grouping != NULL && + strlen(id3.grouping) > 0; + have_titlesort = id3.titlesort != NULL && + strlen(id3.titlesort) > 0; + have_albumsort = id3.albumsort != NULL && + strlen(id3.albumsort) > 0; + have_artistsort = id3.artistsort != NULL && + strlen(id3.artistsort) > 0; + have_albumartistsort = id3.albumartistsort != NULL && + strlen(id3.albumartistsort) > 0; - ADD_TAG(entry, tag_filename, &path); - ADD_TAG(entry, tag_title, &id3.title); - ADD_TAG(entry, tag_artist, &id3.artist); - ADD_TAG(entry, tag_album, &id3.album); - ADD_TAG(entry, tag_genre, &id3.genre_string); - ADD_TAG(entry, tag_composer, &id3.composer); - ADD_TAG(entry, tag_comment, &id3.comment); + offset += add_tag(offset, &entry, tag_filename, &path); + offset += add_tag(offset, &entry, tag_title, &id3.title); + offset += add_tag(offset, &entry, tag_artist, &id3.artist); + offset += add_tag(offset, &entry, tag_album, &id3.album); + offset += add_tag(offset, &entry, tag_genre, &id3.genre_string); + offset += add_tag(offset, &entry, tag_composer, &id3.composer); + offset += add_tag(offset, &entry, tag_comment, &id3.comment); if (has_albumartist) { - ADD_TAG(entry, tag_albumartist, &id3.albumartist); + offset += add_tag(offset, &entry, tag_albumartist, &id3.albumartist); } else { - ADD_TAG(entry, tag_albumartist, &id3.artist); + offset += add_tag(offset, &entry, tag_albumartist, &id3.artist); } if (has_grouping) { - ADD_TAG(entry, tag_grouping, &id3.grouping); + offset += add_tag(offset, &entry, tag_grouping, &id3.grouping); } else { - ADD_TAG(entry, tag_grouping, &id3.title); + offset += add_tag(offset, &entry, tag_grouping, &id3.title); } + if (have_titlesort) + offset += add_tag(offset, &entry, tag_titlesort, &id3.titlesort); + else + offset += add_tag(offset, &entry, tag_titlesort, &id3.title); + + if (have_albumsort) + offset += add_tag(offset, &entry, tag_albumsort, &id3.albumsort); + else + offset += add_tag(offset, &entry, tag_albumsort, &id3.album); + + if (have_artistsort) + offset += add_tag(offset, &entry, tag_artistsort, &id3.artistsort); + else + offset += add_tag(offset, &entry, tag_artistsort, &id3.artist); + + if (have_albumartistsort) + offset += add_tag(offset, &entry, tag_albumartistsort, + &id3.albumartistsort); + else + offset += add_tag(offset, &entry, tag_albumartistsort, + &id3.albumartist); + entry.data_length = offset; /* Write the header */ @@ -1812,22 +1857,37 @@ write_item(id3.genre_string); write_item(id3.composer); write_item(id3.comment); + if (has_albumartist) - { write_item(id3.albumartist); - } else - { write_item(id3.artist); - } + if (has_grouping) - { write_item(id3.grouping); - } else - { write_item(id3.title); - } + + if (have_titlesort) + write_item(id3.titlesort); + else + write_item(id3.title); + + if (have_albumsort) + write_item(id3.albumsort); + else + write_item(id3.album); +DEBUGF("have_artistsort: %d\nartist: %s\nartistsort: %s\n", have_artistsort, id3.artist, id3.artistsort); + if (have_artistsort) + write_item(id3.artistsort); + else + write_item(id3.artist); + + if (have_albumartistsort) + write_item(id3.albumartistsort); + else + write_item(id3.albumartist); + total_entry_count++; } @@ -2395,8 +2455,8 @@ close(fd); return -2; } - - if (entry.tag_length >= (int)sizeof(buf)) + + if (entry.tag_length >= (int)sizeof(buf)) { logf("too long tag #3"); close(fd); Index: apps/tagcache.h =================================================================== --- apps/tagcache.h (Revision 17647) +++ apps/tagcache.h (Arbeitskopie) @@ -23,9 +23,11 @@ #include "id3.h" enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, - tag_filename, tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_year, - tag_discnumber, tag_tracknumber, tag_bitrate, tag_length, tag_playcount, tag_rating, - tag_playtime, tag_lastplayed, tag_commitid, tag_mtime, + tag_filename, tag_composer, tag_comment, tag_albumartist, tag_grouping, + tag_titlesort, tag_albumsort, tag_artistsort, tag_albumartistsort, + tag_year, tag_discnumber, tag_tracknumber, tag_bitrate, tag_length, + tag_playcount, tag_rating, tag_playtime, tag_lastplayed, tag_commitid, + tag_mtime, /* Virtual tags */ tag_virt_length_min, tag_virt_length_sec, tag_virt_playtime_min, tag_virt_playtime_sec, @@ -43,7 +45,7 @@ #define IDX_BUF_DEPTH 64 /* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */ -#define TAGCACHE_MAGIC 0x5443480c +#define TAGCACHE_MAGIC 0x5443480d /* How much to allocate extra space for ramcache. */ #define TAGCACHE_RESERVE 32768 Index: apps/tagtree.c =================================================================== --- apps/tagtree.c (Revision 17647) +++ apps/tagtree.c (Arbeitskopie) @@ -215,6 +215,10 @@ MATCH(tag, buf, "albumartist", tag_albumartist); MATCH(tag, buf, "ensemble", tag_albumartist); MATCH(tag, buf, "grouping", tag_grouping); + MATCH(tag, buf, "titlesort", tag_titlesort); + MATCH(tag, buf, "albumsort", tag_albumsort); + MATCH(tag, buf, "artistsort", tag_artistsort); + MATCH(tag, buf, "albumartistsort", tag_albumartistsort); MATCH(tag, buf, "genre", tag_genre); MATCH(tag, buf, "length", tag_length); MATCH(tag, buf, "Lm", tag_virt_length_min); Index: firmware/export/id3.h =================================================================== --- firmware/export/id3.h (Revision 17647) +++ firmware/export/id3.h (Arbeitskopie) @@ -155,6 +155,10 @@ char* comment; char* albumartist; char* grouping; + char* titlesort; + char* albumsort; + char* artistsort; + char* albumartistsort; int discnum; int tracknum; int version; Index: firmware/id3.c =================================================================== --- firmware/id3.c (Revision 17647) +++ firmware/id3.c (Arbeitskopie) @@ -216,7 +216,7 @@ display it, at a runtime cost.) 2. If any special processing beyond copying the tag value from the Id3 - block to the struct mp3entry is rrequired (such as converting to an + block to the struct mp3entry is required (such as converting to an int), write a function to perform this special processing. This function's prototype must match that of @@ -393,7 +393,7 @@ } #if CONFIG_CODEC == SWCODEC -/* parse user defined text, looking for replaygain information. */ +/* Parse the TXXX frame of ID3v2 for various different bits of data */ static int parseuser( struct mp3entry* entry, char* tag, int bufferpos ) { char* value = NULL; @@ -405,8 +405,15 @@ * parse it */ value = tag + desc_len + 1; - value_len = parse_replaygain(tag, value, entry, tag, - bufferpos - (tag - entry->id3v2buf)); + + if (strncmp("replaygain", tag, 10) == 0) { + /* Note: for ID3v2.4, parse_replaygain will not overwrite replaygain + values already parsed from RVA2 tags */ + value_len = parse_replaygain(tag, value, entry, tag, + bufferpos - (tag - entry->id3v2buf)); + } else if (strncmp("ALBUMARTISTSORT", tag, 15) == 0) { + entry->albumartistsort = value; + } } return tag - entry->id3v2buf + value_len; @@ -502,6 +509,14 @@ { "COMM", 4, offsetof(struct mp3entry, comment), NULL, false }, { "TCON", 4, offsetof(struct mp3entry, genre_string), &parsegenre, false }, { "TCO", 3, offsetof(struct mp3entry, genre_string), &parsegenre, false }, + /* id3v2.4 versions */ + { "TSOA", 4, offsetof(struct mp3entry, albumsort), NULL, false }, + { "TSOP", 4, offsetof(struct mp3entry, artistsort), NULL, false }, + { "TSOT", 4, offsetof(struct mp3entry, titlesort), NULL, false }, + /* these may also appear */ + { "XSOA", 4, offsetof(struct mp3entry, albumsort), NULL, false }, + { "XSOP", 4, offsetof(struct mp3entry, artistsort), NULL, false }, + { "XSOT", 4, offsetof(struct mp3entry, titlesort), NULL, false }, #if CONFIG_CODEC == SWCODEC { "TXXX", 4, 0, &parseuser, false }, { "RVA2", 4, 0, &parserva2, true }, @@ -763,7 +778,9 @@ } entry->id3version = version; entry->tracknum = entry->year = entry->discnum = 0; - entry->title = entry->artist = entry->album = NULL; /* FIXME incomplete */ + entry->title = entry->artist = entry->album = + entry->titlesort = entry->artistsort = + entry->albumsort = entry->albumartistsort = NULL; /* FIXME incomplete */ global_flags = header[5]; @@ -1255,6 +1272,14 @@ entry->albumartist += offset; if (entry->grouping) entry->grouping += offset; + if (entry->artistsort) + entry->artistsort += offset; + if (entry->albumsort) + entry->albumsort += offset; + if (entry->titlesort) + entry->titlesort += offset; + if (entry->albumartistsort) + entry->albumartistsort += offset; #if CONFIG_CODEC == SWCODEC if (entry->track_gain_string) entry->track_gain_string += offset;