summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/playback.c3
-rw-r--r--apps/tagcache.c246
-rw-r--r--apps/tagcache.h8
-rw-r--r--apps/tagtree.c49
4 files changed, 279 insertions, 27 deletions
diff --git a/apps/playback.c b/apps/playback.c
index 7b20beba23..eab6fd104f 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -2130,6 +2130,8 @@ struct mp3entry* audio_current_track(void)
if (track_count > 0 && cur_ti->taginfo_ready)
return (struct mp3entry *)&cur_ti->id3;
+ memset(&temp_id3, 0, sizeof(struct mp3entry));
+
filename = playlist_peek(0);
if (!filename)
filename = "No file!";
@@ -2145,7 +2147,6 @@ struct mp3entry* audio_current_track(void)
else
p++;
- memset(&temp_id3, 0, sizeof(struct mp3entry));
strncpy(temp_id3.path, p, sizeof(temp_id3.path)-1);
temp_id3.title = &temp_id3.path[0];
diff --git a/apps/tagcache.c b/apps/tagcache.c
index 5214e508e8..bc463ab142 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -32,6 +32,7 @@
#include "lang.h"
#include "tagcache.h"
#include "buffer.h"
+#include "atoi.h"
/* Tag Cache thread. */
static struct event_queue tagcache_queue;
@@ -50,8 +51,9 @@ static long tempbuf_left; /* Buffer space left. */
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_title };
-static const int unique_tags[] = { tag_artist, tag_album, tag_genre };
+static const int sorted_tags[] = { tag_artist, tag_album, tag_genre, tag_composer, tag_title };
+static const int unique_tags[] = { tag_artist, tag_album, tag_genre, tag_composer };
+static const int numeric_tags[] = { tag_year, tag_tracknumber, tag_length, tag_bitrate };
/* Queue commands. */
#define Q_STOP_SCAN 0
@@ -63,15 +65,15 @@ static const int unique_tags[] = { tag_artist, tag_album, tag_genre };
#define TAGCACHE_FILE_MASTER ROCKBOX_DIR "/tagcache_idx.tcd"
#define TAGCACHE_FILE_INDEX ROCKBOX_DIR "/tagcache_%d.tcd"
+/* Tag Cache Header version 'TCHxx' */
+#define TAGCACHE_MAGIC 0x54434801
+
/* Tag database structures. */
-#define TAGCACHE_MAGIC 0x01020317
/* Variable-length tag entry in tag files. */
struct tagfile_entry {
short tag_length;
-#ifdef ROCKBOX_STRICT_ALIGN
- short padding;
-#endif
+ short idx_id;
char tag_data[0];
};
@@ -118,6 +120,7 @@ struct tempbuf_id {
struct tempbuf_searchidx {
struct tempbuf_id *id;
+ long idx_id;
char *str;
int seek;
};
@@ -129,6 +132,19 @@ static int total_entry_count = 0;
static int data_size = 0;
static int processed_dir_count;
+static bool is_numeric_tag(int type)
+{
+ int i;
+
+ for (i = 0; i < (int)(sizeof(numeric_tags)/sizeof(numeric_tags[0])); i++)
+ {
+ if (type == numeric_tags[i])
+ return true;
+ }
+
+ return false;
+}
+
#ifdef HAVE_TC_RAMCACHE
static struct index_entry *find_entry_ram(const char *filename,
const struct dircache_entry *dc)
@@ -308,6 +324,50 @@ static struct index_entry *find_entry_disk(const char *filename, bool retrieve)
return &idx;
}
+long tagcache_get_numeric(const struct tagcache_search *tcs, int tag)
+{
+ struct tagcache_header tch;
+ struct index_entry idx;
+ int masterfd;
+
+ if (!is_numeric_tag(tag))
+ return -1;
+
+#ifdef HAVE_TC_RAMCACHE
+ if (tcs->ramsearch)
+ {
+ return hdr->indices[tcs->idx_id].tag_seek[tag];
+ }
+#endif
+
+ masterfd = open(TAGCACHE_FILE_MASTER, O_RDONLY);
+
+ if (masterfd < 0)
+ {
+ logf("open fail");
+ return -2;
+ }
+
+ if (read(masterfd, &tch, sizeof(struct tagcache_header)) !=
+ sizeof(struct tagcache_header) || tch.magic != TAGCACHE_MAGIC)
+ {
+ logf("header error");
+ return -3;
+ }
+
+ lseek(masterfd, tcs->idx_id * sizeof(struct index_entry), SEEK_CUR);
+ if (read(masterfd, &idx, sizeof(struct index_entry)) !=
+ sizeof(struct index_entry))
+ {
+ logf("read error #3");
+ close(masterfd);
+ return -4;
+ }
+ close(masterfd);
+
+ return idx.tag_seek[tag];
+}
+
static bool build_lookup_list(struct tagcache_search *tcs)
{
struct tagcache_header header;
@@ -443,6 +503,9 @@ bool tagcache_search(struct tagcache_search *tcs, int tag)
else
#endif
{
+ if (is_numeric_tag(tcs->type))
+ return true;
+
snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, tcs->type);
tcs->fd = open(buf, O_RDONLY);
if (tcs->fd < 0)
@@ -484,13 +547,17 @@ bool tagcache_get_next(struct tagcache_search *tcs)
if (!tcs->valid)
return false;
- if (tcs->fd < 0
+ if (tcs->fd < 0 && !is_numeric_tag(tcs->type)
#ifdef HAVE_TC_RAMCACHE
&& !tcs->ramsearch
#endif
)
return false;
+ /* Searching not supported for numeric tags yet. */
+ if (is_numeric_tag(tcs->type))
+ return false;
+
/* Relative fetch. */
if (tcs->filter_count > 0)
{
@@ -539,6 +606,7 @@ bool tagcache_get_next(struct tagcache_search *tcs)
tcs->position += sizeof(struct tagfile_entry) + ep->tag_length;
tcs->result = ep->tag_data;
tcs->result_len = ep->tag_length;
+ tcs->idx_id = ep->idx_id;
return true;
}
@@ -571,6 +639,7 @@ bool tagcache_get_next(struct tagcache_search *tcs)
tcs->result = buf;
tcs->result_len = entry.tag_length;
+ tcs->idx_id = entry.idx_id;
return true;
}
@@ -609,7 +678,7 @@ void tagcache_search_finish(struct tagcache_search *tcs)
}
#ifdef HAVE_TC_RAMCACHE
-struct tagfile_entry *get_tag(struct index_entry *entry, int tag)
+static struct tagfile_entry *get_tag(struct index_entry *entry, int tag)
{
return (struct tagfile_entry *)&hdr->tags[tag][entry->tag_seek[tag]];
}
@@ -627,6 +696,7 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename)
id3->artist = get_tag(entry, tag_artist)->tag_data;
id3->album = get_tag(entry, tag_album)->tag_data;
id3->genre_string = get_tag(entry, tag_genre)->tag_data;
+ id3->composer = get_tag(entry, tag_composer)->tag_data;
return true;
}
@@ -658,6 +728,7 @@ static void add_tagcache(const char *path)
struct temp_file_entry entry;
bool ret;
int fd;
+ char tracknumfix[3];
//uint32_t crcbuf[CRC_BUF_LEN];
if (cachefd < 0)
@@ -689,6 +760,8 @@ static void add_tagcache(const char *path)
}
memset(&track, 0, sizeof(struct track_info));
+ memset(&entry, 0, sizeof(struct temp_file_entry));
+ memset(&tracknumfix, 0, sizeof(tracknumfix));
ret = get_metadata(&track, fd, path, false);
close(fd);
@@ -699,19 +772,51 @@ static void add_tagcache(const char *path)
check_if_empty(&track.id3.artist);
check_if_empty(&track.id3.album);
check_if_empty(&track.id3.genre_string);
+ check_if_empty(&track.id3.composer);
entry.tag_length[tag_filename] = strlen(path) + 1;
entry.tag_length[tag_title] = strlen(track.id3.title) + 1;
entry.tag_length[tag_artist] = strlen(track.id3.artist) + 1;
entry.tag_length[tag_album] = strlen(track.id3.album) + 1;
entry.tag_length[tag_genre] = strlen(track.id3.genre_string) + 1;
+ entry.tag_length[tag_composer] = strlen(track.id3.composer) + 1;
entry.tag_offset[tag_filename] = 0;
entry.tag_offset[tag_title] = entry.tag_offset[tag_filename] + entry.tag_length[tag_filename];
entry.tag_offset[tag_artist] = entry.tag_offset[tag_title] + entry.tag_length[tag_title];
entry.tag_offset[tag_album] = entry.tag_offset[tag_artist] + entry.tag_length[tag_artist];
entry.tag_offset[tag_genre] = entry.tag_offset[tag_album] + entry.tag_length[tag_album];
- entry.data_length = entry.tag_offset[tag_genre] + entry.tag_length[tag_genre];
+ entry.tag_offset[tag_composer] = entry.tag_offset[tag_genre] + entry.tag_length[tag_genre];
+ entry.data_length = entry.tag_offset[tag_composer] + entry.tag_length[tag_composer];
+
+ /* Numeric tags */
+ entry.tag_offset[tag_year] = track.id3.year;
+ entry.tag_offset[tag_tracknumber] = track.id3.tracknum;
+ entry.tag_offset[tag_length] = track.id3.length;
+ entry.tag_offset[tag_bitrate] = track.id3.bitrate;
+
+ if (entry.tag_offset[tag_tracknumber] <= 0)
+ {
+ int start, i;
+
+ for (start = 0; path[start] != '\0'; start++)
+ if (isdigit(path[start]))
+ break ;
+
+ for (i = 0; i < (int)sizeof(tracknumfix)-1
+ && path[start+i] != '\0'; i++)
+ {
+ if (isdigit(path[start+i]))
+ tracknumfix[i] = path[start+i];
+ else
+ break ;
+ }
+
+ if (tracknumfix[0] != '\0')
+ entry.tag_offset[tag_tracknumber] = atoi(tracknumfix);
+ else
+ entry.tag_offset[tag_tracknumber] = -1;
+ }
write(cachefd, &entry, sizeof(struct temp_file_entry));
write_item(path);
@@ -719,6 +824,7 @@ static void add_tagcache(const char *path)
write_item(track.id3.artist);
write_item(track.id3.album);
write_item(track.id3.genre_string);
+ write_item(track.id3.composer);
total_entry_count++;
}
@@ -730,12 +836,15 @@ static void remove_files(void)
remove(TAGCACHE_FILE_MASTER);
for (i = 0; i < TAG_COUNT; i++)
{
+ if (is_numeric_tag(i))
+ continue;
+
snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, i);
remove(buf);
}
}
-static bool tempbuf_insert(char *str, int id)
+static bool tempbuf_insert(char *str, int id, int idx_id)
{
struct tempbuf_searchidx *index = (struct tempbuf_searchidx *)tempbuf;
int len = strlen(str)+1;
@@ -759,6 +868,7 @@ static bool tempbuf_insert(char *str, int id)
#endif
index[tempbufidx].id->id = id;
index[tempbufidx].id->next = NULL;
+ index[tempbufidx].idx_id = idx_id;
tempbuf_pos += sizeof(struct tempbuf_id);
index[tempbufidx].seek = -1;
@@ -810,7 +920,7 @@ static bool tempbuf_unique_insert(char *str, int id)
}
}
- return tempbuf_insert(str, id);
+ return tempbuf_insert(str, id, -1);
}
static int compare(const void *p1, const void *p2)
@@ -845,6 +955,7 @@ static int tempbuf_sort(int fd)
index[i].seek = lseek(fd, 0, SEEK_CUR);
length = strlen(index[i].str) + 1;
fe.tag_length = length;
+ fe.idx_id = index[i].idx_id;
#ifdef ROCKBOX_STRICT_ALIGN
/* Make sure the entry is long aligned. */
@@ -944,6 +1055,102 @@ static bool is_sorted_tag(int type)
return false;
}
+static bool build_numeric_index(int index_type, struct tagcache_header *h, int tmpfd)
+{
+ struct tagcache_header tch;
+ struct index_entry idx;
+ int masterfd;
+ int masterfd_pos;
+ long *databuf = (long *)tempbuf;
+ int max_entries;
+ int i;
+
+ max_entries = tempbuf_size / sizeof(long);
+
+ if (h->entry_count >= max_entries)
+ {
+ logf("not enough space!");
+ return false;
+ }
+
+ logf("Building numeric index: %d", index_type);
+
+ /* Walk through the temporary file. */
+ lseek(tmpfd, sizeof(struct tagcache_header), SEEK_SET);
+ for (i = 0; i < h->entry_count; i++)
+ {
+ struct temp_file_entry entry;
+
+ if (read(tmpfd, &entry, sizeof(struct temp_file_entry)) !=
+ sizeof(struct temp_file_entry))
+ {
+ logf("read fail #1");
+ return false;
+ }
+
+ /* Insert data in buffer. */
+ databuf[i] = (long)entry.tag_offset[index_type];
+
+ /* Skip to next. */
+ lseek(tmpfd, entry.data_length, SEEK_CUR);
+ }
+
+ /* Update the entries in index. */
+ masterfd = open(TAGCACHE_FILE_MASTER, O_RDWR);
+
+ if (masterfd < 0)
+ {
+ logf("No master file found!");
+ return false;
+ }
+
+ if (read(masterfd, &tch, sizeof(struct tagcache_header)) !=
+ sizeof(struct tagcache_header) || tch.magic != TAGCACHE_MAGIC)
+ {
+ logf("header error");
+ close(masterfd);
+ return false;
+ }
+
+ masterfd_pos = lseek(masterfd, tch.entry_count * sizeof(struct index_entry),
+ SEEK_CUR);
+ if (masterfd_pos == filesize(masterfd))
+ {
+ logf("we can't append!");
+ close(masterfd);
+ return false;
+ }
+
+ for (i = 0; i < h->entry_count; i++)
+ {
+ int loc = lseek(masterfd, 0, SEEK_CUR);
+
+ if (read(masterfd, &idx, sizeof(struct index_entry)) !=
+ sizeof(struct index_entry))
+ {
+ logf("read fail #2");
+ close(masterfd);
+ return false;
+ }
+
+ idx.tag_seek[index_type] = databuf[i];
+
+ /* Write back the updated index. */
+ lseek(masterfd, loc, SEEK_SET);
+ if (write(masterfd, &idx, sizeof(struct index_entry)) !=
+ sizeof(struct index_entry))
+ {
+ logf("write fail");
+ close(masterfd);
+ return false;
+ }
+ }
+
+ close(masterfd);
+
+ return true;
+}
+
static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
{
int i;
@@ -1020,7 +1227,7 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
* is saved so we can later reindex the master lookup
* table when the index gets resorted.
*/
- tempbuf_insert(buf, loc + TAGFILE_MAX_ENTRIES);
+ tempbuf_insert(buf, loc + TAGFILE_MAX_ENTRIES, entry.idx_id);
}
}
else
@@ -1149,7 +1356,7 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
if (is_unique_tag(index_type))
error = !tempbuf_unique_insert(buf, i);
else
- error = !tempbuf_insert(buf, i);
+ error = !tempbuf_insert(buf, i, tch.entry_count + i);
if (error)
{
@@ -1268,6 +1475,7 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
/* Write to index file. */
idx.tag_seek[index_type] = lseek(fd, 0, SEEK_CUR);
fe.tag_length = entry.tag_length[index_type];
+ fe.idx_id = tch.entry_count + i;
write(fd, &fe, sizeof(struct tagfile_entry));
write(fd, buf, fe.tag_length);
tempbufidx++;
@@ -1375,7 +1583,12 @@ static bool commit(void)
/* Now create the index files. */
for (i = 0; i < TAG_COUNT; i++)
{
- if (!build_index(i, &header, tmpfd))
+ if (is_numeric_tag(i))
+ {
+ build_numeric_index(i, &header, tmpfd);
+ }
+
+ else if (!build_index(i, &header, tmpfd))
{
logf("tagcache failed init");
remove_files();
@@ -1537,6 +1750,9 @@ static bool load_tagcache(void)
struct tagfile_entry *fe;
char buf[MAX_PATH];
+ if (is_numeric_tag(i))
+ continue ;
+
//p = ((void *)p+1);
p = (char *)((long)p & ~0x03) + 0x04;
hdr->tags[i] = p;
@@ -1854,7 +2070,7 @@ static void tagcache_thread(void)
int tagcache_get_progress(void)
{
- int total_count = -1;
+ int total_count = processed_dir_count;
#ifdef HAVE_DIRCACHE
if (dircache_is_enabled())
diff --git a/apps/tagcache.h b/apps/tagcache.h
index 04125e1d5e..ddbb8e1dac 100644
--- a/apps/tagcache.h
+++ b/apps/tagcache.h
@@ -22,8 +22,10 @@
#include "id3.h"
enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
- tag_filename/*, tag_checksum*/ };
-#define TAG_COUNT 5
+ tag_filename, tag_composer, tag_year, tag_tracknumber,
+ tag_bitrate, tag_length };
+
+#define TAG_COUNT 10
#ifdef HAVE_DIRCACHE
#define HAVE_TC_RAMCACHE 1
@@ -47,6 +49,7 @@ struct tagcache_search {
int filter_count;
int seek_list_count;
int seek_pos;
+ int idx_id;
long position;
int entry_count;
bool valid;
@@ -64,6 +67,7 @@ bool tagcache_search_add_filter(struct tagcache_search *tcs,
int tag, int seek);
bool tagcache_get_next(struct tagcache_search *tcs);
void tagcache_search_finish(struct tagcache_search *tcs);
+long tagcache_get_numeric(const struct tagcache_search *tcs, int tag);
int tagcache_get_progress(void);
#ifdef HAVE_TC_RAMCACHE
diff --git a/apps/tagtree.c b/apps/tagtree.c
index cb4135c204..bfa203dfeb 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -38,8 +38,6 @@
#include "keyboard.h"
#include "gui/list.h"
-#define CHUNKED_NEXT -2
-
static int tagtree_play_folder(struct tree_context* c);
static int tagtree_search(struct tree_context* c, char* string);
@@ -52,11 +50,20 @@ struct tagentry {
static struct tagcache_search tcs;
+static int compare(const void *p1, const void *p2)
+{
+ struct tagentry *e1 = (struct tagentry *)p1;
+ struct tagentry *e2 = (struct tagentry *)p2;
+
+ return strncasecmp(e1->name, e2->name, MAX_PATH);
+}
+
int tagtree_load(struct tree_context* c)
{
int i;
int namebufused = 0;
struct tagentry *dptr = (struct tagentry *)c->dircache;
+ bool sort = false;
int table = c->currtable;
int extra = c->currextra;
@@ -153,18 +160,21 @@ int tagtree_load(struct tree_context* c)
logf("artist4genres..");
tagcache_search(&tcs, tag_artist);
tagcache_search_add_filter(&tcs, tag_genre, extra);
+ sort = true;
break;
case albums4artist:
logf("albums4artist..");
tagcache_search(&tcs, tag_album);
tagcache_search_add_filter(&tcs, tag_artist, extra);
+ sort = true;
break;
case songs4album:
logf("songs4album..");
tagcache_search(&tcs, tag_title);
tagcache_search_add_filter(&tcs, tag_album, extra);
+ sort = true;
if (extra2 > 0)
tagcache_search_add_filter(&tcs, tag_artist, extra2);
break;
@@ -173,6 +183,7 @@ int tagtree_load(struct tree_context* c)
logf("songs4artist..");
tagcache_search(&tcs, tag_title);
tagcache_search_add_filter(&tcs, tag_artist, extra);
+ sort = true;
break;
case chunked_next:
@@ -190,20 +201,37 @@ int tagtree_load(struct tree_context* c)
while (tagcache_get_next(&tcs))
{
dptr->newtable = tcs.result_seek;
- if (!tcs.ramsearch)
+ if (!tcs.ramsearch || table == songs4album)
{
dptr->name = &c->name_buffer[namebufused];
- namebufused += tcs.result_len;
- if (namebufused > c->name_buffer_size)
+ if (table == songs4album)
{
- logf("buffer full, 1 entry missed.");
- c->dirfull = true;
- break ;
+ snprintf(dptr->name, c->name_buffer_size - namebufused, "%02d. %s",
+ tagcache_get_numeric(&tcs, tag_tracknumber),
+ tcs.result);
+ namebufused += strlen(dptr->name) + 1;
+ if (namebufused >= c->name_buffer_size)
+ {
+ logf("buffer full, 1 entry missed.");
+ c->dirfull = true;
+ break ;
+ }
+ }
+ else
+ {
+ namebufused += tcs.result_len;
+ if (namebufused >= c->name_buffer_size)
+ {
+ logf("buffer full, 1 entry missed.");
+ c->dirfull = true;
+ break ;
+ }
+ strcpy(dptr->name, tcs.result);
}
- strcpy(dptr->name, tcs.result);
}
else
dptr->name = tcs.result;
+
dptr++;
i++;
@@ -220,6 +248,9 @@ int tagtree_load(struct tree_context* c)
}
+ if (sort)
+ qsort(c->dircache, i, c->dentry_size, compare);
+
if (c->dirfull)
{
dptr->name = "===>";