summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNils Wallménius <nils@rockbox.org>2007-08-06 13:08:36 +0000
committerNils Wallménius <nils@rockbox.org>2007-08-06 13:08:36 +0000
commit5b76936a44de3c7ecd568300f26b5e6421901285 (patch)
tree504d9cf371d8f64c70a7bb40469a3a6f05a1b7cd
parentd755c283caef258ae5d81278d324f907fcf402c8 (diff)
downloadrockbox-5b76936a44de3c7ecd568300f26b5e6421901285.tar.gz
rockbox-5b76936a44de3c7ecd568300f26b5e6421901285.zip
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
-rw-r--r--apps/bookmark.c10
-rw-r--r--apps/filetree.c42
-rw-r--r--apps/filetypes.c2
-rw-r--r--apps/gui/gwps-common.c2
-rw-r--r--apps/gui/splash.c12
-rw-r--r--apps/gui/yesno.c45
-rw-r--r--apps/lang/english.lang121
-rw-r--r--apps/main.c13
-rw-r--r--apps/menus/main_menu.c6
-rw-r--r--apps/menus/playback_menu.c4
-rw-r--r--apps/menus/settings_menu.c6
-rw-r--r--apps/misc.c27
-rw-r--r--apps/onplay.c19
-rw-r--r--apps/playback.c18
-rw-r--r--apps/playback.h1
-rw-r--r--apps/playlist.c102
-rw-r--r--apps/plugin.c2
-rw-r--r--apps/recorder/radio.c18
-rw-r--r--apps/root_menu.c24
-rw-r--r--apps/settings.c7
-rw-r--r--apps/tagtree.c16
-rw-r--r--apps/talk.c42
-rw-r--r--apps/talk.h36
-rw-r--r--apps/tree.c7
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)
186 return write_bookmark(false); 186 return write_bookmark(false);
187 } 187 }
188#ifdef HAVE_LCD_BITMAP 188#ifdef HAVE_LCD_BITMAP
189 unsigned char *lines[]={str(LANG_AUTO_BOOKMARK_QUERY)}; 189 unsigned char *lines[]={ID2P(LANG_AUTO_BOOKMARK_QUERY)};
190 struct text_message message={(char **)lines, 1}; 190 struct text_message message={(char **)lines, 1};
191#else 191#else
192 unsigned char *lines[]={str(LANG_AUTO_BOOKMARK_QUERY), 192 unsigned char *lines[]={ID2P(LANG_AUTO_BOOKMARK_QUERY),
193 str(LANG_CONFIRM_WITH_BUTTON)}; 193 str(LANG_CONFIRM_WITH_BUTTON)};
194 struct text_message message={(char **)lines, 2}; 194 struct text_message message={(char **)lines, 2};
195#endif 195#endif
@@ -244,8 +244,8 @@ static bool write_bookmark(bool create_bookmark_file)
244 } 244 }
245 } 245 }
246 246
247 gui_syncsplash(HZ, str(success ? LANG_BOOKMARK_CREATE_SUCCESS 247 gui_syncsplash(HZ, success ? ID2P(LANG_BOOKMARK_CREATE_SUCCESS)
248 : LANG_BOOKMARK_CREATE_FAILURE)); 248 : ID2P(LANG_BOOKMARK_CREATE_FAILURE));
249 249
250 return true; 250 return true;
251} 251}
@@ -634,7 +634,7 @@ static char* select_bookmark(const char* bookmark_file_name, bool show_dont_resu
634 if (bookmarks->total_count < 1) 634 if (bookmarks->total_count < 1)
635 { 635 {
636 /* No more bookmarks, delete file and exit */ 636 /* No more bookmarks, delete file and exit */
637 gui_syncsplash(HZ, str(LANG_BOOKMARK_LOAD_EMPTY)); 637 gui_syncsplash(HZ, ID2P(LANG_BOOKMARK_LOAD_EMPTY));
638 remove(bookmark_file_name); 638 remove(bookmark_file_name);
639 return NULL; 639 return NULL;
640 } 640 }
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)
342 switch ( file->attr & FILE_ATTR_MASK ) { 342 switch ( file->attr & FILE_ATTR_MASK ) {
343 case FILE_ATTR_M3U: 343 case FILE_ATTR_M3U:
344 if (global_settings.party_mode) { 344 if (global_settings.party_mode) {
345 gui_syncsplash(HZ, str(LANG_PARTY_MODE)); 345 gui_syncsplash(HZ, ID2P(LANG_PARTY_MODE));
346 break; 346 break;
347 } 347 }
348 348
349 if (bookmark_autoload(buf)) 349 if (bookmark_autoload(buf))
350 break; 350 break;
351 351
352 gui_syncsplash(0, str(LANG_WAIT)); 352 gui_syncsplash(0, ID2P(LANG_WAIT));
353 353
354 /* about to create a new current playlist... 354 /* about to create a new current playlist...
355 allow user to cancel the operation */ 355 allow user to cancel the operation */
356 if (global_settings.warnon_erase_dynplaylist && 356 if (global_settings.warnon_erase_dynplaylist &&
357 playlist_modified(NULL)) 357 playlist_modified(NULL))
358 { 358 {
359 char *lines[]={str(LANG_WARN_ERASEDYNPLAYLIST_PROMPT)}; 359 char *lines[]={ID2P(LANG_WARN_ERASEDYNPLAYLIST_PROMPT)};
360 struct text_message message={lines, 1}; 360 struct text_message message={lines, 1};
361 361
362 if(gui_syncyesno_run(&message, NULL, NULL) != YESNO_YES) 362 if(gui_syncyesno_run(&message, NULL, NULL) != YESNO_YES)
@@ -377,7 +377,7 @@ int ft_enter(struct tree_context* c)
377 if (bookmark_autoload(c->currdir)) 377 if (bookmark_autoload(c->currdir))
378 break; 378 break;
379 379
380 gui_syncsplash(0, str(LANG_WAIT)); 380 gui_syncsplash(0, ID2P(LANG_WAIT));
381 381
382 /* about to create a new current playlist... 382 /* about to create a new current playlist...
383 allow user to cancel the operation */ 383 allow user to cancel the operation */
@@ -385,7 +385,7 @@ int ft_enter(struct tree_context* c)
385 !global_settings.party_mode && 385 !global_settings.party_mode &&
386 playlist_modified(NULL)) 386 playlist_modified(NULL))
387 { 387 {
388 char *lines[]={str(LANG_WARN_ERASEDYNPLAYLIST_PROMPT)}; 388 char *lines[]={ID2P(LANG_WARN_ERASEDYNPLAYLIST_PROMPT)};
389 struct text_message message={lines, 1}; 389 struct text_message message={lines, 1};
390 390
391 if(gui_syncyesno_run(&message, NULL, NULL) != YESNO_YES) 391 if(gui_syncyesno_run(&message, NULL, NULL) != YESNO_YES)
@@ -396,7 +396,7 @@ int ft_enter(struct tree_context* c)
396 { 396 {
397 playlist_insert_track(NULL, buf, 397 playlist_insert_track(NULL, buf,
398 PLAYLIST_INSERT_LAST, true, true); 398 PLAYLIST_INSERT_LAST, true, true);
399 gui_syncsplash(HZ, str(LANG_QUEUE_LAST)); 399 gui_syncsplash(HZ, ID2P(LANG_QUEUE_LAST));
400 } 400 }
401 else if (playlist_create(c->currdir, NULL) != -1) 401 else if (playlist_create(c->currdir, NULL) != -1)
402 { 402 {
@@ -421,7 +421,7 @@ int ft_enter(struct tree_context* c)
421 /* fmr preset file */ 421 /* fmr preset file */
422 case FILE_ATTR_FMR: 422 case FILE_ATTR_FMR:
423 423
424 gui_syncsplash(0, str(LANG_WAIT)); 424 gui_syncsplash(0, ID2P(LANG_WAIT));
425 425
426 /* Preset inside the default folder. */ 426 /* Preset inside the default folder. */
427 if(!strncasecmp(FMPRESET_PATH, buf, strlen(FMPRESET_PATH))) 427 if(!strncasecmp(FMPRESET_PATH, buf, strlen(FMPRESET_PATH)))
@@ -448,7 +448,7 @@ int ft_enter(struct tree_context* c)
448 448
449 /* wps config file */ 449 /* wps config file */
450 case FILE_ATTR_WPS: 450 case FILE_ATTR_WPS:
451 gui_syncsplash(0, str(LANG_WAIT)); 451 gui_syncsplash(0, ID2P(LANG_WAIT));
452#if LCD_DEPTH > 1 452#if LCD_DEPTH > 1
453 unload_wps_backdrop(); 453 unload_wps_backdrop();
454#endif 454#endif
@@ -460,7 +460,7 @@ int ft_enter(struct tree_context* c)
460#if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1) 460#if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1)
461 /* remote-wps config file */ 461 /* remote-wps config file */
462 case FILE_ATTR_RWPS: 462 case FILE_ATTR_RWPS:
463 gui_syncsplash(0, str(LANG_WAIT)); 463 gui_syncsplash(0, ID2P(LANG_WAIT));
464#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 464#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
465 unload_remote_wps_backdrop(); 465 unload_remote_wps_backdrop();
466#endif 466#endif
@@ -471,39 +471,39 @@ int ft_enter(struct tree_context* c)
471#endif 471#endif
472 472
473 case FILE_ATTR_CFG: 473 case FILE_ATTR_CFG:
474 gui_syncsplash(0, str(LANG_WAIT)); 474 gui_syncsplash(0, ID2P(LANG_WAIT));
475 if (!settings_load_config(buf,true)) 475 if (!settings_load_config(buf,true))
476 break; 476 break;
477 gui_syncsplash(HZ, str(LANG_SETTINGS_LOADED)); 477 gui_syncsplash(HZ, ID2P(LANG_SETTINGS_LOADED));
478 break; 478 break;
479 479
480 case FILE_ATTR_BMARK: 480 case FILE_ATTR_BMARK:
481 gui_syncsplash(0, str(LANG_WAIT)); 481 gui_syncsplash(0, ID2P(LANG_WAIT));
482 bookmark_load(buf, false); 482 bookmark_load(buf, false);
483 reload_dir = true; 483 reload_dir = true;
484 break; 484 break;
485 485
486 case FILE_ATTR_LNG: 486 case FILE_ATTR_LNG:
487 gui_syncsplash(0, str(LANG_WAIT)); 487 gui_syncsplash(0, ID2P(LANG_WAIT));
488 if(!lang_load(buf)) { 488 if(!lang_load(buf)) {
489 set_file(buf, (char *)global_settings.lang_file, 489 set_file(buf, (char *)global_settings.lang_file,
490 MAX_FILENAME); 490 MAX_FILENAME);
491 talk_init(); /* use voice of same language */ 491 talk_init(); /* use voice of same language */
492 gui_syncsplash(HZ, str(LANG_LANGUAGE_LOADED)); 492 gui_syncsplash(HZ, ID2P(LANG_LANGUAGE_LOADED));
493 } 493 }
494 break; 494 break;
495 495
496#ifdef HAVE_LCD_BITMAP 496#ifdef HAVE_LCD_BITMAP
497 case FILE_ATTR_FONT: 497 case FILE_ATTR_FONT:
498 gui_syncsplash(0, str(LANG_WAIT)); 498 gui_syncsplash(0, ID2P(LANG_WAIT));
499 font_load(buf); 499 font_load(buf);
500 set_file(buf, (char *)global_settings.font_file, MAX_FILENAME); 500 set_file(buf, (char *)global_settings.font_file, MAX_FILENAME);
501 break; 501 break;
502 502
503 case FILE_ATTR_KBD: 503 case FILE_ATTR_KBD:
504 gui_syncsplash(0, str(LANG_WAIT)); 504 gui_syncsplash(0, ID2P(LANG_WAIT));
505 if (!load_kbd(buf)) 505 if (!load_kbd(buf))
506 gui_syncsplash(HZ, str(LANG_KEYBOARD_LOADED)); 506 gui_syncsplash(HZ, ID2P(LANG_KEYBOARD_LOADED));
507 set_file(buf, (char *)global_settings.kbd_file, MAX_FILENAME); 507 set_file(buf, (char *)global_settings.kbd_file, MAX_FILENAME);
508 break; 508 break;
509#endif 509#endif
@@ -511,7 +511,7 @@ int ft_enter(struct tree_context* c)
511#ifndef SIMULATOR 511#ifndef SIMULATOR
512 /* firmware file */ 512 /* firmware file */
513 case FILE_ATTR_MOD: 513 case FILE_ATTR_MOD:
514 gui_syncsplash(0, str(LANG_WAIT)); 514 gui_syncsplash(0, ID2P(LANG_WAIT));
515 rolo_load(buf); 515 rolo_load(buf);
516 break; 516 break;
517#endif 517#endif
@@ -519,11 +519,11 @@ int ft_enter(struct tree_context* c)
519 /* plugin file */ 519 /* plugin file */
520 case FILE_ATTR_ROCK: 520 case FILE_ATTR_ROCK:
521 if (global_settings.party_mode) { 521 if (global_settings.party_mode) {
522 gui_syncsplash(HZ, str(LANG_PARTY_MODE)); 522 gui_syncsplash(HZ, ID2P(LANG_PARTY_MODE));
523 break; 523 break;
524 } 524 }
525 525
526 gui_syncsplash(0, str(LANG_WAIT)); 526 gui_syncsplash(0, ID2P(LANG_WAIT));
527 527
528 if (plugin_load(buf,NULL) == PLUGIN_USB_CONNECTED) 528 if (plugin_load(buf,NULL) == PLUGIN_USB_CONNECTED)
529 { 529 {
@@ -545,7 +545,7 @@ int ft_enter(struct tree_context* c)
545 char* plugin; 545 char* plugin;
546 546
547 if (global_settings.party_mode) { 547 if (global_settings.party_mode) {
548 gui_syncsplash(HZ, str(LANG_PARTY_MODE)); 548 gui_syncsplash(HZ, ID2P(LANG_PARTY_MODE));
549 break; 549 break;
550 } 550 }
551 551
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)
300 { 300 {
301 if (filetype_count >= MAX_FILETYPES) 301 if (filetype_count >= MAX_FILETYPES)
302 { 302 {
303 gui_syncsplash(HZ, str(LANG_FILETYPES_FULL)); 303 gui_syncsplash(HZ, ID2P(LANG_FILETYPES_FULL));
304 break; 304 break;
305 } 305 }
306 rm_whitespaces(line); 306 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)
294#ifdef HAVE_LCD_BITMAP 294#ifdef HAVE_LCD_BITMAP
295 gui_syncstatusbar_draw(&statusbars, true); 295 gui_syncstatusbar_draw(&statusbars, true);
296#endif 296#endif
297 gui_syncsplash(HZ, str(LANG_END_PLAYLIST)); 297 gui_syncsplash(HZ, ID2P(LANG_END_PLAYLIST));
298 return true; 298 return true;
299 } 299 }
300 else 300 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 @@
22#include "stdio.h" 22#include "stdio.h"
23#include "kernel.h" 23#include "kernel.h"
24#include "screen_access.h" 24#include "screen_access.h"
25#include "lang.h"
26#include "settings.h"
27#include "talk.h"
25 28
26#ifndef MAX 29#ifndef MAX
27#define MAX(a, b) (((a)>(b))?(a):(b)) 30#define MAX(a, b) (((a)>(b))?(a):(b))
@@ -197,6 +200,15 @@ void gui_syncsplash(int ticks, const unsigned char *fmt, ...)
197{ 200{
198 va_list ap; 201 va_list ap;
199 int i; 202 int i;
203 long id;
204 /* fmt may be a so called virtual pointer. See settings.h. */
205 if((id = P2ID(fmt)) >= 0)
206 /* If fmt specifies a voicefont ID, and voice menus are
207 enabled, then speak it. */
208 cond_talk_ids_fq(id);
209 /* If fmt is a lang ID then get the corresponding string (which
210 still might contain % place holders). */
211 fmt = P2STR(fmt);
200 va_start( ap, fmt ); 212 va_start( ap, fmt );
201 FOR_NB_SCREENS(i) 213 FOR_NB_SCREENS(i)
202 splash(&(screens[i]), fmt, ap); 214 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 @@
23#include "misc.h" 23#include "misc.h"
24#include "lang.h" 24#include "lang.h"
25#include "action.h" 25#include "action.h"
26#include "talk.h"
26 27
27/* 28/*
28 * Initializes the yesno asker 29 * Initializes the yesno asker
@@ -97,7 +98,28 @@ static bool gui_yesno_draw_result(struct gui_yesno * yn, enum yesno_res result)
97 gui_textarea_put_message(yn->display, message, 0); 98 gui_textarea_put_message(yn->display, message, 0);
98 return(true); 99 return(true);
99} 100}
101
100#include "debug.h" 102#include "debug.h"
103
104/* Processes a text_message whose lines may be virtual pointers
105 representing language / voicefont IDs (see settings.h). Copies out
106 the IDs to the ids array, which is of length maxlen, and replaces
107 the pointers in the text_message with the actual language strings.
108 The ids array is terminated with the TALK_FINAL_ID sentinel
109 element. */
110static void extract_talk_ids(struct text_message *m, long *ids, int maxlen)
111{
112 int line, i=0;
113 if(m)
114 for(line=0; line<m->nb_lines; line++) {
115 long id = P2ID((unsigned char *)m->message_lines[line]);
116 if(id>=0 && i<maxlen-1)
117 ids[i++] = id;
118 m->message_lines[line] = (char *)P2STR((unsigned char *)m->message_lines[line]);
119 }
120 ids[i] = TALK_FINAL_ID;
121}
122
101enum yesno_res gui_syncyesno_run(struct text_message * main_message, 123enum yesno_res gui_syncyesno_run(struct text_message * main_message,
102 struct text_message * yes_message, 124 struct text_message * yes_message,
103 struct text_message * no_message) 125 struct text_message * no_message)
@@ -107,6 +129,13 @@ enum yesno_res gui_syncyesno_run(struct text_message * main_message,
107 int result=-1; 129 int result=-1;
108 bool result_displayed; 130 bool result_displayed;
109 struct gui_yesno yn[NB_SCREENS]; 131 struct gui_yesno yn[NB_SCREENS];
132 long voice_ids[5];
133 long talked_tick = 0;
134 /* The text messages may contain virtual pointers to IDs (see
135 settings.h) instead of plain strings. Copy the IDs out so we
136 can speak them, and unwrap the actual language strings. */
137 extract_talk_ids(main_message, voice_ids,
138 sizeof(voice_ids)/sizeof(voice_ids[0]));
110 FOR_NB_SCREENS(i) 139 FOR_NB_SCREENS(i)
111 { 140 {
112 gui_yesno_init(&(yn[i]), main_message, yes_message, no_message); 141 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,
115 } 144 }
116 while (result==-1) 145 while (result==-1)
117 { 146 {
118 button = get_action(CONTEXT_YESNOSCREEN,TIMEOUT_BLOCK); 147 /* Repeat the question every 5secs (more or less) */
148 if (talk_menus_enabled()
149 && (talked_tick==0 || TIME_AFTER(current_tick, talked_tick+HZ*5)))
150 {
151 talked_tick = current_tick;
152 talk_idarray(voice_ids, false);
153 }
154 button = get_action(CONTEXT_YESNOSCREEN, HZ*5);
119 switch (button) 155 switch (button)
120 { 156 {
121 case ACTION_YESNO_ACCEPT: 157 case ACTION_YESNO_ACCEPT:
@@ -133,6 +169,13 @@ enum yesno_res gui_syncyesno_run(struct text_message * main_message,
133 } 169 }
134 FOR_NB_SCREENS(i) 170 FOR_NB_SCREENS(i)
135 result_displayed=gui_yesno_draw_result(&(yn[i]), result); 171 result_displayed=gui_yesno_draw_result(&(yn[i]), result);
172 extract_talk_ids((result == YESNO_YES) ? yes_message : no_message,
173 voice_ids, sizeof(voice_ids)/sizeof(voice_ids[0]));
174 if (talk_menus_enabled())
175 {
176 talk_idarray(voice_ids, false);
177 talk_force_enqueue_next();
178 }
136 if(result_displayed) 179 if(result_displayed)
137 sleep(HZ); 180 sleep(HZ);
138 return(result); 181 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 @@
197 *: "Loading..." 197 *: "Loading..."
198 </dest> 198 </dest>
199 <voice> 199 <voice>
200 *: "" 200 *: "Loading"
201 </voice> 201 </voice>
202</phrase> 202</phrase>
203<phrase> 203<phrase>
@@ -225,7 +225,7 @@
225 *: "Scanning disk..." 225 *: "Scanning disk..."
226 </dest> 226 </dest>
227 <voice> 227 <voice>
228 *: "" 228 *: "Scanning disk"
229 </voice> 229 </voice>
230</phrase> 230</phrase>
231<phrase> 231<phrase>
@@ -239,7 +239,7 @@
239 *: "Shutting down..." 239 *: "Shutting down..."
240 </dest> 240 </dest>
241 <voice> 241 <voice>
242 *: "" 242 *: "Shutting down"
243 </voice> 243 </voice>
244</phrase> 244</phrase>
245<phrase> 245<phrase>
@@ -267,7 +267,7 @@
267 *: "Cancelled" 267 *: "Cancelled"
268 </dest> 268 </dest>
269 <voice> 269 <voice>
270 *: "" 270 *: "Cancelled"
271 </voice> 271 </voice>
272</phrase> 272</phrase>
273<phrase> 273<phrase>
@@ -281,7 +281,7 @@
281 *: "Failed" 281 *: "Failed"
282 </dest> 282 </dest>
283 <voice> 283 <voice>
284 *: "" 284 *: "Failed"
285 </voice> 285 </voice>
286</phrase> 286</phrase>
287<phrase> 287<phrase>
@@ -309,7 +309,7 @@
309 *: "Are You Sure?" 309 *: "Are You Sure?"
310 </dest> 310 </dest>
311 <voice> 311 <voice>
312 *: "" 312 *: "Are You Sure?"
313 </voice> 313 </voice>
314</phrase> 314</phrase>
315<phrase> 315<phrase>
@@ -632,7 +632,7 @@
632 *: "Create a Bookmark?" 632 *: "Create a Bookmark?"
633 </dest> 633 </dest>
634 <voice> 634 <voice>
635 *: "" 635 *: "Create a Bookmark?"
636 </voice> 636 </voice>
637</phrase> 637</phrase>
638<phrase> 638<phrase>
@@ -646,7 +646,7 @@
646 *: "Bookmark Created" 646 *: "Bookmark Created"
647 </dest> 647 </dest>
648 <voice> 648 <voice>
649 *: "" 649 *: "Bookmark Created"
650 </voice> 650 </voice>
651</phrase> 651</phrase>
652<phrase> 652<phrase>
@@ -660,7 +660,7 @@
660 *: "Bookmark Failed!" 660 *: "Bookmark Failed!"
661 </dest> 661 </dest>
662 <voice> 662 <voice>
663 *: "" 663 *: "Bookmark Failed!"
664 </voice> 664 </voice>
665</phrase> 665</phrase>
666<phrase> 666<phrase>
@@ -674,7 +674,7 @@
674 *: "Bookmark Empty" 674 *: "Bookmark Empty"
675 </dest> 675 </dest>
676 <voice> 676 <voice>
677 *: "" 677 *: "Bookmark Empty"
678 </voice> 678 </voice>
679</phrase> 679</phrase>
680<phrase> 680<phrase>
@@ -2430,7 +2430,11 @@
2430 h10,h10_5gb,e200: "Building database... %d found (PREV to return)" 2430 h10,h10_5gb,e200: "Building database... %d found (PREV to return)"
2431 </dest> 2431 </dest>
2432 <voice> 2432 <voice>
2433 *: "" 2433 *: "entries found for database"
2434 h100,h120,h300: "entries found for database"
2435 ipod*: "entries found for database"
2436 x5,m5: "entries found for database"
2437 h10,h10_5gb,e200: "entries found for database"
2434 </voice> 2438 </voice>
2435</phrase> 2439</phrase>
2436<phrase> 2440<phrase>
@@ -2545,7 +2549,7 @@
2545 *: "Updating in background" 2549 *: "Updating in background"
2546 </dest> 2550 </dest>
2547 <voice> 2551 <voice>
2548 *: "" 2552 *: "Updating in background"
2549 </voice> 2553 </voice>
2550</phrase> 2554</phrase>
2551<phrase> 2555<phrase>
@@ -2559,7 +2563,7 @@
2559 *: "Committing database" 2563 *: "Committing database"
2560 </dest> 2564 </dest>
2561 <voice> 2565 <voice>
2562 *: "" 2566 *: "Committing database"
2563 </voice> 2567 </voice>
2564</phrase> 2568</phrase>
2565<phrase> 2569<phrase>
@@ -4893,7 +4897,7 @@
4893 *: "New Language" 4897 *: "New Language"
4894 </dest> 4898 </dest>
4895 <voice> 4899 <voice>
4896 *: "" 4900 *: "New Language"
4897 </voice> 4901 </voice>
4898</phrase> 4902</phrase>
4899<phrase> 4903<phrase>
@@ -5061,7 +5065,7 @@
5061 *: "Settings Loaded" 5065 *: "Settings Loaded"
5062 </dest> 5066 </dest>
5063 <voice> 5067 <voice>
5064 *: "" 5068 *: "Settings Loaded"
5065 </voice> 5069 </voice>
5066</phrase> 5070</phrase>
5067<phrase> 5071<phrase>
@@ -5089,7 +5093,7 @@
5089 *: "Cleared" 5093 *: "Cleared"
5090 </dest> 5094 </dest>
5091 <voice> 5095 <voice>
5092 *: "" 5096 *: "Settings Cleared"
5093 </voice> 5097 </voice>
5094</phrase> 5098</phrase>
5095<phrase> 5099<phrase>
@@ -5117,7 +5121,7 @@
5117 *: "Settings Saved" 5121 *: "Settings Saved"
5118 </dest> 5122 </dest>
5119 <voice> 5123 <voice>
5120 *: "" 5124 *: "Settings Saved"
5121 </voice> 5125 </voice>
5122</phrase> 5126</phrase>
5123<phrase> 5127<phrase>
@@ -5213,7 +5217,7 @@
5213 </dest> 5217 </dest>
5214 <voice> 5218 <voice>
5215 *: none 5219 *: none
5216 radio: "" 5220 radio: "No presets"
5217 </voice> 5221 </voice>
5218</phrase> 5222</phrase>
5219<phrase> 5223<phrase>
@@ -5281,7 +5285,7 @@
5281 </dest> 5285 </dest>
5282 <voice> 5286 <voice>
5283 *: none 5287 *: none
5284 radio: "" 5288 radio: "Preset Save Failed"
5285 </voice> 5289 </voice>
5286</phrase> 5290</phrase>
5287<phrase> 5291<phrase>
@@ -5298,7 +5302,7 @@
5298 </dest> 5302 </dest>
5299 <voice> 5303 <voice>
5300 *: none 5304 *: none
5301 radio: "" 5305 radio: "The Preset List is Full"
5302 </voice> 5306 </voice>
5303</phrase> 5307</phrase>
5304<phrase> 5308<phrase>
@@ -5468,7 +5472,7 @@
5468 </dest> 5472 </dest>
5469 <voice> 5473 <voice>
5470 *: none 5474 *: none
5471 radio: "" 5475 radio: "Clear Current Presets?"
5472 </voice> 5476 </voice>
5473</phrase> 5477</phrase>
5474<phrase> 5478<phrase>
@@ -5604,7 +5608,7 @@
5604 </dest> 5608 </dest>
5605 <voice> 5609 <voice>
5606 *: none 5610 *: none
5607 radio: "" 5611 radio: "No settings found. Autoscan?"
5608 </voice> 5612 </voice>
5609</phrase> 5613</phrase>
5610<phrase> 5614<phrase>
@@ -5621,7 +5625,7 @@
5621 </dest> 5625 </dest>
5622 <voice> 5626 <voice>
5623 *: none 5627 *: none
5624 radio: "" 5628 radio: "Save Changes?"
5625 </voice> 5629 </voice>
5626</phrase> 5630</phrase>
5627<phrase> 5631<phrase>
@@ -6766,7 +6770,7 @@
6766 *: "Saved %d tracks (%s)" 6770 *: "Saved %d tracks (%s)"
6767 </dest> 6771 </dest>
6768 <voice> 6772 <voice>
6769 *: "" 6773 *: "tracks saved"
6770 </voice> 6774 </voice>
6771</phrase> 6775</phrase>
6772<phrase> 6776<phrase>
@@ -6808,7 +6812,7 @@
6808 *: "Recursively?" 6812 *: "Recursively?"
6809 </dest> 6813 </dest>
6810 <voice> 6814 <voice>
6811 *: "" 6815 *: "Recursively?"
6812 </voice> 6816 </voice>
6813</phrase> 6817</phrase>
6814<phrase> 6818<phrase>
@@ -6836,7 +6840,7 @@
6836 *: "Erase dynamic playlist?" 6840 *: "Erase dynamic playlist?"
6837 </dest> 6841 </dest>
6838 <voice> 6842 <voice>
6839 *: "" 6843 *: "Erase dynamic playlist?"
6840 </voice> 6844 </voice>
6841</phrase> 6845</phrase>
6842<phrase> 6846<phrase>
@@ -7221,7 +7225,7 @@
7221 *: "Inserted %d tracks (%s)" 7225 *: "Inserted %d tracks (%s)"
7222 </dest> 7226 </dest>
7223 <voice> 7227 <voice>
7224 *: "" 7228 *: "tracks inserted"
7225 </voice> 7229 </voice>
7226</phrase> 7230</phrase>
7227<phrase> 7231<phrase>
@@ -7235,7 +7239,7 @@
7235 *: "Queued %d tracks (%s)" 7239 *: "Queued %d tracks (%s)"
7236 </dest> 7240 </dest>
7237 <voice> 7241 <voice>
7238 *: "" 7242 *: "tracks queued"
7239 </voice> 7243 </voice>
7240</phrase> 7244</phrase>
7241<phrase> 7245<phrase>
@@ -7781,7 +7785,7 @@
7781 *: "File/directory exists. Overwrite?" 7785 *: "File/directory exists. Overwrite?"
7782 </dest> 7786 </dest>
7783 <voice> 7787 <voice>
7784 *: "" 7788 *: "File or directory exists. Overwrite?"
7785 </voice> 7789 </voice>
7786</phrase> 7790</phrase>
7787<phrase> 7791<phrase>
@@ -7823,7 +7827,7 @@
7823 *: "Delete?" 7827 *: "Delete?"
7824 </dest> 7828 </dest>
7825 <voice> 7829 <voice>
7826 *: "" 7830 *: "Really delete?"
7827 </voice> 7831 </voice>
7828</phrase> 7832</phrase>
7829<phrase> 7833<phrase>
@@ -7879,7 +7883,7 @@
7879 *: "Deleted" 7883 *: "Deleted"
7880 </dest> 7884 </dest>
7881 <voice> 7885 <voice>
7882 *: "" 7886 *: "Deleted"
7883 </voice> 7887 </voice>
7884</phrase> 7888</phrase>
7885<phrase> 7889<phrase>
@@ -8085,7 +8089,7 @@
8085 *: "Playlist Buffer Full" 8089 *: "Playlist Buffer Full"
8086 </dest> 8090 </dest>
8087 <voice> 8091 <voice>
8088 *: "" 8092 *: "Playlist Buffer Full"
8089 </voice> 8093 </voice>
8090</phrase> 8094</phrase>
8091<phrase> 8095<phrase>
@@ -8101,7 +8105,8 @@
8101 player: "End of List" 8105 player: "End of List"
8102 </dest> 8106 </dest>
8103 <voice> 8107 <voice>
8104 *: "" 8108 *: "End of Song List"
8109 player: "End of List"
8105 </voice> 8110 </voice>
8106</phrase> 8111</phrase>
8107<phrase> 8112<phrase>
@@ -8129,7 +8134,7 @@
8129 *: "Nothing to resume" 8134 *: "Nothing to resume"
8130 </dest> 8135 </dest>
8131 <voice> 8136 <voice>
8132 *: "" 8137 *: "Nothing to resume"
8133 </voice> 8138 </voice>
8134</phrase> 8139</phrase>
8135<phrase> 8140<phrase>
@@ -8143,7 +8148,7 @@
8143 *: "Error updating playlist control file" 8148 *: "Error updating playlist control file"
8144 </dest> 8149 </dest>
8145 <voice> 8150 <voice>
8146 *: "" 8151 *: "Error updating playlist control file"
8147 </voice> 8152 </voice>
8148</phrase> 8153</phrase>
8149<phrase> 8154<phrase>
@@ -8157,7 +8162,7 @@
8157 *: "Error accessing playlist file" 8162 *: "Error accessing playlist file"
8158 </dest> 8163 </dest>
8159 <voice> 8164 <voice>
8160 *: "" 8165 *: "Error accessing playlist file"
8161 </voice> 8166 </voice>
8162</phrase> 8167</phrase>
8163<phrase> 8168<phrase>
@@ -8171,7 +8176,7 @@
8171 *: "Error accessing playlist control file" 8176 *: "Error accessing playlist control file"
8172 </dest> 8177 </dest>
8173 <voice> 8178 <voice>
8174 *: "" 8179 *: "Error accessing playlist control file"
8175 </voice> 8180 </voice>
8176</phrase> 8181</phrase>
8177<phrase> 8182<phrase>
@@ -8185,7 +8190,7 @@
8185 *: "Error accessing directory" 8190 *: "Error accessing directory"
8186 </dest> 8191 </dest>
8187 <voice> 8192 <voice>
8188 *: "" 8193 *: "Error accessing directory"
8189 </voice> 8194 </voice>
8190</phrase> 8195</phrase>
8191<phrase> 8196<phrase>
@@ -8199,7 +8204,7 @@
8199 *: "Playlist control file is invalid" 8204 *: "Playlist control file is invalid"
8200 </dest> 8205 </dest>
8201 <voice> 8206 <voice>
8202 *: "" 8207 *: "Playlist control file is invalid"
8203 </voice> 8208 </voice>
8204</phrase> 8209</phrase>
8205<phrase> 8210<phrase>
@@ -8213,7 +8218,7 @@
8213 *: "Save Failed" 8218 *: "Save Failed"
8214 </dest> 8219 </dest>
8215 <voice> 8220 <voice>
8216 *: "" 8221 *: "Save Failed"
8217 </voice> 8222 </voice>
8218</phrase> 8223</phrase>
8219<phrase> 8224<phrase>
@@ -8419,7 +8424,7 @@
8419 *: "Boot changed" 8424 *: "Boot changed"
8420 </dest> 8425 </dest>
8421 <voice> 8426 <voice>
8422 *: "" 8427 *: "Boot changed"
8423 </voice> 8428 </voice>
8424</phrase> 8429</phrase>
8425<phrase> 8430<phrase>
@@ -8433,7 +8438,7 @@
8433 *: "Reboot now?" 8438 *: "Reboot now?"
8434 </dest> 8439 </dest>
8435 <voice> 8440 <voice>
8436 *: "" 8441 *: "Reboot now?"
8437 </voice> 8442 </voice>
8438</phrase> 8443</phrase>
8439<phrase> 8444<phrase>
@@ -8469,7 +8474,7 @@
8469 *: "No files" 8474 *: "No files"
8470 </dest> 8475 </dest>
8471 <voice> 8476 <voice>
8472 *: "" 8477 *: "No files"
8473 </voice> 8478 </voice>
8474</phrase> 8479</phrase>
8475<phrase> 8480<phrase>
@@ -8483,7 +8488,7 @@
8483 *: "New Keyboard" 8488 *: "New Keyboard"
8484 </dest> 8489 </dest>
8485 <voice> 8490 <voice>
8486 *: "" 8491 *: "New Keyboard"
8487 </voice> 8492 </voice>
8488</phrase> 8493</phrase>
8489<phrase> 8494<phrase>
@@ -8567,7 +8572,7 @@
8567 *: "Extension array full" 8572 *: "Extension array full"
8568 </dest> 8573 </dest>
8569 <voice> 8574 <voice>
8570 *: "" 8575 *: "Extension array full"
8571 </voice> 8576 </voice>
8572</phrase> 8577</phrase>
8573<phrase> 8578<phrase>
@@ -8581,7 +8586,7 @@
8581 *: "Filetype array full" 8586 *: "Filetype array full"
8582 </dest> 8587 </dest>
8583 <voice> 8588 <voice>
8584 *: "" 8589 *: "Filetype array full"
8585 </voice> 8590 </voice>
8586</phrase> 8591</phrase>
8587<phrase> 8592<phrase>
@@ -8595,7 +8600,7 @@
8595 *: "Dir Buffer is Full!" 8600 *: "Dir Buffer is Full!"
8596 </dest> 8601 </dest>
8597 <voice> 8602 <voice>
8598 *: "" 8603 *: "Directory Buffer is Full!"
8599 </voice> 8604 </voice>
8600</phrase> 8605</phrase>
8601<phrase> 8606<phrase>
@@ -8623,7 +8628,7 @@
8623 *: "Plugin name too long" 8628 *: "Plugin name too long"
8624 </dest> 8629 </dest>
8625 <voice> 8630 <voice>
8626 *: "" 8631 *: "Plugin name too long"
8627 </voice> 8632 </voice>
8628</phrase> 8633</phrase>
8629<phrase> 8634<phrase>
@@ -8654,7 +8659,7 @@
8654 *: "Please reboot to enable" 8659 *: "Please reboot to enable"
8655 </dest> 8660 </dest>
8656 <voice> 8661 <voice>
8657 *: "" 8662 *: "Please reboot to enable"
8658 </voice> 8663 </voice>
8659</phrase> 8664</phrase>
8660<phrase> 8665<phrase>
@@ -8720,7 +8725,7 @@
8720 *: "WARNING! Low Battery!" 8725 *: "WARNING! Low Battery!"
8721 </dest> 8726 </dest>
8722 <voice> 8727 <voice>
8723 *: "" 8728 *: "WARNING! Low Battery!"
8724 </voice> 8729 </voice>
8725</phrase> 8730</phrase>
8726<phrase> 8731<phrase>
@@ -8734,7 +8739,7 @@
8734 *: "Battery empty! RECHARGE!" 8739 *: "Battery empty! RECHARGE!"
8735 </dest> 8740 </dest>
8736 <voice> 8741 <voice>
8737 *: "" 8742 *: "Battery empty! RECHARGE!"
8738 </voice> 8743 </voice>
8739</phrase> 8744</phrase>
8740<phrase> 8745<phrase>
@@ -10943,4 +10948,18 @@
10943 agc: "AGC maximum gain" 10948 agc: "AGC maximum gain"
10944 </voice> 10949 </voice>
10945</phrase> 10950</phrase>
10951<phrase>
10952 id: VOICE_OF
10953 desc: spoken only, as in 3/8 => 3 of 8
10954 user:
10955 <source>
10956 *: ""
10957 </source>
10958 <dest>
10959 *: ""
10960 </dest>
10961 <voice>
10962 *: "of"
10963 </voice>
10964</phrase>
10946 10965
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)
217 217
218 if (ret > 0) 218 if (ret > 0)
219 { 219 {
220 static long talked_tick = 0;
221 if(talk_menus_enabled()
222 && (talked_tick == 0
223 || TIME_AFTER(current_tick, talked_tick+7*HZ)))
224 {
225 talked_tick = current_tick;
226 talk_id(LANG_TAGCACHE_INIT, false);
227 talk_number(ret, true);
228 talk_id(VOICE_OF, true);
229 talk_number(tagcache_get_max_commit_step(), true);
230 }
220#ifdef HAVE_LCD_BITMAP 231#ifdef HAVE_LCD_BITMAP
221 gui_syncsplash(0, "%s [%d/%d]", 232 gui_syncsplash(0, "%s [%d/%d]",
222 str(LANG_TAGCACHE_INIT), ret, 233 str(LANG_TAGCACHE_INIT), ret,
@@ -474,7 +485,7 @@ static void init(void)
474 if (button_hold()) 485 if (button_hold())
475#endif 486#endif
476 { 487 {
477 gui_syncsplash(HZ*2, str(LANG_RESET_DONE_CLEAR)); 488 gui_syncsplash(HZ*2, ID2P(LANG_RESET_DONE_CLEAR));
478 settings_reset(); 489 settings_reset();
479 } 490 }
480 else 491 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)
67 67
68static int reset_settings(void) 68static int reset_settings(void)
69{ 69{
70 unsigned char *lines[]={str(LANG_RESET_ASK)}; 70 unsigned char *lines[]={ID2P(LANG_RESET_ASK)};
71 unsigned char *yes_lines[]={ 71 unsigned char *yes_lines[]={
72 str(LANG_SETTINGS), 72 str(LANG_SETTINGS),
73 str(LANG_RESET_DONE_CLEAR) 73 ID2P(LANG_RESET_DONE_CLEAR)
74 }; 74 };
75 unsigned char *no_lines[]={yes_lines[0], str(LANG_CANCEL)}; 75 unsigned char *no_lines[]={yes_lines[0], ID2P(LANG_CANCEL)};
76 struct text_message message={(char **)lines, 1}; 76 struct text_message message={(char **)lines, 1};
77 struct text_message yes_message={(char **)yes_lines, 2}; 77 struct text_message yes_message={(char **)yes_lines, 2};
78 struct text_message no_message={(char **)no_lines, 2}; 78 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)
138 { 138 {
139 case ACTION_EXIT_MENUITEM: /* on exit */ 139 case ACTION_EXIT_MENUITEM: /* on exit */
140 if (!scrobbler_is_enabled() && global_settings.audioscrobbler) 140 if (!scrobbler_is_enabled() && global_settings.audioscrobbler)
141 gui_syncsplash(HZ*2, str(LANG_PLEASE_REBOOT)); 141 gui_syncsplash(HZ*2, ID2P(LANG_PLEASE_REBOOT));
142 142
143 if(scrobbler_is_enabled() && !global_settings.audioscrobbler) 143 if(scrobbler_is_enabled() && !global_settings.audioscrobbler)
144 scrobbler_shutdown(); 144 scrobbler_shutdown();
@@ -156,7 +156,7 @@ int cuesheet_callback(int action,const struct menu_item_ex *this_item)
156 { 156 {
157 case ACTION_EXIT_MENUITEM: /* on exit */ 157 case ACTION_EXIT_MENUITEM: /* on exit */
158 if (!cuesheet_is_enabled() && global_settings.cuesheet) 158 if (!cuesheet_is_enabled() && global_settings.cuesheet)
159 gui_syncsplash(HZ*2, str(LANG_PLEASE_REBOOT)); 159 gui_syncsplash(HZ*2, ID2P(LANG_PLEASE_REBOOT));
160 break; 160 break;
161 } 161 }
162 return action; 162 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 @@
49static void tagcache_rebuild_with_splash(void) 49static void tagcache_rebuild_with_splash(void)
50{ 50{
51 tagcache_rebuild(); 51 tagcache_rebuild();
52 gui_syncsplash(HZ*2, str(LANG_TAGCACHE_FORCE_UPDATE_SPLASH)); 52 gui_syncsplash(HZ*2, ID2P(LANG_TAGCACHE_FORCE_UPDATE_SPLASH));
53} 53}
54 54
55static void tagcache_update_with_splash(void) 55static void tagcache_update_with_splash(void)
56{ 56{
57 tagcache_update(); 57 tagcache_update();
58 gui_syncsplash(HZ*2, str(LANG_TAGCACHE_FORCE_UPDATE_SPLASH)); 58 gui_syncsplash(HZ*2, ID2P(LANG_TAGCACHE_FORCE_UPDATE_SPLASH));
59} 59}
60 60
61#ifdef HAVE_TC_RAMCACHE 61#ifdef HAVE_TC_RAMCACHE
@@ -174,7 +174,7 @@ static int dircache_callback(int action,const struct menu_item_ex *this_item)
174 { 174 {
175 case true: 175 case true:
176 if (!dircache_is_enabled()) 176 if (!dircache_is_enabled())
177 gui_syncsplash(HZ*2, str(LANG_PLEASE_REBOOT)); 177 gui_syncsplash(HZ*2, ID2P(LANG_PLEASE_REBOOT));
178 break; 178 break;
179 case false: 179 case false:
180 if (dircache_is_enabled()) 180 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 @@
62#include "bookmark.h" 62#include "bookmark.h"
63 63
64#include "misc.h" 64#include "misc.h"
65#include "playback.h"
65 66
66#ifdef BOOTFILE 67#ifdef BOOTFILE
67#if !defined(USB_NONE) && !defined(USB_IPODSTYLE) 68#if !defined(USB_NONE) && !defined(USB_IPODSTYLE)
@@ -603,6 +604,7 @@ static bool clean_shutdown(void (*callback)(void *), void *parameter)
603 call_ata_idle_notifys(true); 604 call_ata_idle_notifys(true);
604 exit(0); 605 exit(0);
605#else 606#else
607 long msg_id = -1;
606 int i; 608 int i;
607 609
608 scrobbler_poweroff(); 610 scrobbler_poweroff();
@@ -625,19 +627,23 @@ static bool clean_shutdown(void (*callback)(void *), void *parameter)
625 if (!tagcache_prepare_shutdown()) 627 if (!tagcache_prepare_shutdown())
626 { 628 {
627 cancel_shutdown(); 629 cancel_shutdown();
628 gui_syncsplash(HZ, str(LANG_TAGCACHE_BUSY)); 630 gui_syncsplash(HZ, ID2P(LANG_TAGCACHE_BUSY));
629 return false; 631 return false;
630 } 632 }
631#endif 633#endif
632 if (battery_level() > 10) 634 if (battery_level() > 10)
633 gui_syncsplash(0, str(LANG_SHUTTINGDOWN)); 635 gui_syncsplash(0, str(LANG_SHUTTINGDOWN));
634 else 636 else
637 {
638 msg_id = LANG_WARNING_BATTERY_LOW;
635 gui_syncsplash(0, "%s %s", 639 gui_syncsplash(0, "%s %s",
636 str(LANG_WARNING_BATTERY_LOW), 640 str(LANG_WARNING_BATTERY_LOW),
637 str(LANG_SHUTTINGDOWN)); 641 str(LANG_SHUTTINGDOWN));
642 }
638 } 643 }
639 else 644 else
640 { 645 {
646 msg_id = LANG_WARNING_BATTERY_EMPTY;
641 gui_syncsplash(0, "%s %s", 647 gui_syncsplash(0, "%s %s",
642 str(LANG_WARNING_BATTERY_EMPTY), 648 str(LANG_WARNING_BATTERY_EMPTY),
643 str(LANG_SHUTTINGDOWN)); 649 str(LANG_SHUTTINGDOWN));
@@ -675,6 +681,21 @@ static bool clean_shutdown(void (*callback)(void *), void *parameter)
675#if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC 681#if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
676 audio_close_recording(); 682 audio_close_recording();
677#endif 683#endif
684
685 if(talk_menus_enabled())
686 {
687 bool enqueue = false;
688 if(msg_id != -1)
689 {
690 talk_id(msg_id, enqueue);
691 enqueue = true;
692 }
693 talk_id(LANG_SHUTTINGDOWN, enqueue);
694#if CONFIG_CODEC == SWCODEC
695 voice_wait();
696#endif
697 }
698
678 system_flush(); 699 system_flush();
679#ifdef HAVE_EEPROM_SETTINGS 700#ifdef HAVE_EEPROM_SETTINGS
680 if (firmware_settings.initialized) 701 if (firmware_settings.initialized)
@@ -974,8 +995,8 @@ void check_bootfile(bool do_rolo)
974 if((entry->wrtdate != wrtdate) || 995 if((entry->wrtdate != wrtdate) ||
975 (entry->wrttime != wrttime)) 996 (entry->wrttime != wrttime))
976 { 997 {
977 char *lines[] = { str(LANG_BOOT_CHANGED), 998 char *lines[] = { ID2P(LANG_BOOT_CHANGED),
978 str(LANG_REBOOT_NOW) }; 999 ID2P(LANG_REBOOT_NOW) };
979 struct text_message message={ lines, 2 }; 1000 struct text_message message={ lines, 2 };
980 button_clear_queue(); /* Empty the keyboard buffer */ 1001 button_clear_queue(); /* Empty the keyboard buffer */
981 if(gui_syncyesno_run(&message, NULL, NULL) == YESNO_YES) 1002 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)
160{ 160{
161 bool new_playlist = !(audio_status() & AUDIO_STATUS_PLAY); 161 bool new_playlist = !(audio_status() & AUDIO_STATUS_PLAY);
162 char *lines[] = { 162 char *lines[] = {
163 (char *)str(LANG_RECURSE_DIRECTORY_QUESTION), 163 ID2P(LANG_RECURSE_DIRECTORY_QUESTION),
164 selected_file 164 selected_file
165 }; 165 };
166 struct text_message message={lines, 2}; 166 struct text_message message={lines, 2};
167 167
168 gui_syncsplash(0, str(LANG_WAIT)); 168 gui_syncsplash(0, ID2P(LANG_WAIT));
169 169
170 if (new_playlist) 170 if (new_playlist)
171 playlist_create(NULL, NULL); 171 playlist_create(NULL, NULL);
@@ -502,7 +502,7 @@ static int remove_dir(char* dirname, int len)
502#endif 502#endif
503 if(ACTION_STD_CANCEL == get_action(CONTEXT_STD,TIMEOUT_NOBLOCK)) 503 if(ACTION_STD_CANCEL == get_action(CONTEXT_STD,TIMEOUT_NOBLOCK))
504 { 504 {
505 gui_syncsplash(HZ, str(LANG_CANCEL)); 505 gui_syncsplash(HZ, ID2P(LANG_CANCEL));
506 result = -1; 506 result = -1;
507 break; 507 break;
508 } 508 }
@@ -524,11 +524,11 @@ static int remove_dir(char* dirname, int len)
524static bool delete_handler(bool is_dir) 524static bool delete_handler(bool is_dir)
525{ 525{
526 char *lines[]={ 526 char *lines[]={
527 (char *)str(LANG_REALLY_DELETE), 527 ID2P(LANG_REALLY_DELETE),
528 selected_file 528 selected_file
529 }; 529 };
530 char *yes_lines[]={ 530 char *yes_lines[]={
531 (char *)str(LANG_DELETED), 531 ID2P(LANG_DELETED),
532 selected_file 532 selected_file
533 }; 533 };
534 534
@@ -599,6 +599,7 @@ static bool rename_file(void)
599 lcd_puts(0,0,str(LANG_RENAME)); 599 lcd_puts(0,0,str(LANG_RENAME));
600 lcd_puts(0,1,str(LANG_FAILED)); 600 lcd_puts(0,1,str(LANG_FAILED));
601 lcd_update(); 601 lcd_update();
602 cond_talk_ids_fq(LANG_RENAME, LANG_FAILED);
602 sleep(HZ*2); 603 sleep(HZ*2);
603 } 604 }
604 else 605 else
@@ -628,6 +629,7 @@ static bool create_dir(void)
628 629
629 rc = mkdir(dirname); 630 rc = mkdir(dirname);
630 if (rc < 0) { 631 if (rc < 0) {
632 cond_talk_ids_fq(LANG_CREATE_DIR, LANG_FAILED);
631 gui_syncsplash(HZ, (unsigned char *)"%s %s", 633 gui_syncsplash(HZ, (unsigned char *)"%s %s",
632 str(LANG_CREATE_DIR), str(LANG_FAILED)); 634 str(LANG_CREATE_DIR), str(LANG_FAILED));
633 } else { 635 } else {
@@ -873,7 +875,7 @@ static bool clipboard_paste(void)
873 bool success; 875 bool success;
874 int target_fd; 876 int target_fd;
875 877
876 unsigned char *lines[]={str(LANG_REALLY_OVERWRITE)}; 878 unsigned char *lines[]={ID2P(LANG_REALLY_OVERWRITE)};
877 struct text_message message={(char **)lines, 1}; 879 struct text_message message={(char **)lines, 1};
878 880
879 /* Get the name of the current directory */ 881 /* Get the name of the current directory */
@@ -896,11 +898,11 @@ static bool clipboard_paste(void)
896 } 898 }
897 899
898 if (clipboard_is_copy) { 900 if (clipboard_is_copy) {
899 gui_syncsplash(0, str(LANG_COPYING)); 901 gui_syncsplash(0, ID2P(LANG_COPYING));
900 } 902 }
901 else 903 else
902 { 904 {
903 gui_syncsplash(0, str(LANG_MOVING)); 905 gui_syncsplash(0, ID2P(LANG_MOVING));
904 } 906 }
905 907
906 /* Now figure out what we're doing */ 908 /* Now figure out what we're doing */
@@ -939,6 +941,7 @@ static bool clipboard_paste(void)
939 /* Force reload of the current directory */ 941 /* Force reload of the current directory */
940 onplay_result = ONPLAY_RELOAD_DIR; 942 onplay_result = ONPLAY_RELOAD_DIR;
941 } else { 943 } else {
944 cond_talk_ids_fq(LANG_PASTE, LANG_FAILED);
942 gui_syncsplash(HZ, (unsigned char *)"%s %s", 945 gui_syncsplash(HZ, (unsigned char *)"%s %s",
943 str(LANG_PASTE), str(LANG_FAILED)); 946 str(LANG_PASTE), str(LANG_FAILED));
944 } 947 }
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)
957 pcmbuf_play_stop(); 957 pcmbuf_play_stop();
958#endif 958#endif
959} /* voice_stop */ 959} /* voice_stop */
960
961/* Is voice still speaking */
962/* Unfortunately only reliable when music is not also playing. */
963static bool is_voice_speaking(void)
964{
965 return is_voice_queued()
966 || voice_is_playing
967 || (!playing && pcm_is_playing());
968}
969
970/* Wait for voice to finish speaking. */
971/* Also only reliable when music is not also playing. */
972void voice_wait(void)
973{
974 while (is_voice_speaking())
975 sleep(HZ/10);
976}
977
960#endif /* PLAYBACK_VOICE */ 978#endif /* PLAYBACK_VOICE */
961 979
962static void set_filebuf_watermark(int seconds) 980static 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,
63 bool last_track)); 63 bool last_track));
64void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3, 64void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3,
65 bool last_track)); 65 bool last_track));
66void voice_wait(void);
66 67
67#if CONFIG_CODEC == SWCODEC /* This #ifdef is better here than gui/gwps.c */ 68#if CONFIG_CODEC == SWCODEC /* This #ifdef is better here than gui/gwps.c */
68extern void audio_next_dir(void); 69extern 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);
181static int check_subdir_for_music(char *dir, char *subdir); 181static int check_subdir_for_music(char *dir, char *subdir);
182static int format_track_path(char *dest, char *src, int buf_length, int max, 182static int format_track_path(char *dest, char *src, int buf_length, int max,
183 char *dir); 183 char *dir);
184static void display_playlist_count(int count, const unsigned char *fmt); 184static void display_playlist_count(int count, const unsigned char *fmt,
185 bool final);
185static void display_buffer_full(void); 186static void display_buffer_full(void);
186static int flush_cached_control(struct playlist_info* playlist); 187static int flush_cached_control(struct playlist_info* playlist);
187static int update_control(struct playlist_info* playlist, 188static int update_control(struct playlist_info* playlist,
@@ -288,6 +289,7 @@ static void create_control(struct playlist_info* playlist)
288 { 289 {
289 if (check_rockboxdir()) 290 if (check_rockboxdir())
290 { 291 {
292 cond_talk_ids_fq(LANG_PLAYLIST_CONTROL_ACCESS_ERROR);
291 gui_syncsplash(HZ*2, (unsigned char *)"%s (%d)", 293 gui_syncsplash(HZ*2, (unsigned char *)"%s (%d)",
292 str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR), 294 str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR),
293 playlist->control_fd); 295 playlist->control_fd);
@@ -483,8 +485,7 @@ static int add_indices_to_playlist(struct playlist_info* playlist,
483 else 485 else
484 lcd_setmargins(0, 0); 486 lcd_setmargins(0, 0);
485#endif 487#endif
486 488 gui_syncsplash(0, ID2P(LANG_WAIT));
487 gui_syncsplash(0, str(LANG_WAIT));
488 489
489 if (!buffer) 490 if (!buffer)
490 { 491 {
@@ -770,11 +771,11 @@ static int directory_search_callback(char* filename, void* context)
770 unsigned char* count_str; 771 unsigned char* count_str;
771 772
772 if (c->queue) 773 if (c->queue)
773 count_str = str(LANG_PLAYLIST_QUEUE_COUNT); 774 count_str = ID2P(LANG_PLAYLIST_QUEUE_COUNT);
774 else 775 else
775 count_str = str(LANG_PLAYLIST_INSERT_COUNT); 776 count_str = ID2P(LANG_PLAYLIST_INSERT_COUNT);
776 777
777 display_playlist_count(c->count, count_str); 778 display_playlist_count(c->count, count_str, false);
778 779
779 if ((c->count) == PLAYLIST_DISPLAY_COUNT && 780 if ((c->count) == PLAYLIST_DISPLAY_COUNT &&
780 (audio_status() & AUDIO_STATUS_PLAY) && 781 (audio_status() & AUDIO_STATUS_PLAY) &&
@@ -1350,9 +1351,9 @@ static int get_filename(struct playlist_info* playlist, int index, int seek,
1350 if (max < 0) 1351 if (max < 0)
1351 { 1352 {
1352 if (control_file) 1353 if (control_file)
1353 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); 1354 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR));
1354 else 1355 else
1355 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_ACCESS_ERROR)); 1356 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR));
1356 1357
1357 return max; 1358 return max;
1358 } 1359 }
@@ -1445,7 +1446,7 @@ static int get_next_dir(char *dir, bool is_forward, bool recursion)
1445 1446
1446 if (ft_load(tc, (dir[0]=='\0')?"/":dir) < 0) 1447 if (ft_load(tc, (dir[0]=='\0')?"/":dir) < 0)
1447 { 1448 {
1448 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR)); 1449 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR));
1449 exit = true; 1450 exit = true;
1450 result = -1; 1451 result = -1;
1451 break; 1452 break;
@@ -1530,7 +1531,7 @@ static int check_subdir_for_music(char *dir, char *subdir)
1530 1531
1531 if (ft_load(tc, dir) < 0) 1532 if (ft_load(tc, dir) < 0)
1532 { 1533 {
1533 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR)); 1534 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR));
1534 return -2; 1535 return -2;
1535 } 1536 }
1536 1537
@@ -1584,7 +1585,7 @@ static int check_subdir_for_music(char *dir, char *subdir)
1584 /* we now need to reload our current directory */ 1585 /* we now need to reload our current directory */
1585 if(ft_load(tc, dir) < 0) 1586 if(ft_load(tc, dir) < 0)
1586 gui_syncsplash(HZ*2, 1587 gui_syncsplash(HZ*2,
1587 str(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR)); 1588 ID2P(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR));
1588 } 1589 }
1589 1590
1590 return result; 1591 return result;
@@ -1657,8 +1658,23 @@ static int format_track_path(char *dest, char *src, int buf_length, int max,
1657 * Display splash message showing progress of playlist/directory insertion or 1658 * Display splash message showing progress of playlist/directory insertion or
1658 * save. 1659 * save.
1659 */ 1660 */
1660static void display_playlist_count(int count, const unsigned char *fmt) 1661static void display_playlist_count(int count, const unsigned char *fmt,
1662 bool final)
1661{ 1663{
1664 static long talked_tick = 0;
1665 long id = P2ID(fmt);
1666 if(talk_menus_enabled() && id>=0)
1667 {
1668 if(final || (count && (talked_tick == 0
1669 || TIME_AFTER(current_tick, talked_tick+5*HZ))))
1670 {
1671 talked_tick = current_tick;
1672 talk_number(count, false);
1673 talk_id(id, true);
1674 }
1675 }
1676 fmt = P2STR(fmt);
1677
1662 lcd_clear_display(); 1678 lcd_clear_display();
1663 1679
1664#ifdef HAVE_LCD_BITMAP 1680#ifdef HAVE_LCD_BITMAP
@@ -1676,7 +1692,7 @@ static void display_playlist_count(int count, const unsigned char *fmt)
1676 */ 1692 */
1677static void display_buffer_full(void) 1693static void display_buffer_full(void)
1678{ 1694{
1679 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_BUFFER_FULL)); 1695 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_BUFFER_FULL));
1680} 1696}
1681 1697
1682/* 1698/*
@@ -1755,7 +1771,7 @@ static int flush_cached_control(struct playlist_info* playlist)
1755 else 1771 else
1756 { 1772 {
1757 result = -1; 1773 result = -1;
1758 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR)); 1774 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_UPDATE_ERROR));
1759 } 1775 }
1760 1776
1761 return result; 1777 return result;
@@ -1942,11 +1958,11 @@ int playlist_resume(void)
1942 1958
1943 empty_playlist(playlist, true); 1959 empty_playlist(playlist, true);
1944 1960
1945 gui_syncsplash(0, str(LANG_WAIT)); 1961 gui_syncsplash(0, ID2P(LANG_WAIT));
1946 playlist->control_fd = open(playlist->control_filename, O_RDWR); 1962 playlist->control_fd = open(playlist->control_filename, O_RDWR);
1947 if (playlist->control_fd < 0) 1963 if (playlist->control_fd < 0)
1948 { 1964 {
1949 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); 1965 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR));
1950 return -1; 1966 return -1;
1951 } 1967 }
1952 playlist->control_created = true; 1968 playlist->control_created = true;
@@ -1954,7 +1970,7 @@ int playlist_resume(void)
1954 control_file_size = filesize(playlist->control_fd); 1970 control_file_size = filesize(playlist->control_fd);
1955 if (control_file_size <= 0) 1971 if (control_file_size <= 0)
1956 { 1972 {
1957 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); 1973 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR));
1958 return -1; 1974 return -1;
1959 } 1975 }
1960 1976
@@ -1963,7 +1979,7 @@ int playlist_resume(void)
1963 PLAYLIST_COMMAND_SIZE<buflen?PLAYLIST_COMMAND_SIZE:buflen); 1979 PLAYLIST_COMMAND_SIZE<buflen?PLAYLIST_COMMAND_SIZE:buflen);
1964 if(nread <= 0) 1980 if(nread <= 0)
1965 { 1981 {
1966 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); 1982 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR));
1967 return -1; 1983 return -1;
1968 } 1984 }
1969 1985
@@ -2258,7 +2274,7 @@ int playlist_resume(void)
2258 2274
2259 if (result < 0) 2275 if (result < 0)
2260 { 2276 {
2261 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_INVALID)); 2277 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_INVALID));
2262 return result; 2278 return result;
2263 } 2279 }
2264 2280
@@ -2267,7 +2283,7 @@ int playlist_resume(void)
2267 if ((total_read + count) >= control_file_size) 2283 if ((total_read + count) >= control_file_size)
2268 { 2284 {
2269 /* no newline at end of control file */ 2285 /* no newline at end of control file */
2270 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_INVALID)); 2286 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_INVALID));
2271 return -1; 2287 return -1;
2272 } 2288 }
2273 2289
@@ -2361,6 +2377,7 @@ int playlist_shuffle(int random_seed, int start_index)
2361 start_current = true; 2377 start_current = true;
2362 } 2378 }
2363 2379
2380 cond_talk_ids(LANG_WAIT);
2364 gui_syncsplash(0, str(LANG_PLAYLIST_SHUFFLE)); 2381 gui_syncsplash(0, str(LANG_PLAYLIST_SHUFFLE));
2365 2382
2366 randomise_playlist(playlist, random_seed, start_current, true); 2383 randomise_playlist(playlist, random_seed, start_current, true);
@@ -2853,7 +2870,7 @@ int playlist_insert_track(struct playlist_info* playlist, const char *filename,
2853 2870
2854 if (check_control(playlist) < 0) 2871 if (check_control(playlist) < 0)
2855 { 2872 {
2856 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); 2873 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR));
2857 return -1; 2874 return -1;
2858 } 2875 }
2859 2876
@@ -2884,7 +2901,7 @@ int playlist_insert_directory(struct playlist_info* playlist,
2884 2901
2885 if (check_control(playlist) < 0) 2902 if (check_control(playlist) < 0)
2886 { 2903 {
2887 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); 2904 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR));
2888 return -1; 2905 return -1;
2889 } 2906 }
2890 2907
@@ -2897,11 +2914,11 @@ int playlist_insert_directory(struct playlist_info* playlist,
2897 } 2914 }
2898 2915
2899 if (queue) 2916 if (queue)
2900 count_str = str(LANG_PLAYLIST_QUEUE_COUNT); 2917 count_str = ID2P(LANG_PLAYLIST_QUEUE_COUNT);
2901 else 2918 else
2902 count_str = str(LANG_PLAYLIST_INSERT_COUNT); 2919 count_str = ID2P(LANG_PLAYLIST_INSERT_COUNT);
2903 2920
2904 display_playlist_count(0, count_str); 2921 display_playlist_count(0, count_str, false);
2905 2922
2906 context.playlist = playlist; 2923 context.playlist = playlist;
2907 context.position = position; 2924 context.position = position;
@@ -2917,7 +2934,7 @@ int playlist_insert_directory(struct playlist_info* playlist,
2917 2934
2918 cpu_boost(false); 2935 cpu_boost(false);
2919 2936
2920 display_playlist_count(context.count, count_str); 2937 display_playlist_count(context.count, count_str, true);
2921 2938
2922 if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started) 2939 if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started)
2923 audio_flush_and_reload_tracks(); 2940 audio_flush_and_reload_tracks();
@@ -2950,14 +2967,14 @@ int playlist_insert_playlist(struct playlist_info* playlist, char *filename,
2950 2967
2951 if (check_control(playlist) < 0) 2968 if (check_control(playlist) < 0)
2952 { 2969 {
2953 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); 2970 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR));
2954 return -1; 2971 return -1;
2955 } 2972 }
2956 2973
2957 fd = open(filename, O_RDONLY); 2974 fd = open(filename, O_RDONLY);
2958 if (fd < 0) 2975 if (fd < 0)
2959 { 2976 {
2960 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_ACCESS_ERROR)); 2977 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR));
2961 return -1; 2978 return -1;
2962 } 2979 }
2963 2980
@@ -2971,11 +2988,11 @@ int playlist_insert_playlist(struct playlist_info* playlist, char *filename,
2971 dir = "/"; 2988 dir = "/";
2972 2989
2973 if (queue) 2990 if (queue)
2974 count_str = str(LANG_PLAYLIST_QUEUE_COUNT); 2991 count_str = ID2P(LANG_PLAYLIST_QUEUE_COUNT);
2975 else 2992 else
2976 count_str = str(LANG_PLAYLIST_INSERT_COUNT); 2993 count_str = ID2P(LANG_PLAYLIST_INSERT_COUNT);
2977 2994
2978 display_playlist_count(count, count_str); 2995 display_playlist_count(count, count_str, false);
2979 2996
2980 if (position == PLAYLIST_REPLACE) 2997 if (position == PLAYLIST_REPLACE)
2981 { 2998 {
@@ -3023,7 +3040,7 @@ int playlist_insert_playlist(struct playlist_info* playlist, char *filename,
3023 3040
3024 if ((count%PLAYLIST_DISPLAY_COUNT) == 0) 3041 if ((count%PLAYLIST_DISPLAY_COUNT) == 0)
3025 { 3042 {
3026 display_playlist_count(count, count_str); 3043 display_playlist_count(count, count_str, false);
3027 3044
3028 if (count == PLAYLIST_DISPLAY_COUNT && 3045 if (count == PLAYLIST_DISPLAY_COUNT &&
3029 (audio_status() & AUDIO_STATUS_PLAY) && 3046 (audio_status() & AUDIO_STATUS_PLAY) &&
@@ -3045,7 +3062,7 @@ int playlist_insert_playlist(struct playlist_info* playlist, char *filename,
3045 3062
3046 cpu_boost(false); 3063 cpu_boost(false);
3047 3064
3048 display_playlist_count(count, count_str); 3065 display_playlist_count(count, count_str, true);
3049 3066
3050 if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started) 3067 if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started)
3051 audio_flush_and_reload_tracks(); 3068 audio_flush_and_reload_tracks();
@@ -3070,7 +3087,7 @@ int playlist_delete(struct playlist_info* playlist, int index)
3070 3087
3071 if (check_control(playlist) < 0) 3088 if (check_control(playlist) < 0)
3072 { 3089 {
3073 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); 3090 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR));
3074 return -1; 3091 return -1;
3075 } 3092 }
3076 3093
@@ -3105,7 +3122,7 @@ int playlist_move(struct playlist_info* playlist, int index, int new_index)
3105 3122
3106 if (check_control(playlist) < 0) 3123 if (check_control(playlist) < 0)
3107 { 3124 {
3108 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); 3125 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR));
3109 return -1; 3126 return -1;
3110 } 3127 }
3111 3128
@@ -3368,7 +3385,7 @@ int playlist_save(struct playlist_info* playlist, char *filename)
3368 if (playlist->buffer_size < (int)(playlist->amount * sizeof(int))) 3385 if (playlist->buffer_size < (int)(playlist->amount * sizeof(int)))
3369 { 3386 {
3370 /* not enough buffer space to store updated indices */ 3387 /* not enough buffer space to store updated indices */
3371 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_ACCESS_ERROR)); 3388 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR));
3372 return -1; 3389 return -1;
3373 } 3390 }
3374 3391
@@ -3384,11 +3401,11 @@ int playlist_save(struct playlist_info* playlist, char *filename)
3384 fd = open(path, O_CREAT|O_WRONLY|O_TRUNC); 3401 fd = open(path, O_CREAT|O_WRONLY|O_TRUNC);
3385 if (fd < 0) 3402 if (fd < 0)
3386 { 3403 {
3387 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_ACCESS_ERROR)); 3404 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR));
3388 return -1; 3405 return -1;
3389 } 3406 }
3390 3407
3391 display_playlist_count(count, str(LANG_PLAYLIST_SAVE_COUNT)); 3408 display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT), false);
3392 3409
3393 cpu_boost(true); 3410 cpu_boost(true);
3394 3411
@@ -3425,7 +3442,7 @@ int playlist_save(struct playlist_info* playlist, char *filename)
3425 3442
3426 if (fdprintf(fd, "%s\n", tmp_buf) < 0) 3443 if (fdprintf(fd, "%s\n", tmp_buf) < 0)
3427 { 3444 {
3428 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_ACCESS_ERROR)); 3445 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR));
3429 result = -1; 3446 result = -1;
3430 break; 3447 break;
3431 } 3448 }
@@ -3433,7 +3450,8 @@ int playlist_save(struct playlist_info* playlist, char *filename)
3433 count++; 3450 count++;
3434 3451
3435 if ((count % PLAYLIST_DISPLAY_COUNT) == 0) 3452 if ((count % PLAYLIST_DISPLAY_COUNT) == 0)
3436 display_playlist_count(count, str(LANG_PLAYLIST_SAVE_COUNT)); 3453 display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT),
3454 false);
3437 3455
3438 yield(); 3456 yield();
3439 } 3457 }
@@ -3441,7 +3459,7 @@ int playlist_save(struct playlist_info* playlist, char *filename)
3441 index = (index+1)%playlist->amount; 3459 index = (index+1)%playlist->amount;
3442 } 3460 }
3443 3461
3444 display_playlist_count(count, str(LANG_PLAYLIST_SAVE_COUNT)); 3462 display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT), true);
3445 3463
3446 close(fd); 3464 close(fd);
3447 3465
@@ -3512,7 +3530,7 @@ int playlist_directory_tracksearch(const char* dirname, bool recurse,
3512 3530
3513 if (ft_load(tc, dirname) < 0) 3531 if (ft_load(tc, dirname) < 0)
3514 { 3532 {
3515 gui_syncsplash(HZ*2, str(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR)); 3533 gui_syncsplash(HZ*2, ID2P(LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR));
3516 *(tc->dirfilter) = old_dirfilter; 3534 *(tc->dirfilter) = old_dirfilter;
3517 return -1; 3535 return -1;
3518 } 3536 }
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)
537 plugin_loaded = false; 537 plugin_loaded = false;
538 } 538 }
539 539
540 gui_syncsplash(0, str(LANG_WAIT)); 540 gui_syncsplash(0, ID2P(LANG_WAIT));
541 strcpy(current_plugin,p); 541 strcpy(current_plugin,p);
542 542
543#ifdef SIMULATOR 543#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)
487 radio_start(); 487 radio_start();
488#endif 488#endif
489 489
490 if(num_presets < 1 && yesno_pop(str(LANG_FM_FIRST_AUTOSCAN))) 490 if(num_presets < 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN)))
491 scan_presets(); 491 scan_presets();
492 492
493 curr_preset = find_preset(curr_freq); 493 curr_preset = find_preset(curr_freq);
@@ -551,7 +551,7 @@ int radio_screen(void)
551 done = true; 551 done = true;
552 if(presets_changed) 552 if(presets_changed)
553 { 553 {
554 if(yesno_pop(str(LANG_FM_SAVE_CHANGES))) 554 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
555 { 555 {
556 if(filepreset[0] == '\0') 556 if(filepreset[0] == '\0')
557 save_preset_list(); 557 save_preset_list();
@@ -606,7 +606,7 @@ int radio_screen(void)
606 ret_val = GO_TO_ROOT; 606 ret_val = GO_TO_ROOT;
607 if(presets_changed) 607 if(presets_changed)
608 { 608 {
609 if(yesno_pop(str(LANG_FM_SAVE_CHANGES))) 609 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
610 { 610 {
611 if(filepreset[0] == '\0') 611 if(filepreset[0] == '\0')
612 save_preset_list(); 612 save_preset_list();
@@ -690,7 +690,7 @@ int radio_screen(void)
690 case ACTION_FM_PRESET: 690 case ACTION_FM_PRESET:
691 if(num_presets < 1) 691 if(num_presets < 1)
692 { 692 {
693 gui_syncsplash(HZ, str(LANG_FM_NO_PRESETS)); 693 gui_syncsplash(HZ, ID2P(LANG_FM_NO_PRESETS));
694 update_screen = true; 694 update_screen = true;
695 FOR_NB_SCREENS(i) 695 FOR_NB_SCREENS(i)
696 { 696 {
@@ -996,7 +996,7 @@ static void radio_save_presets(void)
996 } 996 }
997 else 997 else
998 { 998 {
999 gui_syncsplash(HZ, str(LANG_FM_PRESET_SAVE_FAILED)); 999 gui_syncsplash(HZ, ID2P(LANG_FM_PRESET_SAVE_FAILED));
1000 } 1000 }
1001} 1001}
1002 1002
@@ -1082,7 +1082,7 @@ static int radio_add_preset(void)
1082 } 1082 }
1083 else 1083 else
1084 { 1084 {
1085 gui_syncsplash(HZ, str(LANG_FM_NO_FREE_PRESETS)); 1085 gui_syncsplash(HZ, ID2P(LANG_FM_NO_FREE_PRESETS));
1086 } 1086 }
1087 return true; 1087 return true;
1088} 1088}
@@ -1170,7 +1170,7 @@ static int save_preset_list(void)
1170 if((!p1) || (len > MAX_FILENAME) || (len == 0)) 1170 if((!p1) || (len > MAX_FILENAME) || (len == 0))
1171 { 1171 {
1172 /* no slash, too long or too short */ 1172 /* no slash, too long or too short */
1173 gui_syncsplash(HZ, str(LANG_INVALID_FILENAME)); 1173 gui_syncsplash(HZ, ID2P(LANG_INVALID_FILENAME));
1174 } 1174 }
1175 else 1175 else
1176 { 1176 {
@@ -1190,7 +1190,7 @@ static int save_preset_list(void)
1190 } 1190 }
1191 } 1191 }
1192 else 1192 else
1193 gui_syncsplash(HZ, str(LANG_FM_NO_PRESETS)); 1193 gui_syncsplash(HZ, ID2P(LANG_FM_NO_PRESETS));
1194 1194
1195 return true; 1195 return true;
1196} 1196}
@@ -1339,7 +1339,7 @@ static int scan_presets(void)
1339 bool do_scan = true; 1339 bool do_scan = true;
1340 1340
1341 if(num_presets > 0) /* Do that to avoid 2 questions. */ 1341 if(num_presets > 0) /* Do that to avoid 2 questions. */
1342 do_scan = yesno_pop(str(LANG_FM_CLEAR_PRESETS)); 1342 do_scan = yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS));
1343 1343
1344 if(do_scan) 1344 if(do_scan)
1345 { 1345 {
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)
129 /* Maybe just needs to reboot due to delayed commit */ 129 /* Maybe just needs to reboot due to delayed commit */
130 if (stat->commit_delayed) 130 if (stat->commit_delayed)
131 { 131 {
132 gui_syncsplash(HZ*2, str(LANG_PLEASE_REBOOT)); 132 gui_syncsplash(HZ*2, ID2P(LANG_PLEASE_REBOOT));
133 break; 133 break;
134 } 134 }
135 135
@@ -146,7 +146,7 @@ static int browser(void* param)
146 { 146 {
147 /* Prompt the user */ 147 /* Prompt the user */
148 reinit_attempted = true; 148 reinit_attempted = true;
149 char *lines[]={str(LANG_TAGCACHE_BUSY), str(LANG_TAGCACHE_FORCE_UPDATE)}; 149 char *lines[]={ID2P(LANG_TAGCACHE_BUSY), ID2P(LANG_TAGCACHE_FORCE_UPDATE)};
150 struct text_message message={lines, 2}; 150 struct text_message message={lines, 2};
151 if(gui_syncyesno_run(&message, NULL, NULL) == YESNO_NO) 151 if(gui_syncyesno_run(&message, NULL, NULL) == YESNO_NO)
152 break; 152 break;
@@ -159,6 +159,24 @@ static int browser(void* param)
159 } 159 }
160 160
161 /* Display building progress */ 161 /* Display building progress */
162 static long talked_tick = 0;
163 if(talk_menus_enabled() &&
164 (talked_tick == 0
165 || TIME_AFTER(current_tick, talked_tick+7*HZ)))
166 {
167 talked_tick = current_tick;
168 if (stat->commit_step > 0)
169 {
170 talk_id(LANG_TAGCACHE_INIT, false);
171 talk_number(stat->commit_step, true);
172 talk_id(VOICE_OF, true);
173 talk_number(tagcache_get_max_commit_step(), true);
174 } else if(stat->processed_entries)
175 {
176 talk_number(stat->processed_entries, false);
177 talk_id(LANG_BUILDING_DATABASE, true);
178 }
179 }
162 if (stat->commit_step > 0) 180 if (stat->commit_step > 0)
163 { 181 {
164 gui_syncsplash(0, "%s [%d/%d]", 182 gui_syncsplash(0, "%s [%d/%d]",
@@ -236,7 +254,7 @@ static int wpsscrn(void* param)
236 } 254 }
237 else 255 else
238 { 256 {
239 gui_syncsplash(HZ*2, str(LANG_NOTHING_TO_RESUME)); 257 gui_syncsplash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME));
240 } 258 }
241#if LCD_DEPTH > 1 259#if LCD_DEPTH > 1
242 show_main_backdrop(); 260 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 )
544 screens[i].update(); 544 screens[i].update();
545#endif 545#endif
546 } 546 }
547 cond_talk_ids_fq(LANG_SETTINGS_SAVE_FAILED);
547 sleep(HZ*2); 548 sleep(HZ*2);
548 return -1; 549 return -1;
549 } 550 }
@@ -575,15 +576,15 @@ bool settings_save_config(int options)
575 break; 576 break;
576 } 577 }
577 else { 578 else {
578 gui_syncsplash(HZ, str(LANG_CANCEL)); 579 gui_syncsplash(HZ, ID2P(LANG_CANCEL));
579 return false; 580 return false;
580 } 581 }
581 } 582 }
582 583
583 if (settings_write_config(filename, options)) 584 if (settings_write_config(filename, options))
584 gui_syncsplash(HZ, str(LANG_SETTINGS_SAVED)); 585 gui_syncsplash(HZ, ID2P(LANG_SETTINGS_SAVED));
585 else 586 else
586 gui_syncsplash(HZ, str(LANG_FAILED)); 587 gui_syncsplash(HZ, ID2P(LANG_FAILED));
587 return true; 588 return true;
588} 589}
589 590
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)
690 gui_syncsplash(0, str(LANG_CREATING)); 690 gui_syncsplash(0, str(LANG_CREATING));
691 if (!tagcache_create_changelog(&tcs)) 691 if (!tagcache_create_changelog(&tcs))
692 { 692 {
693 gui_syncsplash(HZ*2, str(LANG_FAILED)); 693 gui_syncsplash(HZ*2, ID2P(LANG_FAILED));
694 } 694 }
695 695
696 return false; 696 return false;
@@ -698,10 +698,10 @@ bool tagtree_export(void)
698 698
699bool tagtree_import(void) 699bool tagtree_import(void)
700{ 700{
701 gui_syncsplash(0, str(LANG_WAIT)); 701 gui_syncsplash(0, ID2P(LANG_WAIT));
702 if (!tagcache_import_changelog()) 702 if (!tagcache_import_changelog())
703 { 703 {
704 gui_syncsplash(HZ*2, str(LANG_FAILED)); 704 gui_syncsplash(HZ*2, ID2P(LANG_FAILED));
705 } 705 }
706 706
707 return false; 707 return false;
@@ -1228,7 +1228,7 @@ static int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs,
1228 1228
1229 if (!sort && (sort_inverse || sort_limit)) 1229 if (!sort && (sort_inverse || sort_limit))
1230 { 1230 {
1231 gui_syncsplash(HZ*4, str(LANG_SHOWDIR_BUFFER_FULL), total_count); 1231 gui_syncsplash(HZ*4, ID2P(LANG_SHOWDIR_BUFFER_FULL), total_count);
1232 logf("Too small dir buffer"); 1232 logf("Too small dir buffer");
1233 return 0; 1233 return 0;
1234 } 1234 }
@@ -1419,7 +1419,7 @@ int tagtree_enter(struct tree_context* c)
1419 !global_settings.party_mode && 1419 !global_settings.party_mode &&
1420 playlist_modified(NULL)) 1420 playlist_modified(NULL))
1421 { 1421 {
1422 char *lines[]={str(LANG_WARN_ERASEDYNPLAYLIST_PROMPT)}; 1422 char *lines[]={ID2P(LANG_WARN_ERASEDYNPLAYLIST_PROMPT)};
1423 struct text_message message={lines, 1}; 1423 struct text_message message={lines, 1};
1424 1424
1425 if (gui_syncyesno_run(&message, NULL, NULL) != YESNO_YES) 1425 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
1496 cpu_boost(true); 1496 cpu_boost(true);
1497 if (!tagcache_search(&tcs, tag_filename)) 1497 if (!tagcache_search(&tcs, tag_filename))
1498 { 1498 {
1499 gui_syncsplash(HZ, str(LANG_TAGCACHE_BUSY)); 1499 gui_syncsplash(HZ, ID2P(LANG_TAGCACHE_BUSY));
1500 cpu_boost(false); 1500 cpu_boost(false);
1501 return false; 1501 return false;
1502 } 1502 }
@@ -1599,12 +1599,12 @@ bool tagtree_insert_selection_playlist(int position, bool queue)
1599 } 1599 }
1600 1600
1601 if (tc->filesindir <= 0) 1601 if (tc->filesindir <= 0)
1602 gui_syncsplash(HZ, str(LANG_END_PLAYLIST)); 1602 gui_syncsplash(HZ, ID2P(LANG_END_PLAYLIST));
1603 else 1603 else
1604 { 1604 {
1605 logf("insert_all_playlist"); 1605 logf("insert_all_playlist");
1606 if (!insert_all_playlist(tc, position, queue)) 1606 if (!insert_all_playlist(tc, position, queue))
1607 gui_syncsplash(HZ*2, str(LANG_FAILED)); 1607 gui_syncsplash(HZ*2, ID2P(LANG_FAILED));
1608 } 1608 }
1609 1609
1610 /* Finally return the dirlevel to its original value. */ 1610 /* 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 */
117static struct voicefile* p_voicefile; /* loaded voicefile */ 117static struct voicefile* p_voicefile; /* loaded voicefile */
118static bool has_voicefile; /* a voicefile file is present */ 118static bool has_voicefile; /* a voicefile file is present */
119static struct queue_entry queue[QUEUE_SIZE]; /* queue of scheduled clips */ 119static struct queue_entry queue[QUEUE_SIZE]; /* queue of scheduled clips */
120/* enqueue next utterance even if enqueue is false. */
121static bool force_enqueue_next;
120static int queue_write; /* write index of queue, by application */ 122static int queue_write; /* write index of queue, by application */
121static int queue_read; /* read index of queue, by ISR context */ 123static int queue_read; /* read index of queue, by ISR context */
122static int sent; /* how many bytes handed over to playback, owned by ISR */ 124static 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
134 136
135static void load_voicefile(void); 137static void load_voicefile(void);
136static void mp3_callback(unsigned char** start, size_t* size); 138static void mp3_callback(unsigned char** start, size_t* size);
137static int shutup(void);
138static int queue_clip(unsigned char* buf, long size, bool enqueue); 139static int queue_clip(unsigned char* buf, long size, bool enqueue);
139static int open_voicefile(void); 140static int open_voicefile(void);
140static unsigned char* get_clip(long id, long* p_size); 141static unsigned char* get_clip(long id, long* p_size);
@@ -267,6 +268,13 @@ load_err:
267} 268}
268 269
269 270
271/* Are more voice clips queued and waiting? */
272bool is_voice_queued()
273{
274 return !!QUEUE_LEVEL;
275}
276
277
270/* called in ISR context if mp3 data got consumed */ 278/* called in ISR context if mp3 data got consumed */
271static void mp3_callback(unsigned char** start, size_t* size) 279static void mp3_callback(unsigned char** start, size_t* size)
272{ 280{
@@ -321,7 +329,7 @@ re_check:
321} 329}
322 330
323/* stop the playback and the pending clips */ 331/* stop the playback and the pending clips */
324static int shutup(void) 332static int do_shutup(void)
325{ 333{
326#if CONFIG_CODEC != SWCODEC 334#if CONFIG_CODEC != SWCODEC
327 unsigned char* pos; 335 unsigned char* pos;
@@ -387,6 +395,13 @@ static int shutup(void)
387 return 0; 395 return 0;
388} 396}
389 397
398/* Shutup the voice, except if force_enqueue_next is set. */
399static int shutup(void)
400{
401 if (!force_enqueue_next)
402 return do_shutup();
403 return 0;
404}
390 405
391/* schedule a clip, at the end or discard the existing queue */ 406/* schedule a clip, at the end or discard the existing queue */
392static int queue_clip(unsigned char* buf, long size, bool enqueue) 407static 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)
395 410
396 if (!enqueue) 411 if (!enqueue)
397 shutup(); /* cut off all the pending stuff */ 412 shutup(); /* cut off all the pending stuff */
413 /* Something is being enqueued, force_enqueue_next override is no
414 longer in effect. */
415 force_enqueue_next = false;
398 416
399 if (!size) 417 if (!size)
400 return 0; /* safety check */ 418 return 0; /* safety check */
@@ -617,6 +635,26 @@ int talk_id(long id, bool enqueue)
617 return 0; 635 return 0;
618} 636}
619 637
638/* Speaks zero or more IDs (from an array). */
639int talk_idarray(long *ids, bool enqueue)
640{
641 int r;
642 if(!ids)
643 return 0;
644 while(*ids != TALK_FINAL_ID)
645 {
646 if((r = talk_id(*ids++, enqueue)) <0)
647 return r;
648 enqueue = true;
649 }
650 return 0;
651}
652
653/* Make sure the current utterance is not interrupted by the next one. */
654void talk_force_enqueue_next(void)
655{
656 force_enqueue_next = true;
657}
620 658
621/* play a thumbnail from file */ 659/* play a thumbnail from file */
622int talk_file(const char* filename, bool enqueue) 660int 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 */
66int talk_get_bufsize(void); /* get the loaded voice file size */ 66int talk_get_bufsize(void); /* get the loaded voice file size */
67/* talk_buffer_steal - on SWCODEC, for use by buffer functions only */ 67/* talk_buffer_steal - on SWCODEC, for use by buffer functions only */
68int talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */ 68int talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */
69//int shutup(void); /* Interrupt voice, as when enqueue is false */
70//int do_shutup(void); /* kill voice unconditionally */
71bool is_voice_queued(void); /* Are there more voice clips to be spoken? */
69int talk_id(long id, bool enqueue); /* play a voice ID from voicefont */ 72int talk_id(long id, bool enqueue); /* play a voice ID from voicefont */
70int talk_file(const char* filename, bool enqueue); /* play a thumbnail from file */ 73int talk_file(const char* filename, bool enqueue); /* play a thumbnail from file */
71int talk_number(long n, bool enqueue); /* say a number */ 74int talk_number(long n, bool enqueue); /* say a number */
@@ -74,4 +77,37 @@ int talk_spell(const char* spell, bool enqueue); /* spell a string */
74bool talk_menus_enabled(void); /* returns true if menus should be voiced */ 77bool talk_menus_enabled(void); /* returns true if menus should be voiced */
75void talk_disable_menus(void); /* disable voice menus (temporarily, not persisted) */ 78void talk_disable_menus(void); /* disable voice menus (temporarily, not persisted) */
76void talk_enable_menus(void); /* re-enable voice menus */ 79void talk_enable_menus(void); /* re-enable voice menus */
80
81/* Enqueue next utterance even if enqueue parameter is false: don't
82 interrupt the current utterance. */
83void talk_force_enqueue_next(void);
84
85/* speaks one or more IDs (from an array)). */
86int talk_idarray(long *idarray, bool enqueue);
87/* This (otherwise invalid) ID signals the end of the array. */
88#define TALK_FINAL_ID LANG_LAST_INDEX_IN_ARRAY
89/* This makes an initializer for the array of IDs and takes care to
90 put the final sentinel element at the end. */
91#define TALK_IDARRAY(ids...) ((long[]){ids,TALK_FINAL_ID})
92/* And this handy macro makes it look like a variadic function. */
93#define talk_ids(enqueue, ids...) talk_idarray(TALK_IDARRAY(ids), enqueue)
94/* This version talks only if talking menus are enabled, and does not
95 enqueue the initial id. */
96#define cond_talk_ids(ids...) do { \
97 if (talk_menus_enabled()) \
98 talk_ids(false, ids); \
99 } while(0)
100/* And a version that takes the array parameter... */
101#define cond_talk_idarray(idarray) do { \
102 if (talk_menus_enabled() \
103 talk_idarray(idarray, false); \
104 } while(0)
105/* Convenience macro to conditionally speak something and not have
106 it interrupted. */
107#define cond_talk_ids_fq(ids...) do { \
108 if (talk_menus_enabled()) { \
109 talk_ids(false, ids); \
110 talk_force_enqueue_next(); \
111 } \
112 }while(0)
77#endif /* __TALK_H__ */ 113#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)
325 (tc.dirfull || 325 (tc.dirfull ||
326 tc.filesindir == global_settings.max_files_in_dir) ) 326 tc.filesindir == global_settings.max_files_in_dir) )
327 { 327 {
328 gui_syncsplash(HZ, str(LANG_SHOWDIR_BUFFER_FULL)); 328 gui_syncsplash(HZ, ID2P(LANG_SHOWDIR_BUFFER_FULL));
329 } 329 }
330 } 330 }
331#ifdef HAVE_TAGCACHE 331#ifdef HAVE_TAGCACHE
@@ -556,7 +556,7 @@ static int dirbrowse()
556 556
557 if (*tc.dirfilter > NUM_FILTER_MODES && numentries==0) 557 if (*tc.dirfilter > NUM_FILTER_MODES && numentries==0)
558 { 558 {
559 gui_syncsplash(HZ*2, str(LANG_NO_FILES)); 559 gui_syncsplash(HZ*2, ID2P(LANG_NO_FILES));
560 return false; /* No files found for rockbox_browser() */ 560 return false; /* No files found for rockbox_browser() */
561 } 561 }
562 562
@@ -567,7 +567,7 @@ static int dirbrowse()
567 tc.dirlevel = 0; /* shouldnt be needed.. this code needs work! */ 567 tc.dirlevel = 0; /* shouldnt be needed.. this code needs work! */
568#ifdef BOOTFILE 568#ifdef BOOTFILE
569 if (boot_changed) { 569 if (boot_changed) {
570 char *lines[]={str(LANG_BOOT_CHANGED), str(LANG_REBOOT_NOW)}; 570 char *lines[]={ID2P(LANG_BOOT_CHANGED), ID2P(LANG_REBOOT_NOW)};
571 struct text_message message={lines, 2}; 571 struct text_message message={lines, 2};
572 if(gui_syncyesno_run(&message, NULL, NULL)==YESNO_YES) 572 if(gui_syncyesno_run(&message, NULL, NULL)==YESNO_YES)
573 rolo_load("/" BOOTFILE); 573 rolo_load("/" BOOTFILE);
@@ -1336,6 +1336,7 @@ void tree_restore(void)
1336 str(LANG_SCANNING_DISK)); 1336 str(LANG_SCANNING_DISK));
1337 gui_textarea_update(&screens[i]); 1337 gui_textarea_update(&screens[i]);
1338 } 1338 }
1339 cond_talk_ids_fq(LANG_SCANNING_DISK);
1339 1340
1340 dircache_build(global_status.dircache_size); 1341 dircache_build(global_status.dircache_size);
1341 1342