summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/lang/english.lang54
-rw-r--r--apps/menu.c4
-rw-r--r--apps/settings.c40
-rw-r--r--apps/settings.h5
-rw-r--r--apps/settings_menu.c51
-rw-r--r--apps/sleeptimer.c2
-rw-r--r--apps/sound_menu.c3
-rw-r--r--apps/talk.c12
-rw-r--r--apps/talk.h3
-rw-r--r--apps/tree.c74
10 files changed, 239 insertions, 9 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 5af10d4ab8..ad98416b60 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -2373,3 +2373,57 @@ new:
2373 2373
2374#carry on adding normal LANG_ strings below 2374#carry on adding normal LANG_ strings below
2375 2375
2376id: LANG_VOICE
2377desc: root of voice menu
2378eng: "Voice"
2379voice: "Voice"
2380new:
2381
2382id: LANG_VOICE_MENU
2383desc: item of voice menu, enable/disable the voice UI
2384eng: "Voice Menus"
2385voice: "Voice Menus"
2386new:
2387
2388id: LANG_VOICE_DIR
2389desc: item of voice menu, set the "talkbox" mode for directories
2390eng: "Voice Directories"
2391voice: "Voice Directories"
2392new:
2393
2394id: LANG_VOICE_FILE
2395desc: item of voice menu, set the voive mode for files
2396eng: "Voice Filenames"
2397voice: "Voice Filenames"
2398new:
2399
2400id: LANG_VOICE_NUMBER
2401desc: "talkbox" mode for files+directories
2402eng: "Numbers"
2403voice: "Numbers"
2404new:
2405
2406id: LANG_VOICE_DIR_ENTER
2407desc: "talkbox" mode for directories
2408eng: "on enter"
2409voice: "on enter"
2410new:
2411
2412id: LANG_VOICE_DIR_HOVER
2413desc: "talkbox" mode for directories
2414eng: "while hovering"
2415voice: "while hovering"
2416new:
2417
2418id: VOICE_FILE
2419desc: spoken only, prefix for file number
2420eng: ""
2421voice: "file"
2422new:
2423
2424id: VOICE_DIR
2425desc: spoken only, prefix for directory number
2426eng: ""
2427voice: "folder"
2428new:
2429
diff --git a/apps/menu.c b/apps/menu.c
index d1f073645b..eae5ca2021 100644
--- a/apps/menu.c
+++ b/apps/menu.c
@@ -243,7 +243,7 @@ static void put_cursor(int m, int target)
243 if (do_update) 243 if (do_update)
244 { /* "say" the entry under the cursor */ 244 { /* "say" the entry under the cursor */
245 int voice_id = menus[m].items[menus[m].cursor].voice_id; 245 int voice_id = menus[m].items[menus[m].cursor].voice_id;
246 if (voice_id >= 0) /* valid ID given? */ 246 if (voice_id >= 0 && global_settings.talk_menu) /* valid ID given? */
247 talk_id(voice_id, false); /* say it */ 247 talk_id(voice_id, false); /* say it */
248 } 248 }
249 249
@@ -320,7 +320,7 @@ int menu_show(int m)
320 320
321 /* say current entry */ 321 /* say current entry */
322 voice_id = menus[m].items[menus[m].cursor].voice_id; 322 voice_id = menus[m].items[menus[m].cursor].voice_id;
323 if (voice_id >= 0) /* valid ID given? */ 323 if (voice_id >= 0 && global_settings.talk_menu) /* valid ID given? */
324 talk_id(voice_id, false); /* say it */ 324 talk_id(voice_id, false); /* say it */
325 325
326 while (!exit) { 326 while (!exit) {
diff --git a/apps/settings.c b/apps/settings.c
index 2bc7f45f0b..a9691f3a6a 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -456,6 +456,9 @@ int settings_save( void )
456 456
457 config_block[0xf4]=((unsigned char)global_settings.rec_prerecord_time | 457 config_block[0xf4]=((unsigned char)global_settings.rec_prerecord_time |
458 ((unsigned char)global_settings.rec_directory << 5)); 458 ((unsigned char)global_settings.rec_directory << 5));
459 config_block[0xf5] = (global_settings.talk_dir & 7) |
460 ((global_settings.talk_file & 3) << 3) |
461 ((global_settings.talk_menu & 1) << 5);
459 462
460 if(save_config_buffer()) 463 if(save_config_buffer())
461 { 464 {
@@ -793,6 +796,11 @@ void settings_load(void)
793 global_settings.rec_prerecord_time = config_block[0xf4] & 0x1f; 796 global_settings.rec_prerecord_time = config_block[0xf4] & 0x1f;
794 global_settings.rec_directory = (config_block[0xf4] >> 5) & 3; 797 global_settings.rec_directory = (config_block[0xf4] >> 5) & 3;
795 } 798 }
799 if (config_block[0xf5] != 0xff) {
800 global_settings.talk_dir = config_block[0xf5] & 7;
801 global_settings.talk_file = (config_block[0xf5] >> 3) & 3;
802 global_settings.talk_menu = (config_block[0xf5] >> 5) & 1;
803 }
796 804
797#ifdef HAVE_LCD_CHARCELLS 805#ifdef HAVE_LCD_CHARCELLS
798 if (config_block[0xa8] != 0xff) 806 if (config_block[0xa8] != 0xff)
@@ -1193,6 +1201,20 @@ bool settings_load_config(char* file)
1193 set_cfg_option(&global_settings.playlist_viewer_track_display, 1201 set_cfg_option(&global_settings.playlist_viewer_track_display,
1194 value, options, 2); 1202 value, options, 2);
1195 } 1203 }
1204 else if (!strcasecmp(name, "talk dir"))
1205 {
1206 static char* options[] = {"off", "number", "enter", "hover"};
1207 set_cfg_option(&global_settings.talk_dir, value, options, 4);
1208 }
1209 else if (!strcasecmp(name, "talk file"))
1210 {
1211 static char* options[] = {"off", "number"};
1212 set_cfg_option(&global_settings.talk_dir, value, options, 2);
1213 }
1214 else if (!strcasecmp(name, "talk menu"))
1215 {
1216 set_cfg_bool(&global_settings.talk_menu, value);
1217 }
1196 } 1218 }
1197 1219
1198 close(fd); 1220 close(fd);
@@ -1539,6 +1561,16 @@ bool settings_save_config(void)
1539 options[global_settings.playlist_viewer_track_display]); 1561 options[global_settings.playlist_viewer_track_display]);
1540 } 1562 }
1541 } 1563 }
1564 fprintf(fd, "#\r\n# Voice\r\n#\r\n");
1565 {
1566 static char* options[] = {"off", "number", "enter", "hover"};
1567 fprintf(fd, "talk dir: %s\r\n",
1568 options[global_settings.talk_dir]);
1569 fprintf(fd, "talk file: %s\r\n", /* recycle the options, */
1570 options[global_settings.talk_file]); /* first 2 are alike */
1571 fprintf(fd, "talk menu: %s\r\n",
1572 boolopt[global_settings.talk_menu]);
1573 }
1542 1574
1543 close(fd); 1575 close(fd);
1544 1576
@@ -1646,6 +1678,10 @@ void settings_reset(void) {
1646 global_settings.playlist_viewer_icons = true; 1678 global_settings.playlist_viewer_icons = true;
1647 global_settings.playlist_viewer_indices = true; 1679 global_settings.playlist_viewer_indices = true;
1648 global_settings.playlist_viewer_track_display = 0; 1680 global_settings.playlist_viewer_track_display = 0;
1681 /* talking menu on by default, to help the blind (if voice file present) */
1682 global_settings.talk_menu = 1;
1683 global_settings.talk_dir = 0;
1684 global_settings.talk_file = 0;
1649} 1685}
1650 1686
1651bool set_bool(char* string, bool* variable ) 1687bool set_bool(char* string, bool* variable )
@@ -1713,7 +1749,7 @@ bool set_int(char* string,
1713#endif 1749#endif
1714 lcd_update(); 1750 lcd_update();
1715 1751
1716 if (*variable != last_value) 1752 if (global_settings.talk_menu && *variable != last_value)
1717 { 1753 {
1718 if (voice_unit < UNIT_LAST) 1754 if (voice_unit < UNIT_LAST)
1719 { /* use the available unit definition */ 1755 { /* use the available unit definition */
@@ -1829,7 +1865,7 @@ bool set_option(char* string, void* variable, enum optiontype type,
1829 while ( !done ) { 1865 while ( !done ) {
1830 index = type==INT ? *intvar : (int)*boolvar; 1866 index = type==INT ? *intvar : (int)*boolvar;
1831 lcd_puts(0, 1, options[index].string); 1867 lcd_puts(0, 1, options[index].string);
1832 if (index != oldindex) 1868 if (global_settings.talk_menu && index != oldindex)
1833 { 1869 {
1834 talk_id(options[index].voice_id, false); 1870 talk_id(options[index].voice_id, false);
1835 oldindex = index; 1871 oldindex = index;
diff --git a/apps/settings.h b/apps/settings.h
index 350d14a346..0bf67b474b 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -202,6 +202,11 @@ struct user_settings
202 bool playlist_viewer_icons; /* display icons on viewer */ 202 bool playlist_viewer_icons; /* display icons on viewer */
203 bool playlist_viewer_indices; /* display playlist indices on viewer */ 203 bool playlist_viewer_indices; /* display playlist indices on viewer */
204 int playlist_viewer_track_display; /* how to display tracks in viewer */ 204 int playlist_viewer_track_display; /* how to display tracks in viewer */
205
206 /* voice UI settings */
207 bool talk_menu; /* enable voice UI */
208 int talk_dir; /* talkbox mode: 0=off 1=number 2=clip@enter 3=clip@hover */
209 int talk_file; /* voice filename mode: 0=off, 1=number, other t.b.d. */
205}; 210};
206 211
207enum optiontype { INT, BOOL }; 212enum optiontype { INT, BOOL };
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index 35602f001b..a0f039b9a0 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -876,6 +876,56 @@ static bool language_browse(void)
876 return rockbox_browse(ROCKBOX_DIR LANG_DIR, SHOW_LNG); 876 return rockbox_browse(ROCKBOX_DIR LANG_DIR, SHOW_LNG);
877} 877}
878 878
879static bool voice_menus(void)
880{
881 bool ret;
882 bool temp = global_settings.talk_menu;
883 /* work on a temp variable first, avoid "life" disabling */
884 ret = set_bool( str(LANG_VOICE_MENU), &temp );
885 global_settings.talk_menu = temp;
886 return ret;
887}
888
889static bool voice_dirs(void)
890{
891 struct opt_items names[] = {
892 { STR(LANG_OFF) },
893 { STR(LANG_VOICE_NUMBER) },
894 { STR(LANG_VOICE_DIR_ENTER) },
895 { STR(LANG_VOICE_DIR_HOVER) }
896 };
897 return set_option( str(LANG_VOICE_DIR),
898 &global_settings.talk_dir, INT, names, 4, NULL);
899}
900
901static bool voice_files(void)
902{
903 struct opt_items names[] = {
904 { STR(LANG_OFF) },
905 { STR(LANG_VOICE_NUMBER) }
906 };
907 return set_option( str(LANG_VOICE_DIR),
908 &global_settings.talk_file, INT, names, 2, NULL);
909}
910
911static bool voice_menu(void)
912{
913 int m;
914 bool result;
915
916 struct menu_item items[] = {
917 { STR(LANG_VOICE_MENU), voice_menus },
918 { STR(LANG_VOICE_DIR), voice_dirs },
919 { STR(LANG_VOICE_FILE), voice_files }
920 };
921
922 m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
923 NULL, NULL, NULL);
924 result = menu_run(m);
925 menu_exit(m);
926 return result;
927}
928
879#ifdef HAVE_LCD_BITMAP 929#ifdef HAVE_LCD_BITMAP
880static bool font_browse(void) 930static bool font_browse(void)
881{ 931{
@@ -1283,6 +1333,7 @@ bool settings_menu(void)
1283 { STR(LANG_SYSTEM), system_settings_menu }, 1333 { STR(LANG_SYSTEM), system_settings_menu },
1284 { STR(LANG_BOOKMARK_SETTINGS),bookmark_settings_menu }, 1334 { STR(LANG_BOOKMARK_SETTINGS),bookmark_settings_menu },
1285 { STR(LANG_LANGUAGE), language_browse }, 1335 { STR(LANG_LANGUAGE), language_browse },
1336 { STR(LANG_VOICE), voice_menu },
1286 }; 1337 };
1287 1338
1288 m=menu_init( items, sizeof(items) / sizeof(*items), NULL, 1339 m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
diff --git a/apps/sleeptimer.c b/apps/sleeptimer.c
index 1a6e3ec844..a236ed9ba7 100644
--- a/apps/sleeptimer.c
+++ b/apps/sleeptimer.c
@@ -144,7 +144,7 @@ bool sleeptimer_screen(void)
144 hours, minutes); 144 hours, minutes);
145 lcd_puts(0, 1, buf); 145 lcd_puts(0, 1, buf);
146 146
147 if (sayit) 147 if (sayit && global_settings.talk_menu)
148 { 148 {
149 bool enqueue = false; /* first one should not ne queued */ 149 bool enqueue = false; /* first one should not ne queued */
150 150
diff --git a/apps/sound_menu.c b/apps/sound_menu.c
index 67e6999e8d..23d4c811a5 100644
--- a/apps/sound_menu.c
+++ b/apps/sound_menu.c
@@ -87,7 +87,8 @@ bool set_sound(char* string,
87 { 87 {
88 snprintf(str,sizeof str,"%d %s ", val, unit); 88 snprintf(str,sizeof str,"%d %s ", val, unit);
89 } 89 }
90 talk_value(val, talkunit, false); /* speak it */ 90 if (global_settings.talk_menu)
91 talk_value(val, talkunit, false); /* speak it */
91 } 92 }
92 lcd_puts(0,1,str); 93 lcd_puts(0,1,str);
93 status_draw(true); 94 status_draw(true);
diff --git a/apps/talk.c b/apps/talk.c
index 3849f0e847..6dd0076f06 100644
--- a/apps/talk.c
+++ b/apps/talk.c
@@ -30,14 +30,14 @@
30#include "mpeg.h" 30#include "mpeg.h"
31#include "lang.h" 31#include "lang.h"
32#include "talk.h" 32#include "talk.h"
33#include "screens.h" /* test hack */ 33#include "id3.h"
34#include "kernel.h"
35extern void bitswap(unsigned char *data, int length); /* no header for this */ 34extern void bitswap(unsigned char *data, int length); /* no header for this */
36 35
37/***************** Constants *****************/ 36/***************** Constants *****************/
38 37
39#define QUEUE_SIZE 20 38#define QUEUE_SIZE 20
40const char* voicefont_file = "/.rockbox/langs/english.voice"; 39const char* voicefont_file = "/.rockbox/langs/english.voice";
40const char* dir_thumbnail_name = ".dirname.mp3";
41 41
42 42
43/***************** Data types *****************/ 43/***************** Data types *****************/
@@ -317,6 +317,7 @@ int talk_file(char* filename, bool enqueue)
317{ 317{
318 int fd; 318 int fd;
319 int size; 319 int size;
320 struct mp3entry info;
320 321
321 if (mpeg_status()) /* busy, buffer in use */ 322 if (mpeg_status()) /* busy, buffer in use */
322 return -1; 323 return -1;
@@ -324,12 +325,19 @@ int talk_file(char* filename, bool enqueue)
324 if (p_thumbnail == NULL || size_for_thumbnail <= 0) 325 if (p_thumbnail == NULL || size_for_thumbnail <= 0)
325 return -1; 326 return -1;
326 327
328 if(mp3info(&info, filename)) /* use this to find real start */
329 {
330 return 0; /* failed to open, or invalid */
331 }
332
327 fd = open(filename, O_RDONLY); 333 fd = open(filename, O_RDONLY);
328 if (fd < 0) /* failed to open */ 334 if (fd < 0) /* failed to open */
329 { 335 {
330 return 0; 336 return 0;
331 } 337 }
332 338
339 lseek(fd, info.first_frame_offset, SEEK_SET); /* behind ID data */
340
333 size = read(fd, p_thumbnail, size_for_thumbnail); 341 size = read(fd, p_thumbnail, size_for_thumbnail);
334 close(fd); 342 close(fd);
335 343
diff --git a/apps/talk.h b/apps/talk.h
index 518549ed74..f3c1366bb0 100644
--- a/apps/talk.h
+++ b/apps/talk.h
@@ -54,6 +54,9 @@ enum {
54/* convenience macro to have both string and ID as arguments */ 54/* convenience macro to have both string and ID as arguments */
55#define STR(id) str(id), id 55#define STR(id) str(id), id
56 56
57/* publish this string, so it's stored only once (better than #define) */
58extern const char* dir_thumbnail_name;
59
57 60
58void talk_init(void); 61void talk_init(void);
59int talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */ 62int talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */
diff --git a/apps/tree.c b/apps/tree.c
index d56dacc130..9d6a66684e 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -55,6 +55,7 @@
55#include "plugin.h" 55#include "plugin.h"
56#include "power.h" 56#include "power.h"
57#include "action.h" 57#include "action.h"
58#include "talk.h"
58 59
59#ifdef HAVE_LCD_BITMAP 60#ifdef HAVE_LCD_BITMAP
60#include "widgets.h" 61#include "widgets.h"
@@ -112,6 +113,7 @@ static int dircursor;
112static int dirstart; 113static int dirstart;
113static int dirlevel; 114static int dirlevel;
114static int filesindir; 115static int filesindir;
116static int dirsindir; /* how many of the dircache entries are directories */
115static int dirpos[MAX_DIR_LEVELS]; 117static int dirpos[MAX_DIR_LEVELS];
116static int cursorpos[MAX_DIR_LEVELS]; 118static int cursorpos[MAX_DIR_LEVELS];
117static char lastdir[MAX_PATH]; 119static char lastdir[MAX_PATH];
@@ -122,6 +124,7 @@ static bool reload_dir = false;
122static int boot_size = 0; 124static int boot_size = 0;
123static int boot_cluster; 125static int boot_cluster;
124static bool boot_changed = false; 126static bool boot_changed = false;
127static bool enqueue_next = false;
125 128
126static bool start_wps = false; 129static bool start_wps = false;
127static bool dirbrowse(char *root, int *dirfilter); 130static bool dirbrowse(char *root, int *dirfilter);
@@ -199,7 +202,8 @@ static int build_playlist(int start_index)
199 202
200 for(i = 0;i < filesindir;i++) 203 for(i = 0;i < filesindir;i++)
201 { 204 {
202 if((dircache[i].attr & TREE_ATTR_MASK) == TREE_ATTR_MPA) 205 if((dircache[i].attr & TREE_ATTR_MASK) == TREE_ATTR_MPA
206 && (strcmp(dircache[i].name, dir_thumbnail_name) != 0))
203 { 207 {
204 DEBUGF("Adding %s\n", dircache[i].name); 208 DEBUGF("Adding %s\n", dircache[i].name);
205 if (playlist_add(dircache[i].name) < 0) 209 if (playlist_add(dircache[i].name) < 0)
@@ -216,6 +220,36 @@ static int build_playlist(int start_index)
216 return start_index; 220 return start_index;
217} 221}
218 222
223
224static int play_dirname(int start_index, bool enqueue)
225{
226 int fd;
227 char dirname_mp3_filename[MAX_PATH+1];
228
229 if (mpeg_status() & MPEG_STATUS_PLAY)
230 return 0;
231
232 snprintf(dirname_mp3_filename, sizeof(dirname_mp3_filename), "%s/%s/%s",
233 currdir, dircache[start_index].name, dir_thumbnail_name);
234
235 DEBUGF("Checking for %s\n", dirname_mp3_filename);
236
237 fd = open(dirname_mp3_filename, O_RDONLY);
238 if (fd < 0)
239 {
240 DEBUGF("Failed to find: %s\n", dirname_mp3_filename);
241 return -1;
242 }
243
244 close(fd);
245
246 DEBUGF("Found: %s\n", dirname_mp3_filename);
247
248 talk_file(dirname_mp3_filename, enqueue);
249 return 1;
250}
251
252
219static int compare(const void* p1, const void* p2) 253static int compare(const void* p1, const void* p2)
220{ 254{
221 struct entry* e1 = (struct entry*)p1; 255 struct entry* e1 = (struct entry*)p1;
@@ -278,6 +312,7 @@ struct entry* load_and_sort_directory(char *dirname, int *dirfilter,
278 return NULL; /* not a directory */ 312 return NULL; /* not a directory */
279 313
280 name_buffer_length = 0; 314 name_buffer_length = 0;
315 dirsindir = 0;
281 *buffer_full = false; 316 *buffer_full = false;
282 317
283 for ( i=0; i < max_files_in_dir; i++ ) { 318 for ( i=0; i < max_files_in_dir; i++ ) {
@@ -369,6 +404,9 @@ struct entry* load_and_sort_directory(char *dirname, int *dirfilter,
369 dptr->name = &name_buffer[name_buffer_length]; 404 dptr->name = &name_buffer[name_buffer_length];
370 strcpy(dptr->name,entry->d_name); 405 strcpy(dptr->name,entry->d_name);
371 name_buffer_length += len + 1; 406 name_buffer_length += len + 1;
407
408 if (dptr->attr & ATTR_DIRECTORY) /* count the remaining dirs */
409 dirsindir++;
372 } 410 }
373 *num_files = i; 411 *num_files = i;
374 closedir(dir); 412 closedir(dir);
@@ -1019,6 +1057,14 @@ static bool dirbrowse(char *root, int *dirfilter)
1019 snprintf(buf,sizeof(buf),"/%s",file->name); 1057 snprintf(buf,sizeof(buf),"/%s",file->name);
1020 1058
1021 if (file->attr & ATTR_DIRECTORY) { 1059 if (file->attr & ATTR_DIRECTORY) {
1060 if (global_settings.talk_dir == 2) /* enter */
1061 {
1062 /* play_dirname */
1063 DEBUGF("Playing directory thumbnail: %s", currdir);
1064 play_dirname(dircursor+dirstart, false);
1065 /* avoid reading getting cut by next filename */
1066 enqueue_next = true;
1067 }
1022 memcpy(currdir,buf,sizeof(currdir)); 1068 memcpy(currdir,buf,sizeof(currdir));
1023 if ( dirlevel < MAX_DIR_LEVELS ) { 1069 if ( dirlevel < MAX_DIR_LEVELS ) {
1024 dirpos[dirlevel] = dirstart; 1070 dirpos[dirlevel] = dirstart;
@@ -1425,6 +1471,32 @@ static bool dirbrowse(char *root, int *dirfilter)
1425 1471
1426 showfileline(dircursor, i, true, dirfilter); /* scroll please */ 1472 showfileline(dircursor, i, true, dirfilter); /* scroll please */
1427 need_update = true; 1473 need_update = true;
1474
1475 if (dircache[i].attr & ATTR_DIRECTORY) /* directory? */
1476 {
1477 int ret = 0;
1478 /* play directory thumbnail */
1479 if (global_settings.talk_dir == 3) /* hover */
1480 {
1481 DEBUGF("Playing directory thumbnail: %s", currdir);
1482 ret = play_dirname(dircursor+dirstart, false);
1483 }
1484
1485 if (global_settings.talk_dir == 1 /* dirs as numbers */
1486 || ret == -1) /* or no thumbnail found above */
1487 {
1488 talk_id(VOICE_DIR, false);
1489 talk_number(i+1, true);
1490 }
1491 }
1492 else if (global_settings.talk_file == 1) /* files as numbers */
1493 {
1494 /* enqueue_next is true if still talking the dir name */
1495 talk_id(VOICE_FILE, enqueue_next);
1496 talk_number(i-dirsindir+1, true);
1497 enqueue_next = false;
1498 }
1499
1428 } 1500 }
1429 } 1501 }
1430 1502