Index: apps/screens.c =================================================================== --- apps/screens.c (revision 13721) +++ apps/screens.c (working copy) @@ -1131,6 +1131,7 @@ LANG_ID3_ARTIST, LANG_ID3_ALBUM, LANG_ID3_ALBUMARTIST, + LANG_ID3_GROUPING, LANG_ID3_TRACKNUM, LANG_ID3_COMMENT, LANG_ID3_GENRE, @@ -1172,7 +1173,10 @@ case 3:/*LANG_ID3_ALBUMARTIST*/ info=id3->albumartist; break; - case 4:/*LANG_ID3_TRACKNUM*/ + case 4:/*LANG_ID3_GROUPING*/ + info=id3->grouping; + break; + case 5:/*LANG_ID3_TRACKNUM*/ if (id3->track_string) info = id3->track_string; else if (id3->tracknum) @@ -1181,13 +1185,13 @@ info = buffer; } break; - case 5:/*LANG_ID3_COMMENT*/ + case 6:/*LANG_ID3_COMMENT*/ info=id3->comment; break; - case 6:/*LANG_ID3_GENRE*/ + case 7:/*LANG_ID3_GENRE*/ info = id3->genre_string; break; - case 7:/*LANG_ID3_YEAR*/ + case 8:/*LANG_ID3_YEAR*/ if (id3->year_string) info = id3->year_string; else if (id3->year) @@ -1196,34 +1200,34 @@ info = buffer; } break; - case 8:/*LANG_ID3_LENGTH*/ + case 9:/*LANG_ID3_LENGTH*/ format_time(buffer, MAX_PATH, id3->length); info=buffer; break; - case 9:/*LANG_ID3_PLAYLIST*/ + case 10:/*LANG_ID3_PLAYLIST*/ snprintf(buffer, MAX_PATH, "%d/%d", playlist_get_display_index(), playlist_amount()); info=buffer; break; - case 10:/*LANG_ID3_BITRATE*/ + case 11:/*LANG_ID3_BITRATE*/ snprintf(buffer, MAX_PATH, "%d kbps%s", id3->bitrate, id3->vbr ? str(LANG_ID3_VBR) : (const unsigned char*) ""); info=buffer; break; - case 11:/*LANG_ID3_FRECUENCY*/ + case 12:/*LANG_ID3_FRECUENCY*/ snprintf(buffer, MAX_PATH, "%ld Hz", id3->frequency); info=buffer; break; #if CONFIG_CODEC == SWCODEC - case 12:/*LANG_ID3_TRACK_GAIN*/ + case 13:/*LANG_ID3_TRACK_GAIN*/ info=id3->track_gain_string; break; - case 13:/*LANG_ID3_ALBUM_GAIN*/ + case 14:/*LANG_ID3_ALBUM_GAIN*/ info=id3->album_gain_string; break; - case 14:/*LANG_ID3_PATH*/ + case 15:/*LANG_ID3_PATH*/ #else - case 12:/*LANG_ID3_PATH*/ + case 13:/*LANG_ID3_PATH*/ #endif info=id3->path; break; Index: apps/metadata/mp4.c =================================================================== --- apps/metadata/mp4.c (revision 13721) +++ apps/metadata/mp4.c (working copy) @@ -37,6 +37,7 @@ #define MP4_alac MP4_ID('a', 'l', 'a', 'c') #define MP4_calb MP4_ID(0xa9, 'a', 'l', 'b') #define MP4_cART MP4_ID(0xa9, 'A', 'R', 'T') +#define MP4_cgrp MP4_ID(0xa9, 'g', 'r', 'p') #define MP4_cnam MP4_ID(0xa9, 'n', 'a', 'm') #define MP4_cwrt MP4_ID(0xa9, 'w', 'r', 't') #define MP4_esds MP4_ID('e', 's', 'd', 's') @@ -378,6 +379,11 @@ &id3->album); break; + case MP4_cgrp: + read_mp4_tag_string(fd, size, &buffer, &buffer_left, + &id3->grouping); + break; + case MP4_cwrt: read_mp4_tag_string(fd, size, &buffer, &buffer_left, &id3->composer); Index: apps/metadata/metadata_common.c =================================================================== --- apps/metadata/metadata_common.c (revision 13721) +++ apps/metadata/metadata_common.c (working copy) @@ -242,6 +242,18 @@ { p = &(id3->albumartist); } + else if (strcasecmp(name, "grouping") == 0) + { + p = &(id3->grouping); + } + else if (strcasecmp(name, "content group") == 0) + { + p = &(id3->grouping); + } + else if (strcasecmp(name, "contentgroup") == 0) + { + p = &(id3->grouping); + } else { len = parse_replaygain(name, value, id3, buf, buf_remaining); Index: apps/lang/deutsch.lang =================================================================== --- apps/lang/deutsch.lang (revision 13721) +++ apps/lang/deutsch.lang (working copy) @@ -10643,3 +10643,17 @@ *: "US/Kanada" + + id: LANG_ID3_GROUPING + desc: in tag viewer + user: + + *: "[Work]" + + + *: "[Werk]" + + + *: "" + + Index: apps/lang/english.lang =================================================================== --- apps/lang/english.lang (revision 13721) +++ apps/lang/english.lang (working copy) @@ -11006,3 +11006,17 @@ *: "Use File .talk Clips" + + id: LANG_ID3_GROUPING + desc: in tag viewer + user: + + *: "[Work]" + + + *: "[Work]" + + + *: "" + + Index: apps/gui/gwps-common.c =================================================================== --- apps/gui/gwps-common.c (revision 13721) +++ apps/gui/gwps-common.c (working copy) @@ -859,6 +859,9 @@ case WPS_TOKEN_METADATA_ALBUM_ARTIST: return id3->albumartist; + case WPS_TOKEN_METADATA_GROUPING: + return id3->grouping; + case WPS_TOKEN_METADATA_GENRE: return id3->genre_string; Index: apps/gui/wps_debug.c =================================================================== --- apps/gui/wps_debug.c (revision 13721) +++ apps/gui/wps_debug.c (working copy) @@ -289,6 +289,11 @@ next_str(next)); break; + case WPS_TOKEN_METADATA_GROUPING: + snprintf(buf, sizeof(buf), "%strack grouping", + next_str(next)); + break; + case WPS_TOKEN_METADATA_GENRE: snprintf(buf, sizeof(buf), "%strack genre", next_str(next)); Index: apps/gui/gwps.h =================================================================== --- apps/gui/gwps.h (revision 13721) +++ apps/gui/gwps.h (working copy) @@ -191,6 +191,7 @@ WPS_TOKEN_METADATA_ARTIST, WPS_TOKEN_METADATA_COMPOSER, WPS_TOKEN_METADATA_ALBUM_ARTIST, + WPS_TOKEN_METADATA_GROUPING, WPS_TOKEN_METADATA_ALBUM, WPS_TOKEN_METADATA_GENRE, WPS_TOKEN_METADATA_TRACK_NUMBER, Index: apps/gui/wps_parser.c =================================================================== --- apps/gui/wps_parser.c (revision 13721) +++ apps/gui/wps_parser.c (working copy) @@ -200,6 +200,7 @@ { WPS_TOKEN_METADATA_COMPOSER, "ic", WPS_REFRESH_STATIC, NULL }, { WPS_TOKEN_METADATA_ALBUM, "id", WPS_REFRESH_STATIC, NULL }, { WPS_TOKEN_METADATA_ALBUM_ARTIST, "iA", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_METADATA_GROUPING, "iG", WPS_REFRESH_STATIC, NULL }, { WPS_TOKEN_METADATA_GENRE, "ig", WPS_REFRESH_STATIC, NULL }, { WPS_TOKEN_METADATA_TRACK_NUMBER, "in", WPS_REFRESH_STATIC, NULL }, { WPS_TOKEN_METADATA_TRACK_TITLE, "it", WPS_REFRESH_STATIC, NULL }, @@ -212,6 +213,7 @@ { WPS_TOKEN_METADATA_COMPOSER, "Ic", WPS_REFRESH_DYNAMIC, NULL }, { WPS_TOKEN_METADATA_ALBUM, "Id", WPS_REFRESH_DYNAMIC, NULL }, { WPS_TOKEN_METADATA_ALBUM_ARTIST, "IA", WPS_REFRESH_DYNAMIC, NULL }, + { WPS_TOKEN_METADATA_GROUPING, "IG", WPS_REFRESH_DYNAMIC, NULL }, { WPS_TOKEN_METADATA_GENRE, "Ig", WPS_REFRESH_DYNAMIC, NULL }, { WPS_TOKEN_METADATA_TRACK_NUMBER, "In", WPS_REFRESH_DYNAMIC, NULL }, { WPS_TOKEN_METADATA_TRACK_TITLE, "It", WPS_REFRESH_DYNAMIC, NULL }, Index: apps/tagcache.c =================================================================== --- apps/tagcache.c (revision 13721) +++ apps/tagcache.c (working copy) @@ -108,11 +108,11 @@ /* 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_title }; + tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_title }; /* 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_composer, tag_comment, tag_albumartist, tag_grouping }; /* Numeric tags (we can use these tags with conditional clauses). */ static const int numeric_tags[] = { tag_year, tag_tracknumber, tag_length, @@ -123,7 +123,7 @@ /* 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", "year", "tracknumber", + "filename", "composer", "comment", "albumartist", "grouping", "year", "tracknumber", "bitrate", "length", "playcount", "rating", "playtime", "lastplayed", "commitid" }; /* Status information of the tagcache. */ @@ -170,7 +170,7 @@ /* For the endianess correction */ static const char *tagfile_entry_ec = "ss"; -static const char *index_entry_ec = "llllllllllllllllll"; /* (1 + TAG_COUNT) * l */ +static const char *index_entry_ec = "lllllllllllllllllll"; /* (1 + TAG_COUNT) * l */ static const char *tagcache_header_ec = "lll"; static const char *master_header_ec = "llllll"; @@ -1531,6 +1531,7 @@ id3->composer = get_tag_string(entry, tag_composer); id3->comment = get_tag_string(entry, tag_comment); id3->albumartist = get_tag_string(entry, tag_albumartist); + id3->grouping = get_tag_string(entry, tag_grouping); id3->playcount = get_tag_numeric(entry, tag_playcount); id3->rating = get_tag_numeric(entry, tag_rating); @@ -1596,6 +1597,7 @@ int offset = 0; int path_length = strlen(path); bool has_albumartist; + bool has_grouping; if (cachefd < 0) return ; @@ -1688,6 +1690,8 @@ /* String tags. */ has_albumartist = track.id3.albumartist != NULL && strlen(track.id3.albumartist) > 0; + has_grouping = track.id3.grouping != NULL + && strlen(track.id3.grouping) > 0; ADD_TAG(entry, tag_filename, &path); ADD_TAG(entry, tag_title, &track.id3.title); @@ -1704,6 +1708,14 @@ { ADD_TAG(entry, tag_albumartist, &track.id3.artist); } + if (has_grouping) + { + ADD_TAG(entry, tag_grouping, &track.id3.grouping); + } + else + { + ADD_TAG(entry, tag_grouping, &track.id3.title); + } entry.data_length = offset; /* Write the header */ @@ -1725,6 +1737,14 @@ { write_item(track.id3.artist); } + if (has_grouping) + { + write_item(track.id3.grouping); + } + else + { + write_item(track.id3.title); + } total_entry_count++; } Index: apps/tagcache.h =================================================================== --- apps/tagcache.h (revision 13721) +++ apps/tagcache.h (working copy) @@ -23,7 +23,7 @@ #include "id3.h" enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, - tag_filename, tag_composer, tag_comment, tag_albumartist, tag_year, + tag_filename, tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_year, tag_tracknumber, tag_bitrate, tag_length, tag_playcount, tag_rating, tag_playtime, tag_lastplayed, tag_commitid, /* Virtual tags */ @@ -31,7 +31,7 @@ tag_virt_playtime_min, tag_virt_playtime_sec, tag_virt_entryage, tag_virt_autoscore }; -#define TAG_COUNT 17 +#define TAG_COUNT 18 /* Maximum length of a single tag. */ #define TAG_MAXLEN (MAX_PATH*2) @@ -43,7 +43,7 @@ #define IDX_BUF_DEPTH 64 /* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */ -#define TAGCACHE_MAGIC 0x54434809 +#define TAGCACHE_MAGIC 0x5443480a /* How much to allocate extra space for ramcache. */ #define TAGCACHE_RESERVE 32768 Index: apps/tagtree.c =================================================================== --- apps/tagtree.c (revision 13721) +++ apps/tagtree.c (working copy) @@ -200,6 +200,8 @@ MATCH(tag, buf, "comment", tag_comment); MATCH(tag, buf, "albumartist", tag_albumartist); MATCH(tag, buf, "ensemble", tag_albumartist); + MATCH(tag, buf, "grouping", tag_grouping); + MATCH(tag, buf, "contentgroup", tag_grouping); 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 13721) +++ firmware/export/id3.h (working copy) @@ -149,6 +149,7 @@ char* composer; char* comment; char* albumartist; + char* grouping; int tracknum; int version; int layer; Index: firmware/id3.c =================================================================== --- firmware/id3.c (revision 13721) +++ firmware/id3.c (working copy) @@ -449,7 +449,9 @@ { "TYE", 3, offsetof(struct mp3entry, year_string), &parseyearnum, false }, { "TCOM", 4, offsetof(struct mp3entry, composer), NULL, false }, { "TPE2", 4, offsetof(struct mp3entry, albumartist), NULL, false }, - { "TP2", 3, offsetof(struct mp3entry, albumartist), NULL, false }, + { "TP2", 3, offsetof(struct mp3entry, albumartist), NULL, false }, + { "TIT1", 4, offsetof(struct mp3entry, grouping), NULL, false }, + { "TT1", 3, offsetof(struct mp3entry, grouping), NULL, false }, { "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 }, @@ -1178,6 +1180,8 @@ entry->comment += offset; if (entry->albumartist) entry->albumartist += offset; + if (entry->grouping) + entry->grouping += offset; #if CONFIG_CODEC == SWCODEC if (entry->track_gain_string) entry->track_gain_string += offset;