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
#endif
tree.c
dbtree.c
database.c
tagtree.c
filetree.c
screen_access.c
@ -69,7 +68,6 @@ recorder/recording.c
#if CONFIG_CODEC == SWCODEC
pcmbuf.c
playback.c
metadata.c
codecs.c
dsp.c
eq.c
@ -81,3 +79,5 @@ eq_arm.S
#endif
eq_menu.c
#endif
metadata.c
tagcache.c

View file

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

View file

@ -85,12 +85,12 @@
#define CODEC_MAGIC 0x52434F44 /* RCOD */
/* 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
backwards compatibility (and please take the opportunity to sort in any
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 */
enum codec_status {
@ -248,12 +248,6 @@ struct codec_api {
void (*audio_flush_and_reload_tracks)(void);
int (*audio_get_file_pos)(void);
/* tag database */
struct tagdb_header *tagdbheader;
int *tagdb_fd;
int *tagdb_initialized;
int (*tagdb_init) (void);
/* misc */
void (*srand)(unsigned int seed);
int (*rand)(void);

View file

@ -49,6 +49,8 @@
#include "screens.h"
#include "misc.h"
#include "splash.h"
#include "dircache.h"
#include "tagcache.h"
#include "lcd-remote.h"
#ifdef HAVE_LCD_BITMAP
@ -1855,6 +1857,10 @@ static bool dbg_dircache_info(void)
dircache_get_build_ticks() / HZ);
lcd_puts(0, line++, buf);
snprintf(buf, sizeof(buf), "Entry count: %d",
dircache_get_entry_count());
lcd_puts(0, line++, buf);
lcd_update();
switch (button_get_w_tmo(HZ/2))
@ -1871,6 +1877,38 @@ static bool dbg_dircache_info(void)
#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
bool dbg_save_roms(void)
{
@ -2014,6 +2052,7 @@ bool debug_menu(void)
#ifdef HAVE_DIRCACHE
{ "View dircache info", dbg_dircache_info },
#endif
{ "View tagcache info", dbg_tagcache_info },
#ifdef HAVE_LCD_BITMAP
{ "View audio thread", dbg_audio_thread },
#ifdef PM_DEBUG

View file

@ -3838,3 +3838,45 @@ desc: Backlight behaviour setting
eng: "First keypress enables backlight only"
voice: "First keypress enables backlight only"
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 "database.h"
#include "dircache.h"
#include "tagcache.h"
#include "lang.h"
#include "string.h"
#include "splash.h"
@ -138,6 +139,29 @@ void init_dircache(void)
# define init_dircache(...)
#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
void init(void)
@ -162,6 +186,7 @@ void init(void)
gui_sync_wps_init();
settings_apply();
init_dircache();
init_tagcache();
sleep(HZ/2);
tree_init();
playlist_init();
@ -350,6 +375,7 @@ void init(void)
init_dircache();
init_tagcache();
gui_sync_wps_init();
settings_apply();
@ -379,7 +405,6 @@ void init(void)
#endif
talk_init();
/* runtime database has to be initialized after audio_init() */
rundb_init();
cpu_boost(false);
#ifdef AUTOROCK

View file

@ -68,6 +68,7 @@ static const struct format_list formats[] =
{ AFMT_MPA_L2, "mp2" },
{ AFMT_MPA_L2, "mpa" },
{ AFMT_MPA_L3, "mp3" },
#if CONFIG_CODEC == SWCODEC
{ AFMT_OGG_VORBIS, "ogg" },
{ AFMT_PCM_WAV, "wav" },
{ AFMT_FLAC, "flac" },
@ -80,8 +81,10 @@ static const struct format_list formats[] =
{ AFMT_SHN, "shn" },
{ AFMT_AIFF, "aif" },
{ AFMT_AIFF, "aiff" },
#endif
};
#if CONFIG_CODEC == SWCODEC
static const unsigned short a52_bitrates[] =
{
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;
return true;
}
#endif /* CONFIG_CODEC == SWCODEC */
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. */
static unsigned int probe_file_format(const char *filename)
unsigned int probe_file_format(const char *filename)
{
char *suffix;
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 v1first)
{
#if CONFIG_CODEC == SWCODEC
unsigned char* buf;
unsigned long totalsamples;
int i;
#endif
/* Take our best guess at the codec type based on file extension */
track->id3.codectype = probe_file_format(trackname);
@ -1369,6 +1375,7 @@ bool get_metadata(struct track_info* track, int fd, const char* trackname,
break;
#if CONFIG_CODEC == SWCODEC
case AFMT_FLAC:
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 */
break;
#endif /* CONFIG_CODEC == SWCODEC */
case AFMT_AIFF:
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;
}

View file

@ -22,6 +22,7 @@
#include "playback.h"
unsigned int probe_file_format(const char *filename);
bool get_metadata(struct track_info* track, int fd, const char* trackname,
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].function = browse_id3;
i++;
if(rundb_initialized)
/* if(rundb_initialized)
{
items[i].desc = ID2P(LANG_MENU_SET_RATING);
items[i].function = set_rating;
i++;
}
}*/
}
#ifdef HAVE_MULTIVOLUME

View file

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

View file

@ -99,12 +99,12 @@
#define PLUGIN_MAGIC 0x526F634B /* RocK */
/* 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
backwards compatibility (and please take the opportunity to sort in any
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 */
enum plugin_status {
@ -387,16 +387,6 @@ struct plugin_api {
#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 */
int (*menu_init)(const struct menu_item* mitems, int count,
int (*callback)(int, int),

View file

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

View file

@ -15,7 +15,7 @@ metronome.c
#endif
mosaique.c
rockbox_flash.c
search.c
/* search.c */
snow.c
sort.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(bg_color),LCD_DEFAULT_BG,"background color","rgb"},
#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. */
/* new stuff to be added at the end */

View file

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

View file

@ -49,6 +49,7 @@
#include "database.h"
#include "dir.h"
#include "dircache.h"
#include "tagcache.h"
#include "rbunicode.h"
#include "splash.h"
#include "yesno.h"
@ -1259,15 +1260,15 @@ static bool next_folder(void)
static bool runtimedb(void)
{
bool rc;
bool old = global_settings.runtimedb;
// bool old = global_settings.runtimedb;
rc = set_bool( str(LANG_RUNTIMEDB_ACTIVE),
&global_settings.runtimedb );
if (old && !global_settings.runtimedb)
/* if (old && !global_settings.runtimedb)
rundb_shutdown();
if (!old && global_settings.runtimedb)
rundb_init();
*/
return rc;
}
@ -1479,6 +1480,7 @@ static bool beep(void)
}
#endif
#ifdef HAVE_DIRCACHE
static bool dircache(void)
{
@ -1497,6 +1499,16 @@ static bool dircache(void)
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 */
static bool playback_settings_menu(void)
@ -1523,6 +1535,10 @@ static bool playback_settings_menu(void)
#endif
{ ID2P(LANG_ID3_ORDER), id3_order },
{ 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 },
};

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

View file

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

View file

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