1
0
Fork 0
forked from len0rd/rockbox

Initial version of tagcache! There are still some bugs in the engine

and much more problems with the UI.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9256 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Miika Pekkarinen 2006-03-26 11:33:42 +00:00
parent 50d40ea434
commit 7c4e0c8730
23 changed files with 2698 additions and 64 deletions

View file

@ -25,8 +25,7 @@ status.c
talk.c talk.c
#endif #endif
tree.c tree.c
dbtree.c tagtree.c
database.c
filetree.c filetree.c
screen_access.c screen_access.c
@ -69,7 +68,6 @@ recorder/recording.c
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
pcmbuf.c pcmbuf.c
playback.c playback.c
metadata.c
codecs.c codecs.c
dsp.c dsp.c
eq.c eq.c
@ -81,3 +79,5 @@ eq_arm.S
#endif #endif
eq_menu.c eq_menu.c
#endif #endif
metadata.c
tagcache.c

View file

@ -177,12 +177,6 @@ struct codec_api ci = {
audio_flush_and_reload_tracks, audio_flush_and_reload_tracks,
audio_get_file_pos, audio_get_file_pos,
/* tag database */
&tagdbheader,
&tagdb_fd,
&tagdb_initialized,
tagdb_init,
/* misc */ /* misc */
srand, srand,
rand, rand,

View file

@ -85,12 +85,12 @@
#define CODEC_MAGIC 0x52434F44 /* RCOD */ #define CODEC_MAGIC 0x52434F44 /* RCOD */
/* increase this every time the api struct changes */ /* increase this every time the api struct changes */
#define CODEC_API_VERSION 5 #define CODEC_API_VERSION 6
/* update this to latest version if a change to the api struct breaks /* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */ new function which are "waiting" at the end of the function table) */
#define CODEC_MIN_API_VERSION 5 #define CODEC_MIN_API_VERSION 6
/* codec return codes */ /* codec return codes */
enum codec_status { enum codec_status {
@ -248,12 +248,6 @@ struct codec_api {
void (*audio_flush_and_reload_tracks)(void); void (*audio_flush_and_reload_tracks)(void);
int (*audio_get_file_pos)(void); int (*audio_get_file_pos)(void);
/* tag database */
struct tagdb_header *tagdbheader;
int *tagdb_fd;
int *tagdb_initialized;
int (*tagdb_init) (void);
/* misc */ /* misc */
void (*srand)(unsigned int seed); void (*srand)(unsigned int seed);
int (*rand)(void); int (*rand)(void);

View file

@ -49,6 +49,8 @@
#include "screens.h" #include "screens.h"
#include "misc.h" #include "misc.h"
#include "splash.h" #include "splash.h"
#include "dircache.h"
#include "tagcache.h"
#include "lcd-remote.h" #include "lcd-remote.h"
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP
@ -1855,6 +1857,10 @@ static bool dbg_dircache_info(void)
dircache_get_build_ticks() / HZ); dircache_get_build_ticks() / HZ);
lcd_puts(0, line++, buf); lcd_puts(0, line++, buf);
snprintf(buf, sizeof(buf), "Entry count: %d",
dircache_get_entry_count());
lcd_puts(0, line++, buf);
lcd_update(); lcd_update();
switch (button_get_w_tmo(HZ/2)) switch (button_get_w_tmo(HZ/2))
@ -1871,6 +1877,38 @@ static bool dbg_dircache_info(void)
#endif /* HAVE_DIRCACHE */ #endif /* HAVE_DIRCACHE */
static bool dbg_tagcache_info(void)
{
bool done = false;
int line;
char buf[32];
lcd_setmargins(0, 0);
lcd_setfont(FONT_SYSFIXED);
while (!done)
{
line = 0;
lcd_clear_display();
snprintf(buf, sizeof(buf), "Current progress: %d%%",
tagcache_get_progress());
lcd_puts(0, line++, buf);
lcd_update();
switch (button_get_w_tmo(HZ/2))
{
case SETTINGS_OK:
case SETTINGS_CANCEL:
done = true;
break;
}
}
return false;
}
#if CONFIG_CPU == SH7034 #if CONFIG_CPU == SH7034
bool dbg_save_roms(void) bool dbg_save_roms(void)
{ {
@ -2014,6 +2052,7 @@ bool debug_menu(void)
#ifdef HAVE_DIRCACHE #ifdef HAVE_DIRCACHE
{ "View dircache info", dbg_dircache_info }, { "View dircache info", dbg_dircache_info },
#endif #endif
{ "View tagcache info", dbg_tagcache_info },
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP
{ "View audio thread", dbg_audio_thread }, { "View audio thread", dbg_audio_thread },
#ifdef PM_DEBUG #ifdef PM_DEBUG

View file

@ -3838,3 +3838,45 @@ desc: Backlight behaviour setting
eng: "First keypress enables backlight only" eng: "First keypress enables backlight only"
voice: "First keypress enables backlight only" voice: "First keypress enables backlight only"
new: new:
id: LANG_ID3DB_GENRES
desc: in tag cache
eng: "Genres"
voice: "Genres"
new:
id: LANG_TAGCACHE
desc: in tag cache settings
eng: "Tag cache"
voice: "Tag cache"
new:
id: LANG_TAGCACHE_INIT
desc: while initializing tagcache on boot
eng: "Committing tagcache"
voice:
new:
id: LANG_TAGCACHE_DISK
desc: in tag cache settings
eng: "Keep on disk"
voice: "Keep on disk"
new:
id: LANG_TAGCACHE_RAM
desc: in tag cache settings
eng: "Load to ram"
voice: "Load to ram"
new:
id: LANG_TAGCACHE_FORCE_UPDATE
desc: in tag cache settings
eng: "Force tag cache update"
voice: "Force tag cache update"
new:
id: LANG_TAGCACHE_FORCE_UPDATE_SPLASH
desc: in tag cache settings
eng: "Updating in background"
voice: "Updating in background"
new:

View file

@ -60,6 +60,7 @@
#include "misc.h" #include "misc.h"
#include "database.h" #include "database.h"
#include "dircache.h" #include "dircache.h"
#include "tagcache.h"
#include "lang.h" #include "lang.h"
#include "string.h" #include "string.h"
#include "splash.h" #include "splash.h"
@ -138,6 +139,29 @@ void init_dircache(void)
# define init_dircache(...) # define init_dircache(...)
#endif #endif
void init_tagcache(void)
{
int font_w, font_h;
#ifdef HAVE_LCD_BITMAP
/* Print "Scanning disk..." to the display. */
lcd_getstringsize("A", &font_w, &font_h);
lcd_putsxy((LCD_WIDTH/2) - ((strlen(str(LANG_TAGCACHE_INIT))*font_w)/2),
LCD_HEIGHT-font_h*3, str(LANG_TAGCACHE_INIT));
lcd_update();
#endif
tagcache_init();
#ifdef HAVE_LCD_BITMAP
/* Clean the text when we are done. */
lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
lcd_fillrect(0, LCD_HEIGHT-font_h*3, LCD_WIDTH, font_h);
lcd_set_drawmode(DRMODE_SOLID);
lcd_update();
#endif
}
#ifdef SIMULATOR #ifdef SIMULATOR
void init(void) void init(void)
@ -162,6 +186,7 @@ void init(void)
gui_sync_wps_init(); gui_sync_wps_init();
settings_apply(); settings_apply();
init_dircache(); init_dircache();
init_tagcache();
sleep(HZ/2); sleep(HZ/2);
tree_init(); tree_init();
playlist_init(); playlist_init();
@ -350,6 +375,7 @@ void init(void)
init_dircache(); init_dircache();
init_tagcache();
gui_sync_wps_init(); gui_sync_wps_init();
settings_apply(); settings_apply();
@ -379,7 +405,6 @@ void init(void)
#endif #endif
talk_init(); talk_init();
/* runtime database has to be initialized after audio_init() */ /* runtime database has to be initialized after audio_init() */
rundb_init();
cpu_boost(false); cpu_boost(false);
#ifdef AUTOROCK #ifdef AUTOROCK

View file

@ -68,6 +68,7 @@ static const struct format_list formats[] =
{ AFMT_MPA_L2, "mp2" }, { AFMT_MPA_L2, "mp2" },
{ AFMT_MPA_L2, "mpa" }, { AFMT_MPA_L2, "mpa" },
{ AFMT_MPA_L3, "mp3" }, { AFMT_MPA_L3, "mp3" },
#if CONFIG_CODEC == SWCODEC
{ AFMT_OGG_VORBIS, "ogg" }, { AFMT_OGG_VORBIS, "ogg" },
{ AFMT_PCM_WAV, "wav" }, { AFMT_PCM_WAV, "wav" },
{ AFMT_FLAC, "flac" }, { AFMT_FLAC, "flac" },
@ -80,8 +81,10 @@ static const struct format_list formats[] =
{ AFMT_SHN, "shn" }, { AFMT_SHN, "shn" },
{ AFMT_AIFF, "aif" }, { AFMT_AIFF, "aif" },
{ AFMT_AIFF, "aiff" }, { AFMT_AIFF, "aiff" },
#endif
}; };
#if CONFIG_CODEC == SWCODEC
static const unsigned short a52_bitrates[] = static const unsigned short a52_bitrates[] =
{ {
32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160,
@ -1246,6 +1249,7 @@ static bool get_musepack_metadata(int fd, struct mp3entry *id3)
id3->bitrate = id3->filesize*8/id3->length; id3->bitrate = id3->filesize*8/id3->length;
return true; return true;
} }
#endif /* CONFIG_CODEC == SWCODEC */
static bool get_aiff_metadata(int fd, struct mp3entry* id3) static bool get_aiff_metadata(int fd, struct mp3entry* id3)
{ {
@ -1318,7 +1322,7 @@ static bool get_aiff_metadata(int fd, struct mp3entry* id3)
} }
/* Simple file type probing by looking at the filename extension. */ /* Simple file type probing by looking at the filename extension. */
static unsigned int probe_file_format(const char *filename) unsigned int probe_file_format(const char *filename)
{ {
char *suffix; char *suffix;
unsigned int i; unsigned int i;
@ -1349,9 +1353,11 @@ static unsigned int probe_file_format(const char *filename)
bool get_metadata(struct track_info* track, int fd, const char* trackname, bool get_metadata(struct track_info* track, int fd, const char* trackname,
bool v1first) bool v1first)
{ {
#if CONFIG_CODEC == SWCODEC
unsigned char* buf; unsigned char* buf;
unsigned long totalsamples; unsigned long totalsamples;
int i; int i;
#endif
/* Take our best guess at the codec type based on file extension */ /* Take our best guess at the codec type based on file extension */
track->id3.codectype = probe_file_format(trackname); track->id3.codectype = probe_file_format(trackname);
@ -1369,6 +1375,7 @@ bool get_metadata(struct track_info* track, int fd, const char* trackname,
break; break;
#if CONFIG_CODEC == SWCODEC
case AFMT_FLAC: case AFMT_FLAC:
if (!get_flac_metadata(fd, &(track->id3))) if (!get_flac_metadata(fd, &(track->id3)))
{ {
@ -1519,6 +1526,7 @@ bool get_metadata(struct track_info* track, int fd, const char* trackname,
} }
/* TODO: read the id3v2 header if it exists */ /* TODO: read the id3v2 header if it exists */
break; break;
#endif /* CONFIG_CODEC == SWCODEC */
case AFMT_AIFF: case AFMT_AIFF:
if (!get_aiff_metadata(fd, &(track->id3))) if (!get_aiff_metadata(fd, &(track->id3)))
@ -1543,3 +1551,4 @@ bool get_metadata(struct track_info* track, int fd, const char* trackname,
return true; return true;
} }

View file

@ -22,6 +22,7 @@
#include "playback.h" #include "playback.h"
unsigned int probe_file_format(const char *filename);
bool get_metadata(struct track_info* track, int fd, const char* trackname, bool get_metadata(struct track_info* track, int fd, const char* trackname,
bool v1first); bool v1first);

View file

@ -820,12 +820,12 @@ int onplay(char* file, int attr, int from)
items[i].desc = ID2P(LANG_MENU_SHOW_ID3_INFO); items[i].desc = ID2P(LANG_MENU_SHOW_ID3_INFO);
items[i].function = browse_id3; items[i].function = browse_id3;
i++; i++;
if(rundb_initialized) /* if(rundb_initialized)
{ {
items[i].desc = ID2P(LANG_MENU_SET_RATING); items[i].desc = ID2P(LANG_MENU_SET_RATING);
items[i].function = set_rating; items[i].function = set_rating;
i++; i++;
} }*/
} }
#ifdef HAVE_MULTIVOLUME #ifdef HAVE_MULTIVOLUME

View file

@ -333,16 +333,6 @@ static const struct plugin_api rockbox_api = {
#endif #endif
#endif /* !SIMULATOR && CONFIG_CODEC != SWCODEC */ #endif /* !SIMULATOR && CONFIG_CODEC != SWCODEC */
/* tag database */
&tagdbheader,
&tagdb_fd,
&tagdb_initialized,
tagdb_init,
/* runtime database */
&rundbheader,
&rundb_fd,
&rundb_initialized,
/* menu */ /* menu */
menu_init, menu_init,
menu_exit, menu_exit,

View file

@ -99,12 +99,12 @@
#define PLUGIN_MAGIC 0x526F634B /* RocK */ #define PLUGIN_MAGIC 0x526F634B /* RocK */
/* increase this every time the api struct changes */ /* increase this every time the api struct changes */
#define PLUGIN_API_VERSION 13 #define PLUGIN_API_VERSION 14
/* update this to latest version if a change to the api struct breaks /* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */ new function which are "waiting" at the end of the function table) */
#define PLUGIN_MIN_API_VERSION 13 #define PLUGIN_MIN_API_VERSION 14
/* plugin return codes */ /* plugin return codes */
enum plugin_status { enum plugin_status {
@ -387,16 +387,6 @@ struct plugin_api {
#endif #endif
#endif #endif
/* tag database */
struct tagdb_header *tagdbheader;
int *tagdb_fd;
int *tagdb_initialized;
int (*tagdb_init) (void);
/* runtime database */
struct rundb_header *rundbheader;
int *rundb_fd;
int *rundb_initialized;
/* menu */ /* menu */
int (*menu_init)(const struct menu_item* mitems, int count, int (*menu_init)(const struct menu_item* mitems, int count,
int (*callback)(int, int), int (*callback)(int, int),

View file

@ -60,7 +60,8 @@ DIRS = .
# Subdirs containing multi-file plugins # Subdirs containing multi-file plugins
#for all targets #for all targets
SUBDIRS += searchengine databox # SUBDIRS += searchengine databox
SUBDIRS += databox
#for any recorder, iRiver or iPod model #for any recorder, iRiver or iPod model
ifneq (,$(strip $(foreach tgt,RECORDER IRIVER IPOD_COLOR IPOD_VIDEO GIGABEAT,$(findstring $(tgt),$(TARGET))))) ifneq (,$(strip $(foreach tgt,RECORDER IRIVER IPOD_COLOR IPOD_VIDEO GIGABEAT,$(findstring $(tgt),$(TARGET)))))

View file

@ -15,7 +15,7 @@ metronome.c
#endif #endif
mosaique.c mosaique.c
rockbox_flash.c rockbox_flash.c
search.c /* search.c */
snow.c snow.c
sort.c sort.c
stats.c stats.c

View file

@ -565,6 +565,11 @@ static const struct bit_entry hd_bits[] =
{LCD_DEPTH,S_O(fg_color),LCD_DEFAULT_FG,"foreground color","rgb"}, {LCD_DEPTH,S_O(fg_color),LCD_DEFAULT_FG,"foreground color","rgb"},
{LCD_DEPTH,S_O(bg_color),LCD_DEFAULT_BG,"background color","rgb"}, {LCD_DEPTH,S_O(bg_color),LCD_DEFAULT_BG,"background color","rgb"},
#endif #endif
#ifdef HAVE_DIRCACHE
{1, S_O(tagcache_ram), 0, "tagcache_ram", off_on },
#endif
/* If values are just added to the end, no need to bump the version. */ /* If values are just added to the end, no need to bump the version. */
/* new stuff to be added at the end */ /* new stuff to be added at the end */

View file

@ -419,6 +419,7 @@ struct user_settings
#ifdef HAVE_DIRCACHE #ifdef HAVE_DIRCACHE
bool dircache; /* enable directory cache */ bool dircache; /* enable directory cache */
int dircache_size; /* directory cache structure last size, 22 bits */ int dircache_size; /* directory cache structure last size, 22 bits */
bool tagcache_ram; /* tag cache mode (0=disabled,1=disk,2=ram) */
#endif #endif
int default_codepage; /* set default codepage for tag conversion */ int default_codepage; /* set default codepage for tag conversion */
#ifdef HAVE_REMOTE_LCD #ifdef HAVE_REMOTE_LCD

View file

@ -49,6 +49,7 @@
#include "database.h" #include "database.h"
#include "dir.h" #include "dir.h"
#include "dircache.h" #include "dircache.h"
#include "tagcache.h"
#include "rbunicode.h" #include "rbunicode.h"
#include "splash.h" #include "splash.h"
#include "yesno.h" #include "yesno.h"
@ -1259,15 +1260,15 @@ static bool next_folder(void)
static bool runtimedb(void) static bool runtimedb(void)
{ {
bool rc; bool rc;
bool old = global_settings.runtimedb; // bool old = global_settings.runtimedb;
rc = set_bool( str(LANG_RUNTIMEDB_ACTIVE), rc = set_bool( str(LANG_RUNTIMEDB_ACTIVE),
&global_settings.runtimedb ); &global_settings.runtimedb );
if (old && !global_settings.runtimedb) /* if (old && !global_settings.runtimedb)
rundb_shutdown(); rundb_shutdown();
if (!old && global_settings.runtimedb) if (!old && global_settings.runtimedb)
rundb_init(); rundb_init();
*/
return rc; return rc;
} }
@ -1479,6 +1480,7 @@ static bool beep(void)
} }
#endif #endif
#ifdef HAVE_DIRCACHE #ifdef HAVE_DIRCACHE
static bool dircache(void) static bool dircache(void)
{ {
@ -1497,6 +1499,16 @@ static bool dircache(void)
return result; return result;
} }
static bool tagcache_ram(void)
{
bool result = set_bool_options(str(LANG_TAGCACHE),
&global_settings.tagcache_ram,
STR(LANG_TAGCACHE_RAM),
STR(LANG_TAGCACHE_DISK),
NULL);
return result;
}
#endif /* HAVE_DIRCACHE */ #endif /* HAVE_DIRCACHE */
static bool playback_settings_menu(void) static bool playback_settings_menu(void)
@ -1523,6 +1535,10 @@ static bool playback_settings_menu(void)
#endif #endif
{ ID2P(LANG_ID3_ORDER), id3_order }, { ID2P(LANG_ID3_ORDER), id3_order },
{ ID2P(LANG_NEXT_FOLDER), next_folder }, { ID2P(LANG_NEXT_FOLDER), next_folder },
#ifdef HAVE_DIRCACHE
{ ID2P(LANG_TAGCACHE), tagcache_ram },
#endif
{ ID2P(LANG_TAGCACHE_FORCE_UPDATE), tagcache_force_update },
{ ID2P(LANG_RUNTIMEDB_ACTIVE), runtimedb }, { ID2P(LANG_RUNTIMEDB_ACTIVE), runtimedb },
}; };

1868
apps/tagcache.c Normal file

File diff suppressed because it is too large Load diff

78
apps/tagcache.h Normal file
View file

@ -0,0 +1,78 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005 by Miika Pekkarinen
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef _TAGCACHE_H
#define _TAGCACHE_H
#include "id3.h"
enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
tag_filename/*, tag_checksum*/ };
#define TAG_COUNT 5
#ifdef HAVE_DIRCACHE
#define HAVE_TC_RAMCACHE 1
#endif
/* Allow a little drift to the filename ordering. */
#define POS_HISTORY_COUNT 4
/* How many entries we can create in one tag file (for sorting). */
#define TAGFILE_MAX_ENTRIES 20000
#define SEEK_LIST_SIZE 50
#define TAGCACHE_MAX_FILTERS 3
struct tagcache_search {
/* For internal use only. */
int fd;
long seek_list[SEEK_LIST_SIZE];
long filter_tag[TAGCACHE_MAX_FILTERS];
long filter_seek[TAGCACHE_MAX_FILTERS];
int filter_count;
int seek_list_count;
int seek_pos;
long position;
int entry_count;
bool valid;
/* Exported variables. */
bool ramsearch;
int type;
char *result;
int result_len;
long result_seek;
};
bool tagcache_fill_tags(struct mp3entry *id3, const char *filename);
bool tagcache_search(struct tagcache_search *tcs, int tag);
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);
int tagcache_get_progress(void);
#ifdef HAVE_TC_RAMCACHE
bool tagcache_is_ramcache(void);
#endif
void tagcache_init(void);
void tagcache_start_scan(void);
void tagcache_stop_scan(void);
bool tagcache_force_update(void);
#endif

536
apps/tagtree.c Normal file
View file

@ -0,0 +1,536 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005 by Miika Pekkarinen
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
/**
* Basic structure on this file was copied from dbtree.c and modified to
* support the tag cache interface.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "system.h"
#include "kernel.h"
#include "splash.h"
#include "icons.h"
#include "tree.h"
#include "settings.h"
#include "tagcache.h"
#include "tagtree.h"
#include "lang.h"
#include "logf.h"
#include "playlist.h"
#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);
static char searchstring[32];
struct tagentry {
char *name;
int newtable;
int extraseek;
};
static struct tagcache_search tcs;
int tagtree_load(struct tree_context* c)
{
int i;
int namebufused = 0;
struct tagentry *dptr = (struct tagentry *)c->dircache;
int table = c->currtable;
int extra = c->currextra;
int extra2 = c->currextra2;
c->dentry_size = sizeof(struct tagentry);
if (!table)
{
c->dirfull = false;
table = root;
c->currtable = table;
}
if (c->dirfull)
table = chunked_next;
switch (table) {
case root: {
static const int tables[] = {allartists, allalbums, allgenres, allsongs,
search };
unsigned char* labels[] = { str(LANG_ID3DB_ARTISTS),
str(LANG_ID3DB_ALBUMS),
str(LANG_ID3DB_GENRES),
str(LANG_ID3DB_SONGS),
str(LANG_ID3DB_SEARCH)};
for (i = 0; i < 5; i++) {
dptr->name = &c->name_buffer[namebufused];
dptr->newtable = tables[i];
strcpy(dptr->name, (char *)labels[i]);
namebufused += strlen(dptr->name) + 1;
dptr++;
}
c->dirlength = c->filesindir = i;
return i;
}
case search: {
static const int tables[] = {searchartists,
searchalbums,
searchsongs};
unsigned char* labels[] = { str(LANG_ID3DB_SEARCH_ARTISTS),
str(LANG_ID3DB_SEARCH_ALBUMS),
str(LANG_ID3DB_SEARCH_SONGS)};
for (i = 0; i < 3; i++) {
dptr->name = &c->name_buffer[namebufused];
dptr->newtable = tables[i];
strcpy(dptr->name, (char *)labels[i]);
namebufused += strlen(dptr->name) + 1;
dptr++;
}
c->dirlength = c->filesindir = i;
return i;
}
case searchartists:
case searchalbums:
case searchsongs:
i = tagtree_search(c, searchstring);
c->dirlength = c->filesindir = i;
if (c->dirfull) {
gui_syncsplash(HZ, true, (unsigned char *)"%s %s",
str(LANG_SHOWDIR_ERROR_BUFFER),
str(LANG_SHOWDIR_ERROR_FULL));
c->dirfull = false;
}
else
gui_syncsplash(HZ, true, str(LANG_ID3DB_MATCHES), i);
return i;
case allsongs:
logf("songs..");
tagcache_search(&tcs, tag_title);
break;
case allgenres:
logf("genres..");
tagcache_search(&tcs, tag_genre);
break;
case allalbums:
logf("albums..");
tagcache_search(&tcs, tag_album);
break;
case allartists:
logf("artists..");
tagcache_search(&tcs, tag_artist);
break;
case artist4genres:
logf("artist4genres..");
tagcache_search(&tcs, tag_artist);
tagcache_search_add_filter(&tcs, tag_genre, extra);
break;
case albums4artist:
logf("albums4artist..");
tagcache_search(&tcs, tag_album);
tagcache_search_add_filter(&tcs, tag_artist, extra);
break;
case songs4album:
logf("songs4album..");
tagcache_search(&tcs, tag_title);
tagcache_search_add_filter(&tcs, tag_album, extra);
if (extra2 > 0)
tagcache_search_add_filter(&tcs, tag_artist, extra2);
break;
case songs4artist:
logf("songs4artist..");
tagcache_search(&tcs, tag_title);
tagcache_search_add_filter(&tcs, tag_artist, extra);
break;
case chunked_next:
logf("chunked next...");
break;
default:
logf("Unsupported table %d\n", table);
return -1;
}
i = 0;
namebufused = 0;
c->dirfull = false;
while (tagcache_get_next(&tcs))
{
dptr->newtable = tcs.result_seek;
if (!tcs.ramsearch)
{
dptr->name = &c->name_buffer[namebufused];
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);
}
else
dptr->name = tcs.result;
dptr++;
i++;
/**
* Estimate when we are running out of space so we can stop
* and enabled chunked browsing without missing entries.
*/
if (i >= global_settings.max_files_in_dir - 1
|| namebufused + 200 > c->name_buffer_size)
{
c->dirfull = true;
break ;
}
}
if (c->dirfull)
{
dptr->name = "===>";
dptr->newtable = chunked_next;
dptr++;
i++;
}
else
tagcache_search_finish(&tcs);
c->dirlength = c->filesindir = i;
return i;
}
static int tagtree_search(struct tree_context* c, char* string)
{
struct tagentry *dptr = (struct tagentry *)c->dircache;
int hits = 0;
int namebufused = 0;
switch (c->currtable) {
case searchartists:
tagcache_search(&tcs, tag_artist);
break;
case searchalbums:
tagcache_search(&tcs, tag_album);
break;
case searchsongs:
tagcache_search(&tcs, tag_title);
break;
default:
logf("Invalid table %d\n", c->currtable);
return 0;
}
while (tagcache_get_next(&tcs))
{
if (!strcasestr(tcs.result, string))
continue ;
if (!tcs.ramsearch)
{
dptr->name = &c->name_buffer[namebufused];
namebufused += tcs.result_len;
strcpy(dptr->name, tcs.result);
}
else
dptr->name = tcs.result;
dptr->newtable = tcs.result_seek;
dptr++;
hits++;
}
tagcache_search_finish(&tcs);
return hits;
}
int tagtree_enter(struct tree_context* c)
{
int rc = 0;
struct tagentry *dptr = (struct tagentry *)c->dircache;
int newextra;
dptr += c->selected_item;
if (dptr->newtable == chunked_next)
{
c->selected_item=0;
gui_synclist_select_item(&tree_lists, c->selected_item);
return 0;
}
c->dirfull = false;
newextra = dptr->newtable;
if (c->dirlevel >= MAX_DIR_LEVELS)
return 0;
c->selected_item_history[c->dirlevel]=c->selected_item;
c->table_history[c->dirlevel] = c->currtable;
c->extra_history[c->dirlevel] = c->currextra;
c->pos_history[c->dirlevel] = c->firstpos;
c->dirlevel++;
switch (c->currtable) {
case root:
c->currtable = newextra;
c->currextra = newextra;
break;
case allartists:
case searchartists:
c->currtable = albums4artist;
c->currextra = newextra;
break;
case allgenres:
c->currtable = artist4genres;
c->currextra = newextra;
break;
case artist4genres:
c->currtable = albums4artist;
c->currextra = newextra;
break;
case allalbums:
c->currtable = songs4album;
c->currextra = newextra;
c->currextra2 = -1;
break;
case albums4artist:
case searchalbums:
c->currtable = songs4album;
c->currextra2 = c->currextra;
c->currextra = newextra;
break;
case allsongs:
case songs4album:
case songs4artist:
case searchsongs:
c->dirlevel--;
if (tagtree_play_folder(c) >= 0)
rc = 2;
break;
case search:
rc = kbd_input(searchstring, sizeof(searchstring));
if (rc == -1 || !searchstring[0])
c->dirlevel--;
else
c->currtable = newextra;
break;
default:
c->dirlevel--;
break;
}
c->selected_item=0;
gui_synclist_select_item(&tree_lists, c->selected_item);
return rc;
}
void tagtree_exit(struct tree_context* c)
{
c->dirfull = false;
c->dirlevel--;
c->selected_item=c->selected_item_history[c->dirlevel];
gui_synclist_select_item(&tree_lists, c->selected_item);
c->currtable = c->table_history[c->dirlevel];
c->currextra = c->extra_history[c->dirlevel];
c->firstpos = c->pos_history[c->dirlevel];
/* Just to be sure when chunked browsing is used. */
tagcache_search_finish(&tcs);
}
int tagtree_get_filename(struct tree_context* c, char *buf, int buflen)
{
struct tagentry *entry = (struct tagentry *)c->dircache;
entry += c->selected_item;
tagcache_search(&tcs, tag_filename);
tagcache_search_add_filter(&tcs, tag_title, entry->newtable);
if (!tagcache_get_next(&tcs))
{
tagcache_search_finish(&tcs);
return -1;
}
strncpy(buf, tcs.result, buflen-1);
tagcache_search_finish(&tcs);
return 0;
}
#if 0
bool tagtree_rename_tag(struct tree_context *c, const char *newtext)
{
struct tagentry *dptr = (struct tagentry *)c->dircache;
int extra, extra2;
int type;
dptr += c->selected_item;
extra = dptr->newtable;
extra2 = dptr->extraseek;
switch (c->currtable) {
case allgenres:
tagcache_search(&tcs, tag_title);
tagcache_search_add_filter(&tcs, tag_genre, extra);
type = tag_genre;
break;
case allalbums:
tagcache_search(&tcs, tag_title);
tagcache_search_add_filter(&tcs, tag_album, extra);
type = tag_album;
break;
case allartists:
tagcache_search(&tcs, tag_title);
tagcache_search_add_filter(&tcs, tag_artist, extra);
type = tag_artist;
break;
case artist4genres:
tagcache_search(&tcs, tag_title);
tagcache_search_add_filter(&tcs, tag_genre, extra);
type = tag_artist;
break;
case albums4artist:
tagcache_search(&tcs, tag_title);
tagcache_search_add_filter(&tcs, tag_album, extra);
tagcache_search_add_filter(&tcs, tag_artist, extra2);
type = tag_album;
break;
default:
logf("wrong table");
return false;
}
while (tagcache_get_next(&tcs))
{
// tagcache_modify(&tcs, type, newtext);
}
tagcache_search_finish(&tcs);
return true;
}
#endif
static int tagtree_play_folder(struct tree_context* c)
{
struct tagentry *entry = (struct tagentry *)c->dircache;
int i;
if (playlist_create(NULL, NULL) < 0) {
logf("Failed creating playlist\n");
return -1;
}
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
cpu_boost(true);
#endif
for (i=0; i < c->filesindir; i++) {
tagcache_search(&tcs, tag_filename);
tagcache_search_add_filter(&tcs, tag_title, entry[i].newtable);
if (!tagcache_get_next(&tcs))
{
tagcache_search_finish(&tcs);
continue ;
}
playlist_insert_track(NULL, tcs.result, PLAYLIST_INSERT, false);
tagcache_search_finish(&tcs);
}
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
cpu_boost(false);
#endif
if (global_settings.playlist_shuffle)
c->selected_item = playlist_shuffle(current_tick, c->selected_item);
if (!global_settings.play_selected)
c->selected_item = 0;
gui_synclist_select_item(&tree_lists, c->selected_item);
playlist_start(c->selected_item,0);
return 0;
}
#ifdef HAVE_LCD_BITMAP
const char* tagtree_get_icon(struct tree_context* c)
#else
int tagtree_get_icon(struct tree_context* c)
#endif
{
int icon;
switch (c->currtable)
{
case allsongs:
case songs4album:
case songs4artist:
case searchsongs:
icon = Icon_Audio;
break;
default:
icon = Icon_Folder;
break;
}
#ifdef HAVE_LCD_BITMAP
return (char *)bitmap_icons_6x8[icon];
#else
return icon;
#endif
}

41
apps/tagtree.h Normal file
View file

@ -0,0 +1,41 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005 by Miika Pekkarinen
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef _TAGTREE_H
#define _TAGTREE_H
#include "tagcache.h"
#include "tree.h"
enum table { invalid, root, allsongs, allalbums, allartists, allgenres,
albums4artist, songs4album, songs4artist, artist4genres,
search, searchartists, searchalbums, searchsongs,
chunked_next };
int tagtree_enter(struct tree_context* c);
void tagtree_exit(struct tree_context* c);
int tagtree_load(struct tree_context* c);
#ifdef HAVE_LCD_BITMAP
const char* tagtree_get_icon(struct tree_context* c);
#else
int tagtree_get_icon(struct tree_context* c);
#endif
int tagtree_get_filename(struct tree_context* c, char *buf, int buflen);
#endif

View file

@ -57,10 +57,11 @@
#include "filetypes.h" #include "filetypes.h"
#include "misc.h" #include "misc.h"
#include "filetree.h" #include "filetree.h"
#include "dbtree.h" #include "tagtree.h"
#include "recorder/recording.h" #include "recorder/recording.h"
#include "rtc.h" #include "rtc.h"
#include "dircache.h" #include "dircache.h"
#include "tagcache.h"
#include "yesno.h" #include "yesno.h"
/* gui api */ /* gui api */
@ -164,7 +165,8 @@ char * tree_get_filename(int selected_item, void * data, char *buffer)
bool id3db = *(local_tc->dirfilter) == SHOW_ID3DB; bool id3db = *(local_tc->dirfilter) == SHOW_ID3DB;
if (id3db) { if (id3db) {
name = ((char**)local_tc->dircache)[selected_item * local_tc->dentry_size]; char **buf = local_tc->dircache;
name = buf[selected_item * (local_tc->dentry_size/sizeof(int))];
} }
else { else {
struct entry* dc = local_tc->dircache; struct entry* dc = local_tc->dircache;
@ -189,7 +191,7 @@ void tree_get_fileicon(int selected_item, void * data, ICON * icon)
struct tree_context * local_tc=(struct tree_context *)data; struct tree_context * local_tc=(struct tree_context *)data;
bool id3db = *(local_tc->dirfilter) == SHOW_ID3DB; bool id3db = *(local_tc->dirfilter) == SHOW_ID3DB;
if (id3db) { if (id3db) {
*icon = (ICON)db_get_icon(&tc); *icon = (ICON)tagtree_get_icon(&tc);
} }
else { else {
struct entry* dc = local_tc->dircache; struct entry* dc = local_tc->dircache;
@ -267,6 +269,7 @@ struct tree_context* tree_get_context(void)
int tree_get_file_position(char * filename) int tree_get_file_position(char * filename)
{ {
int i; int i;
/* use lastfile to determine the selected item (default=0) */ /* use lastfile to determine the selected item (default=0) */
for (i=0; i < tc.filesindir; i++) for (i=0; i < tc.filesindir; i++)
{ {
@ -292,7 +295,7 @@ static int update_dir(void)
tc.currextra != lastextra || tc.currextra != lastextra ||
tc.firstpos != lastfirstpos) tc.firstpos != lastfirstpos)
{ {
if (db_load(&tc) < 0) if (tagtree_load(&tc) < 0)
return -1; return -1;
lasttable = tc.currtable; lasttable = tc.currtable;
@ -494,7 +497,7 @@ static bool check_changed_id3mode(bool currmode)
currmode = global_settings.dirfilter == SHOW_ID3DB; currmode = global_settings.dirfilter == SHOW_ID3DB;
if (currmode) { if (currmode) {
curr_context=CONTEXT_ID3DB; curr_context=CONTEXT_ID3DB;
db_load(&tc); tagtree_load(&tc);
} }
else else
{ {
@ -600,7 +603,7 @@ static bool dirbrowse(void)
if ( numentries == 0 ) if ( numentries == 0 )
break; break;
switch (id3db?db_enter(&tc):ft_enter(&tc)) switch (id3db?tagtree_enter(&tc):ft_enter(&tc))
{ {
case 1: reload_dir = true; break; case 1: reload_dir = true; break;
case 2: start_wps = true; break; case 2: start_wps = true; break;
@ -624,7 +627,7 @@ static bool dirbrowse(void)
break; break;
if (id3db) if (id3db)
db_exit(&tc); tagtree_exit(&tc);
else else
if (ft_exit(&tc) == 3) if (ft_exit(&tc) == 3)
exit_func = true; exit_func = true;
@ -732,6 +735,7 @@ static bool dirbrowse(void)
restore = true; restore = true;
id3db = check_changed_id3mode(id3db); id3db = check_changed_id3mode(id3db);
reload_dir = true;
break; break;
} }
@ -772,7 +776,7 @@ static bool dirbrowse(void)
case songs4artist: case songs4artist:
case searchsongs: case searchsongs:
attr=TREE_ATTR_MPA; attr=TREE_ATTR_MPA;
db_get_filename(&tc, buf, sizeof(buf)); tagtree_get_filename(&tc, buf, sizeof(buf));
break; break;
} }
} }
@ -906,6 +910,7 @@ static bool dirbrowse(void)
lastextra = -1; lastextra = -1;
reload_root = false; reload_root = false;
} }
if (! reload_dir ) if (! reload_dir )
{ {
gui_synclist_select_item(&tree_lists, 0); gui_synclist_select_item(&tree_lists, 0);
@ -935,6 +940,7 @@ static bool dirbrowse(void)
need_update = true; need_update = true;
reload_dir = false; reload_dir = false;
} }
if(need_update) { if(need_update) {
tc.selected_item = gui_synclist_get_sel_pos(&tree_lists); tc.selected_item = gui_synclist_get_sel_pos(&tree_lists);
need_update=false; need_update=false;
@ -1177,8 +1183,6 @@ void tree_init(void)
memset(&tc, 0, sizeof(tc)); memset(&tc, 0, sizeof(tc));
tc.dirfilter = &global_settings.dirfilter; tc.dirfilter = &global_settings.dirfilter;
tagdb_init();
tc.name_buffer_size = AVERAGE_FILENAME_LENGTH * max_files; tc.name_buffer_size = AVERAGE_FILENAME_LENGTH * max_files;
tc.name_buffer = buffer_alloc(tc.name_buffer_size); tc.name_buffer = buffer_alloc(tc.name_buffer_size);
@ -1331,9 +1335,9 @@ void ft_play_filename(char *dir, char *file)
/* These two functions are called by the USB and shutdown handlers */ /* These two functions are called by the USB and shutdown handlers */
void tree_flush(void) void tree_flush(void)
{ {
rundb_shutdown(); tagcache_stop_scan();
tagdb_shutdown();
playlist_shutdown(); playlist_shutdown();
#ifdef HAVE_DIRCACHE #ifdef HAVE_DIRCACHE
if (global_settings.dircache) if (global_settings.dircache)
{ {
@ -1351,8 +1355,6 @@ void tree_flush(void)
void tree_restore(void) void tree_restore(void)
{ {
tagdb_init();
rundb_init();
#ifdef HAVE_DIRCACHE #ifdef HAVE_DIRCACHE
if (global_settings.dircache) if (global_settings.dircache)
{ {
@ -1376,5 +1378,6 @@ void tree_restore(void)
gui_textarea_clear(&screens[i]); gui_textarea_clear(&screens[i]);
} }
} }
tagcache_start_scan();
#endif #endif
} }

View file

@ -213,6 +213,7 @@ struct tree_context {
int extra_history[MAX_DIR_LEVELS]; /* db use */ int extra_history[MAX_DIR_LEVELS]; /* db use */
int currtable; /* db use */ int currtable; /* db use */
int currextra; /* db use */ int currextra; /* db use */
int currextra2; /* db use */
/* A big buffer with plenty of entry structs, /* A big buffer with plenty of entry structs,
* contains all files and dirs in the current * contains all files and dirs in the current
* dir (with filters applied) */ * dir (with filters applied) */

View file

@ -84,8 +84,8 @@ static struct dircache_entry* allocate_entry(void)
/* Make sure the entry is long aligned. */ /* Make sure the entry is long aligned. */
if ((long)next_entry & 0x03) if ((long)next_entry & 0x03)
{ {
next_entry = (struct dircache_entry *)(((long)next_entry & ~0x03) + 0x04);
dircache_size += 4 - ((long)next_entry & 0x03); dircache_size += 4 - ((long)next_entry & 0x03);
next_entry = (struct dircache_entry *)(((long)next_entry & ~0x03) + 0x04);
} }
#endif #endif
next_entry->name_len = 0; next_entry->name_len = 0;
@ -95,7 +95,6 @@ static struct dircache_entry* allocate_entry(void)
next_entry->next = NULL; next_entry->next = NULL;
dircache_size += sizeof(struct dircache_entry); dircache_size += sizeof(struct dircache_entry);
entry_count++;
return next_entry; return next_entry;
} }
@ -186,6 +185,7 @@ static int dircache_scan(struct travel_data *td)
td->ce->wrttime = td->entry.wrttime; td->ce->wrttime = td->entry.wrttime;
memcpy(td->ce->d_name, td->entry.name, td->ce->name_len); memcpy(td->ce->d_name, td->entry.name, td->ce->name_len);
dircache_size += td->ce->name_len; dircache_size += td->ce->name_len;
entry_count++;
if (td->entry.attr & FAT_ATTR_DIRECTORY) if (td->entry.attr & FAT_ATTR_DIRECTORY)
{ {