diff --git a/apps/gui/gwps-common.c b/apps/gui/gwps-common.c index 82bf7541f2..3c74509ec8 100644 --- a/apps/gui/gwps-common.c +++ b/apps/gui/gwps-common.c @@ -866,6 +866,9 @@ static char *get_token_value(struct gui_wps *gwps, 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; diff --git a/apps/gui/gwps.h b/apps/gui/gwps.h index b02b87f2c9..83ff14b80b 100644 --- a/apps/gui/gwps.h +++ b/apps/gui/gwps.h @@ -191,6 +191,7 @@ enum wps_token_type { 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_DISC_NUMBER, diff --git a/apps/gui/wps_debug.c b/apps/gui/wps_debug.c index 50ffcce119..58e6ab49aa 100644 --- a/apps/gui/wps_debug.c +++ b/apps/gui/wps_debug.c @@ -289,6 +289,11 @@ static void dump_wps_tokens(struct wps_data *data) 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)); diff --git a/apps/gui/wps_parser.c b/apps/gui/wps_parser.c index d66e47dfe7..8471bff7d8 100644 --- a/apps/gui/wps_parser.c +++ b/apps/gui/wps_parser.c @@ -200,6 +200,7 @@ static const struct wps_tag all_tags[] = { { 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_DISC_NUMBER, "ik", WPS_REFRESH_STATIC, NULL }, { WPS_TOKEN_METADATA_TRACK_NUMBER, "in", WPS_REFRESH_STATIC, NULL }, @@ -213,6 +214,7 @@ static const struct wps_tag all_tags[] = { { 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_DISC_NUMBER, "Ik", WPS_REFRESH_DYNAMIC, NULL }, { WPS_TOKEN_METADATA_TRACK_NUMBER, "In", WPS_REFRESH_DYNAMIC, NULL }, diff --git a/apps/lang/deutsch.lang b/apps/lang/deutsch.lang index a50d021c4e..51ff6e454f 100644 --- a/apps/lang/deutsch.lang +++ b/apps/lang/deutsch.lang @@ -11017,3 +11017,17 @@ *: "Als Aufnahmeverzeichnis festlegen" + + id: LANG_ID3_GROUPING + desc: in tag viewer + user: + + *: "[Work]" + + + *: "[Werk]" + + + *: "" + + diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 6f631282f7..4fd4ecf54d 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -11004,3 +11004,17 @@ *: "Demos" + + id: LANG_ID3_GROUPING + desc: in tag viewer + user: + + *: "[Work]" + + + *: "[Work]" + + + *: "" + + diff --git a/apps/metadata/metadata_common.c b/apps/metadata/metadata_common.c index d1a1087188..e3579473f0 100644 --- a/apps/metadata/metadata_common.c +++ b/apps/metadata/metadata_common.c @@ -280,6 +280,18 @@ long parse_tag(const char* name, char* value, struct mp3entry* id3, { 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); diff --git a/apps/metadata/mp4.c b/apps/metadata/mp4.c index aecb4cf17f..8162cd987f 100644 --- a/apps/metadata/mp4.c +++ b/apps/metadata/mp4.c @@ -38,6 +38,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_cgen MP4_ID(0xa9, 'g', 'e', 'n') #define MP4_cnam MP4_ID(0xa9, 'n', 'a', 'm') #define MP4_cwrt MP4_ID(0xa9, 'w', 'r', 't') @@ -378,6 +379,11 @@ static bool read_mp4_tags(int fd, struct mp3entry* id3, &id3->albumartist); break; + case MP4_cgrp: + read_mp4_tag_string(fd, size, &buffer, &buffer_left, + &id3->grouping); + break; + case MP4_calb: read_mp4_tag_string(fd, size, &buffer, &buffer_left, &id3->album); diff --git a/apps/screens.c b/apps/screens.c index 1f0939ab8d..b74347405e 100644 --- a/apps/screens.c +++ b/apps/screens.c @@ -1151,6 +1151,7 @@ static const int id3_headers[]= LANG_ID3_ARTIST, LANG_ID3_ALBUM, LANG_ID3_ALBUMARTIST, + LANG_ID3_GROUPING, LANG_ID3_DISCNUM, LANG_ID3_TRACKNUM, LANG_ID3_COMMENT, @@ -1193,7 +1194,10 @@ static char * id3_get_info(int selected_item, void* data, char *buffer) case 3:/*LANG_ID3_ALBUMARTIST*/ info=id3->albumartist; break; - case 4:/*LANG_ID3_DISCNUM*/ + case 4:/*LANG_ID3_ALBUMARTIST*/ + info=id3->grouping; + break; + case 5:/*LANG_ID3_DISCNUM*/ if (id3->disc_string) info = id3->disc_string; else if (id3->discnum) @@ -1202,7 +1206,7 @@ static char * id3_get_info(int selected_item, void* data, char *buffer) info = buffer; } break; - case 5:/*LANG_ID3_TRACKNUM*/ + case 6:/*LANG_ID3_TRACKNUM*/ if (id3->track_string) info = id3->track_string; else if (id3->tracknum) @@ -1211,13 +1215,13 @@ static char * id3_get_info(int selected_item, void* data, char *buffer) info = buffer; } break; - case 6:/*LANG_ID3_COMMENT*/ + case 7:/*LANG_ID3_COMMENT*/ info=id3->comment; break; - case 7:/*LANG_ID3_GENRE*/ + case 8:/*LANG_ID3_GENRE*/ info = id3->genre_string; break; - case 8:/*LANG_ID3_YEAR*/ + case 9:/*LANG_ID3_YEAR*/ if (id3->year_string) info = id3->year_string; else if (id3->year) @@ -1226,34 +1230,34 @@ static char * id3_get_info(int selected_item, void* data, char *buffer) info = buffer; } break; - case 9:/*LANG_ID3_LENGTH*/ + case 10:/*LANG_ID3_LENGTH*/ format_time(buffer, MAX_PATH, id3->length); info=buffer; break; - case 10:/*LANG_ID3_PLAYLIST*/ + case 11:/*LANG_ID3_PLAYLIST*/ snprintf(buffer, MAX_PATH, "%d/%d", playlist_get_display_index(), playlist_amount()); info=buffer; break; - case 11:/*LANG_ID3_BITRATE*/ + case 12:/*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 12:/*LANG_ID3_FREQUENCY*/ + case 13:/*LANG_ID3_FREQUENCY*/ snprintf(buffer, MAX_PATH, "%ld Hz", id3->frequency); info=buffer; break; #if CONFIG_CODEC == SWCODEC - case 13:/*LANG_ID3_TRACK_GAIN*/ + case 14:/*LANG_ID3_TRACK_GAIN*/ info=id3->track_gain_string; break; - case 14:/*LANG_ID3_ALBUM_GAIN*/ + case 15:/*LANG_ID3_ALBUM_GAIN*/ info=id3->album_gain_string; break; - case 15:/*LANG_ID3_PATH*/ + case 16:/*LANG_ID3_PATH*/ #else - case 13:/*LANG_ID3_PATH*/ + case 17:/*LANG_ID3_PATH*/ #endif info=id3->path; break; diff --git a/apps/tagcache.c b/apps/tagcache.c index da51e0c4e9..309718a932 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c @@ -108,11 +108,11 @@ static long tempbuf_pos; /* 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_discnumber, tag_tracknumber, tag_length, @@ -123,7 +123,7 @@ static const int numeric_tags[] = { tag_year, tag_discnumber, tag_tracknumber, t /* 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", "discnumber", "tracknumber", + "filename", "composer", "comment", "albumartist", "grouping", "year", "discnumber", "tracknumber", "bitrate", "length", "playcount", "rating", "playtime", "lastplayed", "commitid" }; /* Status information of the tagcache. */ @@ -188,7 +188,7 @@ struct master_header { /* For the endianess correction */ static const char *tagfile_entry_ec = "ss"; -static const char *index_entry_ec = "lllllllllllllllllll"; /* (1 + TAG_COUNT) * l */ +static const char *index_entry_ec = "llllllllllllllllllll"; /* (1 + TAG_COUNT) * l */ static const char *tagcache_header_ec = "lll"; static const char *master_header_ec = "llllll"; @@ -1549,6 +1549,7 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename) 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); @@ -1615,6 +1616,7 @@ static void add_tagcache(char *path) int offset = 0; int path_length = strlen(path); bool has_albumartist; + bool has_grouping; if (cachefd < 0) return ; @@ -1708,6 +1710,8 @@ static void add_tagcache(char *path) /* 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); @@ -1724,6 +1728,14 @@ static void add_tagcache(char *path) { 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 */ @@ -1745,6 +1757,14 @@ static void add_tagcache(char *path) { write_item(track.id3.artist); } + if (has_grouping) + { + write_item(track.id3.grouping); + } + else + { + write_item(track.id3.title); + } total_entry_count++; } diff --git a/apps/tagcache.h b/apps/tagcache.h index ada624783a..118b4c4119 100644 --- a/apps/tagcache.h +++ b/apps/tagcache.h @@ -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_discnumber, tag_tracknumber, tag_bitrate, tag_length, tag_playcount, tag_rating, tag_playtime, tag_lastplayed, tag_commitid, /* Virtual tags */ @@ -31,7 +31,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, tag_virt_playtime_min, tag_virt_playtime_sec, tag_virt_entryage, tag_virt_autoscore }; -#define TAG_COUNT 18 +#define TAG_COUNT 19 /* Maximum length of a single tag. */ #define TAG_MAXLEN (MAX_PATH*2) @@ -43,7 +43,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, #define IDX_BUF_DEPTH 64 /* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */ -#define TAGCACHE_MAGIC 0x5443480A +#define TAGCACHE_MAGIC 0x5443480b /* How much to allocate extra space for ramcache. */ #define TAGCACHE_RESERVE 32768 diff --git a/apps/tagtree.c b/apps/tagtree.c index 59fb8c131f..f9ae0bebd3 100644 --- a/apps/tagtree.c +++ b/apps/tagtree.c @@ -200,6 +200,7 @@ static int get_tag(int *tag) 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, "genre", tag_genre); MATCH(tag, buf, "length", tag_length); MATCH(tag, buf, "Lm", tag_virt_length_min); diff --git a/docs/CREDITS b/docs/CREDITS index 84d8d9f528..4dbc2dfd84 100644 --- a/docs/CREDITS +++ b/docs/CREDITS @@ -311,6 +311,7 @@ Tobias Schladt John Zhou Charles Voelger Gerritt Gonzales +Dieter Pellkofer The libmad team The wavpack team The ffmpeg team diff --git a/firmware/export/id3.h b/firmware/export/id3.h index 8c91456040..2751fde6f5 100644 --- a/firmware/export/id3.h +++ b/firmware/export/id3.h @@ -153,6 +153,7 @@ struct mp3entry { char* composer; char* comment; char* albumartist; + char* grouping; int discnum; int tracknum; int version; diff --git a/firmware/id3.c b/firmware/id3.c index a66318b2fc..851aa83a5a 100644 --- a/firmware/id3.c +++ b/firmware/id3.c @@ -460,7 +460,9 @@ static const struct tag_resolver taglist[] = { { "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 }, @@ -1192,6 +1194,8 @@ void adjust_mp3entry(struct mp3entry *entry, void *dest, void *orig) 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;