forked from len0rd/rockbox
Improvement for talking filenames: While loading the directory, already cache for which files are clips available. This avoids unsuccessful spinups while browsing.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5317 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
a24bf1caef
commit
40ae63b4fc
5 changed files with 145 additions and 42 deletions
|
|
@ -924,8 +924,16 @@ static bool voice_dirs(void)
|
||||||
|
|
||||||
static bool voice_files(void)
|
static bool voice_files(void)
|
||||||
{
|
{
|
||||||
return set_option( str(LANG_VOICE_FILE),
|
int oldval = global_settings.talk_file;
|
||||||
|
bool ret;
|
||||||
|
ret = set_option( str(LANG_VOICE_FILE),
|
||||||
&global_settings.talk_file, INT, voice_names, 4, NULL);
|
&global_settings.talk_file, INT, voice_names, 4, NULL);
|
||||||
|
if (oldval != 3 && global_settings.talk_file == 3)
|
||||||
|
{ /* force reload if newly talking thumbnails,
|
||||||
|
because the clip presence is cached only if enabled */
|
||||||
|
reload_directory();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool voice_menu(void)
|
static bool voice_menu(void)
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
#define QUEUE_SIZE 64 /* must be a power of two */
|
#define QUEUE_SIZE 64 /* must be a power of two */
|
||||||
#define QUEUE_MASK (QUEUE_SIZE-1)
|
#define QUEUE_MASK (QUEUE_SIZE-1)
|
||||||
const char* const dir_thumbnail_name = "_dirname.talk";
|
const char* const dir_thumbnail_name = "_dirname.talk";
|
||||||
|
const char* const file_thumbnail_ext = ".talk";
|
||||||
|
|
||||||
/***************** Functional Macros *****************/
|
/***************** Functional Macros *****************/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,9 @@ enum {
|
||||||
/* convenience macro to have both virtual pointer and ID as arguments */
|
/* convenience macro to have both virtual pointer and ID as arguments */
|
||||||
#define STR(id) ID2P(id), id
|
#define STR(id) ID2P(id), id
|
||||||
|
|
||||||
/* publish this string, so it's stored only once (better than #define) */
|
/* publish these strings, so they're stored only once (better than #define) */
|
||||||
extern const char* const dir_thumbnail_name; /* "_dirname.talk" */
|
extern const char* const dir_thumbnail_name; /* "_dirname.talk" */
|
||||||
#define TALK_EXT ".talk" /* extra extension for file voicing */
|
extern const char* const file_thumbnail_ext; /* ".talk" for file voicing */
|
||||||
|
|
||||||
void talk_init(void);
|
void talk_init(void);
|
||||||
int talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */
|
int talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */
|
||||||
|
|
|
||||||
151
apps/tree.c
151
apps/tree.c
|
|
@ -269,29 +269,19 @@ static int play_dirname(int start_index)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int play_filename(char *dir, char *file)
|
static void play_filename(char *dir, char *file)
|
||||||
{
|
{
|
||||||
int fd;
|
|
||||||
char name_mp3_filename[MAX_PATH+1];
|
char name_mp3_filename[MAX_PATH+1];
|
||||||
|
|
||||||
if (mpeg_status() & MPEG_STATUS_PLAY)
|
if (mpeg_status() & MPEG_STATUS_PLAY)
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
if (strcasecmp(&file[strlen(file) - strlen(TALK_EXT)], TALK_EXT))
|
if (strcasecmp(&file[strlen(file) - strlen(file_thumbnail_ext)],
|
||||||
|
file_thumbnail_ext))
|
||||||
{ /* file has no .talk extension */
|
{ /* file has no .talk extension */
|
||||||
snprintf(name_mp3_filename, sizeof(name_mp3_filename),
|
snprintf(name_mp3_filename, sizeof(name_mp3_filename),
|
||||||
"%s/%s" TALK_EXT, dir, file);
|
"%s/%s%s", dir, file, file_thumbnail_ext);
|
||||||
|
|
||||||
/* check if a corresponding .talk file exists */
|
|
||||||
DEBUGF("Checking for Filename Thumb %s\n", name_mp3_filename);
|
|
||||||
fd = open(name_mp3_filename, O_RDONLY);
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
DEBUGF("Failed to find: %s\n", name_mp3_filename);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
DEBUGF("Found: %s\n", name_mp3_filename);
|
|
||||||
close(fd);
|
|
||||||
talk_file(name_mp3_filename, false);
|
talk_file(name_mp3_filename, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -301,8 +291,6 @@ static int play_filename(char *dir, char *file)
|
||||||
talk_id(LANG_VOICE_DIR_HOVER, false); /* prefix it */
|
talk_id(LANG_VOICE_DIR_HOVER, false); /* prefix it */
|
||||||
talk_file(name_mp3_filename, true);
|
talk_file(name_mp3_filename, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int compare(const void* p1, const void* p2)
|
static int compare(const void* p1, const void* p2)
|
||||||
|
|
@ -388,6 +376,94 @@ static void showfileline(int line, int direntry, bool scroll, const int *dirfilt
|
||||||
*dotpos = '.';
|
*dotpos = '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* walk a directory and check all dircache entries if a .talk file exists */
|
||||||
|
void check_file_thumbnails(const char *dirname, int num_files)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct dirent *entry;
|
||||||
|
DIR *dir;
|
||||||
|
|
||||||
|
dir = opendir(dirname);
|
||||||
|
if(!dir)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i=0; i<num_files; i++) /* mark all files as non talking, except the .talk ones */
|
||||||
|
{
|
||||||
|
if (dircache[i].attr & ATTR_DIRECTORY)
|
||||||
|
continue; /* we're not touching directories */
|
||||||
|
|
||||||
|
if (strcasecmp(file_thumbnail_ext,
|
||||||
|
&dircache[i].name[strlen(dircache[i].name)
|
||||||
|
- strlen(file_thumbnail_ext)]))
|
||||||
|
{ /* no .talk file */
|
||||||
|
dircache[i].attr &= ~TREE_ATTR_THUMBNAIL; /* clear */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ /* .talk file, we later let them speak themselves */
|
||||||
|
dircache[i].attr |= TREE_ATTR_THUMBNAIL; /* set */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while((entry = readdir(dir)) != 0) /* walk directory */
|
||||||
|
{
|
||||||
|
int ext_pos;
|
||||||
|
|
||||||
|
ext_pos = strlen(entry->d_name) - strlen(file_thumbnail_ext);
|
||||||
|
if (ext_pos <= 0 /* too short to carry ".talk" */
|
||||||
|
|| (entry->attribute & ATTR_DIRECTORY) /* no file */
|
||||||
|
|| strcasecmp(&entry->d_name[ext_pos], file_thumbnail_ext))
|
||||||
|
{ /* or doesn't end with ".talk", no candidate */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* terminate the (disposable) name in dir buffer,
|
||||||
|
this truncates off the ".talk" without needing an extra buffer */
|
||||||
|
entry->d_name[ext_pos] = '\0';
|
||||||
|
|
||||||
|
/* search corresponding file in dir cache */
|
||||||
|
for (i=0; i<num_files; i++)
|
||||||
|
{
|
||||||
|
if (!strcasecmp(dircache[i].name, entry->d_name))
|
||||||
|
{ /* match */
|
||||||
|
dircache[i].attr |= TREE_ATTR_THUMBNAIL; /* set the flag */
|
||||||
|
break; /* exit search loop, because we found it */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check all dircache directories if they contain a "_dirname.talk" file */
|
||||||
|
#if 0 /* not practical, this is too slow */
|
||||||
|
void check_dir_thumbnails(const char *dirname, int num_files)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int fd;
|
||||||
|
char clipfile[MAX_PATH];
|
||||||
|
|
||||||
|
for (i=0; i<num_files; i++)
|
||||||
|
{
|
||||||
|
if (!(dircache[i].attr & ATTR_DIRECTORY))
|
||||||
|
continue; /* only directories are interesting */
|
||||||
|
|
||||||
|
/* compose pathname of directory name clip file */
|
||||||
|
snprintf(clipfile, sizeof(clipfile), "%s%s/%s",
|
||||||
|
dirname, dircache[i].name, dir_thumbnail_name);
|
||||||
|
|
||||||
|
fd = open(clipfile, O_RDONLY); /* check if exists */
|
||||||
|
if (fd >= 0)
|
||||||
|
{ /* there is one */
|
||||||
|
dircache[i].attr |= TREE_ATTR_THUMBNAIL; /* set the flag */
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ /* none found, clear the flag */
|
||||||
|
dircache[i].attr &= ~TREE_ATTR_THUMBNAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* #if 0 */
|
||||||
|
|
||||||
/* load sorted directory into dircache. returns NULL on failure. */
|
/* load sorted directory into dircache. returns NULL on failure. */
|
||||||
struct entry* load_and_sort_directory(const char *dirname, const int *dirfilter,
|
struct entry* load_and_sort_directory(const char *dirname, const int *dirfilter,
|
||||||
int *num_files, bool *buffer_full)
|
int *num_files, bool *buffer_full)
|
||||||
|
|
@ -490,6 +566,14 @@ struct entry* load_and_sort_directory(const char *dirname, const int *dirfilter,
|
||||||
lastdir[sizeof(lastdir)-1] = 0;
|
lastdir[sizeof(lastdir)-1] = 0;
|
||||||
qsort(dircache,i,sizeof(struct entry),compare);
|
qsort(dircache,i,sizeof(struct entry),compare);
|
||||||
|
|
||||||
|
/* If thumbnail talking is enabled, make an extra run to mark files with
|
||||||
|
associated thumbnails, so we don't do unsuccessful spinups later. */
|
||||||
|
if (global_settings.talk_file == 3)
|
||||||
|
check_file_thumbnails(dirname, i); /* map .talk to ours */
|
||||||
|
#if 0 /* not practical, this is too slow */
|
||||||
|
if (global_settings.talk_dir == 3)
|
||||||
|
check_dir_thumbnails(dirname, i); /* try in the directories */
|
||||||
|
#endif /* #if 0 */
|
||||||
return dircache;
|
return dircache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1375,13 +1459,10 @@ static bool dirbrowse(const char *root, const int *dirfilter)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DEBUGF("Playing file thumbnail: %s/%s%s\n",
|
DEBUGF("Playing file thumbnail: %s/%s%s\n",
|
||||||
currdir, dircache[lasti].name, TALK_EXT);
|
currdir, dircache[lasti].name, file_thumbnail_ext);
|
||||||
res = play_filename(currdir, dircache[lasti].name);
|
/* no fallback necessary, we knew in advance
|
||||||
if (res < 0) /* failed, not existing */
|
that the file exists */
|
||||||
{ /* say the number instead, as a fallback */
|
play_filename(currdir, dircache[lasti].name);
|
||||||
play_filenumber(lasti-dirsindir+1,
|
|
||||||
dircache[lasti].attr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
thumbnail_time = -1; /* job done */
|
thumbnail_time = -1; /* job done */
|
||||||
}
|
}
|
||||||
|
|
@ -1501,20 +1582,30 @@ static bool dirbrowse(const char *root, const int *dirfilter)
|
||||||
talk_spell(dircache[i].name, false);
|
talk_spell(dircache[i].name, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (global_settings.talk_file == 1) /* files as numbers */
|
else /* file */
|
||||||
|
{
|
||||||
|
int voicemethod = global_settings.talk_file;
|
||||||
|
if (voicemethod == 3) /* thumbnail clip */
|
||||||
|
{ /* "schedule" a thumbnail, to have a little delay */
|
||||||
|
if (dircache[i].attr & TREE_ATTR_THUMBNAIL)
|
||||||
|
{
|
||||||
|
thumbnail_time = current_tick + HOVER_DELAY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ /* say the number as fallback */
|
||||||
|
voicemethod = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (voicemethod == 1) /* files as numbers */
|
||||||
{
|
{
|
||||||
play_filenumber(i-dirsindir+1,
|
play_filenumber(i-dirsindir+1,
|
||||||
dircache[i].attr & TREE_ATTR_MASK);
|
dircache[i].attr & TREE_ATTR_MASK);
|
||||||
}
|
}
|
||||||
else if (global_settings.talk_file == 2) /* files spelled */
|
else if (voicemethod == 2) /* files spelled */
|
||||||
{
|
{
|
||||||
talk_spell(dircache[i].name, false);
|
talk_spell(dircache[i].name, false);
|
||||||
}
|
}
|
||||||
else if (global_settings.talk_file == 3) /* hover */
|
|
||||||
{ /* "schedule" a thumbnail, to have a little dalay */
|
|
||||||
thumbnail_time = current_tick + HOVER_DELAY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,10 @@ struct filetype {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* using attribute not used by FAT */
|
/* using attribute bits not used by FAT (FAT uses lower 6) */
|
||||||
|
|
||||||
|
#define TREE_ATTR_THUMBNAIL 0x0080 /* corresponding .talk file exists */
|
||||||
|
|
||||||
/* (this also reflects the sort order if by type) */
|
/* (this also reflects the sort order if by type) */
|
||||||
#define TREE_ATTR_BMARK 0x0100 /* book mark file */
|
#define TREE_ATTR_BMARK 0x0100 /* book mark file */
|
||||||
#define TREE_ATTR_M3U 0x0200 /* playlist */
|
#define TREE_ATTR_M3U 0x0200 /* playlist */
|
||||||
|
|
@ -99,7 +102,7 @@ struct filetype {
|
||||||
#define TREE_ATTR_LNG 0x0700 /* binary lang file */
|
#define TREE_ATTR_LNG 0x0700 /* binary lang file */
|
||||||
#define TREE_ATTR_ROCK 0x0800 /* binary rockbox plugin */
|
#define TREE_ATTR_ROCK 0x0800 /* binary rockbox plugin */
|
||||||
#define TREE_ATTR_MOD 0x0900 /* firmware file */
|
#define TREE_ATTR_MOD 0x0900 /* firmware file */
|
||||||
#define TREE_ATTR_MASK 0xFFC0 /* which bits tree.c uses (above) */
|
#define TREE_ATTR_MASK 0xFF00 /* which bits tree.c uses for file types */
|
||||||
|
|
||||||
void tree_get_filetypes(const struct filetype**, int*);
|
void tree_get_filetypes(const struct filetype**, int*);
|
||||||
void tree_init(void);
|
void tree_init(void);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue