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)
2130 if (track_count > 0 && cur_ti->taginfo_ready) 2130 if (track_count > 0 && cur_ti->taginfo_ready)
2131 return (struct mp3entry *)&cur_ti->id3; 2131 return (struct mp3entry *)&cur_ti->id3;
2132 2132
2133 memset(&temp_id3, 0, sizeof(struct mp3entry));
2134
2133 filename = playlist_peek(0); 2135 filename = playlist_peek(0);
2134 if (!filename) 2136 if (!filename)
2135 filename = "No file!"; 2137 filename = "No file!";
@@ -2145,7 +2147,6 @@ struct mp3entry* audio_current_track(void)
2145 else 2147 else
2146 p++; 2148 p++;
2147 2149
2148 memset(&temp_id3, 0, sizeof(struct mp3entry));
2149 strncpy(temp_id3.path, p, sizeof(temp_id3.path)-1); 2150 strncpy(temp_id3.path, p, sizeof(temp_id3.path)-1);
2150 temp_id3.title = &temp_id3.path[0]; 2151 temp_id3.title = &temp_id3.path[0];
2151 2152
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 @@
32#include "lang.h" 32#include "lang.h"
33#include "tagcache.h" 33#include "tagcache.h"
34#include "buffer.h" 34#include "buffer.h"
35#include "atoi.h"
35 36
36/* Tag Cache thread. */ 37/* Tag Cache thread. */
37static struct event_queue tagcache_queue; 38static struct event_queue tagcache_queue;
@@ -50,8 +51,9 @@ static long tempbuf_left; /* Buffer space left. */
50static long tempbuf_pos; 51static long tempbuf_pos;
51 52
52/* Tags we want to get sorted (loaded to the tempbuf). */ 53/* Tags we want to get sorted (loaded to the tempbuf). */
53static const int sorted_tags[] = { tag_artist, tag_album, tag_genre, tag_title }; 54static const int sorted_tags[] = { tag_artist, tag_album, tag_genre, tag_composer, tag_title };
54static const int unique_tags[] = { tag_artist, tag_album, tag_genre }; 55static const int unique_tags[] = { tag_artist, tag_album, tag_genre, tag_composer };
56static const int numeric_tags[] = { tag_year, tag_tracknumber, tag_length, tag_bitrate };
55 57
56/* Queue commands. */ 58/* Queue commands. */
57#define Q_STOP_SCAN 0 59#define Q_STOP_SCAN 0
@@ -63,15 +65,15 @@ static const int unique_tags[] = { tag_artist, tag_album, tag_genre };
63#define TAGCACHE_FILE_MASTER ROCKBOX_DIR "/tagcache_idx.tcd" 65#define TAGCACHE_FILE_MASTER ROCKBOX_DIR "/tagcache_idx.tcd"
64#define TAGCACHE_FILE_INDEX ROCKBOX_DIR "/tagcache_%d.tcd" 66#define TAGCACHE_FILE_INDEX ROCKBOX_DIR "/tagcache_%d.tcd"
65 67
68/* Tag Cache Header version 'TCHxx' */
69#define TAGCACHE_MAGIC 0x54434801
70
66/* Tag database structures. */ 71/* Tag database structures. */
67#define TAGCACHE_MAGIC 0x01020317
68 72
69/* Variable-length tag entry in tag files. */ 73/* Variable-length tag entry in tag files. */
70struct tagfile_entry { 74struct tagfile_entry {
71 short tag_length; 75 short tag_length;
72#ifdef ROCKBOX_STRICT_ALIGN 76 short idx_id;
73 short padding;
74#endif
75 char tag_data[0]; 77 char tag_data[0];
76}; 78};
77 79
@@ -118,6 +120,7 @@ struct tempbuf_id {
118 120
119struct tempbuf_searchidx { 121struct tempbuf_searchidx {
120 struct tempbuf_id *id; 122 struct tempbuf_id *id;
123 long idx_id;
121 char *str; 124 char *str;
122 int seek; 125 int seek;
123}; 126};
@@ -129,6 +132,19 @@ static int total_entry_count = 0;
129static int data_size = 0; 132static int data_size = 0;
130static int processed_dir_count; 133static int processed_dir_count;
131 134
135static bool is_numeric_tag(int type)
136{
137 int i;
138
139 for (i = 0; i < (int)(sizeof(numeric_tags)/sizeof(numeric_tags[0])); i++)
140 {
141 if (type == numeric_tags[i])
142 return true;
143 }
144
145 return false;
146}
147
132#ifdef HAVE_TC_RAMCACHE 148#ifdef HAVE_TC_RAMCACHE
133static struct index_entry *find_entry_ram(const char *filename, 149static struct index_entry *find_entry_ram(const char *filename,
134 const struct dircache_entry *dc) 150 const struct dircache_entry *dc)
@@ -308,6 +324,50 @@ static struct index_entry *find_entry_disk(const char *filename, bool retrieve)
308 return &idx; 324 return &idx;
309} 325}
310 326
327long tagcache_get_numeric(const struct tagcache_search *tcs, int tag)
328{
329 struct tagcache_header tch;
330 struct index_entry idx;
331 int masterfd;
332
333 if (!is_numeric_tag(tag))
334 return -1;
335
336#ifdef HAVE_TC_RAMCACHE
337 if (tcs->ramsearch)
338 {
339 return hdr->indices[tcs->idx_id].tag_seek[tag];
340 }
341#endif
342
343 masterfd = open(TAGCACHE_FILE_MASTER, O_RDONLY);
344
345 if (masterfd < 0)
346 {
347 logf("open fail");
348 return -2;
349 }
350
351 if (read(masterfd, &tch, sizeof(struct tagcache_header)) !=
352 sizeof(struct tagcache_header) || tch.magic != TAGCACHE_MAGIC)
353 {
354 logf("header error");
355 return -3;
356 }
357
358 lseek(masterfd, tcs->idx_id * sizeof(struct index_entry), SEEK_CUR);
359 if (read(masterfd, &idx, sizeof(struct index_entry)) !=
360 sizeof(struct index_entry))
361 {
362 logf("read error #3");
363 close(masterfd);
364 return -4;
365 }
366 close(masterfd);
367
368 return idx.tag_seek[tag];
369}
370
311static bool build_lookup_list(struct tagcache_search *tcs) 371static bool build_lookup_list(struct tagcache_search *tcs)
312{ 372{
313 struct tagcache_header header; 373 struct tagcache_header header;
@@ -443,6 +503,9 @@ bool tagcache_search(struct tagcache_search *tcs, int tag)
443 else 503 else
444#endif 504#endif
445 { 505 {
506 if (is_numeric_tag(tcs->type))
507 return true;
508
446 snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, tcs->type); 509 snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, tcs->type);
447 tcs->fd = open(buf, O_RDONLY); 510 tcs->fd = open(buf, O_RDONLY);
448 if (tcs->fd < 0) 511 if (tcs->fd < 0)
@@ -484,13 +547,17 @@ bool tagcache_get_next(struct tagcache_search *tcs)
484 if (!tcs->valid) 547 if (!tcs->valid)
485 return false; 548 return false;
486 549
487 if (tcs->fd < 0 550 if (tcs->fd < 0 && !is_numeric_tag(tcs->type)
488#ifdef HAVE_TC_RAMCACHE 551#ifdef HAVE_TC_RAMCACHE
489 && !tcs->ramsearch 552 && !tcs->ramsearch
490#endif 553#endif
491 ) 554 )
492 return false; 555 return false;
493 556
557 /* Searching not supported for numeric tags yet. */
558 if (is_numeric_tag(tcs->type))
559 return false;
560
494 /* Relative fetch. */ 561 /* Relative fetch. */
495 if (tcs->filter_count > 0) 562 if (tcs->filter_count > 0)
496 { 563 {
@@ -539,6 +606,7 @@ bool tagcache_get_next(struct tagcache_search *tcs)
539 tcs->position += sizeof(struct tagfile_entry) + ep->tag_length; 606 tcs->position += sizeof(struct tagfile_entry) + ep->tag_length;
540 tcs->result = ep->tag_data; 607 tcs->result = ep->tag_data;
541 tcs->result_len = ep->tag_length; 608 tcs->result_len = ep->tag_length;
609 tcs->idx_id = ep->idx_id;
542 610
543 return true; 611 return true;
544 } 612 }
@@ -571,6 +639,7 @@ bool tagcache_get_next(struct tagcache_search *tcs)
571 639
572 tcs->result = buf; 640 tcs->result = buf;
573 tcs->result_len = entry.tag_length; 641 tcs->result_len = entry.tag_length;
642 tcs->idx_id = entry.idx_id;
574 643
575 return true; 644 return true;
576} 645}
@@ -609,7 +678,7 @@ void tagcache_search_finish(struct tagcache_search *tcs)
609} 678}
610 679
611#ifdef HAVE_TC_RAMCACHE 680#ifdef HAVE_TC_RAMCACHE
612struct tagfile_entry *get_tag(struct index_entry *entry, int tag) 681static struct tagfile_entry *get_tag(struct index_entry *entry, int tag)
613{ 682{
614 return (struct tagfile_entry *)&hdr->tags[tag][entry->tag_seek[tag]]; 683 return (struct tagfile_entry *)&hdr->tags[tag][entry->tag_seek[tag]];
615} 684}
@@ -627,6 +696,7 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename)
627 id3->artist = get_tag(entry, tag_artist)->tag_data; 696 id3->artist = get_tag(entry, tag_artist)->tag_data;
628 id3->album = get_tag(entry, tag_album)->tag_data; 697 id3->album = get_tag(entry, tag_album)->tag_data;
629 id3->genre_string = get_tag(entry, tag_genre)->tag_data; 698 id3->genre_string = get_tag(entry, tag_genre)->tag_data;
699 id3->composer = get_tag(entry, tag_composer)->tag_data;
630 700
631 return true; 701 return true;
632} 702}
@@ -658,6 +728,7 @@ static void add_tagcache(const char *path)
658 struct temp_file_entry entry; 728 struct temp_file_entry entry;
659 bool ret; 729 bool ret;
660 int fd; 730 int fd;
731 char tracknumfix[3];
661 //uint32_t crcbuf[CRC_BUF_LEN]; 732 //uint32_t crcbuf[CRC_BUF_LEN];
662 733
663 if (cachefd < 0) 734 if (cachefd < 0)
@@ -689,6 +760,8 @@ static void add_tagcache(const char *path)
689 } 760 }
690 761
691 memset(&track, 0, sizeof(struct track_info)); 762 memset(&track, 0, sizeof(struct track_info));
763 memset(&entry, 0, sizeof(struct temp_file_entry));
764 memset(&tracknumfix, 0, sizeof(tracknumfix));
692 ret = get_metadata(&track, fd, path, false); 765 ret = get_metadata(&track, fd, path, false);
693 close(fd); 766 close(fd);
694 767
@@ -699,19 +772,51 @@ static void add_tagcache(const char *path)
699 check_if_empty(&track.id3.artist); 772 check_if_empty(&track.id3.artist);
700 check_if_empty(&track.id3.album); 773 check_if_empty(&track.id3.album);
701 check_if_empty(&track.id3.genre_string); 774 check_if_empty(&track.id3.genre_string);
775 check_if_empty(&track.id3.composer);
702 776
703 entry.tag_length[tag_filename] = strlen(path) + 1; 777 entry.tag_length[tag_filename] = strlen(path) + 1;
704 entry.tag_length[tag_title] = strlen(track.id3.title) + 1; 778 entry.tag_length[tag_title] = strlen(track.id3.title) + 1;
705 entry.tag_length[tag_artist] = strlen(track.id3.artist) + 1; 779 entry.tag_length[tag_artist] = strlen(track.id3.artist) + 1;
706 entry.tag_length[tag_album] = strlen(track.id3.album) + 1; 780 entry.tag_length[tag_album] = strlen(track.id3.album) + 1;
707 entry.tag_length[tag_genre] = strlen(track.id3.genre_string) + 1; 781 entry.tag_length[tag_genre] = strlen(track.id3.genre_string) + 1;
782 entry.tag_length[tag_composer] = strlen(track.id3.composer) + 1;
708 783
709 entry.tag_offset[tag_filename] = 0; 784 entry.tag_offset[tag_filename] = 0;
710 entry.tag_offset[tag_title] = entry.tag_offset[tag_filename] + entry.tag_length[tag_filename]; 785 entry.tag_offset[tag_title] = entry.tag_offset[tag_filename] + entry.tag_length[tag_filename];
711 entry.tag_offset[tag_artist] = entry.tag_offset[tag_title] + entry.tag_length[tag_title]; 786 entry.tag_offset[tag_artist] = entry.tag_offset[tag_title] + entry.tag_length[tag_title];
712 entry.tag_offset[tag_album] = entry.tag_offset[tag_artist] + entry.tag_length[tag_artist]; 787 entry.tag_offset[tag_album] = entry.tag_offset[tag_artist] + entry.tag_length[tag_artist];
713 entry.tag_offset[tag_genre] = entry.tag_offset[tag_album] + entry.tag_length[tag_album]; 788 entry.tag_offset[tag_genre] = entry.tag_offset[tag_album] + entry.tag_length[tag_album];
714 entry.data_length = entry.tag_offset[tag_genre] + entry.tag_length[tag_genre]; 789 entry.tag_offset[tag_composer] = entry.tag_offset[tag_genre] + entry.tag_length[tag_genre];
790 entry.data_length = entry.tag_offset[tag_composer] + entry.tag_length[tag_composer];
791
792 /* Numeric tags */
793 entry.tag_offset[tag_year] = track.id3.year;
794 entry.tag_offset[tag_tracknumber] = track.id3.tracknum;
795 entry.tag_offset[tag_length] = track.id3.length;
796 entry.tag_offset[tag_bitrate] = track.id3.bitrate;
797
798 if (entry.tag_offset[tag_tracknumber] <= 0)
799 {
800 int start, i;
801
802 for (start = 0; path[start] != '\0'; start++)
803 if (isdigit(path[start]))
804 break ;
805
806 for (i = 0; i < (int)sizeof(tracknumfix)-1
807 && path[start+i] != '\0'; i++)
808 {
809 if (isdigit(path[start+i]))
810 tracknumfix[i] = path[start+i];
811 else
812 break ;
813 }
814
815 if (tracknumfix[0] != '\0')
816 entry.tag_offset[tag_tracknumber] = atoi(tracknumfix);
817 else
818 entry.tag_offset[tag_tracknumber] = -1;
819 }
715 820
716 write(cachefd, &entry, sizeof(struct temp_file_entry)); 821 write(cachefd, &entry, sizeof(struct temp_file_entry));
717 write_item(path); 822 write_item(path);
@@ -719,6 +824,7 @@ static void add_tagcache(const char *path)
719 write_item(track.id3.artist); 824 write_item(track.id3.artist);
720 write_item(track.id3.album); 825 write_item(track.id3.album);
721 write_item(track.id3.genre_string); 826 write_item(track.id3.genre_string);
827 write_item(track.id3.composer);
722 total_entry_count++; 828 total_entry_count++;
723} 829}
724 830
@@ -730,12 +836,15 @@ static void remove_files(void)
730 remove(TAGCACHE_FILE_MASTER); 836 remove(TAGCACHE_FILE_MASTER);
731 for (i = 0; i < TAG_COUNT; i++) 837 for (i = 0; i < TAG_COUNT; i++)
732 { 838 {
839 if (is_numeric_tag(i))
840 continue;
841
733 snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, i); 842 snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, i);
734 remove(buf); 843 remove(buf);
735 } 844 }
736} 845}
737 846
738static bool tempbuf_insert(char *str, int id) 847static bool tempbuf_insert(char *str, int id, int idx_id)
739{ 848{
740 struct tempbuf_searchidx *index = (struct tempbuf_searchidx *)tempbuf; 849 struct tempbuf_searchidx *index = (struct tempbuf_searchidx *)tempbuf;
741 int len = strlen(str)+1; 850 int len = strlen(str)+1;
@@ -759,6 +868,7 @@ static bool tempbuf_insert(char *str, int id)
759#endif 868#endif
760 index[tempbufidx].id->id = id; 869 index[tempbufidx].id->id = id;
761 index[tempbufidx].id->next = NULL; 870 index[tempbufidx].id->next = NULL;
871 index[tempbufidx].idx_id = idx_id;
762 tempbuf_pos += sizeof(struct tempbuf_id); 872 tempbuf_pos += sizeof(struct tempbuf_id);
763 873
764 index[tempbufidx].seek = -1; 874 index[tempbufidx].seek = -1;
@@ -810,7 +920,7 @@ static bool tempbuf_unique_insert(char *str, int id)
810 } 920 }
811 } 921 }
812 922
813 return tempbuf_insert(str, id); 923 return tempbuf_insert(str, id, -1);
814} 924}
815 925
816static int compare(const void *p1, const void *p2) 926static int compare(const void *p1, const void *p2)
@@ -845,6 +955,7 @@ static int tempbuf_sort(int fd)
845 index[i].seek = lseek(fd, 0, SEEK_CUR); 955 index[i].seek = lseek(fd, 0, SEEK_CUR);
846 length = strlen(index[i].str) + 1; 956 length = strlen(index[i].str) + 1;
847 fe.tag_length = length; 957 fe.tag_length = length;
958 fe.idx_id = index[i].idx_id;
848 959
849#ifdef ROCKBOX_STRICT_ALIGN 960#ifdef ROCKBOX_STRICT_ALIGN
850 /* Make sure the entry is long aligned. */ 961 /* Make sure the entry is long aligned. */
@@ -944,6 +1055,102 @@ static bool is_sorted_tag(int type)
944 return false; 1055 return false;
945} 1056}
946 1057
1058static bool build_numeric_index(int index_type, struct tagcache_header *h, int tmpfd)
1059{
1060 struct tagcache_header tch;
1061 struct index_entry idx;
1062 int masterfd;
1063 int masterfd_pos;
1064 long *databuf = (long *)tempbuf;
1065 int max_entries;
1066 int i;
1067
1068 max_entries = tempbuf_size / sizeof(long);
1069
1070 if (h->entry_count >= max_entries)
1071 {
1072 logf("not enough space!");
1073 return false;
1074 }
1075
1076 logf("Building numeric index: %d", index_type);
1077
1078 /* Walk through the temporary file. */
1079 lseek(tmpfd, sizeof(struct tagcache_header), SEEK_SET);
1080 for (i = 0; i < h->entry_count; i++)
1081 {
1082 struct temp_file_entry entry;
1083
1084 if (read(tmpfd, &entry, sizeof(struct temp_file_entry)) !=
1085 sizeof(struct temp_file_entry))
1086 {
1087 logf("read fail #1");
1088 return false;
1089 }
1090
1091 /* Insert data in buffer. */
1092 databuf[i] = (long)entry.tag_offset[index_type];
1093
1094 /* Skip to next. */
1095 lseek(tmpfd, entry.data_length, SEEK_CUR);
1096 }
1097
1098 /* Update the entries in index. */
1099 masterfd = open(TAGCACHE_FILE_MASTER, O_RDWR);
1100
1101 if (masterfd < 0)
1102 {
1103 logf("No master file found!");
1104 return false;
1105 }
1106
1107 if (read(masterfd, &tch, sizeof(struct tagcache_header)) !=
1108 sizeof(struct tagcache_header) || tch.magic != TAGCACHE_MAGIC)
1109 {
1110 logf("header error");
1111 close(masterfd);
1112 return false;
1113 }
1114
1115 masterfd_pos = lseek(masterfd, tch.entry_count * sizeof(struct index_entry),
1116 SEEK_CUR);
1117 if (masterfd_pos == filesize(masterfd))
1118 {
1119 logf("we can't append!");
1120 close(masterfd);
1121 return false;
1122 }
1123
1124 for (i = 0; i < h->entry_count; i++)
1125 {
1126 int loc = lseek(masterfd, 0, SEEK_CUR);
1127
1128 if (read(masterfd, &idx, sizeof(struct index_entry)) !=
1129 sizeof(struct index_entry))
1130 {
1131 logf("read fail #2");
1132 close(masterfd);
1133 return false;
1134 }
1135
1136 idx.tag_seek[index_type] = databuf[i];
1137
1138 /* Write back the updated index. */
1139 lseek(masterfd, loc, SEEK_SET);
1140 if (write(masterfd, &idx, sizeof(struct index_entry)) !=
1141 sizeof(struct index_entry))
1142 {
1143 logf("write fail");
1144 close(masterfd);
1145 return false;
1146 }
1147 }
1148
1149 close(masterfd);
1150
1151 return true;
1152}
1153
947static bool build_index(int index_type, struct tagcache_header *h, int tmpfd) 1154static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
948{ 1155{
949 int i; 1156 int i;
@@ -1020,7 +1227,7 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
1020 * is saved so we can later reindex the master lookup 1227 * is saved so we can later reindex the master lookup
1021 * table when the index gets resorted. 1228 * table when the index gets resorted.
1022 */ 1229 */
1023 tempbuf_insert(buf, loc + TAGFILE_MAX_ENTRIES); 1230 tempbuf_insert(buf, loc + TAGFILE_MAX_ENTRIES, entry.idx_id);
1024 } 1231 }
1025 } 1232 }
1026 else 1233 else
@@ -1149,7 +1356,7 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
1149 if (is_unique_tag(index_type)) 1356 if (is_unique_tag(index_type))
1150 error = !tempbuf_unique_insert(buf, i); 1357 error = !tempbuf_unique_insert(buf, i);
1151 else 1358 else
1152 error = !tempbuf_insert(buf, i); 1359 error = !tempbuf_insert(buf, i, tch.entry_count + i);
1153 1360
1154 if (error) 1361 if (error)
1155 { 1362 {
@@ -1268,6 +1475,7 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
1268 /* Write to index file. */ 1475 /* Write to index file. */
1269 idx.tag_seek[index_type] = lseek(fd, 0, SEEK_CUR); 1476 idx.tag_seek[index_type] = lseek(fd, 0, SEEK_CUR);
1270 fe.tag_length = entry.tag_length[index_type]; 1477 fe.tag_length = entry.tag_length[index_type];
1478 fe.idx_id = tch.entry_count + i;
1271 write(fd, &fe, sizeof(struct tagfile_entry)); 1479 write(fd, &fe, sizeof(struct tagfile_entry));
1272 write(fd, buf, fe.tag_length); 1480 write(fd, buf, fe.tag_length);
1273 tempbufidx++; 1481 tempbufidx++;
@@ -1375,7 +1583,12 @@ static bool commit(void)
1375 /* Now create the index files. */ 1583 /* Now create the index files. */
1376 for (i = 0; i < TAG_COUNT; i++) 1584 for (i = 0; i < TAG_COUNT; i++)
1377 { 1585 {
1378 if (!build_index(i, &header, tmpfd)) 1586 if (is_numeric_tag(i))
1587 {
1588 build_numeric_index(i, &header, tmpfd);
1589 }
1590
1591 else if (!build_index(i, &header, tmpfd))
1379 { 1592 {
1380 logf("tagcache failed init"); 1593 logf("tagcache failed init");
1381 remove_files(); 1594 remove_files();
@@ -1537,6 +1750,9 @@ static bool load_tagcache(void)
1537 struct tagfile_entry *fe; 1750 struct tagfile_entry *fe;
1538 char buf[MAX_PATH]; 1751 char buf[MAX_PATH];
1539 1752
1753 if (is_numeric_tag(i))
1754 continue ;
1755
1540 //p = ((void *)p+1); 1756 //p = ((void *)p+1);
1541 p = (char *)((long)p & ~0x03) + 0x04; 1757 p = (char *)((long)p & ~0x03) + 0x04;
1542 hdr->tags[i] = p; 1758 hdr->tags[i] = p;
@@ -1854,7 +2070,7 @@ static void tagcache_thread(void)
1854 2070
1855int tagcache_get_progress(void) 2071int tagcache_get_progress(void)
1856{ 2072{
1857 int total_count = -1; 2073 int total_count = processed_dir_count;
1858 2074
1859#ifdef HAVE_DIRCACHE 2075#ifdef HAVE_DIRCACHE
1860 if (dircache_is_enabled()) 2076 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 @@
22#include "id3.h" 22#include "id3.h"
23 23
24enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, 24enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
25 tag_filename/*, tag_checksum*/ }; 25 tag_filename, tag_composer, tag_year, tag_tracknumber,
26#define TAG_COUNT 5 26 tag_bitrate, tag_length };
27
28#define TAG_COUNT 10
27 29
28#ifdef HAVE_DIRCACHE 30#ifdef HAVE_DIRCACHE
29#define HAVE_TC_RAMCACHE 1 31#define HAVE_TC_RAMCACHE 1
@@ -47,6 +49,7 @@ struct tagcache_search {
47 int filter_count; 49 int filter_count;
48 int seek_list_count; 50 int seek_list_count;
49 int seek_pos; 51 int seek_pos;
52 int idx_id;
50 long position; 53 long position;
51 int entry_count; 54 int entry_count;
52 bool valid; 55 bool valid;
@@ -64,6 +67,7 @@ bool tagcache_search_add_filter(struct tagcache_search *tcs,
64 int tag, int seek); 67 int tag, int seek);
65bool tagcache_get_next(struct tagcache_search *tcs); 68bool tagcache_get_next(struct tagcache_search *tcs);
66void tagcache_search_finish(struct tagcache_search *tcs); 69void tagcache_search_finish(struct tagcache_search *tcs);
70long tagcache_get_numeric(const struct tagcache_search *tcs, int tag);
67 71
68int tagcache_get_progress(void); 72int tagcache_get_progress(void);
69#ifdef HAVE_TC_RAMCACHE 73#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 @@
38#include "keyboard.h" 38#include "keyboard.h"
39#include "gui/list.h" 39#include "gui/list.h"
40 40
41#define CHUNKED_NEXT -2
42
43static int tagtree_play_folder(struct tree_context* c); 41static int tagtree_play_folder(struct tree_context* c);
44static int tagtree_search(struct tree_context* c, char* string); 42static int tagtree_search(struct tree_context* c, char* string);
45 43
@@ -52,11 +50,20 @@ struct tagentry {
52 50
53static struct tagcache_search tcs; 51static struct tagcache_search tcs;
54 52
53static int compare(const void *p1, const void *p2)
54{
55 struct tagentry *e1 = (struct tagentry *)p1;
56 struct tagentry *e2 = (struct tagentry *)p2;
57
58 return strncasecmp(e1->name, e2->name, MAX_PATH);
59}
60
55int tagtree_load(struct tree_context* c) 61int tagtree_load(struct tree_context* c)
56{ 62{
57 int i; 63 int i;
58 int namebufused = 0; 64 int namebufused = 0;
59 struct tagentry *dptr = (struct tagentry *)c->dircache; 65 struct tagentry *dptr = (struct tagentry *)c->dircache;
66 bool sort = false;
60 67
61 int table = c->currtable; 68 int table = c->currtable;
62 int extra = c->currextra; 69 int extra = c->currextra;
@@ -153,18 +160,21 @@ int tagtree_load(struct tree_context* c)
153 logf("artist4genres.."); 160 logf("artist4genres..");
154 tagcache_search(&tcs, tag_artist); 161 tagcache_search(&tcs, tag_artist);
155 tagcache_search_add_filter(&tcs, tag_genre, extra); 162 tagcache_search_add_filter(&tcs, tag_genre, extra);
163 sort = true;
156 break; 164 break;
157 165
158 case albums4artist: 166 case albums4artist:
159 logf("albums4artist.."); 167 logf("albums4artist..");
160 tagcache_search(&tcs, tag_album); 168 tagcache_search(&tcs, tag_album);
161 tagcache_search_add_filter(&tcs, tag_artist, extra); 169 tagcache_search_add_filter(&tcs, tag_artist, extra);
170 sort = true;
162 break; 171 break;
163 172
164 case songs4album: 173 case songs4album:
165 logf("songs4album.."); 174 logf("songs4album..");
166 tagcache_search(&tcs, tag_title); 175 tagcache_search(&tcs, tag_title);
167 tagcache_search_add_filter(&tcs, tag_album, extra); 176 tagcache_search_add_filter(&tcs, tag_album, extra);
177 sort = true;
168 if (extra2 > 0) 178 if (extra2 > 0)
169 tagcache_search_add_filter(&tcs, tag_artist, extra2); 179 tagcache_search_add_filter(&tcs, tag_artist, extra2);
170 break; 180 break;
@@ -173,6 +183,7 @@ int tagtree_load(struct tree_context* c)
173 logf("songs4artist.."); 183 logf("songs4artist..");
174 tagcache_search(&tcs, tag_title); 184 tagcache_search(&tcs, tag_title);
175 tagcache_search_add_filter(&tcs, tag_artist, extra); 185 tagcache_search_add_filter(&tcs, tag_artist, extra);
186 sort = true;
176 break; 187 break;
177 188
178 case chunked_next: 189 case chunked_next:
@@ -190,20 +201,37 @@ int tagtree_load(struct tree_context* c)
190 while (tagcache_get_next(&tcs)) 201 while (tagcache_get_next(&tcs))
191 { 202 {
192 dptr->newtable = tcs.result_seek; 203 dptr->newtable = tcs.result_seek;
193 if (!tcs.ramsearch) 204 if (!tcs.ramsearch || table == songs4album)
194 { 205 {
195 dptr->name = &c->name_buffer[namebufused]; 206 dptr->name = &c->name_buffer[namebufused];
196 namebufused += tcs.result_len; 207 if (table == songs4album)
197 if (namebufused > c->name_buffer_size)
198 { 208 {
199 logf("buffer full, 1 entry missed."); 209 snprintf(dptr->name, c->name_buffer_size - namebufused, "%02d. %s",
200 c->dirfull = true; 210 tagcache_get_numeric(&tcs, tag_tracknumber),
201 break ; 211 tcs.result);
212 namebufused += strlen(dptr->name) + 1;
213 if (namebufused >= c->name_buffer_size)
214 {
215 logf("buffer full, 1 entry missed.");
216 c->dirfull = true;
217 break ;
218 }
219 }
220 else
221 {
222 namebufused += tcs.result_len;
223 if (namebufused >= c->name_buffer_size)
224 {
225 logf("buffer full, 1 entry missed.");
226 c->dirfull = true;
227 break ;
228 }
229 strcpy(dptr->name, tcs.result);
202 } 230 }
203 strcpy(dptr->name, tcs.result);
204 } 231 }
205 else 232 else
206 dptr->name = tcs.result; 233 dptr->name = tcs.result;
234
207 dptr++; 235 dptr++;
208 i++; 236 i++;
209 237
@@ -220,6 +248,9 @@ int tagtree_load(struct tree_context* c)
220 248
221 } 249 }
222 250
251 if (sort)
252 qsort(c->dircache, i, c->dentry_size, compare);
253
223 if (c->dirfull) 254 if (c->dirfull)
224 { 255 {
225 dptr->name = "===>"; 256 dptr->name = "===>";