Index: trunk/apps/talk.c =================================================================== --- trunk.orig/apps/talk.c +++ trunk/apps/talk.c @@ -658,7 +658,9 @@ void talk_force_enqueue_next(void) } /* play a thumbnail from file */ -int talk_file(const char* filename, bool enqueue) +/* Returns size of spoken thumbnail, so >0 means something is spoken, + <=0 means something went wrong. */ +int talk_file(const char* filename, long *prefix_ids, bool enqueue) { int fd; int size; @@ -712,6 +714,13 @@ int talk_file(const char* filename, bool #if CONFIG_CODEC != SWCODEC bitswap(p_thumbnail, size); #endif + + if(prefix_ids) + /* prefix thumbnail by speaking these ids, but only now + that we know there's actually a thumbnail to be + spoken. */ + talk_idarray(prefix_ids, true); + thumbnail_buf_busy = true; queue_clip(p_thumbnail, size, true); } @@ -719,6 +728,109 @@ int talk_file(const char* filename, bool return size; } +/* Play a file's .talk thumbnail, fallback to spelling the filename, or + go straight to spelling depending on settings. + If dirname is non-NULL, it is prepended to the filename, otherwise + the filename should be a full path name. */ +int talk_file_or_spell(const char *dirname, const char* filename, + long *prefix_ids, bool enqueue) +{ + if (global_settings.talk_file_clip) + { /* .talk clips enabled */ + char buf[MAX_PATH]; + /* Does dirname end with a slash */ + char *slash = (dirname && strlen(dirname) >1 + && dirname[strlen(dirname)-1] != '/') ? "/" : ""; + snprintf(buf, MAX_PATH, "%s%s%s%s", + dirname ? dirname : "", + slash, + filename, + file_thumbnail_ext); + if(talk_file(buf, prefix_ids, enqueue) > 0) + return 0; + } + if (global_settings.talk_file == 2) + { /* Either .talk clips are disabled, or as a fallback */ + if(prefix_ids) + { + talk_idarray(prefix_ids, enqueue); + enqueue = true; + } + /* Spelling is slow, so speak only the basename (after the + last slash ) */ + const char *ptr = strrchr(filename, '/'); + if(ptr) + ++ptr; + else ptr = filename; + return talk_spell(ptr, enqueue); + } + return 0; +} + +/* Play a directory's .talk thumbnail, fallback to spelling the filename, or + go straight to spelling depending on settings. */ +int talk_dir_or_spell(const char* dirname, + long *prefix_ids, bool enqueue) +{ + if (global_settings.talk_dir_clip) + { /* .talk clips enabled */ + char buf[MAX_PATH]; + /* Does directory name end in slash? */ + char *slash = (strlen(dirname) >1 + && dirname[strlen(dirname)-1] != '/') ? "/" : ""; + snprintf(buf, MAX_PATH, "%s%s%s", + dirname, slash, dir_thumbnail_name); + if(talk_file(buf, prefix_ids, enqueue) > 0) + return 0; + } + if (global_settings.talk_file == 2) + { /* Either .talk clips disabled or as a fallback */ + if(prefix_ids) + { + talk_idarray(prefix_ids, enqueue); + enqueue = false; + } + char buf[MAX_PATH]; + /* Spell only the path component after the last slash */ + strncpy(buf, dirname, MAX_PATH); + if(strlen(buf) >1 && buf[strlen(buf)-1] == '/') + /* strip trailing slash */ + buf[strlen(buf)-1] = '\0'; + char *ptr = strrchr(buf, '/'); + if(ptr && strlen(buf) >1) + ++ptr; + else ptr = buf; + return talk_spell(ptr, enqueue); + } + return 0; +} + +/* Speak thumbnail for each component of a full path, again falling + back or going straight to spelling depending on settings. */ +int talk_fullpath(const char* path, bool enqueue) +{ + if (!enqueue) + shutup(); + if(path[0] != '/') + /* path ought to start with /... */ + return talk_spell(path, true); + talk_id(VOICE_CHAR_SLASH, true); + char buf[MAX_PATH]; + strncpy(buf, path, MAX_PATH); + char *start = buf+1; /* start of current component */ + char *ptr = strchr(start, '/'); /* end of current component */ + while(ptr) { /* There are more slashes ahead */ + /* temporarily poke a NULL at end of component to truncate string */ + *ptr = '\0'; + talk_dir_or_spell(buf, NULL, true); + *ptr = '/'; /* restore string */ + start = ptr+1; /* setup for next component */ + ptr = strchr(start, '/'); + talk_id(VOICE_CHAR_SLASH, true); + } + /* no more slashes, final component is a filename */ + return talk_file_or_spell(NULL, buf, NULL, true); +} /* say a numeric value, this word ordering works for english, but not necessarily for other languages (e.g. german) */ @@ -910,6 +1022,8 @@ int talk_spell(const char* spell, bool e talk_id(VOICE_DOT, true); else if (c == ' ') talk_id(VOICE_PAUSE, true); + else if (c == '/') + talk_id(VOICE_CHAR_SLASH, true); } return 0; Index: trunk/apps/talk.h =================================================================== --- trunk.orig/apps/talk.h +++ trunk/apps/talk.h @@ -71,7 +71,16 @@ int talk_get_bufsize(void); /* get the l int talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */ bool is_voice_queued(void); /* Are there more voice clips to be spoken? */ int talk_id(long id, bool enqueue); /* play a voice ID from voicefont */ -int talk_file(const char* filename, bool enqueue); /* play a thumbnail from file */ +/* play a thumbnail from file */ +int talk_file(const char* filename, long *prefix_ids, bool enqueue); +/* play file's thumbnail or spell name */ +int talk_file_or_spell(const char *dirname, const char* filename, + long *prefix_ids, bool enqueue); +/* play dir's thumbnail or spell name */ +int talk_dir_or_spell(const char* filename, + long *prefix_ids, bool enqueue); +/* play thumbnails for each components of full path, or spell */ +int talk_fullpath(const char* path, bool enqueue); int talk_number(long n, bool enqueue); /* say a number */ int talk_value(long n, int unit, bool enqueue); /* say a numeric value */ int talk_spell(const char* spell, bool enqueue); /* spell a string */ Index: trunk/apps/tree.c =================================================================== --- trunk.orig/apps/tree.c +++ trunk/apps/tree.c @@ -1318,7 +1318,7 @@ static int ft_play_dirname(char* name) DEBUGF("Found: %s\n", dirname_mp3_filename); - talk_file(dirname_mp3_filename, false); + talk_file(dirname_mp3_filename, NULL, false); if(global_settings.talk_filetype) talk_id(VOICE_DIR, true); return 1; @@ -1339,7 +1339,7 @@ static void ft_play_filename(char *dir, snprintf(name_mp3_filename, sizeof(name_mp3_filename), "%s/%s%s", dir, file, file_thumbnail_ext); - talk_file(name_mp3_filename, false); + talk_file(name_mp3_filename, NULL, false); /* We could have saved the attribute to say the filetype, but there seems little point since the extension was just spoken. */ } @@ -1348,7 +1348,8 @@ static void ft_play_filename(char *dir, snprintf(name_mp3_filename, sizeof(name_mp3_filename), "%s/%s", dir, file); talk_id(LANG_VOICE_DIR_HOVER, false); /* prefix it */ - talk_file(name_mp3_filename, true); + talk_file(name_mp3_filename, TALK_IDARRAY(LANG_VOICE_DIR_HOVER), + false); } } Index: trunk/apps/lang/english.lang =================================================================== --- trunk.orig/apps/lang/english.lang +++ trunk/apps/lang/english.lang @@ -9845,24 +9845,38 @@ user: *: "" *: "" *: "dot" + id: VOICE_CHAR_SLASH + desc: spoken only, for spelling + user: + + *: "" + + + *: "" + + + *: "slash" + + + id: VOICE_PAUSE desc: spoken only, for spelling, a split second of silence (difficult to author) user: *: "" *: "" *: " "