summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/settings_menu.c10
-rw-r--r--apps/talk.c1
-rw-r--r--apps/talk.h4
-rw-r--r--apps/tree.c165
-rw-r--r--apps/tree.h7
5 files changed, 145 insertions, 42 deletions
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index 9ddf4c4..ab4f242 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -924,8 +924,16 @@ static bool voice_dirs(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);
+ 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)
diff --git a/apps/talk.c b/apps/talk.c
index 7cfcb46..db52afc 100644
--- a/apps/talk.c
+++ b/apps/talk.c
@@ -39,6 +39,7 @@
#define QUEUE_SIZE 64 /* must be a power of two */
#define QUEUE_MASK (QUEUE_SIZE-1)
const char* const dir_thumbnail_name = "_dirname.talk";
+const char* const file_thumbnail_ext = ".talk";
/***************** Functional Macros *****************/
diff --git a/apps/talk.h b/apps/talk.h
index 09d7186..d07f955 100644
--- a/apps/talk.h
+++ b/apps/talk.h
@@ -54,9 +54,9 @@ enum {
/* convenience macro to have both virtual pointer and ID as arguments */
#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" */
-#define TALK_EXT ".talk" /* extra extension for file voicing */
+extern const char* const file_thumbnail_ext; /* ".talk" for file voicing */
void talk_init(void);
int talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */
diff --git a/apps/tree.c b/apps/tree.c
index 1025306..89864f5 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -269,29 +269,19 @@ static int play_dirname(int start_index)
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];
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 */
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);
}
else
@@ -301,8 +291,6 @@ static int play_filename(char *dir, char *file)
talk_id(LANG_VOICE_DIR_HOVER, false); /* prefix it */
talk_file(name_mp3_filename, true);
}
-
- return 1;
}
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 = '.';
}
+/* 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. */
struct entry* load_and_sort_directory(const char *dirname, const int *dirfilter,
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;
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;
}
@@ -1373,15 +1457,12 @@ static bool dirbrowse(const char *root, const int *dirfilter)
}
}
else
- {
+ {
DEBUGF("Playing file thumbnail: %s/%s%s\n",
- currdir, dircache[lasti].name, TALK_EXT);
- res = play_filename(currdir, dircache[lasti].name);
- if (res < 0) /* failed, not existing */
- { /* say the number instead, as a fallback */
- play_filenumber(lasti-dirsindir+1,
- dircache[lasti].attr);
- }
+ currdir, dircache[lasti].name, file_thumbnail_ext);
+ /* no fallback necessary, we knew in advance
+ that the file exists */
+ play_filename(currdir, dircache[lasti].name);
}
thumbnail_time = -1; /* job done */
}
@@ -1501,20 +1582,30 @@ static bool dirbrowse(const char *root, const int *dirfilter)
talk_spell(dircache[i].name, false);
}
}
- else if (global_settings.talk_file == 1) /* files as numbers */
- {
- play_filenumber(i-dirsindir+1,
- dircache[i].attr & TREE_ATTR_MASK);
- }
- else if (global_settings.talk_file == 2) /* files spelled */
+ else /* file */
{
- 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;
+ 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,
+ dircache[i].attr & TREE_ATTR_MASK);
+ }
+ else if (voicemethod == 2) /* files spelled */
+ {
+ talk_spell(dircache[i].name, false);
+ }
}
-
}
}
diff --git a/apps/tree.h b/apps/tree.h
index 297d611..de5f2d0 100644
--- a/apps/tree.h
+++ b/apps/tree.h
@@ -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) */
#define TREE_ATTR_BMARK 0x0100 /* book mark file */
#define TREE_ATTR_M3U 0x0200 /* playlist */
@@ -99,7 +102,7 @@ struct filetype {
#define TREE_ATTR_LNG 0x0700 /* binary lang file */
#define TREE_ATTR_ROCK 0x0800 /* binary rockbox plugin */
#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_init(void);