summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/bookmark.c6
-rw-r--r--apps/debug_menu.c30
-rw-r--r--apps/main.c2
-rw-r--r--apps/main_menu.c22
-rw-r--r--apps/menu.c17
-rw-r--r--apps/menu.h6
-rw-r--r--apps/onplay.c18
-rw-r--r--apps/playlist.c3
-rw-r--r--apps/playlist_menu.c8
-rw-r--r--apps/playlist_viewer.c11
-rw-r--r--apps/plugin.c2
-rw-r--r--apps/recorder/radio.c10
-rw-r--r--apps/settings_menu.c152
-rw-r--r--apps/sound_menu.c24
-rw-r--r--firmware/export/talk.h34
-rw-r--r--firmware/mpeg.c3
-rw-r--r--firmware/talk.c209
-rw-r--r--uisimulator/common/stubs.c19
18 files changed, 454 insertions, 122 deletions
diff --git a/apps/bookmark.c b/apps/bookmark.c
index 51b720bf32..e832165b3c 100644
--- a/apps/bookmark.c
+++ b/apps/bookmark.c
@@ -93,9 +93,9 @@ bool bookmark_menu(void)
93 bool result; 93 bool result;
94 94
95 struct menu_items items[] = { 95 struct menu_items items[] = {
96 { str(LANG_BOOKMARK_MENU_CREATE), bookmark_create_menu}, 96 { STR(LANG_BOOKMARK_MENU_CREATE), bookmark_create_menu},
97 { str(LANG_BOOKMARK_MENU_LIST), bookmark_load_menu}, 97 { STR(LANG_BOOKMARK_MENU_LIST), bookmark_load_menu},
98 { str(LANG_BOOKMARK_MENU_RECENT_BOOKMARKS), bookmark_mrb_load}, 98 { STR(LANG_BOOKMARK_MENU_RECENT_BOOKMARKS), bookmark_mrb_load},
99 }; 99 };
100 100
101 m=menu_init( items, sizeof items / sizeof(struct menu_items), NULL ); 101 m=menu_init( items, sizeof items / sizeof(struct menu_items), NULL );
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index b77014a846..d0c575ba12 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -1476,36 +1476,36 @@ bool debug_menu(void)
1476 bool result; 1476 bool result;
1477 1477
1478 struct menu_items items[] = { 1478 struct menu_items items[] = {
1479 { "Dump ROM contents", dbg_save_roms }, 1479 { "Dump ROM contents", -1, dbg_save_roms },
1480 { "View I/O ports", dbg_ports }, 1480 { "View I/O ports", -1, dbg_ports },
1481#ifdef HAVE_LCD_BITMAP 1481#ifdef HAVE_LCD_BITMAP
1482#ifdef HAVE_RTC 1482#ifdef HAVE_RTC
1483 { "View/clr RTC RAM", dbg_rtc }, 1483 { "View/clr RTC RAM", -1, dbg_rtc },
1484#endif /* HAVE_RTC */ 1484#endif /* HAVE_RTC */
1485#endif /* HAVE_LCD_BITMAP */ 1485#endif /* HAVE_LCD_BITMAP */
1486 { "View OS stacks", dbg_os }, 1486 { "View OS stacks", -1, dbg_os },
1487#ifdef HAVE_MAS3507D 1487#ifdef HAVE_MAS3507D
1488 { "View MAS info", dbg_mas_info }, 1488 { "View MAS info", -1, dbg_mas_info },
1489#endif 1489#endif
1490 { "View MAS regs", dbg_mas }, 1490 { "View MAS regs", -1, dbg_mas },
1491#ifdef HAVE_MAS3587F 1491#ifdef HAVE_MAS3587F
1492 { "View MAS codec", dbg_mas_codec }, 1492 { "View MAS codec", -1, dbg_mas_codec },
1493#endif 1493#endif
1494#ifdef HAVE_LCD_BITMAP 1494#ifdef HAVE_LCD_BITMAP
1495 { "View battery", view_battery }, 1495 { "View battery", -1, view_battery },
1496#endif 1496#endif
1497 { "View HW info", dbg_hw_info }, 1497 { "View HW info", -1, dbg_hw_info },
1498 { "View partitions", dbg_partitions }, 1498 { "View partitions", -1, dbg_partitions },
1499 { "View disk info", dbg_disk_info }, 1499 { "View disk info", -1, dbg_disk_info },
1500#ifdef HAVE_LCD_BITMAP 1500#ifdef HAVE_LCD_BITMAP
1501 { "View mpeg thread", dbg_mpeg_thread }, 1501 { "View mpeg thread", -1, dbg_mpeg_thread },
1502#ifdef PM_DEBUG 1502#ifdef PM_DEBUG
1503 { "pm histogram", peak_meter_histogram}, 1503 { "pm histogram", -1, peak_meter_histogram},
1504#endif /* PM_DEBUG */ 1504#endif /* PM_DEBUG */
1505#endif /* HAVE_LCD_BITMAP */ 1505#endif /* HAVE_LCD_BITMAP */
1506 { "View runtime", view_runtime }, 1506 { "View runtime", -1, view_runtime },
1507#ifdef HAVE_FMRADIO 1507#ifdef HAVE_FMRADIO
1508 { "FM Radio", dbg_fm_radio }, 1508 { "FM Radio", -1, dbg_fm_radio },
1509#endif 1509#endif
1510 }; 1510 };
1511 1511
diff --git a/apps/main.c b/apps/main.c
index d6be594d07..2c2f9ac854 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -54,6 +54,7 @@
54#include "rolo.h" 54#include "rolo.h"
55#include "screens.h" 55#include "screens.h"
56#include "power.h" 56#include "power.h"
57#include "talk.h"
57 58
58char appsversion[]=APPSVERSION; 59char appsversion[]=APPSVERSION;
59 60
@@ -208,6 +209,7 @@ void init(void)
208 global_settings.avc, 209 global_settings.avc,
209 global_settings.channel_config ); 210 global_settings.channel_config );
210 mpeg_init(); 211 mpeg_init();
212 talk_init();
211 213
212 /* no auto-rolo on startup any more, but I leave it here for reference */ 214 /* no auto-rolo on startup any more, but I leave it here for reference */
213#if 0 215#if 0
diff --git a/apps/main_menu.c b/apps/main_menu.c
index f42655b0c2..ade6e7bd99 100644
--- a/apps/main_menu.c
+++ b/apps/main_menu.c
@@ -262,8 +262,8 @@ bool rec_menu(void)
262 262
263 /* recording menu */ 263 /* recording menu */
264 struct menu_items items[] = { 264 struct menu_items items[] = {
265 { str(LANG_RECORDING_MENU), recording_screen }, 265 { STR(LANG_RECORDING_MENU), recording_screen },
266 { str(LANG_RECORDING_SETTINGS), recording_settings}, 266 { STR(LANG_RECORDING_SETTINGS), recording_settings},
267 }; 267 };
268 268
269 m=menu_init( items, sizeof items / sizeof(struct menu_items), NULL ); 269 m=menu_init( items, sizeof items / sizeof(struct menu_items), NULL );
@@ -281,13 +281,13 @@ bool info_menu(void)
281 281
282 /* info menu */ 282 /* info menu */
283 struct menu_items items[] = { 283 struct menu_items items[] = {
284 { str(LANG_MENU_SHOW_ID3_INFO), browse_id3 }, 284 { STR(LANG_MENU_SHOW_ID3_INFO), browse_id3 },
285 { str(LANG_INFO_MENU), show_info }, 285 { STR(LANG_INFO_MENU), show_info },
286 { str(LANG_VERSION), show_credits }, 286 { STR(LANG_VERSION), show_credits },
287#ifndef SIMULATOR 287#ifndef SIMULATOR
288 { str(LANG_DEBUG), debug_menu }, 288 { STR(LANG_DEBUG), debug_menu },
289#else 289#else
290 { str(LANG_USB), simulate_usb }, 290 { STR(LANG_USB), simulate_usb },
291#endif 291#endif
292 }; 292 };
293 293
@@ -308,33 +308,41 @@ bool main_menu(void)
308 struct menu_items items[8]; 308 struct menu_items items[8];
309 309
310 items[i].desc = str(LANG_BOOKMARK_MENU); 310 items[i].desc = str(LANG_BOOKMARK_MENU);
311 items[i].voice_id = LANG_BOOKMARK_MENU;
311 items[i++].function = bookmark_menu; 312 items[i++].function = bookmark_menu;
312 313
313 items[i].desc = str(LANG_SOUND_SETTINGS); 314 items[i].desc = str(LANG_SOUND_SETTINGS);
315 items[i].voice_id = LANG_SOUND_SETTINGS;
314 items[i++].function = sound_menu; 316 items[i++].function = sound_menu;
315 317
316 items[i].desc = str(LANG_GENERAL_SETTINGS); 318 items[i].desc = str(LANG_GENERAL_SETTINGS);
319 items[i].voice_id = LANG_GENERAL_SETTINGS;
317 items[i++].function = settings_menu; 320 items[i++].function = settings_menu;
318 321
319#ifdef HAVE_FMRADIO 322#ifdef HAVE_FMRADIO
320 if(radio_hardware_present()) { 323 if(radio_hardware_present()) {
321 items[i].desc = str(LANG_FM_RADIO); 324 items[i].desc = str(LANG_FM_RADIO);
325 items[i].voice_id = LANG_FM_RADIO;
322 items[i++].function = radio_screen; 326 items[i++].function = radio_screen;
323 } 327 }
324#endif 328#endif
325 329
326#ifdef HAVE_MAS3587F 330#ifdef HAVE_MAS3587F
327 items[i].desc = str(LANG_RECORDING); 331 items[i].desc = str(LANG_RECORDING);
332 items[i].voice_id = LANG_RECORDING;
328 items[i++].function = rec_menu; 333 items[i++].function = rec_menu;
329#endif 334#endif
330 335
331 items[i].desc = str(LANG_PLAYLIST_MENU); 336 items[i].desc = str(LANG_PLAYLIST_MENU);
337 items[i].voice_id = LANG_PLAYLIST_MENU;
332 items[i++].function = playlist_menu; 338 items[i++].function = playlist_menu;
333 339
334 items[i].desc = str(LANG_PLUGINS); 340 items[i].desc = str(LANG_PLUGINS);
341 items[i].voice_id = LANG_PLUGINS;
335 items[i++].function = plugin_browse; 342 items[i++].function = plugin_browse;
336 343
337 items[i].desc = str(LANG_INFO); 344 items[i].desc = str(LANG_INFO);
345 items[i].voice_id = LANG_INFO;
338 items[i++].function = info_menu; 346 items[i++].function = info_menu;
339 347
340 m=menu_init( items, i, NULL ); 348 m=menu_init( items, i, NULL );
diff --git a/apps/menu.c b/apps/menu.c
index f187b5d82b..f9443548f6 100644
--- a/apps/menu.c
+++ b/apps/menu.c
@@ -32,6 +32,7 @@
32#include "settings.h" 32#include "settings.h"
33#include "status.h" 33#include "status.h"
34#include "screens.h" 34#include "screens.h"
35#include "talk.h"
35 36
36#ifdef HAVE_LCD_BITMAP 37#ifdef HAVE_LCD_BITMAP
37#include "icons.h" 38#include "icons.h"
@@ -216,6 +217,13 @@ static void put_cursor(int m, int target)
216 lcd_update(); 217 lcd_update();
217 } 218 }
218 219
220 if (do_update)
221 { /* "say" the entry under the cursor */
222 int voice_id = menus[m].items[menus[m].cursor].voice_id;
223 if (voice_id >= 0) /* valid ID given? */
224 talk_id(voice_id, false); /* say it */
225 }
226
219} 227}
220 228
221int menu_init(struct menu_items* mitems, int count, int (*callback)(int, int)) 229int menu_init(struct menu_items* mitems, int count, int (*callback)(int, int))
@@ -250,6 +258,7 @@ int menu_show(int m)
250{ 258{
251 bool exit = false; 259 bool exit = false;
252 int key; 260 int key;
261 int voice_id;
253#ifdef HAVE_LCD_BITMAP 262#ifdef HAVE_LCD_BITMAP
254 int fw, fh; 263 int fw, fh;
255 int menu_lines; 264 int menu_lines;
@@ -263,9 +272,16 @@ int menu_show(int m)
263 272
264 menu_draw(m); 273 menu_draw(m);
265 274
275 /* say current entry */
276 voice_id = menus[m].items[menus[m].cursor].voice_id;
277 if (voice_id >= 0) /* valid ID given? */
278 talk_id(voice_id, false); /* say it */
279
266 while (!exit) { 280 while (!exit) {
267 key = button_get_w_tmo(HZ/2); 281 key = button_get_w_tmo(HZ/2);
282
268 283
284
269 /* 285 /*
270 * "short-circuit" the default keypresses by running the callback function 286 * "short-circuit" the default keypresses by running the callback function
271 */ 287 */
@@ -274,6 +290,7 @@ int menu_show(int m)
274 key = menus[m].callback(key, m); /* make sure there's no match in the switch */ 290 key = menus[m].callback(key, m); /* make sure there's no match in the switch */
275 291
276 switch( key ) { 292 switch( key ) {
293
277#ifdef HAVE_RECORDER_KEYPAD 294#ifdef HAVE_RECORDER_KEYPAD
278 case BUTTON_UP: 295 case BUTTON_UP:
279 case BUTTON_UP | BUTTON_REPEAT: 296 case BUTTON_UP | BUTTON_REPEAT:
diff --git a/apps/menu.h b/apps/menu.h
index 827de1da36..dbe5151178 100644
--- a/apps/menu.h
+++ b/apps/menu.h
@@ -23,10 +23,14 @@
23#include <stdbool.h> 23#include <stdbool.h>
24 24
25struct menu_items { 25struct menu_items {
26 unsigned char *desc; 26 unsigned char *desc; /* string */
27 int voice_id; /* the associated voice clip, -1 if none */
27 bool (*function) (void); /* return true if USB was connected */ 28 bool (*function) (void); /* return true if USB was connected */
28}; 29};
29 30
31/* convenience macro to have both string and ID as arguments */
32#define STR(id) str(id), id
33
30int menu_init(struct menu_items* items, int count, int (*callback) (int keycode, int menu)); 34int menu_init(struct menu_items* items, int count, int (*callback) (int keycode, int menu));
31void menu_exit(int menu); 35void menu_exit(int menu);
32 36
diff --git a/apps/onplay.c b/apps/onplay.c
index e4733fba53..9dab34c283 100644
--- a/apps/onplay.c
+++ b/apps/onplay.c
@@ -41,6 +41,7 @@
41#include "settings.h" 41#include "settings.h"
42#include "status.h" 42#include "status.h"
43#include "playlist_viewer.h" 43#include "playlist_viewer.h"
44#include "talk.h"
44#include "onplay.h" 45#include "onplay.h"
45 46
46static char* selected_file = NULL; 47static char* selected_file = NULL;
@@ -147,6 +148,7 @@ static bool playlist_options(void)
147 if ((selected_file_attr & TREE_ATTR_MASK) == TREE_ATTR_M3U) 148 if ((selected_file_attr & TREE_ATTR_MASK) == TREE_ATTR_M3U)
148 { 149 {
149 menu[i].desc = str(LANG_VIEW); 150 menu[i].desc = str(LANG_VIEW);
151 menu[i].voice_id = LANG_VIEW;
150 menu[i].function = view_playlist; 152 menu[i].function = view_playlist;
151 i++; 153 i++;
152 pstart++; 154 pstart++;
@@ -155,31 +157,37 @@ static bool playlist_options(void)
155 if (mpeg_status() & MPEG_STATUS_PLAY) 157 if (mpeg_status() & MPEG_STATUS_PLAY)
156 { 158 {
157 menu[i].desc = str(LANG_INSERT); 159 menu[i].desc = str(LANG_INSERT);
160 menu[i].voice_id = LANG_INSERT;
158 args[i].position = PLAYLIST_INSERT; 161 args[i].position = PLAYLIST_INSERT;
159 args[i].queue = false; 162 args[i].queue = false;
160 i++; 163 i++;
161 164
162 menu[i].desc = str(LANG_INSERT_FIRST); 165 menu[i].desc = str(LANG_INSERT_FIRST);
166 menu[i].voice_id = LANG_INSERT_FIRST;
163 args[i].position = PLAYLIST_INSERT_FIRST; 167 args[i].position = PLAYLIST_INSERT_FIRST;
164 args[i].queue = false; 168 args[i].queue = false;
165 i++; 169 i++;
166 170
167 menu[i].desc = str(LANG_INSERT_LAST); 171 menu[i].desc = str(LANG_INSERT_LAST);
172 menu[i].voice_id = LANG_INSERT_LAST;
168 args[i].position = PLAYLIST_INSERT_LAST; 173 args[i].position = PLAYLIST_INSERT_LAST;
169 args[i].queue = false; 174 args[i].queue = false;
170 i++; 175 i++;
171 176
172 menu[i].desc = str(LANG_QUEUE); 177 menu[i].desc = str(LANG_QUEUE);
178 menu[i].voice_id = LANG_QUEUE;
173 args[i].position = PLAYLIST_INSERT; 179 args[i].position = PLAYLIST_INSERT;
174 args[i].queue = true; 180 args[i].queue = true;
175 i++; 181 i++;
176 182
177 menu[i].desc = str(LANG_QUEUE_FIRST); 183 menu[i].desc = str(LANG_QUEUE_FIRST);
184 menu[i].voice_id = LANG_QUEUE_FIRST;
178 args[i].position = PLAYLIST_INSERT_FIRST; 185 args[i].position = PLAYLIST_INSERT_FIRST;
179 args[i].queue = true; 186 args[i].queue = true;
180 i++; 187 i++;
181 188
182 menu[i].desc = str(LANG_QUEUE_LAST); 189 menu[i].desc = str(LANG_QUEUE_LAST);
190 menu[i].voice_id = LANG_QUEUE_LAST;
183 args[i].position = PLAYLIST_INSERT_LAST; 191 args[i].position = PLAYLIST_INSERT_LAST;
184 args[i].queue = true; 192 args[i].queue = true;
185 i++; 193 i++;
@@ -188,6 +196,7 @@ static bool playlist_options(void)
188 (selected_file_attr & ATTR_DIRECTORY)) 196 (selected_file_attr & ATTR_DIRECTORY))
189 { 197 {
190 menu[i].desc = str(LANG_INSERT); 198 menu[i].desc = str(LANG_INSERT);
199 menu[i].voice_id = LANG_INSERT;
191 args[i].position = PLAYLIST_INSERT; 200 args[i].position = PLAYLIST_INSERT;
192 args[i].queue = false; 201 args[i].queue = false;
193 i++; 202 i++;
@@ -283,6 +292,8 @@ static int insert_data_in_file(char *fname, int fpos, char *buf, int num_bytes)
283 int orig_fd, fd; 292 int orig_fd, fd;
284 char tmpname[MAX_PATH]; 293 char tmpname[MAX_PATH];
285 294
295 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
296
286 snprintf(tmpname, MAX_PATH, "%s.tmp", fname); 297 snprintf(tmpname, MAX_PATH, "%s.tmp", fname);
287 298
288 orig_fd = open(fname, O_RDONLY); 299 orig_fd = open(fname, O_RDONLY);
@@ -384,6 +395,8 @@ static bool vbr_fix(void)
384 return onplay_result; 395 return onplay_result;
385 } 396 }
386 397
398 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
399
387 lcd_clear_display(); 400 lcd_clear_display();
388 lcd_puts_scroll(0, 0, selected_file); 401 lcd_puts_scroll(0, 0, selected_file);
389 lcd_update(); 402 lcd_update();
@@ -552,17 +565,20 @@ int onplay(char* file, int attr)
552 ((attr & TREE_ATTR_MASK) == TREE_ATTR_M3U)) 565 ((attr & TREE_ATTR_MASK) == TREE_ATTR_M3U))
553 { 566 {
554 menu[i].desc = str(LANG_PLAYINDICES_PLAYLIST); 567 menu[i].desc = str(LANG_PLAYINDICES_PLAYLIST);
568 menu[i].voice_id = LANG_PLAYINDICES_PLAYLIST;
555 menu[i].function = playlist_options; 569 menu[i].function = playlist_options;
556 i++; 570 i++;
557 } 571 }
558 572
559 menu[i].desc = str(LANG_RENAME); 573 menu[i].desc = str(LANG_RENAME);
574 menu[i].voice_id = LANG_RENAME;
560 menu[i].function = rename_file; 575 menu[i].function = rename_file;
561 i++; 576 i++;
562 577
563 if (!(attr & ATTR_DIRECTORY)) 578 if (!(attr & ATTR_DIRECTORY))
564 { 579 {
565 menu[i].desc = str(LANG_DELETE); 580 menu[i].desc = str(LANG_DELETE);
581 menu[i].voice_id = LANG_DELETE;
566 menu[i].function = delete_file; 582 menu[i].function = delete_file;
567 i++; 583 i++;
568 } 584 }
@@ -570,12 +586,14 @@ int onplay(char* file, int attr)
570 if ((attr & TREE_ATTR_MASK) == TREE_ATTR_MPA) 586 if ((attr & TREE_ATTR_MASK) == TREE_ATTR_MPA)
571 { 587 {
572 menu[i].desc = str(LANG_VBRFIX); 588 menu[i].desc = str(LANG_VBRFIX);
589 menu[i].voice_id = LANG_VBRFIX;
573 menu[i].function = vbr_fix; 590 menu[i].function = vbr_fix;
574 i++; 591 i++;
575 } 592 }
576 } 593 }
577 594
578 menu[i].desc = str(LANG_CREATE_DIR); 595 menu[i].desc = str(LANG_CREATE_DIR);
596 menu[i].voice_id = LANG_CREATE_DIR;
579 menu[i].function = create_dir; 597 menu[i].function = create_dir;
580 i++; 598 i++;
581 599
diff --git a/apps/playlist.c b/apps/playlist.c
index 572eb26456..53a18c606e 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -91,6 +91,7 @@
91#endif 91#endif
92 92
93#include "lang.h" 93#include "lang.h"
94#include "talk.h"
94 95
95#define PLAYLIST_CONTROL_FILE ROCKBOX_DIR "/.playlist_control" 96#define PLAYLIST_CONTROL_FILE ROCKBOX_DIR "/.playlist_control"
96#define PLAYLIST_CONTROL_FILE_VERSION 2 97#define PLAYLIST_CONTROL_FILE_VERSION 2
@@ -337,6 +338,7 @@ static int add_indices_to_playlist(struct playlist_info* playlist,
337 { 338 {
338 /* use mp3 buffer for maximum load speed */ 339 /* use mp3 buffer for maximum load speed */
339 mpeg_stop(); 340 mpeg_stop();
341 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
340 342
341 buffer = mp3buf; 343 buffer = mp3buf;
342 buflen = (mp3end - mp3buf); 344 buflen = (mp3end - mp3buf);
@@ -1192,6 +1194,7 @@ int playlist_resume(void)
1192 }; 1194 };
1193 1195
1194 /* use mp3 buffer for maximum load speed */ 1196 /* use mp3 buffer for maximum load speed */
1197 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
1195 buflen = (mp3end - mp3buf); 1198 buflen = (mp3end - mp3buf);
1196 buffer = mp3buf; 1199 buffer = mp3buf;
1197 1200
diff --git a/apps/playlist_menu.c b/apps/playlist_menu.c
index 87862ab252..6eafe0c547 100644
--- a/apps/playlist_menu.c
+++ b/apps/playlist_menu.c
@@ -65,10 +65,10 @@ bool playlist_menu(void)
65 bool result; 65 bool result;
66 66
67 struct menu_items items[] = { 67 struct menu_items items[] = {
68 { str(LANG_CREATE_PLAYLIST), create_playlist }, 68 { STR(LANG_CREATE_PLAYLIST), create_playlist },
69 { str(LANG_VIEW_DYNAMIC_PLAYLIST), playlist_viewer }, 69 { STR(LANG_VIEW_DYNAMIC_PLAYLIST), playlist_viewer },
70 { str(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist }, 70 { STR(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist },
71 { str(LANG_RECURSE_DIRECTORY), recurse_directory }, 71 { STR(LANG_RECURSE_DIRECTORY), recurse_directory },
72 }; 72 };
73 73
74 m = menu_init( items, sizeof items / sizeof(struct menu_items), NULL ); 74 m = menu_init( items, sizeof items / sizeof(struct menu_items), NULL );
diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c
index 58052afd6b..8b9470cdca 100644
--- a/apps/playlist_viewer.c
+++ b/apps/playlist_viewer.c
@@ -685,12 +685,15 @@ static int onplay_menu(int index)
685 bool current = (tracks[index].index == viewer.current_playing_track); 685 bool current = (tracks[index].index == viewer.current_playing_track);
686 686
687 menu[i].desc = str(LANG_REMOVE); 687 menu[i].desc = str(LANG_REMOVE);
688 menu[i].voice_id = LANG_REMOVE;
688 i++; 689 i++;
689 690
690 menu[i].desc = str(LANG_MOVE); 691 menu[i].desc = str(LANG_MOVE);
692 menu[i].voice_id = LANG_MOVE;
691 i++; 693 i++;
692 694
693 menu[i].desc = str(LANG_FILE_OPTIONS); 695 menu[i].desc = str(LANG_FILE_OPTIONS);
696 menu[i].voice_id = LANG_FILE_OPTIONS;
694 i++; 697 i++;
695 698
696 m = menu_init(menu, i, NULL); 699 m = menu_init(menu, i, NULL);
@@ -757,10 +760,10 @@ static bool viewer_menu(void)
757 bool result; 760 bool result;
758 761
759 struct menu_items items[] = { 762 struct menu_items items[] = {
760 { str(LANG_SHOW_ICONS), show_icons }, 763 { STR(LANG_SHOW_ICONS), show_icons },
761 { str(LANG_SHOW_INDICES), show_indices }, 764 { STR(LANG_SHOW_INDICES), show_indices },
762 { str(LANG_TRACK_DISPLAY), track_display }, 765 { STR(LANG_TRACK_DISPLAY), track_display },
763 { str(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist }, 766 { STR(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist },
764 }; 767 };
765 768
766 m=menu_init( items, sizeof(items) / sizeof(*items), NULL ); 769 m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
diff --git a/apps/plugin.c b/apps/plugin.c
index 08c98017e1..cdb787a0b0 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -38,6 +38,7 @@
38#include "mp3_playback.h" 38#include "mp3_playback.h"
39#include "backlight.h" 39#include "backlight.h"
40#include "ata.h" 40#include "ata.h"
41#include "talk.h"
41 42
42#ifdef HAVE_LCD_BITMAP 43#ifdef HAVE_LCD_BITMAP
43#include "widgets.h" 44#include "widgets.h"
@@ -325,6 +326,7 @@ void* plugin_get_mp3_buffer(int* buffer_size)
325 return buf; 326 return buf;
326#else 327#else
327 mpeg_stop(); 328 mpeg_stop();
329 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
328 *buffer_size = mp3end - mp3buf; 330 *buffer_size = mp3end - mp3buf;
329 return mp3buf; 331 return mp3buf;
330#endif 332#endif
diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c
index a9937a3f60..86e11f9546 100644
--- a/apps/recorder/radio.c
+++ b/apps/recorder/radio.c
@@ -595,6 +595,7 @@ bool radio_preset_select(void)
595 if(presets[i].frequency) 595 if(presets[i].frequency)
596 { 596 {
597 menu[num_presets].desc = presets[i].name; 597 menu[num_presets].desc = presets[i].name;
598 menu[num_presets].voice_id = -1;
598 /* We use the function pointer entry for the preset 599 /* We use the function pointer entry for the preset
599 entry index */ 600 entry index */
600 menu[num_presets++].function = (void *)i; 601 menu[num_presets++].function = (void *)i;
@@ -669,6 +670,7 @@ bool radio_delete_preset(void)
669 if(presets[i].frequency) 670 if(presets[i].frequency)
670 { 671 {
671 menu[num_presets].desc = presets[i].name; 672 menu[num_presets].desc = presets[i].name;
673 menu[num_presets].voice_id = -1;
672 /* We use the function pointer entry for the preset 674 /* We use the function pointer entry for the preset
673 entry index */ 675 entry index */
674 menu[num_presets++].function = (void *)i; 676 menu[num_presets++].function = (void *)i;
@@ -715,10 +717,10 @@ static bool fm_recording_settings(void)
715bool radio_menu(void) 717bool radio_menu(void)
716{ 718{
717 struct menu_items radio_menu_items[] = { 719 struct menu_items radio_menu_items[] = {
718 { str(LANG_FM_SAVE_PRESET), radio_add_preset }, 720 { STR(LANG_FM_SAVE_PRESET), radio_add_preset },
719 { str(LANG_FM_DELETE_PRESET), radio_delete_preset }, 721 { STR(LANG_FM_DELETE_PRESET), radio_delete_preset },
720 { str(LANG_SOUND_SETTINGS), sound_menu }, 722 { STR(LANG_SOUND_SETTINGS), sound_menu },
721 { str(LANG_RECORDING_SETTINGS), fm_recording_settings } 723 { STR(LANG_RECORDING_SETTINGS), fm_recording_settings }
722 }; 724 };
723 int m; 725 int m;
724 bool result; 726 bool result;
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index 7c060c4533..75c78a7de3 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -368,16 +368,16 @@ static bool peak_meter_menu(void)
368 bool result; 368 bool result;
369 369
370 struct menu_items items[] = { 370 struct menu_items items[] = {
371 { str(LANG_PM_RELEASE) , peak_meter_release }, 371 { STR(LANG_PM_RELEASE) , peak_meter_release },
372 { str(LANG_PM_PEAK_HOLD), peak_meter_hold }, 372 { STR(LANG_PM_PEAK_HOLD), peak_meter_hold },
373 { str(LANG_PM_CLIP_HOLD), peak_meter_clip_hold }, 373 { STR(LANG_PM_CLIP_HOLD), peak_meter_clip_hold },
374 { str(LANG_PM_PERFORMANCE), peak_meter_performance }, 374 { STR(LANG_PM_PERFORMANCE), peak_meter_performance },
375#ifdef PM_DEBUG 375#ifdef PM_DEBUG
376 { "Refresh rate" , peak_meter_fps_menu }, 376 { "Refresh rate" , -1 , peak_meter_fps_menu },
377#endif 377#endif
378 { str(LANG_PM_SCALE) , peak_meter_scale }, 378 { STR(LANG_PM_SCALE) , peak_meter_scale },
379 { str(LANG_PM_MIN) , peak_meter_min }, 379 { STR(LANG_PM_MIN) , peak_meter_min },
380 { str(LANG_PM_MAX) , peak_meter_max }, 380 { STR(LANG_PM_MAX) , peak_meter_max },
381 }; 381 };
382 382
383 m=menu_init( items, sizeof(items) / sizeof(*items), NULL ); 383 m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
@@ -791,8 +791,8 @@ static bool ff_rewind_settings_menu(void)
791 bool result; 791 bool result;
792 792
793 struct menu_items items[] = { 793 struct menu_items items[] = {
794 { str(LANG_FFRW_STEP), ff_rewind_min_step }, 794 { STR(LANG_FFRW_STEP), ff_rewind_min_step },
795 { str(LANG_FFRW_ACCEL), ff_rewind_accel }, 795 { STR(LANG_FFRW_ACCEL), ff_rewind_accel },
796 }; 796 };
797 797
798 m=menu_init( items, sizeof(items) / sizeof(*items), NULL ); 798 m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
@@ -808,13 +808,13 @@ static bool playback_settings_menu(void)
808 bool result; 808 bool result;
809 809
810 struct menu_items items[] = { 810 struct menu_items items[] = {
811 { str(LANG_SHUFFLE), shuffle }, 811 { STR(LANG_SHUFFLE), shuffle },
812 { str(LANG_REPEAT), repeat_mode }, 812 { STR(LANG_REPEAT), repeat_mode },
813 { str(LANG_PLAY_SELECTED), play_selected }, 813 { STR(LANG_PLAY_SELECTED), play_selected },
814 { str(LANG_RESUME), resume }, 814 { STR(LANG_RESUME), resume },
815 { str(LANG_WIND_MENU), ff_rewind_settings_menu }, 815 { STR(LANG_WIND_MENU), ff_rewind_settings_menu },
816 { str(LANG_MP3BUFFER_MARGIN), buffer_margin }, 816 { STR(LANG_MP3BUFFER_MARGIN), buffer_margin },
817 { str(LANG_FADE_ON_STOP), set_fade_on_stop }, 817 { STR(LANG_FADE_ON_STOP), set_fade_on_stop },
818 }; 818 };
819 819
820 bool old_shuffle = global_settings.playlist_shuffle; 820 bool old_shuffle = global_settings.playlist_shuffle;
@@ -843,9 +843,9 @@ static bool bookmark_settings_menu(void)
843 bool result; 843 bool result;
844 844
845 struct menu_items items[] = { 845 struct menu_items items[] = {
846 { str(LANG_BOOKMARK_SETTINGS_AUTOCREATE), autocreatebookmark}, 846 { STR(LANG_BOOKMARK_SETTINGS_AUTOCREATE), autocreatebookmark},
847 { str(LANG_BOOKMARK_SETTINGS_AUTOLOAD), autoloadbookmark}, 847 { STR(LANG_BOOKMARK_SETTINGS_AUTOLOAD), autoloadbookmark},
848 { str(LANG_BOOKMARK_SETTINGS_MAINTAIN_RECENT_BOOKMARKS), useMRB}, 848 { STR(LANG_BOOKMARK_SETTINGS_MAINTAIN_RECENT_BOOKMARKS), useMRB},
849 }; 849 };
850 850
851 m=menu_init( items, sizeof items / sizeof(struct menu_items), NULL ); 851 m=menu_init( items, sizeof items / sizeof(struct menu_items), NULL );
@@ -910,10 +910,10 @@ static bool fileview_settings_menu(void)
910 bool result; 910 bool result;
911 911
912 struct menu_items items[] = { 912 struct menu_items items[] = {
913 { str(LANG_CASE_MENU), sort_case }, 913 { STR(LANG_CASE_MENU), sort_case },
914 { str(LANG_FILTER), dir_filter }, 914 { STR(LANG_FILTER), dir_filter },
915 { str(LANG_FOLLOW), browse_current }, 915 { STR(LANG_FOLLOW), browse_current },
916 { str(LANG_SHOW_ICONS), show_icons }, 916 { STR(LANG_SHOW_ICONS), show_icons },
917 }; 917 };
918 918
919 m=menu_init( items, sizeof(items) / sizeof(*items), NULL ); 919 m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
@@ -929,15 +929,15 @@ static bool scroll_settings_menu(void)
929 bool result; 929 bool result;
930 930
931 struct menu_items items[] = { 931 struct menu_items items[] = {
932 { str(LANG_SCROLL_SPEED), scroll_speed }, 932 { STR(LANG_SCROLL_SPEED), scroll_speed },
933 { str(LANG_SCROLL_DELAY), scroll_delay }, 933 { STR(LANG_SCROLL_DELAY), scroll_delay },
934#ifdef HAVE_LCD_BITMAP 934#ifdef HAVE_LCD_BITMAP
935 { str(LANG_SCROLL_STEP), scroll_step }, 935 { STR(LANG_SCROLL_STEP), scroll_step },
936#endif 936#endif
937 { str(LANG_BIDIR_SCROLL), bidir_limit }, 937 { STR(LANG_BIDIR_SCROLL), bidir_limit },
938#ifdef HAVE_LCD_CHARCELLS 938#ifdef HAVE_LCD_CHARCELLS
939 { str(LANG_JUMP_SCROLL), jump_scroll }, 939 { STR(LANG_JUMP_SCROLL), jump_scroll },
940 { str(LANG_JUMP_SCROLL_DELAY), jump_scroll_delay }, 940 { STR(LANG_JUMP_SCROLL_DELAY), jump_scroll_delay },
941#endif 941#endif
942 }; 942 };
943 943
@@ -953,14 +953,14 @@ static bool lcd_settings_menu(void)
953 bool result; 953 bool result;
954 954
955 struct menu_items items[] = { 955 struct menu_items items[] = {
956 { str(LANG_BACKLIGHT), backlight_timer }, 956 { STR(LANG_BACKLIGHT), backlight_timer },
957 { str(LANG_BACKLIGHT_ON_WHEN_CHARGING), backlight_on_when_charging }, 957 { STR(LANG_BACKLIGHT_ON_WHEN_CHARGING), backlight_on_when_charging },
958 { str(LANG_CAPTION_BACKLIGHT), caption_backlight }, 958 { STR(LANG_CAPTION_BACKLIGHT), caption_backlight },
959 { str(LANG_CONTRAST), contrast }, 959 { STR(LANG_CONTRAST), contrast },
960#ifdef HAVE_LCD_BITMAP 960#ifdef HAVE_LCD_BITMAP
961 { str(LANG_INVERT), invert }, 961 { STR(LANG_INVERT), invert },
962 { str(LANG_FLIP_DISPLAY), flip_display }, 962 { STR(LANG_FLIP_DISPLAY), flip_display },
963 { str(LANG_INVERT_CURSOR), invert_cursor }, 963 { STR(LANG_INVERT_CURSOR), invert_cursor },
964#endif 964#endif
965 }; 965 };
966 966
@@ -977,10 +977,10 @@ static bool bars_settings_menu(void)
977 bool result; 977 bool result;
978 978
979 struct menu_items items[] = { 979 struct menu_items items[] = {
980 { str(LANG_SCROLL_BAR), scroll_bar }, 980 { STR(LANG_SCROLL_BAR), scroll_bar },
981 { str(LANG_STATUS_BAR), status_bar }, 981 { STR(LANG_STATUS_BAR), status_bar },
982 { str(LANG_VOLUME_DISPLAY), volume_type }, 982 { STR(LANG_VOLUME_DISPLAY), volume_type },
983 { str(LANG_BATTERY_DISPLAY), battery_type }, 983 { STR(LANG_BATTERY_DISPLAY), battery_type },
984 }; 984 };
985 985
986 m=menu_init( items, sizeof(items) / sizeof(*items), NULL ); 986 m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
@@ -998,14 +998,14 @@ static bool display_settings_menu(void)
998 998
999 struct menu_items items[] = { 999 struct menu_items items[] = {
1000#ifdef HAVE_LCD_BITMAP 1000#ifdef HAVE_LCD_BITMAP
1001 { str(LANG_CUSTOM_FONT), font_browse }, 1001 { STR(LANG_CUSTOM_FONT), font_browse },
1002#endif 1002#endif
1003 { str(LANG_WHILE_PLAYING), custom_wps_browse }, 1003 { STR(LANG_WHILE_PLAYING), custom_wps_browse },
1004 { str(LANG_LCD_MENU), lcd_settings_menu }, 1004 { STR(LANG_LCD_MENU), lcd_settings_menu },
1005 { str(LANG_SCROLL_MENU), scroll_settings_menu }, 1005 { STR(LANG_SCROLL_MENU), scroll_settings_menu },
1006#ifdef HAVE_LCD_BITMAP 1006#ifdef HAVE_LCD_BITMAP
1007 { str(LANG_BARS_MENU), bars_settings_menu }, 1007 { STR(LANG_BARS_MENU), bars_settings_menu },
1008 { str(LANG_PM_MENU), peak_meter_menu }, 1008 { STR(LANG_PM_MENU), peak_meter_menu },
1009#endif 1009#endif
1010 }; 1010 };
1011 1011
@@ -1028,11 +1028,11 @@ static bool battery_settings_menu(void)
1028 1028
1029 struct menu_items items[] = { 1029 struct menu_items items[] = {
1030#ifdef HAVE_CHARGE_CTRL 1030#ifdef HAVE_CHARGE_CTRL
1031 { str(LANG_DISCHARGE), deep_discharge }, 1031 { STR(LANG_DISCHARGE), deep_discharge },
1032 { str(LANG_TRICKLE_CHARGE), trickle_charge }, 1032 { STR(LANG_TRICKLE_CHARGE), trickle_charge },
1033#endif 1033#endif
1034#ifndef SIMULATOR 1034#ifndef SIMULATOR
1035 { str(LANG_BATTERY_CAPACITY), battery_capacity }, 1035 { STR(LANG_BATTERY_CAPACITY), battery_capacity },
1036#endif 1036#endif
1037 }; 1037 };
1038 1038
@@ -1048,9 +1048,9 @@ static bool disk_settings_menu(void)
1048 bool result; 1048 bool result;
1049 1049
1050 struct menu_items items[] = { 1050 struct menu_items items[] = {
1051 { str(LANG_SPINDOWN), spindown }, 1051 { STR(LANG_SPINDOWN), spindown },
1052#ifdef HAVE_ATA_POWER_OFF 1052#ifdef HAVE_ATA_POWER_OFF
1053 { str(LANG_POWEROFF), poweroff }, 1053 { STR(LANG_POWEROFF), poweroff },
1054#endif 1054#endif
1055 }; 1055 };
1056 1056
@@ -1067,8 +1067,8 @@ static bool time_settings_menu(void)
1067 bool result; 1067 bool result;
1068 1068
1069 struct menu_items items[] = { 1069 struct menu_items items[] = {
1070 { str(LANG_TIME), timedate_set }, 1070 { STR(LANG_TIME), timedate_set },
1071 { str(LANG_TIMEFORMAT), timeformat_set }, 1071 { STR(LANG_TIMEFORMAT), timeformat_set },
1072 }; 1072 };
1073 1073
1074 m=menu_init( items, sizeof(items) / sizeof(*items), NULL ); 1074 m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
@@ -1084,10 +1084,10 @@ static bool manage_settings_menu(void)
1084 bool result; 1084 bool result;
1085 1085
1086 struct menu_items items[] = { 1086 struct menu_items items[] = {
1087 { str(LANG_CUSTOM_CFG), custom_cfg_browse }, 1087 { STR(LANG_CUSTOM_CFG), custom_cfg_browse },
1088 { str(LANG_FIRMWARE), firmware_browse }, 1088 { STR(LANG_FIRMWARE), firmware_browse },
1089 { str(LANG_RESET), reset_settings }, 1089 { STR(LANG_RESET), reset_settings },
1090 { str(LANG_SAVE_SETTINGS), settings_save_config }, 1090 { STR(LANG_SAVE_SETTINGS), settings_save_config },
1091 }; 1091 };
1092 1092
1093 m=menu_init( items, sizeof(items) / sizeof(*items), NULL ); 1093 m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
@@ -1102,8 +1102,8 @@ static bool limits_settings_menu(void)
1102 bool result; 1102 bool result;
1103 1103
1104 struct menu_items items[] = { 1104 struct menu_items items[] = {
1105 { str(LANG_MAX_FILES_IN_DIR), max_files_in_dir }, 1105 { STR(LANG_MAX_FILES_IN_DIR), max_files_in_dir },
1106 { str(LANG_MAX_FILES_IN_PLAYLIST), max_files_in_playlist }, 1106 { STR(LANG_MAX_FILES_IN_PLAYLIST), max_files_in_playlist },
1107 }; 1107 };
1108 1108
1109 m=menu_init( items, sizeof(items) / sizeof(*items), NULL ); 1109 m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
@@ -1119,22 +1119,22 @@ static bool system_settings_menu(void)
1119 bool result; 1119 bool result;
1120 1120
1121 struct menu_items items[] = { 1121 struct menu_items items[] = {
1122 { str(LANG_BATTERY_MENU), battery_settings_menu }, 1122 { STR(LANG_BATTERY_MENU), battery_settings_menu },
1123 { str(LANG_DISK_MENU), disk_settings_menu }, 1123 { STR(LANG_DISK_MENU), disk_settings_menu },
1124#ifdef HAVE_RTC 1124#ifdef HAVE_RTC
1125 { str(LANG_TIME_MENU), time_settings_menu }, 1125 { STR(LANG_TIME_MENU), time_settings_menu },
1126#endif 1126#endif
1127 { str(LANG_POWEROFF_IDLE), poweroff_idle_timer }, 1127 { STR(LANG_POWEROFF_IDLE), poweroff_idle_timer },
1128 { str(LANG_SLEEP_TIMER), sleeptimer_screen }, 1128 { STR(LANG_SLEEP_TIMER), sleeptimer_screen },
1129#ifdef HAVE_ALARM_MOD 1129#ifdef HAVE_ALARM_MOD
1130 { str(LANG_ALARM_MOD_ALARM_MENU), alarm_screen }, 1130 { STR(LANG_ALARM_MOD_ALARM_MENU), alarm_screen },
1131#endif 1131#endif
1132 { str(LANG_LIMITS_MENU), limits_settings_menu }, 1132 { STR(LANG_LIMITS_MENU), limits_settings_menu },
1133#ifdef HAVE_MAS3507D 1133#ifdef HAVE_MAS3507D
1134 { str(LANG_LINE_IN), line_in }, 1134 { STR(LANG_LINE_IN), line_in },
1135#endif 1135#endif
1136 { str(LANG_CAR_ADAPTER_MODE), car_adapter_mode }, 1136 { STR(LANG_CAR_ADAPTER_MODE), car_adapter_mode },
1137 { str(LANG_MANAGE_MENU), manage_settings_menu }, 1137 { STR(LANG_MANAGE_MENU), manage_settings_menu },
1138 }; 1138 };
1139 1139
1140 m=menu_init( items, sizeof(items) / sizeof(*items), NULL ); 1140 m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
@@ -1149,12 +1149,12 @@ bool settings_menu(void)
1149 bool result; 1149 bool result;
1150 1150
1151 struct menu_items items[] = { 1151 struct menu_items items[] = {
1152 { str(LANG_PLAYBACK), playback_settings_menu }, 1152 { STR(LANG_PLAYBACK), playback_settings_menu },
1153 { str(LANG_FILE), fileview_settings_menu }, 1153 { STR(LANG_FILE), fileview_settings_menu },
1154 { str(LANG_DISPLAY), display_settings_menu }, 1154 { STR(LANG_DISPLAY), display_settings_menu },
1155 { str(LANG_SYSTEM), system_settings_menu }, 1155 { STR(LANG_SYSTEM), system_settings_menu },
1156 { str(LANG_BOOKMARK_SETTINGS),bookmark_settings_menu }, 1156 { STR(LANG_BOOKMARK_SETTINGS),bookmark_settings_menu },
1157 { str(LANG_LANGUAGE), language_browse }, 1157 { STR(LANG_LANGUAGE), language_browse },
1158 }; 1158 };
1159 1159
1160 m=menu_init( items, sizeof(items) / sizeof(*items), NULL ); 1160 m=menu_init( items, sizeof(items) / sizeof(*items), NULL );
diff --git a/apps/sound_menu.c b/apps/sound_menu.c
index 256da0b81a..e0415cd293 100644
--- a/apps/sound_menu.c
+++ b/apps/sound_menu.c
@@ -295,15 +295,15 @@ bool sound_menu(void)
295 int m; 295 int m;
296 bool result; 296 bool result;
297 struct menu_items items[] = { 297 struct menu_items items[] = {
298 { str(LANG_VOLUME), volume }, 298 { STR(LANG_VOLUME), volume },
299 { str(LANG_BASS), bass }, 299 { STR(LANG_BASS), bass },
300 { str(LANG_TREBLE), treble }, 300 { STR(LANG_TREBLE), treble },
301 { str(LANG_BALANCE), balance }, 301 { STR(LANG_BALANCE), balance },
302 { str(LANG_CHANNEL_MENU), chanconf }, 302 { STR(LANG_CHANNEL_MENU), chanconf },
303#ifdef HAVE_MAS3587F 303#ifdef HAVE_MAS3587F
304 { str(LANG_LOUDNESS), loudness }, 304 { STR(LANG_LOUDNESS), loudness },
305 { str(LANG_BBOOST), bass_boost }, 305 { STR(LANG_BBOOST), bass_boost },
306 { str(LANG_AUTOVOL), avc } 306 { STR(LANG_AUTOVOL), avc }
307#endif 307#endif
308 }; 308 };
309 309
@@ -323,22 +323,30 @@ bool recording_menu(bool no_source)
323 bool result; 323 bool result;
324 324
325 menu[i].desc = str(LANG_RECORDING_QUALITY); 325 menu[i].desc = str(LANG_RECORDING_QUALITY);
326 menu[i].voice_id = LANG_RECORDING_QUALITY;
326 menu[i++].function = recquality; 327 menu[i++].function = recquality;
327 menu[i].desc = str(LANG_RECORDING_FREQUENCY); 328 menu[i].desc = str(LANG_RECORDING_FREQUENCY);
329 menu[i].voice_id = LANG_RECORDING_FREQUENCY;
328 menu[i++].function = recfrequency; 330 menu[i++].function = recfrequency;
329 if(!no_source) { 331 if(!no_source) {
330 menu[i].desc = str(LANG_RECORDING_SOURCE); 332 menu[i].desc = str(LANG_RECORDING_SOURCE);
333 menu[i].voice_id = LANG_RECORDING_SOURCE;
331 menu[i++].function = recsource; 334 menu[i++].function = recsource;
332 } 335 }
333 menu[i].desc = str(LANG_RECORDING_CHANNELS); 336 menu[i].desc = str(LANG_RECORDING_CHANNELS);
337 menu[i].voice_id = LANG_RECORDING_CHANNELS;
334 menu[i++].function = recchannels; 338 menu[i++].function = recchannels;
335 menu[i].desc = str(LANG_RECORDING_EDITABLE); 339 menu[i].desc = str(LANG_RECORDING_EDITABLE);
340 menu[i].voice_id = LANG_RECORDING_EDITABLE;
336 menu[i++].function = receditable; 341 menu[i++].function = receditable;
337 menu[i].desc = str(LANG_RECORD_TIMESPLIT); 342 menu[i].desc = str(LANG_RECORD_TIMESPLIT);
343 menu[i].voice_id = LANG_RECORD_TIMESPLIT;
338 menu[i++].function = rectimesplit; 344 menu[i++].function = rectimesplit;
339 menu[i].desc = str(LANG_RECORD_PRERECORD_TIME); 345 menu[i].desc = str(LANG_RECORD_PRERECORD_TIME);
346 menu[i].voice_id = LANG_RECORD_PRERECORD_TIME;
340 menu[i++].function = recprerecord; 347 menu[i++].function = recprerecord;
341 menu[i].desc = str(LANG_RECORD_DIRECTORY); 348 menu[i].desc = str(LANG_RECORD_DIRECTORY);
349 menu[i].voice_id = LANG_RECORD_DIRECTORY;
342 menu[i++].function = recdirectory; 350 menu[i++].function = recdirectory;
343 351
344 m=menu_init( menu, i, NULL ); 352 m=menu_init( menu, i, NULL );
diff --git a/firmware/export/talk.h b/firmware/export/talk.h
new file mode 100644
index 0000000000..b2af46f15e
--- /dev/null
+++ b/firmware/export/talk.h
@@ -0,0 +1,34 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2004 Jörg Hohensohn
11 *
12 * This module collects the Talkbox and voice UI functions.
13 * (Talkbox reads directory names from mp3 clips called thumbnails,
14 * the voice UI lets menus and screens "talk" from a voicefont in memory.
15 *
16 * All files in this archive are subject to the GNU General Public License.
17 * See the file COPYING in the source tree root for full license agreement.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24#ifndef __TALK_H__
25#define __TALK_H__
26
27#include <stdbool.h>
28
29void talk_init(void);
30int talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */
31int talk_id(int id, bool block); /* play a voice ID from voicefont */
32int talk_file(char* filename, bool block); /* play a thumbnail from file */
33
34#endif /* __TALK_H__ */
diff --git a/firmware/mpeg.c b/firmware/mpeg.c
index ff545f03d0..0f676f1612 100644
--- a/firmware/mpeg.c
+++ b/firmware/mpeg.c
@@ -2134,6 +2134,7 @@ void mpeg_record(char *filename)
2134 recording_filename[MAX_PATH - 1] = 0; 2134 recording_filename[MAX_PATH - 1] = 0;
2135 2135
2136 disable_xing_header = false; 2136 disable_xing_header = false;
2137 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
2137 queue_post(&mpeg_queue, MPEG_RECORD, NULL); 2138 queue_post(&mpeg_queue, MPEG_RECORD, NULL);
2138} 2139}
2139 2140
@@ -2148,6 +2149,7 @@ static void start_prerecording(void)
2148 prerecord_timeout = current_tick + HZ; 2149 prerecord_timeout = current_tick + HZ;
2149 memset(prerecord_buffer, 0, sizeof(prerecord_buffer)); 2150 memset(prerecord_buffer, 0, sizeof(prerecord_buffer));
2150 reset_mp3_buffer(); 2151 reset_mp3_buffer();
2152 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
2151 2153
2152 is_prerecording = true; 2154 is_prerecording = true;
2153 2155
@@ -2404,6 +2406,7 @@ void mpeg_play(int offset)
2404#else 2406#else
2405 is_playing = true; 2407 is_playing = true;
2406 2408
2409 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
2407 queue_post(&mpeg_queue, MPEG_PLAY, (void*)offset); 2410 queue_post(&mpeg_queue, MPEG_PLAY, (void*)offset);
2408#endif /* #ifdef SIMULATOR */ 2411#endif /* #ifdef SIMULATOR */
2409 2412
diff --git a/firmware/talk.c b/firmware/talk.c
new file mode 100644
index 0000000000..d02a4efd7f
--- /dev/null
+++ b/firmware/talk.c
@@ -0,0 +1,209 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2004 Jörg Hohensohn
11 *
12 * This module collects the Talkbox and voice UI functions.
13 * (Talkbox reads directory names from mp3 clips called thumbnails,
14 * the voice UI lets menus and screens "talk" from a voicefont in memory.
15 *
16 * All files in this archive are subject to the GNU General Public License.
17 * See the file COPYING in the source tree root for full license agreement.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24#include <stdio.h>
25#include <stddef.h>
26#include "file.h"
27#include "buffer.h"
28#include "kernel.h"
29#include "mp3_playback.h"
30#include "mpeg.h"
31#include "talk.h"
32extern void bitswap(unsigned char *data, int length); /* no header for this */
33
34/***************** Constants *****************/
35
36#define VOICEFONT_FILENAME "/.rockbox/voicefont"
37
38
39/***************** Data types *****************/
40
41struct clip_entry /* one entry of the index table */
42{
43 int offset; /* offset from start of voicefont file */
44 int size; /* size of the clip */
45};
46
47struct voicefont /* file format of our "voicefont" */
48{
49 int version; /* version of the voicefont */
50 int headersize; /* size of the header, =offset to index */
51 int id_max; /* number of clips contained */
52 struct clip_entry index[]; /* followed by the index table */
53 /* and finally the bitswapped mp3 clips, not visible here */
54};
55
56
57/***************** Globals *****************/
58
59static unsigned char* p_thumbnail; /* buffer for thumbnail */
60static long size_for_thumbnail; /* leftover buffer size for it */
61static struct voicefont* p_voicefont; /* loaded voicefont */
62static bool has_voicefont; /* a voicefont file is present */
63static bool is_playing; /* we're currently playing */
64
65
66
67/***************** Private implementation *****************/
68
69static int load_voicefont(void)
70{
71 int fd;
72 int size;
73
74 p_voicefont = NULL; /* indicate no voicefont if we fail below */
75
76 fd = open(VOICEFONT_FILENAME, O_RDONLY);
77 if (fd < 0) /* failed to open */
78 {
79 p_voicefont = NULL; /* indicate no voicefont */
80 has_voicefont = false; /* don't try again */
81 return 0;
82 }
83
84 size = read(fd, mp3buf, mp3end - mp3buf);
85 if (size > 1000
86 && ((struct voicefont*)mp3buf)->headersize
87 == offsetof(struct voicefont, index))
88 {
89 p_voicefont = (struct voicefont*)mp3buf;
90
91 /* thumbnail buffer is the remaining space behind */
92 p_thumbnail = mp3buf + size;
93 p_thumbnail += (int)p_thumbnail % 2; /* 16-bit align */
94 size_for_thumbnail = mp3end - p_thumbnail;
95
96 /* max. DMA size, fixme */
97 if (size_for_thumbnail > 0xFFFF)
98 size_for_thumbnail = 0xFFFF;
99 }
100 else
101 {
102 has_voicefont = false; /* don't try again */
103 }
104 close(fd);
105
106 return size;
107}
108
109
110/* called in ISR context if mp3 data got consumed */
111void mp3_callback(unsigned char** start, int* size)
112{
113 (void)start; /* unused parameter, avoid warning */
114 *size = 0; /* end of data */
115 is_playing = false;
116 mp3_play_stop(); /* fixme: should be done by caller */
117}
118
119/***************** Public implementation *****************/
120
121void talk_init(void)
122{
123 has_voicefont = true; /* unless we fail later, assume we have one */
124 talk_buffer_steal();
125}
126
127
128/* somebody else claims the mp3 buffer, e.g. for regular play/record */
129int talk_buffer_steal(void)
130{
131 p_voicefont = NULL; /* indicate no voicefont (trashed) */
132 p_thumbnail = mp3buf; /* whole space for thumbnail */
133 size_for_thumbnail = mp3end - mp3buf;
134 /* max. DMA size, fixme */
135 if (size_for_thumbnail > 0xFFFF)
136 size_for_thumbnail = 0xFFFF;
137 return 0;
138}
139
140
141/* play a voice ID from voicefont */
142int talk_id(int id, bool block)
143{
144 int clipsize;
145
146 if (mpeg_status()) /* busy, buffer in use */
147 return -1;
148
149 if (p_voicefont == NULL && has_voicefont)
150 load_voicefont(); /* reload needed */
151
152 if (p_voicefont == NULL) /* still no voices? */
153 return -1;
154
155 if (id >= p_voicefont->id_max)
156 return -1;
157
158 clipsize = p_voicefont->index[id].size;
159 if (clipsize == 0) /* clip not included in voicefont */
160 return -1;
161
162 is_playing = true;
163 mp3_play_data(mp3buf + p_voicefont->index[id].offset,
164 clipsize, mp3_callback);
165 mp3_play_pause(true); /* kickoff audio */
166
167 while(block && is_playing)
168 sleep(1);
169
170 return 0;
171}
172
173
174/* play a thumbnail from file */
175int talk_file(char* filename, bool block)
176{
177 int fd;
178 int size;
179
180 if (mpeg_status()) /* busy, buffer in use */
181 return -1;
182
183 if (p_thumbnail == NULL || size_for_thumbnail <= 0)
184 return -1;
185
186 fd = open(filename, O_RDONLY);
187 if (fd < 0) /* failed to open */
188 {
189 return 0;
190 }
191
192 size = read(fd, p_thumbnail, size_for_thumbnail);
193 close(fd);
194
195 /* ToDo: find audio, skip ID headers and trailers */
196
197 if (size)
198 {
199 bitswap(p_thumbnail, size);
200 is_playing = true;
201 mp3_play_data(p_thumbnail, size, mp3_callback);
202 mp3_play_pause(true); /* kickoff audio */
203
204 while(block && is_playing)
205 sleep(1);
206 }
207
208 return size;
209}
diff --git a/uisimulator/common/stubs.c b/uisimulator/common/stubs.c
index 23a6728db4..4098c0b4c4 100644
--- a/uisimulator/common/stubs.c
+++ b/uisimulator/common/stubs.c
@@ -225,3 +225,22 @@ void button_set_flip(bool yesno)
225{ 225{
226 (void)yesno; 226 (void)yesno;
227} 227}
228
229int talk_buffer_steal(void)
230{
231 return 0;
232}
233
234int talk_id(int id, bool block)
235{
236 (void)id;
237 (void)block;
238 return 0;
239}
240
241int talk_file(char* filename, bool block)
242{
243 (void)filename;
244 (void)block;
245 return 0;
246}