Index: apps/gui/gwps-common.c =================================================================== --- apps/gui/gwps-common.c (revision 14243) +++ apps/gui/gwps-common.c (working copy) @@ -960,6 +960,14 @@ (id3->frequency % 1000) / 100); return buf; + case WPS_TOKEN_FILE_AART: + *intval = id3->albumart; + return aa_strings[(*intval)++]; + + case WPS_TOKEN_FILE_LYRICS: + *intval = id3->lyrics; + return lyr_strings[(*intval)++]; + case WPS_TOKEN_FILE_NAME: if (get_dir(buf, buf_size, id3->path, 0)) { /* Remove extension */ Index: apps/gui/gwps.h =================================================================== --- apps/gui/gwps.h (revision 14243) +++ apps/gui/gwps.h (working copy) @@ -171,6 +171,8 @@ WPS_TOKEN_FILE_CODEC, WPS_TOKEN_FILE_FREQUENCY, WPS_TOKEN_FILE_FREQUENCY_KHZ, + WPS_TOKEN_FILE_AART, + WPS_TOKEN_FILE_LYRICS, WPS_TOKEN_FILE_NAME, WPS_TOKEN_FILE_NAME_WITH_EXTENSION, WPS_TOKEN_FILE_PATH, Index: apps/gui/wps_parser.c =================================================================== --- apps/gui/wps_parser.c (revision 14243) +++ apps/gui/wps_parser.c (working copy) @@ -173,6 +173,8 @@ { WPS_TOKEN_FILE_BITRATE, "fb", WPS_REFRESH_STATIC, NULL }, { WPS_TOKEN_FILE_CODEC, "fc", WPS_REFRESH_STATIC, NULL }, { WPS_TOKEN_FILE_FREQUENCY, "ff", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_FILE_AART, "fa", WPS_REFRESH_STATIC, NULL }, + { WPS_TOKEN_FILE_LYRICS, "fl", WPS_REFRESH_STATIC, NULL }, { WPS_TOKEN_FILE_FREQUENCY_KHZ, "fk", WPS_REFRESH_STATIC, NULL }, { WPS_TOKEN_FILE_NAME_WITH_EXTENSION, "fm", WPS_REFRESH_STATIC, NULL }, { WPS_TOKEN_FILE_NAME, "fn", WPS_REFRESH_STATIC, NULL }, @@ -186,6 +188,8 @@ { WPS_TOKEN_FILE_BITRATE, "Fb", WPS_REFRESH_DYNAMIC, NULL }, { WPS_TOKEN_FILE_CODEC, "Fc", WPS_REFRESH_DYNAMIC, NULL }, { WPS_TOKEN_FILE_FREQUENCY, "Ff", WPS_REFRESH_DYNAMIC, NULL }, + { WPS_TOKEN_FILE_AART, "Fa", WPS_REFRESH_DYNAMIC, NULL }, + { WPS_TOKEN_FILE_LYRICS, "Fl", WPS_REFRESH_DYNAMIC, NULL }, { WPS_TOKEN_FILE_FREQUENCY_KHZ, "Fk", WPS_REFRESH_DYNAMIC, NULL }, { WPS_TOKEN_FILE_NAME_WITH_EXTENSION, "Fm", WPS_REFRESH_DYNAMIC, NULL }, { WPS_TOKEN_FILE_NAME, "Fn", WPS_REFRESH_DYNAMIC, NULL }, Index: apps/metadata.c =================================================================== --- apps/metadata.c (revision 14243) +++ apps/metadata.c (working copy) @@ -23,6 +23,7 @@ #include #include "system.h" +#include "dircache.h" #include "playback.h" #include "debug.h" #include "logf.h" @@ -60,6 +61,102 @@ #endif /* CONFIG_CODEC == SWCODEC */ +#if LCD_DEPTH > 2 +#define AA_EXT ".bmp" +#else +#define AA_EXT ".jpg" +#endif + +unsigned char aa_strings[4][6] = {"NONE", "FILE", "ALBUM", "DIR"}; + +/* checks for existence of file if possible using dircache */ +bool exists(const char* pathname) { + + bool found = false; + int fd; + +/* debugf("EXISTS %s?\n", pathname);*/ + +#ifdef HAVE_DIRCACHE + if(dircache_is_enabled()) + found = (NULL != dircache_get_entry_ptr(pathname)); + else +#endif + + { + fd=open(pathname, O_RDONLY); + if(fd>-1) { + close(fd); + found = true; + } + } + return found; + +} + +void has_albumart(struct mp3entry* id3) { + + int found = 0; + unsigned char *path, *dot, *slash; + int length, alength; + + /* is valid id3 ? */ + if(!(id3 && (path=id3->path) && (dot=strrchr(path,'.')))) + return; + + length=dot-path; + + /* try .jpg */ + memcpy(path+length,AA_EXT,5); + if(exists(path)) found = 1; + + slash=strrchr(path,'/'); + length = slash ? slash-path+1 : 0; + + /* try .jpg */ + if((!found) && (id3->album != NULL)){ + + alength = strlen(id3->album); + memcpy(path+length,id3->album,alength); + + memcpy(path+length+alength,AA_EXT,5); + if(exists(path)) found = 2; + } + + /* try folder.jpg */ + if(!found){ + memcpy(path+length,"folder" AA_EXT,11); + if(exists(path)) found = 3; + } + + id3->albumart = found; + +} + +unsigned char lyr_strings[5][5] = {"NONE", "LRC8", "LRC", "SNC", "TXT"}; + +void has_lyrics(struct mp3entry* id3) { + + + int found = 0; + unsigned char *path, *dot; + int length, i; + + /* is valid id3 ? */ + if(!(id3 && (path=id3->path) && (dot=strrchr(path,'.')))) + return; + + length=dot-path+1; + + for(i=1; (i<5) && (found==0); i++) { + memcpy(path+length,lyr_strings[i],strlen(lyr_strings[i])+1); + if(exists(path)) found = i; + } + + id3->lyrics = found; + +} + /* Simple file type probing by looking at the filename extension. */ unsigned int probe_file_format(const char *filename) { @@ -375,6 +472,13 @@ strncpy(track->id3.path, trackname, sizeof(track->id3.path)); track->taginfo_ready = true; + has_lyrics(id3); +/* only changes extensions - no need to restore path */ +/* strncpy(id3->path, trackname, sizeof(id3->path)); */ + + has_albumart(id3); + strncpy(id3->path, trackname, sizeof(id3->path)); + return true; } Index: apps/tagcache.c =================================================================== --- apps/tagcache.c (revision 14243) +++ apps/tagcache.c (working copy) @@ -115,15 +115,15 @@ 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, +static const int numeric_tags[] = { tag_year, tag_lyrics, tag_albumart, tag_discnumber, tag_tracknumber, tag_length, tag_bitrate, tag_playcount, tag_rating, tag_playtime, tag_lastplayed, tag_commitid, tag_virt_length_min, tag_virt_length_sec, tag_virt_playtime_min, tag_virt_playtime_sec, - tag_virt_entryage, tag_virt_autoscore }; + tag_virt_entryage, tag_virt_autoscore, tag_virt_relplay }; /* 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", + "filename", "composer", "comment", "albumartist", "grouping", "year", "lyrics", "albumart", "discnumber", "tracknumber", "bitrate", "length", "playcount", "rating", "playtime", "lastplayed", "commitid" }; /* Status information of the tagcache. */ @@ -188,7 +188,7 @@ /* For the endianess correction */ static const char *tagfile_entry_ec = "ss"; -static const char *index_entry_ec = "llllllllllllllllllll"; /* (1 + TAG_COUNT) * l */ +static const char *index_entry_ec = "llllllllllllllllllllll"; /* (1 + TAG_COUNT) * l */ static const char *tagcache_header_ec = "lll"; static const char *master_header_ec = "llllll"; @@ -711,6 +711,7 @@ data = (idx->tag_seek[tag_playtime]/1000) / 60; break; + case tag_virt_relplay: case tag_virt_autoscore: if (idx->tag_seek[tag_length] == 0 || idx->tag_seek[tag_playcount] == 0) @@ -720,8 +721,10 @@ else { data = 100 * idx->tag_seek[tag_playtime] - / idx->tag_seek[tag_length] - / idx->tag_seek[tag_playcount]; + / idx->tag_seek[tag_length]; + + if(tag == tag_virt_autoscore) + data /= idx->tag_seek[tag_playcount]; } break; @@ -1553,6 +1556,8 @@ id3->playcount = get_tag_numeric(entry, tag_playcount); id3->rating = get_tag_numeric(entry, tag_rating); + id3->lyrics = get_tag_numeric(entry, tag_lyrics); + id3->albumart = get_tag_numeric(entry, tag_albumart); id3->lastplayed = get_tag_numeric(entry, tag_lastplayed); id3->score = get_tag_numeric(entry, tag_virt_autoscore) / 10; id3->year = get_tag_numeric(entry, tag_year); @@ -1702,6 +1707,8 @@ /* Numeric tags */ entry.tag_offset[tag_year] = track.id3.year; + entry.tag_offset[tag_lyrics] = track.id3.lyrics; + entry.tag_offset[tag_albumart] = track.id3.albumart; entry.tag_offset[tag_discnumber] = track.id3.discnum; entry.tag_offset[tag_tracknumber] = track.id3.tracknum; entry.tag_offset[tag_length] = track.id3.length; Index: apps/tagcache.h =================================================================== --- apps/tagcache.h (revision 14243) +++ apps/tagcache.h (working copy) @@ -24,14 +24,15 @@ 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_lyrics, tag_albumart, tag_discnumber, tag_tracknumber, tag_bitrate, tag_length, tag_playcount, tag_rating, tag_playtime, tag_lastplayed, tag_commitid, /* Virtual tags */ tag_virt_length_min, tag_virt_length_sec, tag_virt_playtime_min, tag_virt_playtime_sec, - tag_virt_entryage, tag_virt_autoscore }; + tag_virt_entryage, tag_virt_autoscore, tag_virt_relplay }; -#define TAG_COUNT 19 +#define TAG_COUNT 21 /* Maximum length of a single tag. */ #define TAG_MAXLEN (MAX_PATH*2) @@ -43,7 +44,7 @@ #define IDX_BUF_DEPTH 64 /* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */ -#define TAGCACHE_MAGIC 0x5443480b +#define TAGCACHE_MAGIC 0x54434882 /* How much to allocate extra space for ramcache. */ #define TAGCACHE_RESERVE 32768 Index: apps/tagtree.c =================================================================== --- apps/tagtree.c (revision 14243) +++ apps/tagtree.c (working copy) @@ -212,12 +212,15 @@ MATCH(tag, buf, "tracknum", tag_tracknumber); MATCH(tag, buf, "discnum", tag_discnumber); MATCH(tag, buf, "year", tag_year); + MATCH(tag, buf, "lyrics", tag_lyrics); + MATCH(tag, buf, "albumart", tag_albumart); MATCH(tag, buf, "playcount", tag_playcount); MATCH(tag, buf, "rating", tag_rating); MATCH(tag, buf, "lastplayed", tag_lastplayed); MATCH(tag, buf, "commitid", tag_commitid); MATCH(tag, buf, "entryage", tag_virt_entryage); MATCH(tag, buf, "autoscore", tag_virt_autoscore); + MATCH(tag, buf, "relplay", tag_virt_relplay); MATCH(tag, buf, "%sort", var_sorttype); MATCH(tag, buf, "%limit", var_limit); MATCH(tag, buf, "%strip", var_strip); @@ -636,6 +639,13 @@ id3->tagcache_idx = tcs.idx_id; tagcache_search_finish(&tcs); + + /* update potentially stale DB info */ + tagcache_update_numeric(id3->tagcache_idx, tag_year, id3->year); + tagcache_update_numeric(id3->tagcache_idx, tag_discnumber, id3->discnum); + tagcache_update_numeric(id3->tagcache_idx, tag_tracknumber, id3->tracknum); + tagcache_update_numeric(id3->tagcache_idx, tag_lyrics, id3->lyrics); + tagcache_update_numeric(id3->tagcache_idx, tag_albumart, id3->albumart); } static void tagtree_unbuffer_event(struct mp3entry *id3, bool last_track) @@ -684,6 +694,8 @@ tagcache_update_numeric(id3->tagcache_idx, tag_playcount, playcount); tagcache_update_numeric(id3->tagcache_idx, tag_playtime, playtime); tagcache_update_numeric(id3->tagcache_idx, tag_lastplayed, lastplayed); + + tagcache_update_numeric(id3->tagcache_idx, tag_rating, id3->rating); } bool tagtree_export(void) @@ -1182,6 +1194,11 @@ } else dptr->name = tcs->result; + + if(tcs->type == tag_lyrics) + dptr->name = lyr_strings[atoi(tcs->result)]; + else if(tcs->type == tag_albumart) + dptr->name = aa_strings[atoi(tcs->result)]; dptr++; current_entry_count++; Index: firmware/export/id3.h =================================================================== --- firmware/export/id3.h (revision 14243) +++ firmware/export/id3.h (working copy) @@ -29,6 +29,10 @@ /* NOTE: The values of the AFMT_* items are used for the %fc tag in the WPS - so new entries MUST be added to the end to maintain compatibility. */ + +extern unsigned char aa_strings[4][6]; +extern unsigned char lyr_strings[5][5]; + enum { AFMT_UNKNOWN = 0, /* Unknown file format */ @@ -204,6 +208,10 @@ long songentryoffset; long rundbentryoffset; + /* associated file indicators */ + short lyrics; + short albumart; + /* runtime database fields */ long tagcache_idx; short rating; Index: firmware/include/file.h =================================================================== --- firmware/include/file.h (revision 14243) +++ firmware/include/file.h (working copy) @@ -25,7 +25,7 @@ #undef MAX_PATH /* this avoids problems when building simulator */ #define MAX_PATH 260 -#define MAX_OPEN_FILES 11 +#define MAX_OPEN_FILES 14 #ifndef SEEK_SET #define SEEK_SET 0