From 5b76936a44de3c7ecd568300f26b5e6421901285 Mon Sep 17 00:00:00 2001 From: Nils Wallménius Date: Mon, 6 Aug 2007 13:08:36 +0000 Subject: Accept FS#6159 'Add voice to roughly 100 splash screens and yes-no menus' by Stephane Doyon with some minor tweaks by me. Rerun 'configure' and do a 'make clean' before rebuilding your voice files. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@14213 a1c6a512-1295-4272-9138-f99709370657 --- apps/bookmark.c | 10 ++-- apps/filetree.c | 42 ++++++++-------- apps/filetypes.c | 2 +- apps/gui/gwps-common.c | 2 +- apps/gui/splash.c | 12 +++++ apps/gui/yesno.c | 45 ++++++++++++++++- apps/lang/english.lang | 121 ++++++++++++++++++++++++++------------------- apps/main.c | 13 ++++- apps/menus/main_menu.c | 6 +-- apps/menus/playback_menu.c | 4 +- apps/menus/settings_menu.c | 6 +-- apps/misc.c | 27 ++++++++-- apps/onplay.c | 19 ++++--- apps/playback.c | 18 +++++++ apps/playback.h | 1 + apps/playlist.c | 102 ++++++++++++++++++++++---------------- apps/plugin.c | 2 +- apps/recorder/radio.c | 18 +++---- apps/root_menu.c | 24 +++++++-- apps/settings.c | 7 +-- apps/tagtree.c | 16 +++--- apps/talk.c | 42 +++++++++++++++- apps/talk.h | 36 ++++++++++++++ apps/tree.c | 7 +-- 24 files changed, 411 insertions(+), 171 deletions(-) diff --git a/apps/bookmark.c b/apps/bookmark.c index 512fb009ec..b350cccd3a 100644 --- a/apps/bookmark.c +++ b/apps/bookmark.c @@ -186,10 +186,10 @@ bool bookmark_autobookmark(void) return write_bookmark(false); } #ifdef HAVE_LCD_BITMAP - unsigned char *lines[]={str(LANG_AUTO_BOOKMARK_QUERY)}; + unsigned char *lines[]={ID2P(LANG_AUTO_BOOKMARK_QUERY)}; struct text_message message={(char **)lines, 1}; #else - unsigned char *lines[]={str(LANG_AUTO_BOOKMARK_QUERY), + unsigned char *lines[]={ID2P(LANG_AUTO_BOOKMARK_QUERY), str(LANG_CONFIRM_WITH_BUTTON)}; struct text_message message={(char **)lines, 2}; #endif @@ -244,8 +244,8 @@ static bool write_bookmark(bool create_bookmark_file) } } - gui_syncsplash(HZ, str(success ? LANG_BOOKMARK_CREATE_SUCCESS - : LANG_BOOKMARK_CREATE_FAILURE)); + gui_syncsplash(HZ, success ? ID2P(LANG_BOOKMARK_CREATE_SUCCESS) + : ID2P(LANG_BOOKMARK_CREATE_FAILURE)); return true; } @@ -634,7 +634,7 @@ static char* select_bookmark(const char* bookmark_file_name, bool show_dont_resu if (bookmarks->total_count < 1) { /* No more bookmarks, delete file and exit */ - gui_syncsplash(HZ, str(LANG_BOOKMARK_LOAD_EMPTY)); + gui_syncsplash(HZ, ID2P(LANG_BOOKMARK_LOAD_EMPTY)); remove(bookmark_file_name); return NULL; } diff --git a/apps/filetree.c b/apps/filetree.c index bc4709baab..35be92e4b5 100644 --- a/apps/filetree.c +++ b/apps/filetree.c @@ -342,21 +342,21 @@ int ft_enter(struct tree_context* c) switch ( file->attr & FILE_ATTR_MASK ) { case FILE_ATTR_M3U: if (global_settings.party_mode) { - gui_syncsplash(HZ, str(LANG_PARTY_MODE)); + gui_syncsplash(HZ, ID2P(LANG_PARTY_MODE)); break; } if (bookmark_autoload(buf)) break; - gui_syncsplash(0, str(LANG_WAIT)); + gui_syncsplash(0, ID2P(LANG_WAIT)); /* about to create a new current playlist... allow user to cancel the operation */ if (global_settings.warnon_erase_dynplaylist && playlist_modified(NULL)) { - char *lines[]={str(LANG_WARN_ERASEDYNPLAYLIST_PROMPT)}; + char *lines[]={ID2P(LANG_WARN_ERASEDYNPLAYLIST_PROMPT)}; struct text_message message={lines, 1}; if(gui_syncyesno_run(&message, NULL, NULL) != YESNO_YES) @@ -377,7 +377,7 @@ int ft_enter(struct tree_context* c) if (bookmark_autoload(c->currdir)) break; - gui_syncsplash(0, str(LANG_WAIT)); + gui_syncsplash(0, ID2P(LANG_WAIT)); /* about to create a new current playlist... allow user to cancel the operation */ @@ -385,7 +385,7 @@ int ft_enter(struct tree_context* c) !global_settings.party_mode && playlist_modified(NULL)) { - char *lines[]={str(LANG_WARN_ERASEDYNPLAYLIST_PROMPT)}; + char *lines[]={ID2P(LANG_WARN_ERASEDYNPLAYLIST_PROMPT)}; struct text_message message={lines, 1}; if(gui_syncyesno_run(&message, NULL, NULL) != YESNO_YES) @@ -396,7 +396,7 @@ int ft_enter(struct tree_context* c) { playlist_insert_track(NULL, buf, PLAYLIST_INSERT_LAST, true, true); - gui_syncsplash(HZ, str(LANG_QUEUE_LAST)); + gui_syncsplash(HZ, ID2P(LANG_QUEUE_LAST)); } else if (playlist_create(c->currdir, NULL) != -1) { @@ -421,7 +421,7 @@ int ft_enter(struct tree_context* c) /* fmr preset file */ case FILE_ATTR_FMR: - gui_syncsplash(0, str(LANG_WAIT)); + gui_syncsplash(0, ID2P(LANG_WAIT)); /* Preset inside the default folder. */ if(!strncasecmp(FMPRESET_PATH, buf, strlen(FMPRESET_PATH))) @@ -448,7 +448,7 @@ int ft_enter(struct tree_context* c) /* wps config file */ case FILE_ATTR_WPS: - gui_syncsplash(0, str(LANG_WAIT)); + gui_syncsplash(0, ID2P(LANG_WAIT)); #if LCD_DEPTH > 1 unload_wps_backdrop(); #endif @@ -460,7 +460,7 @@ int ft_enter(struct tree_context* c) #if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1) /* remote-wps config file */ case FILE_ATTR_RWPS: - gui_syncsplash(0, str(LANG_WAIT)); + gui_syncsplash(0, ID2P(LANG_WAIT)); #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 unload_remote_wps_backdrop(); #endif @@ -471,39 +471,39 @@ int ft_enter(struct tree_context* c) #endif case FILE_ATTR_CFG: - gui_syncsplash(0, str(LANG_WAIT)); + gui_syncsplash(0, ID2P(LANG_WAIT)); if (!settings_load_config(buf,true)) break; - gui_syncsplash(HZ, str(LANG_SETTINGS_LOADED)); + gui_syncsplash(HZ, ID2P(LANG_SETTINGS_LOADED)); break; case FILE_ATTR_BMARK: - gui_syncsplash(0, str(LANG_WAIT)); + gui_syncsplash(0, ID2P(LANG_WAIT)); bookmark_load(buf, false); reload_dir = true; break; case FILE_ATTR_LNG: - gui_syncsplash(0, str(LANG_WAIT)); + gui_syncsplash(0, ID2P(LANG_WAIT)); if(!lang_load(buf)) { set_file(buf, (char *)global_settings.lang_file, MAX_FILENAME); talk_init(); /* use voice of same language */ - gui_syncsplash(HZ, str(LANG_LANGUAGE_LOADED)); + gui_syncsplash(HZ, ID2P(LANG_LANGUAGE_LOADED)); } break; #ifdef HAVE_LCD_BITMAP case FILE_ATTR_FONT: - gui_syncsplash(0, str(LANG_WAIT)); + gui_syncsplash(0, ID2P(LANG_WAIT)); font_load(buf); set_file(buf, (char *)global_settings.font_file, MAX_FILENAME); break; case FILE_ATTR_KBD: - gui_syncsplash(0, str(LANG_WAIT)); + gui_syncsplash(0, ID2P(LANG_WAIT)); if (!load_kbd(buf)) - gui_syncsplash(HZ, str(LANG_KEYBOARD_LOADED)); + gui_syncsplash(HZ, ID2P(LANG_KEYBOARD_LOADED)); set_file(buf, (char *)global_settings.kbd_file, MAX_FILENAME); break; #endif @@ -511,7 +511,7 @@ int ft_enter(struct tree_context* c) #ifndef SIMULATOR /* firmware file */ case FILE_ATTR_MOD: - gui_syncsplash(0, str(LANG_WAIT)); + gui_syncsplash(0, ID2P(LANG_WAIT)); rolo_load(buf); break; #endif @@ -519,11 +519,11 @@ int ft_enter(struct tree_context* c) /* plugin file */ case FILE_ATTR_ROCK: if (global_settings.party_mode) { - gui_syncsplash(HZ, str(LANG_PARTY_MODE)); + gui_syncsplash(HZ, ID2P(LANG_PARTY_MODE)); break; } - gui_syncsplash(0, str(LANG_WAIT)); + gui_syncsplash(0, ID2P(LANG_WAIT)); if (plugin_load(buf,NULL) == PLUGIN_USB_CONNECTED) { @@ -545,7 +545,7 @@ int ft_enter(struct tree_context* c) char* plugin; if (global_settings.party_mode) { - gui_syncsplash(HZ, str(LANG_PARTY_MODE)); + gui_syncsplash(HZ, ID2P(LANG_PARTY_MODE)); break; } diff --git a/apps/filetypes.c b/apps/filetypes.c index 059589db89..7590b1b3e7 100644 --- a/apps/filetypes.c +++ b/apps/filetypes.c @@ -300,7 +300,7 @@ static void read_config(char* config_file) { if (filetype_count >= MAX_FILETYPES) { - gui_syncsplash(HZ, str(LANG_FILETYPES_FULL)); + gui_syncsplash(HZ, ID2P(LANG_FILETYPES_FULL)); break; } rm_whitespaces(line); diff --git a/apps/gui/gwps-common.c b/apps/gui/gwps-common.c index 5f437824b8..82bf7541f2 100644 --- a/apps/gui/gwps-common.c +++ b/apps/gui/gwps-common.c @@ -294,7 +294,7 @@ bool gui_wps_display(void) #ifdef HAVE_LCD_BITMAP gui_syncstatusbar_draw(&statusbars, true); #endif - gui_syncsplash(HZ, str(LANG_END_PLAYLIST)); + gui_syncsplash(HZ, ID2P(LANG_END_PLAYLIST)); return true; } else diff --git a/apps/gui/splash.c b/apps/gui/splash.c index 72279a371d..94d9ef6a5c 100644 --- a/apps/gui/splash.c +++ b/apps/gui/splash.c @@ -22,6 +22,9 @@ #include "stdio.h" #include "kernel.h" #include "screen_access.h" +#include "lang.h" +#include "settings.h" +#include "talk.h" #ifndef MAX #define MAX(a, b) (((a)>(b))?(a):(b)) @@ -197,6 +200,15 @@ void gui_syncsplash(int ticks, const unsigned char *fmt, ...) { va_list ap; int i; + long id; + /* fmt may be a so called virtual pointer. See settings.h. */ + if((id = P2ID(fmt)) >= 0) + /* If fmt specifies a voicefont ID, and voice menus are + enabled, then speak it. */ + cond_talk_ids_fq(id); + /* If fmt is a lang ID then get the corresponding string (which + still might contain % place holders). */ + fmt = P2STR(fmt); va_start( ap, fmt ); FOR_NB_SCREENS(i) splash(&(screens[i]), fmt, ap); diff --git a/apps/gui/yesno.c b/apps/gui/yesno.c index b689ad923b..69912637f4 100644 --- a/apps/gui/yesno.c +++ b/apps/gui/yesno.c @@ -23,6 +23,7 @@ #include "misc.h" #include "lang.h" #include "action.h" +#include "talk.h" /* * Initializes the yesno asker @@ -97,7 +98,28 @@ static bool gui_yesno_draw_result(struct gui_yesno * yn, enum yesno_res result) gui_textarea_put_message(yn->display, message, 0); return(true); } + #include "debug.h" + +/* Processes a text_message whose lines may be virtual pointers + representing language / voicefont IDs (see settings.h). Copies out + the IDs to the ids array, which is of length maxlen, and replaces + the pointers in the text_message with the actual language strings. + The ids array is terminated with the TALK_FINAL_ID sentinel + element. */ +static void extract_talk_ids(struct text_message *m, long *ids, int maxlen) +{ + int line, i=0; + if(m) + for(line=0; linenb_lines; line++) { + long id = P2ID((unsigned char *)m->message_lines[line]); + if(id>=0 && imessage_lines[line] = (char *)P2STR((unsigned char *)m->message_lines[line]); + } + ids[i] = TALK_FINAL_ID; +} + enum yesno_res gui_syncyesno_run(struct text_message * main_message, struct text_message * yes_message, struct text_message * no_message) @@ -107,6 +129,13 @@ enum yesno_res gui_syncyesno_run(struct text_message * main_message, int result=-1; bool result_displayed; struct gui_yesno yn[NB_SCREENS]; + long voice_ids[5]; + long talked_tick = 0; + /* The text messages may contain virtual pointers to IDs (see + settings.h) instead of plain strings. Copy the IDs out so we + can speak them, and unwrap the actual language strings. */ + extract_talk_ids(main_message, voice_ids, + sizeof(voice_ids)/sizeof(voice_ids[0])); FOR_NB_SCREENS(i) { gui_yesno_init(&(yn[i]), main_message, yes_message, no_message); @@ -115,7 +144,14 @@ enum yesno_res gui_syncyesno_run(struct text_message * main_message, } while (result==-1) { - button = get_action(CONTEXT_YESNOSCREEN,TIMEOUT_BLOCK); + /* Repeat the question every 5secs (more or less) */ + if (talk_menus_enabled() + && (talked_tick==0 || TIME_AFTER(current_tick, talked_tick+HZ*5))) + { + talked_tick = current_tick; + talk_idarray(voice_ids, false); + } + button = get_action(CONTEXT_YESNOSCREEN, HZ*5); switch (button) { case ACTION_YESNO_ACCEPT: @@ -133,6 +169,13 @@ enum yesno_res gui_syncyesno_run(struct text_message * main_message, } FOR_NB_SCREENS(i) result_displayed=gui_yesno_draw_result(&(yn[i]), result); + extract_talk_ids((result == YESNO_YES) ? yes_message : no_message, + voice_ids, sizeof(voice_ids)/sizeof(voice_ids[0])); + if (talk_menus_enabled()) + { + talk_idarray(voice_ids, false); + talk_force_enqueue_next(); + } if(result_displayed) sleep(HZ); return(result); diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 63ef4993f7..332ca66195 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -197,7 +197,7 @@ *: "Loading..." - *: "" + *: "Loading" @@ -225,7 +225,7 @@ *: "Scanning disk..." - *: "" + *: "Scanning disk" @@ -239,7 +239,7 @@ *: "Shutting down..." - *: "" + *: "Shutting down" @@ -267,7 +267,7 @@ *: "Cancelled" - *: "" + *: "Cancelled" @@ -281,7 +281,7 @@ *: "Failed" - *: "" + *: "Failed" @@ -309,7 +309,7 @@ *: "Are You Sure?" - *: "" + *: "Are You Sure?" @@ -632,7 +632,7 @@ *: "Create a Bookmark?" - *: "" + *: "Create a Bookmark?" @@ -646,7 +646,7 @@ *: "Bookmark Created" - *: "" + *: "Bookmark Created" @@ -660,7 +660,7 @@ *: "Bookmark Failed!" - *: "" + *: "Bookmark Failed!" @@ -674,7 +674,7 @@ *: "Bookmark Empty" - *: "" + *: "Bookmark Empty" @@ -2430,7 +2430,11 @@ h10,h10_5gb,e200: "Building database... %d found (PREV to return)" - *: "" + *: "entries found for database" + h100,h120,h300: "entries found for database" + ipod*: "entries found for database" + x5,m5: "entries found for database" + h10,h10_5gb,e200: "entries found for database" @@ -2545,7 +2549,7 @@ *: "Updating in background" - *: "" + *: "Updating in background" @@ -2559,7 +2563,7 @@ *: "Committing database" - *: "" + *: "Committing database" @@ -4893,7 +4897,7 @@ *: "New Language" - *: "" + *: "New Language" @@ -5061,7 +5065,7 @@ *: "Settings Loaded" - *: "" + *: "Settings Loaded" @@ -5089,7 +5093,7 @@ *: "Cleared" - *: "" + *: "Settings Cleared" @@ -5117,7 +5121,7 @@ *: "Settings Saved" - *: "" + *: "Settings Saved" @@ -5213,7 +5217,7 @@ *: none - radio: "" + radio: "No presets" @@ -5281,7 +5285,7 @@ *: none - radio: "" + radio: "Preset Save Failed" @@ -5298,7 +5302,7 @@ *: none - radio: "" + radio: "The Preset List is Full" @@ -5468,7 +5472,7 @@ *: none - radio: "" + radio: "Clear Current Presets?" @@ -5604,7 +5608,7 @@ *: none - radio: "" + radio: "No settings found. Autoscan?" @@ -5621,7 +5625,7 @@ *: none - radio: "" + radio: "Save Changes?" @@ -6766,7 +6770,7 @@ *: "Saved %d tracks (%s)" - *: "" + *: "tracks saved" @@ -6808,7 +6812,7 @@ *: "Recursively?" - *: "" + *: "Recursively?" @@ -6836,7 +6840,7 @@ *: "Erase dynamic playlist?" - *: "" + *: "Erase dynamic playlist?" @@ -7221,7 +7225,7 @@ *: "Inserted %d tracks (%s)" - *: "" + *: "tracks inserted" @@ -7235,7 +7239,7 @@ *: "Queued %d tracks (%s)" - *: "" + *: "tracks queued" @@ -7781,7 +7785,7 @@ *: "File/directory exists. Overwrite?" - *: "" + *: "File or directory exists. Overwrite?" @@ -7823,7 +7827,7 @@ *: "Delete?" - *: "" + *: "Really delete?" @@ -7879,7 +7883,7 @@ *: "Deleted" - *: "" + *: "Deleted" @@ -8085,7 +8089,7 @@ *: "Playlist Buffer Full" - *: "" + *: "Playlist Buffer Full" @@ -8101,7 +8105,8 @@ player: "End of List" - *: "" + *: "End of Song List" + player: "End of List" @@ -8129,7 +8134,7 @@ *: "Nothing to resume" - *: "" + *: "Nothing to resume" @@ -8143,7 +8148,7 @@ *: "Error updating playlist control file" - *: "" + *: "Error updating playlist control file" @@ -8157,7 +8162,7 @@ *: "Error accessing playlist file" - *: "" + *: "Error accessing playlist file" @@ -8171,7 +8176,7 @@ *: "Error accessing playlist control file" - *: "" + *: "Error accessing playlist control file" @@ -8185,7 +8190,7 @@ *: "Error accessing directory" - *: "" + *: "Error accessing directory" @@ -8199,7 +8204,7 @@ *: "Playlist control file is invalid" - *: "" + *: "Playlist control file is invalid" @@ -8213,7 +8218,7 @@ *: "Save Failed" - *: "" + *: "Save Failed" @@ -8419,7 +8424,7 @@ *: "Boot changed" - *: "" + *: "Boot changed" @@ -8433,7 +8438,7 @@ *: "Reboot now?" - *: "" + *: "Reboot now?" @@ -8469,7 +8474,7 @@ *: "No files" - *: "" + *: "No files" @@ -8483,7 +8488,7 @@ *: "New Keyboard" - *: "" + *: "New Keyboard" @@ -8567,7 +8572,7 @@ *: "Extension array full" - *: "" + *: "Extension array full" @@ -8581,7 +8586,7 @@ *: "Filetype array full" - *: "" + *: "Filetype array full" @@ -8595,7 +8600,7 @@ *: "Dir Buffer is Full!" - *: "" + *: "Directory Buffer is Full!" @@ -8623,7 +8628,7 @@ *: "Plugin name too long" - *: "" + *: "Plugin name too long" @@ -8654,7 +8659,7 @@ *: "Please reboot to enable" - *: "" + *: "Please reboot to enable" @@ -8720,7 +8725,7 @@ *: "WARNING! Low Battery!" - *: "" + *: "WARNING! Low Battery!" @@ -8734,7 +8739,7 @@ *: "Battery empty! RECHARGE!" - *: "" + *: "Battery empty! RECHARGE!" @@ -10943,4 +10948,18 @@ agc: "AGC maximum gain" + + id: VOICE_OF + desc: spoken only, as in 3/8 => 3 of 8 + user: + + *: "" + + + *: "" + + + *: "of" + + diff --git a/apps/main.c b/apps/main.c index c15cb39d3d..a1019f8a5e 100644 --- a/apps/main.c +++ b/apps/main.c @@ -217,6 +217,17 @@ static void init_tagcache(void) if (ret > 0) { + static long talked_tick = 0; + if(talk_menus_enabled() + && (talked_tick == 0 + || TIME_AFTER(current_tick, talked_tick+7*HZ))) + { + talked_tick = current_tick; + talk_id(LANG_TAGCACHE_INIT, false); + talk_number(ret, true); + talk_id(VOICE_OF, true); + talk_number(tagcache_get_max_commit_step(), true); + } #ifdef HAVE_LCD_BITMAP gui_syncsplash(0, "%s [%d/%d]", str(LANG_TAGCACHE_INIT), ret, @@ -474,7 +485,7 @@ static void init(void) if (button_hold()) #endif { - gui_syncsplash(HZ*2, str(LANG_RESET_DONE_CLEAR)); + gui_syncsplash(HZ*2, ID2P(LANG_RESET_DONE_CLEAR)); settings_reset(); } else diff --git a/apps/menus/main_menu.c b/apps/menus/main_menu.c index 9529d93027..313d7c10e9 100644 --- a/apps/menus/main_menu.c +++ b/apps/menus/main_menu.c @@ -67,12 +67,12 @@ int browse_folder(void *param) static int reset_settings(void) { - unsigned char *lines[]={str(LANG_RESET_ASK)}; + unsigned char *lines[]={ID2P(LANG_RESET_ASK)}; unsigned char *yes_lines[]={ str(LANG_SETTINGS), - str(LANG_RESET_DONE_CLEAR) + ID2P(LANG_RESET_DONE_CLEAR) }; - unsigned char *no_lines[]={yes_lines[0], str(LANG_CANCEL)}; + unsigned char *no_lines[]={yes_lines[0], ID2P(LANG_CANCEL)}; struct text_message message={(char **)lines, 1}; struct text_message yes_message={(char **)yes_lines, 2}; struct text_message no_message={(char **)no_lines, 2}; diff --git a/apps/menus/playback_menu.c b/apps/menus/playback_menu.c index 17e54d7771..0d4162c584 100644 --- a/apps/menus/playback_menu.c +++ b/apps/menus/playback_menu.c @@ -138,7 +138,7 @@ int audioscrobbler_callback(int action,const struct menu_item_ex *this_item) { case ACTION_EXIT_MENUITEM: /* on exit */ if (!scrobbler_is_enabled() && global_settings.audioscrobbler) - gui_syncsplash(HZ*2, str(LANG_PLEASE_REBOOT)); + gui_syncsplash(HZ*2, ID2P(LANG_PLEASE_REBOOT)); if(scrobbler_is_enabled() && !global_settings.audioscrobbler) scrobbler_shutdown(); @@ -156,7 +156,7 @@ int cuesheet_callback(int action,const struct menu_item_ex *this_item) { case ACTION_EXIT_MENUITEM: /* on exit */ if (!cuesheet_is_enabled() && global_settings.cuesheet) - gui_syncsplash(HZ*2, str(LANG_PLEASE_REBOOT)); + gui_syncsplash(HZ*2, ID2P(LANG_PLEASE_REBOOT)); break; } return action; diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c index 1e09abed5d..b1ba6680be 100644 --- a/apps/menus/settings_menu.c +++ b/apps/menus/settings_menu.c @@ -49,13 +49,13 @@ static void tagcache_rebuild_with_splash(void) { tagcache_rebuild(); - gui_syncsplash(HZ*2, str(LANG_TAGCACHE_FORCE_UPDATE_SPLASH)); + gui_syncsplash(HZ*2, ID2P(LANG_TAGCACHE_FORCE_UPDATE_SPLASH)); } static void tagcache_update_with_splash(void) { tagcache_update(); - gui_syncsplash(HZ*2, str(LANG_TAGCACHE_FORCE_UPDATE_SPLASH)); + gui_syncsplash(HZ*2, ID2P(LANG_TAGCACHE_FORCE_UPDATE_SPLASH)); } #ifdef HAVE_TC_RAMCACHE @@ -174,7 +174,7 @@ static int dircache_callback(int action,const struct menu_item_ex *this_item) { case true: if (!dircache_is_enabled()) - gui_syncsplash(HZ*2, str(LANG_PLEASE_REBOOT)); + gui_syncsplash(HZ*2, ID2P(LANG_PLEASE_REBOOT)); break; case false: if (dircache_is_enabled()) diff --git a/apps/misc.c b/apps/misc.c index 83b0324ea3..bd42ca9e34 100644 --- a/apps/misc.c +++ b/apps/misc.c @@ -62,6 +62,7 @@ #include "bookmark.h" #include "misc.h" +#include "playback.h" #ifdef BOOTFILE #if !defined(USB_NONE) && !defined(USB_IPODSTYLE) @@ -603,6 +604,7 @@ static bool clean_shutdown(void (*callback)(void *), void *parameter) call_ata_idle_notifys(true); exit(0); #else + long msg_id = -1; int i; scrobbler_poweroff(); @@ -625,19 +627,23 @@ static bool clean_shutdown(void (*callback)(void *), void *parameter) if (!tagcache_prepare_shutdown()) { cancel_shutdown(); - gui_syncsplash(HZ, str(LANG_TAGCACHE_BUSY)); + gui_syncsplash(HZ, ID2P(LANG_TAGCACHE_BUSY)); return false; } #endif if (battery_level() > 10) gui_syncsplash(0, str(LANG_SHUTTINGDOWN)); else + { + msg_id = LANG_WARNING_BATTERY_LOW; gui_syncsplash(0, "%s %s", str(LANG_WARNING_BATTERY_LOW), str(LANG_SHUTTINGDOWN)); + } } else { + msg_id = LANG_WARNING_BATTERY_EMPTY; gui_syncsplash(0, "%s %s", str(LANG_WARNING_BATTERY_EMPTY), str(LANG_SHUTTINGDOWN)); @@ -675,6 +681,21 @@ static bool clean_shutdown(void (*callback)(void *), void *parameter) #if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC audio_close_recording(); #endif + + if(talk_menus_enabled()) + { + bool enqueue = false; + if(msg_id != -1) + { + talk_id(msg_id, enqueue); + enqueue = true; + } + talk_id(LANG_SHUTTINGDOWN, enqueue); +#if CONFIG_CODEC == SWCODEC + voice_wait(); +#endif + } + system_flush(); #ifdef HAVE_EEPROM_SETTINGS if (firmware_settings.initialized) @@ -974,8 +995,8 @@ void check_bootfile(bool do_rolo) if((entry->wrtdate != wrtdate) || (entry->wrttime != wrttime)) { - char *lines[] = { str(LANG_BOOT_CHANGED), - str(LANG_REBOOT_NOW) }; + char *lines[] = { ID2P(LANG_BOOT_CHANGED), + ID2P(LANG_REBOOT_NOW) }; struct text_message message={ lines, 2 }; button_clear_queue(); /* Empty the keyboard buffer */ if(gui_syncyesno_run(&message, NULL, NULL) == YESNO_YES) diff --git a/apps/onplay.c b/apps/onplay.c index 6c34d18d74..4921e7e428 100644 --- a/apps/onplay.c +++ b/apps/onplay.c @@ -160,12 +160,12 @@ static bool add_to_playlist(int position, bool queue) { bool new_playlist = !(audio_status() & AUDIO_STATUS_PLAY); char *lines[] = { - (char *)str(LANG_RECURSE_DIRECTORY_QUESTION), + ID2P(LANG_RECURSE_DIRECTORY_QUESTION), selected_file }; struct text_message message={lines, 2}; - gui_syncsplash(0, str(LANG_WAIT)); + gui_syncsplash(0, ID2P(LANG_WAIT)); if (new_playlist) playlist_create(NULL, NULL); @@ -502,7 +502,7 @@ static int remove_dir(char* dirname, int len) #endif if(ACTION_STD_CANCEL == get_action(CONTEXT_STD,TIMEOUT_NOBLOCK)) { - gui_syncsplash(HZ, str(LANG_CANCEL)); + gui_syncsplash(HZ, ID2P(LANG_CANCEL)); result = -1; break; } @@ -524,11 +524,11 @@ static int remove_dir(char* dirname, int len) static bool delete_handler(bool is_dir) { char *lines[]={ - (char *)str(LANG_REALLY_DELETE), + ID2P(LANG_REALLY_DELETE), selected_file }; char *yes_lines[]={ - (char *)str(LANG_DELETED), + ID2P(LANG_DELETED), selected_file }; @@ -599,6 +599,7 @@ static bool rename_file(void) lcd_puts(0,0,str(LANG_RENAME)); lcd_puts(0,1,str(LANG_FAILED)); lcd_update(); + cond_talk_ids_fq(LANG_RENAME, LANG_FAILED); sleep(HZ*2); } else @@ -628,6 +629,7 @@ static bool create_dir(void) rc = mkdir(dirname); if (rc < 0) { + cond_talk_ids_fq(LANG_CREATE_DIR, LANG_FAILED); gui_syncsplash(HZ, (unsigned char *)"%s %s", str(LANG_CREATE_DIR), str(LANG_FAILED)); } else { @@ -873,7 +875,7 @@ static bool clipboard_paste(void) bool success; int target_fd; - unsigned char *lines[]={str(LANG_REALLY_OVERWRITE)}; + unsigned char *lines[]={ID2P(LANG_REALLY_OVERWRITE)}; struct text_message message={(char **)lines, 1}; /* Get the name of the current directory */ @@ -896,11 +898,11 @@ static bool clipboard_paste(void) } if (clipboard_is_copy) { - gui_syncsplash(0, str(LANG_COPYING)); + gui_syncsplash(0, ID2P(LANG_COPYING)); } else { - gui_syncsplash(0, str(LANG_MOVING)); + gui_syncsplash(0, ID2P(LANG_MOVING)); } /* Now figure out what we're doing */ @@ -939,6 +941,7 @@ static bool clipboard_paste(void) /* Force reload of the current directory */ onplay_result = ONPLAY_RELOAD_DIR; } else { + cond_talk_ids_fq(LANG_PASTE, LANG_FAILED); gui_syncsplash(HZ, (unsigned char *)"%s %s", str(LANG_PASTE), str(LANG_FAILED)); } diff --git a/apps/playback.c b/apps/playback.c index 1b1ba23ce8..43c3b0acdd 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -957,6 +957,24 @@ static void voice_stop(void) pcmbuf_play_stop(); #endif } /* voice_stop */ + +/* Is voice still speaking */ +/* Unfortunately only reliable when music is not also playing. */ +static bool is_voice_speaking(void) +{ + return is_voice_queued() + || voice_is_playing + || (!playing && pcm_is_playing()); +} + +/* Wait for voice to finish speaking. */ +/* Also only reliable when music is not also playing. */ +void voice_wait(void) +{ + while (is_voice_speaking()) + sleep(HZ/10); +} + #endif /* PLAYBACK_VOICE */ static void set_filebuf_watermark(int seconds) diff --git a/apps/playback.h b/apps/playback.h index eaab4386e0..ac3adc4d3e 100644 --- a/apps/playback.h +++ b/apps/playback.h @@ -63,6 +63,7 @@ void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3, bool last_track)); void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3, bool last_track)); +void voice_wait(void); #if CONFIG_CODEC == SWCODEC /* This #ifdef is better here than gui/gwps.c */ extern void audio_next_dir(void); diff --git a/apps/playlist.c b/apps/playlist.c index caf5856ae8..873db30a7d 100644 --- a/apps/playlist.c +++ b/apps/playlist.c @@ -181,7 +181,8 @@ static int get_previous_directory(char *dir); static int check_subdir_for_music(char *dir, char *subdir); static int format_track_path(char *dest, char *src, int buf_length, int max, char *dir); -static void display_playlist_count(int count, const unsigned char *fmt); +static void display_playlist_count(int count, const unsigned char *fmt, + bool final); static void display_buffer_full(void); static int flush_cached_control(struct playlist_info* playlist); static int update_control(struct playlist_info* playlist, @@ -288,6 +289,7 @@ static void create_control(struct playlist_info* playlist) { if (check_rockboxdir()) { + cond_talk_ids_fq(LANG_PLAYLIST_CONTROL_ACCESS_ERROR); gui_syncsplash(HZ*2, (unsigned char *)"%s (%d)", str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR), playlist->control_fd); @@ -483,8 +485,7 @@ static int add_indices_to_playlist(struct playlist_info* playlist, else lcd_setmargins(0, 0); #endif - - gui_syncsplash(0, str(LANG_WAIT)); + gui_syncsplash(0, ID2P(LANG_WAIT)); if (!buffer) { @@ -770,11 +771,11 @@ static int directory_search_callback(char* filename, void* context) unsigned char* count_str; if (c->queue) - count_str = str(LANG_PLAYLIST_QUEUE_COUNT); + count_str = ID2P(LANG_PLAYLIST_QUEUE_COUNT); else - count_str = str(LANG_PLAYLIST_INSERT_COUNT); + count_str = ID2P(LANG_PLAYLIST_INSERT_COUNT); - display_playlist_count(c->count, count_str); + display_playlist_count(c->count, count_str, false); if ((c->count) == PLAYLIST_DISPLAY_COUNT && (audio_status() & AUDIO_STATUS_PLAY) && @@ -1350,9 +1351,9 @@ static int get_filename(struct playlist_info* playlist, int index, int seek, if (max < 0) { if (control_file) - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); else - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_ACCESS_ERROR)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR)); return max; } @@ -1445,7 +1446,7 @@ static int get_next_dir(char *dir, bool is_forward, bool recursion) if (ft_load(tc, (dir[0]=='\0')?"/":dir) < 0) { - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR)); exit = true; result = -1; break; @@ -1530,7 +1531,7 @@ static int check_subdir_for_music(char *dir, char *subdir) if (ft_load(tc, dir) < 0) { - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR)); return -2; } @@ -1584,7 +1585,7 @@ static int check_subdir_for_music(char *dir, char *subdir) /* we now need to reload our current directory */ if(ft_load(tc, dir) < 0) gui_syncsplash(HZ*2, - str(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR)); + ID2P(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR)); } return result; @@ -1657,8 +1658,23 @@ static int format_track_path(char *dest, char *src, int buf_length, int max, * Display splash message showing progress of playlist/directory insertion or * save. */ -static void display_playlist_count(int count, const unsigned char *fmt) +static void display_playlist_count(int count, const unsigned char *fmt, + bool final) { + static long talked_tick = 0; + long id = P2ID(fmt); + if(talk_menus_enabled() && id>=0) + { + if(final || (count && (talked_tick == 0 + || TIME_AFTER(current_tick, talked_tick+5*HZ)))) + { + talked_tick = current_tick; + talk_number(count, false); + talk_id(id, true); + } + } + fmt = P2STR(fmt); + lcd_clear_display(); #ifdef HAVE_LCD_BITMAP @@ -1676,7 +1692,7 @@ static void display_playlist_count(int count, const unsigned char *fmt) */ static void display_buffer_full(void) { - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_BUFFER_FULL)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_BUFFER_FULL)); } /* @@ -1755,7 +1771,7 @@ static int flush_cached_control(struct playlist_info* playlist) else { result = -1; - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_UPDATE_ERROR)); } return result; @@ -1942,11 +1958,11 @@ int playlist_resume(void) empty_playlist(playlist, true); - gui_syncsplash(0, str(LANG_WAIT)); + gui_syncsplash(0, ID2P(LANG_WAIT)); playlist->control_fd = open(playlist->control_filename, O_RDWR); if (playlist->control_fd < 0) { - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); return -1; } playlist->control_created = true; @@ -1954,7 +1970,7 @@ int playlist_resume(void) control_file_size = filesize(playlist->control_fd); if (control_file_size <= 0) { - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); return -1; } @@ -1963,7 +1979,7 @@ int playlist_resume(void) PLAYLIST_COMMAND_SIZE= control_file_size) { /* no newline at end of control file */ - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_INVALID)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_INVALID)); return -1; } @@ -2361,6 +2377,7 @@ int playlist_shuffle(int random_seed, int start_index) start_current = true; } + cond_talk_ids(LANG_WAIT); gui_syncsplash(0, str(LANG_PLAYLIST_SHUFFLE)); randomise_playlist(playlist, random_seed, start_current, true); @@ -2853,7 +2870,7 @@ int playlist_insert_track(struct playlist_info* playlist, const char *filename, if (check_control(playlist) < 0) { - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); return -1; } @@ -2884,7 +2901,7 @@ int playlist_insert_directory(struct playlist_info* playlist, if (check_control(playlist) < 0) { - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); return -1; } @@ -2897,11 +2914,11 @@ int playlist_insert_directory(struct playlist_info* playlist, } if (queue) - count_str = str(LANG_PLAYLIST_QUEUE_COUNT); + count_str = ID2P(LANG_PLAYLIST_QUEUE_COUNT); else - count_str = str(LANG_PLAYLIST_INSERT_COUNT); + count_str = ID2P(LANG_PLAYLIST_INSERT_COUNT); - display_playlist_count(0, count_str); + display_playlist_count(0, count_str, false); context.playlist = playlist; context.position = position; @@ -2917,7 +2934,7 @@ int playlist_insert_directory(struct playlist_info* playlist, cpu_boost(false); - display_playlist_count(context.count, count_str); + display_playlist_count(context.count, count_str, true); if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started) audio_flush_and_reload_tracks(); @@ -2950,14 +2967,14 @@ int playlist_insert_playlist(struct playlist_info* playlist, char *filename, if (check_control(playlist) < 0) { - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); return -1; } fd = open(filename, O_RDONLY); if (fd < 0) { - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_ACCESS_ERROR)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR)); return -1; } @@ -2971,11 +2988,11 @@ int playlist_insert_playlist(struct playlist_info* playlist, char *filename, dir = "/"; if (queue) - count_str = str(LANG_PLAYLIST_QUEUE_COUNT); + count_str = ID2P(LANG_PLAYLIST_QUEUE_COUNT); else - count_str = str(LANG_PLAYLIST_INSERT_COUNT); + count_str = ID2P(LANG_PLAYLIST_INSERT_COUNT); - display_playlist_count(count, count_str); + display_playlist_count(count, count_str, false); if (position == PLAYLIST_REPLACE) { @@ -3023,7 +3040,7 @@ int playlist_insert_playlist(struct playlist_info* playlist, char *filename, if ((count%PLAYLIST_DISPLAY_COUNT) == 0) { - display_playlist_count(count, count_str); + display_playlist_count(count, count_str, false); if (count == PLAYLIST_DISPLAY_COUNT && (audio_status() & AUDIO_STATUS_PLAY) && @@ -3045,7 +3062,7 @@ int playlist_insert_playlist(struct playlist_info* playlist, char *filename, cpu_boost(false); - display_playlist_count(count, count_str); + display_playlist_count(count, count_str, true); if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started) audio_flush_and_reload_tracks(); @@ -3070,7 +3087,7 @@ int playlist_delete(struct playlist_info* playlist, int index) if (check_control(playlist) < 0) { - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); return -1; } @@ -3105,7 +3122,7 @@ int playlist_move(struct playlist_info* playlist, int index, int new_index) if (check_control(playlist) < 0) { - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); return -1; } @@ -3368,7 +3385,7 @@ int playlist_save(struct playlist_info* playlist, char *filename) if (playlist->buffer_size < (int)(playlist->amount * sizeof(int))) { /* not enough buffer space to store updated indices */ - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_ACCESS_ERROR)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR)); return -1; } @@ -3384,11 +3401,11 @@ int playlist_save(struct playlist_info* playlist, char *filename) fd = open(path, O_CREAT|O_WRONLY|O_TRUNC); if (fd < 0) { - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_ACCESS_ERROR)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR)); return -1; } - display_playlist_count(count, str(LANG_PLAYLIST_SAVE_COUNT)); + display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT), false); cpu_boost(true); @@ -3425,7 +3442,7 @@ int playlist_save(struct playlist_info* playlist, char *filename) if (fdprintf(fd, "%s\n", tmp_buf) < 0) { - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_ACCESS_ERROR)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR)); result = -1; break; } @@ -3433,7 +3450,8 @@ int playlist_save(struct playlist_info* playlist, char *filename) count++; if ((count % PLAYLIST_DISPLAY_COUNT) == 0) - display_playlist_count(count, str(LANG_PLAYLIST_SAVE_COUNT)); + display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT), + false); yield(); } @@ -3441,7 +3459,7 @@ int playlist_save(struct playlist_info* playlist, char *filename) index = (index+1)%playlist->amount; } - display_playlist_count(count, str(LANG_PLAYLIST_SAVE_COUNT)); + display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT), true); close(fd); @@ -3512,7 +3530,7 @@ int playlist_directory_tracksearch(const char* dirname, bool recurse, if (ft_load(tc, dirname) < 0) { - gui_syncsplash(HZ*2, str(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR)); + gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR)); *(tc->dirfilter) = old_dirfilter; return -1; } diff --git a/apps/plugin.c b/apps/plugin.c index 20ecafb532..bdb9c23f22 100644 --- a/apps/plugin.c +++ b/apps/plugin.c @@ -537,7 +537,7 @@ int plugin_load(const char* plugin, void* parameter) plugin_loaded = false; } - gui_syncsplash(0, str(LANG_WAIT)); + gui_syncsplash(0, ID2P(LANG_WAIT)); strcpy(current_plugin,p); #ifdef SIMULATOR diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c index fb178ace47..7513a26a1f 100644 --- a/apps/recorder/radio.c +++ b/apps/recorder/radio.c @@ -487,7 +487,7 @@ int radio_screen(void) radio_start(); #endif - if(num_presets < 1 && yesno_pop(str(LANG_FM_FIRST_AUTOSCAN))) + if(num_presets < 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN))) scan_presets(); curr_preset = find_preset(curr_freq); @@ -551,7 +551,7 @@ int radio_screen(void) done = true; if(presets_changed) { - if(yesno_pop(str(LANG_FM_SAVE_CHANGES))) + if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES))) { if(filepreset[0] == '\0') save_preset_list(); @@ -606,7 +606,7 @@ int radio_screen(void) ret_val = GO_TO_ROOT; if(presets_changed) { - if(yesno_pop(str(LANG_FM_SAVE_CHANGES))) + if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES))) { if(filepreset[0] == '\0') save_preset_list(); @@ -690,7 +690,7 @@ int radio_screen(void) case ACTION_FM_PRESET: if(num_presets < 1) { - gui_syncsplash(HZ, str(LANG_FM_NO_PRESETS)); + gui_syncsplash(HZ, ID2P(LANG_FM_NO_PRESETS)); update_screen = true; FOR_NB_SCREENS(i) { @@ -996,7 +996,7 @@ static void radio_save_presets(void) } else { - gui_syncsplash(HZ, str(LANG_FM_PRESET_SAVE_FAILED)); + gui_syncsplash(HZ, ID2P(LANG_FM_PRESET_SAVE_FAILED)); } } @@ -1082,7 +1082,7 @@ static int radio_add_preset(void) } else { - gui_syncsplash(HZ, str(LANG_FM_NO_FREE_PRESETS)); + gui_syncsplash(HZ, ID2P(LANG_FM_NO_FREE_PRESETS)); } return true; } @@ -1170,7 +1170,7 @@ static int save_preset_list(void) if((!p1) || (len > MAX_FILENAME) || (len == 0)) { /* no slash, too long or too short */ - gui_syncsplash(HZ, str(LANG_INVALID_FILENAME)); + gui_syncsplash(HZ, ID2P(LANG_INVALID_FILENAME)); } else { @@ -1190,7 +1190,7 @@ static int save_preset_list(void) } } else - gui_syncsplash(HZ, str(LANG_FM_NO_PRESETS)); + gui_syncsplash(HZ, ID2P(LANG_FM_NO_PRESETS)); return true; } @@ -1339,7 +1339,7 @@ static int scan_presets(void) bool do_scan = true; if(num_presets > 0) /* Do that to avoid 2 questions. */ - do_scan = yesno_pop(str(LANG_FM_CLEAR_PRESETS)); + do_scan = yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS)); if(do_scan) { diff --git a/apps/root_menu.c b/apps/root_menu.c index df59b1b846..b2684abfda 100644 --- a/apps/root_menu.c +++ b/apps/root_menu.c @@ -129,7 +129,7 @@ static int browser(void* param) /* Maybe just needs to reboot due to delayed commit */ if (stat->commit_delayed) { - gui_syncsplash(HZ*2, str(LANG_PLEASE_REBOOT)); + gui_syncsplash(HZ*2, ID2P(LANG_PLEASE_REBOOT)); break; } @@ -146,7 +146,7 @@ static int browser(void* param) { /* Prompt the user */ reinit_attempted = true; - char *lines[]={str(LANG_TAGCACHE_BUSY), str(LANG_TAGCACHE_FORCE_UPDATE)}; + char *lines[]={ID2P(LANG_TAGCACHE_BUSY), ID2P(LANG_TAGCACHE_FORCE_UPDATE)}; struct text_message message={lines, 2}; if(gui_syncyesno_run(&message, NULL, NULL) == YESNO_NO) break; @@ -159,6 +159,24 @@ static int browser(void* param) } /* Display building progress */ + static long talked_tick = 0; + if(talk_menus_enabled() && + (talked_tick == 0 + || TIME_AFTER(current_tick, talked_tick+7*HZ))) + { + talked_tick = current_tick; + if (stat->commit_step > 0) + { + talk_id(LANG_TAGCACHE_INIT, false); + talk_number(stat->commit_step, true); + talk_id(VOICE_OF, true); + talk_number(tagcache_get_max_commit_step(), true); + } else if(stat->processed_entries) + { + talk_number(stat->processed_entries, false); + talk_id(LANG_BUILDING_DATABASE, true); + } + } if (stat->commit_step > 0) { gui_syncsplash(0, "%s [%d/%d]", @@ -236,7 +254,7 @@ static int wpsscrn(void* param) } else { - gui_syncsplash(HZ*2, str(LANG_NOTHING_TO_RESUME)); + gui_syncsplash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME)); } #if LCD_DEPTH > 1 show_main_backdrop(); diff --git a/apps/settings.c b/apps/settings.c index 7815bdb81c..8b826066a1 100644 --- a/apps/settings.c +++ b/apps/settings.c @@ -544,6 +544,7 @@ int settings_save( void ) screens[i].update(); #endif } + cond_talk_ids_fq(LANG_SETTINGS_SAVE_FAILED); sleep(HZ*2); return -1; } @@ -575,15 +576,15 @@ bool settings_save_config(int options) break; } else { - gui_syncsplash(HZ, str(LANG_CANCEL)); + gui_syncsplash(HZ, ID2P(LANG_CANCEL)); return false; } } if (settings_write_config(filename, options)) - gui_syncsplash(HZ, str(LANG_SETTINGS_SAVED)); + gui_syncsplash(HZ, ID2P(LANG_SETTINGS_SAVED)); else - gui_syncsplash(HZ, str(LANG_FAILED)); + gui_syncsplash(HZ, ID2P(LANG_FAILED)); return true; } diff --git a/apps/tagtree.c b/apps/tagtree.c index 22b7125701..59fb8c131f 100644 --- a/apps/tagtree.c +++ b/apps/tagtree.c @@ -690,7 +690,7 @@ bool tagtree_export(void) gui_syncsplash(0, str(LANG_CREATING)); if (!tagcache_create_changelog(&tcs)) { - gui_syncsplash(HZ*2, str(LANG_FAILED)); + gui_syncsplash(HZ*2, ID2P(LANG_FAILED)); } return false; @@ -698,10 +698,10 @@ bool tagtree_export(void) bool tagtree_import(void) { - gui_syncsplash(0, str(LANG_WAIT)); + gui_syncsplash(0, ID2P(LANG_WAIT)); if (!tagcache_import_changelog()) { - gui_syncsplash(HZ*2, str(LANG_FAILED)); + gui_syncsplash(HZ*2, ID2P(LANG_FAILED)); } return false; @@ -1228,7 +1228,7 @@ static int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs, if (!sort && (sort_inverse || sort_limit)) { - gui_syncsplash(HZ*4, str(LANG_SHOWDIR_BUFFER_FULL), total_count); + gui_syncsplash(HZ*4, ID2P(LANG_SHOWDIR_BUFFER_FULL), total_count); logf("Too small dir buffer"); return 0; } @@ -1419,7 +1419,7 @@ int tagtree_enter(struct tree_context* c) !global_settings.party_mode && playlist_modified(NULL)) { - char *lines[]={str(LANG_WARN_ERASEDYNPLAYLIST_PROMPT)}; + char *lines[]={ID2P(LANG_WARN_ERASEDYNPLAYLIST_PROMPT)}; struct text_message message={lines, 1}; if (gui_syncyesno_run(&message, NULL, NULL) != YESNO_YES) @@ -1496,7 +1496,7 @@ static bool insert_all_playlist(struct tree_context *c, int position, bool queue cpu_boost(true); if (!tagcache_search(&tcs, tag_filename)) { - gui_syncsplash(HZ, str(LANG_TAGCACHE_BUSY)); + gui_syncsplash(HZ, ID2P(LANG_TAGCACHE_BUSY)); cpu_boost(false); return false; } @@ -1599,12 +1599,12 @@ bool tagtree_insert_selection_playlist(int position, bool queue) } if (tc->filesindir <= 0) - gui_syncsplash(HZ, str(LANG_END_PLAYLIST)); + gui_syncsplash(HZ, ID2P(LANG_END_PLAYLIST)); else { logf("insert_all_playlist"); if (!insert_all_playlist(tc, position, queue)) - gui_syncsplash(HZ*2, str(LANG_FAILED)); + gui_syncsplash(HZ*2, ID2P(LANG_FAILED)); } /* Finally return the dirlevel to its original value. */ diff --git a/apps/talk.c b/apps/talk.c index 89ab3901c4..3b7ab2a03f 100644 --- a/apps/talk.c +++ b/apps/talk.c @@ -117,6 +117,8 @@ static long size_for_thumbnail; /* leftover buffer size for it */ static struct voicefile* p_voicefile; /* loaded voicefile */ static bool has_voicefile; /* a voicefile file is present */ static struct queue_entry queue[QUEUE_SIZE]; /* queue of scheduled clips */ +/* enqueue next utterance even if enqueue is false. */ +static bool force_enqueue_next; static int queue_write; /* write index of queue, by application */ static int queue_read; /* read index of queue, by ISR context */ static int sent; /* how many bytes handed over to playback, owned by ISR */ @@ -134,7 +136,6 @@ static int talk_menu_disable; /* if non-zero, temporarily disable voice UI (not static void load_voicefile(void); static void mp3_callback(unsigned char** start, size_t* size); -static int shutup(void); static int queue_clip(unsigned char* buf, long size, bool enqueue); static int open_voicefile(void); static unsigned char* get_clip(long id, long* p_size); @@ -267,6 +268,13 @@ load_err: } +/* Are more voice clips queued and waiting? */ +bool is_voice_queued() +{ + return !!QUEUE_LEVEL; +} + + /* called in ISR context if mp3 data got consumed */ static void mp3_callback(unsigned char** start, size_t* size) { @@ -321,7 +329,7 @@ re_check: } /* stop the playback and the pending clips */ -static int shutup(void) +static int do_shutup(void) { #if CONFIG_CODEC != SWCODEC unsigned char* pos; @@ -387,6 +395,13 @@ static int shutup(void) return 0; } +/* Shutup the voice, except if force_enqueue_next is set. */ +static int shutup(void) +{ + if (!force_enqueue_next) + return do_shutup(); + return 0; +} /* schedule a clip, at the end or discard the existing queue */ static int queue_clip(unsigned char* buf, long size, bool enqueue) @@ -395,6 +410,9 @@ static int queue_clip(unsigned char* buf, long size, bool enqueue) if (!enqueue) shutup(); /* cut off all the pending stuff */ + /* Something is being enqueued, force_enqueue_next override is no + longer in effect. */ + force_enqueue_next = false; if (!size) return 0; /* safety check */ @@ -617,6 +635,26 @@ int talk_id(long id, bool enqueue) return 0; } +/* Speaks zero or more IDs (from an array). */ +int talk_idarray(long *ids, bool enqueue) +{ + int r; + if(!ids) + return 0; + while(*ids != TALK_FINAL_ID) + { + if((r = talk_id(*ids++, enqueue)) <0) + return r; + enqueue = true; + } + return 0; +} + +/* Make sure the current utterance is not interrupted by the next one. */ +void talk_force_enqueue_next(void) +{ + force_enqueue_next = true; +} /* play a thumbnail from file */ int talk_file(const char* filename, bool enqueue) diff --git a/apps/talk.h b/apps/talk.h index d5a6bc7060..d471ec7ca8 100644 --- a/apps/talk.h +++ b/apps/talk.h @@ -66,6 +66,9 @@ bool talk_voice_required(void); /* returns true if voice codec required */ int talk_get_bufsize(void); /* get the loaded voice file size */ /* talk_buffer_steal - on SWCODEC, for use by buffer functions only */ int talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */ +//int shutup(void); /* Interrupt voice, as when enqueue is false */ +//int do_shutup(void); /* kill voice unconditionally */ +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 */ int talk_number(long n, bool enqueue); /* say a number */ @@ -74,4 +77,37 @@ int talk_spell(const char* spell, bool enqueue); /* spell a string */ bool talk_menus_enabled(void); /* returns true if menus should be voiced */ void talk_disable_menus(void); /* disable voice menus (temporarily, not persisted) */ void talk_enable_menus(void); /* re-enable voice menus */ + +/* Enqueue next utterance even if enqueue parameter is false: don't + interrupt the current utterance. */ +void talk_force_enqueue_next(void); + +/* speaks one or more IDs (from an array)). */ +int talk_idarray(long *idarray, bool enqueue); +/* This (otherwise invalid) ID signals the end of the array. */ +#define TALK_FINAL_ID LANG_LAST_INDEX_IN_ARRAY +/* This makes an initializer for the array of IDs and takes care to + put the final sentinel element at the end. */ +#define TALK_IDARRAY(ids...) ((long[]){ids,TALK_FINAL_ID}) +/* And this handy macro makes it look like a variadic function. */ +#define talk_ids(enqueue, ids...) talk_idarray(TALK_IDARRAY(ids), enqueue) +/* This version talks only if talking menus are enabled, and does not + enqueue the initial id. */ +#define cond_talk_ids(ids...) do { \ + if (talk_menus_enabled()) \ + talk_ids(false, ids); \ + } while(0) +/* And a version that takes the array parameter... */ +#define cond_talk_idarray(idarray) do { \ + if (talk_menus_enabled() \ + talk_idarray(idarray, false); \ + } while(0) +/* Convenience macro to conditionally speak something and not have + it interrupted. */ +#define cond_talk_ids_fq(ids...) do { \ + if (talk_menus_enabled()) { \ + talk_ids(false, ids); \ + talk_force_enqueue_next(); \ + } \ + }while(0) #endif /* __TALK_H__ */ diff --git a/apps/tree.c b/apps/tree.c index e795cb9b0f..d59d84fc1f 100644 --- a/apps/tree.c +++ b/apps/tree.c @@ -325,7 +325,7 @@ static int update_dir(void) (tc.dirfull || tc.filesindir == global_settings.max_files_in_dir) ) { - gui_syncsplash(HZ, str(LANG_SHOWDIR_BUFFER_FULL)); + gui_syncsplash(HZ, ID2P(LANG_SHOWDIR_BUFFER_FULL)); } } #ifdef HAVE_TAGCACHE @@ -556,7 +556,7 @@ static int dirbrowse() if (*tc.dirfilter > NUM_FILTER_MODES && numentries==0) { - gui_syncsplash(HZ*2, str(LANG_NO_FILES)); + gui_syncsplash(HZ*2, ID2P(LANG_NO_FILES)); return false; /* No files found for rockbox_browser() */ } @@ -567,7 +567,7 @@ static int dirbrowse() tc.dirlevel = 0; /* shouldnt be needed.. this code needs work! */ #ifdef BOOTFILE if (boot_changed) { - char *lines[]={str(LANG_BOOT_CHANGED), str(LANG_REBOOT_NOW)}; + char *lines[]={ID2P(LANG_BOOT_CHANGED), ID2P(LANG_REBOOT_NOW)}; struct text_message message={lines, 2}; if(gui_syncyesno_run(&message, NULL, NULL)==YESNO_YES) rolo_load("/" BOOTFILE); @@ -1336,6 +1336,7 @@ void tree_restore(void) str(LANG_SCANNING_DISK)); gui_textarea_update(&screens[i]); } + cond_talk_ids_fq(LANG_SCANNING_DISK); dircache_build(global_status.dircache_size); -- cgit v1.2.3