diff options
-rw-r--r-- | apps/bookmark.c | 6 | ||||
-rw-r--r-- | apps/debug_menu.c | 30 | ||||
-rw-r--r-- | apps/main.c | 2 | ||||
-rw-r--r-- | apps/main_menu.c | 22 | ||||
-rw-r--r-- | apps/menu.c | 17 | ||||
-rw-r--r-- | apps/menu.h | 6 | ||||
-rw-r--r-- | apps/onplay.c | 18 | ||||
-rw-r--r-- | apps/playlist.c | 3 | ||||
-rw-r--r-- | apps/playlist_menu.c | 8 | ||||
-rw-r--r-- | apps/playlist_viewer.c | 11 | ||||
-rw-r--r-- | apps/plugin.c | 2 | ||||
-rw-r--r-- | apps/recorder/radio.c | 10 | ||||
-rw-r--r-- | apps/settings_menu.c | 152 | ||||
-rw-r--r-- | apps/sound_menu.c | 24 | ||||
-rw-r--r-- | firmware/export/talk.h | 34 | ||||
-rw-r--r-- | firmware/mpeg.c | 3 | ||||
-rw-r--r-- | firmware/talk.c | 209 | ||||
-rw-r--r-- | uisimulator/common/stubs.c | 19 |
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) bool result; struct menu_items items[] = { - { str(LANG_BOOKMARK_MENU_CREATE), bookmark_create_menu}, - { str(LANG_BOOKMARK_MENU_LIST), bookmark_load_menu}, - { str(LANG_BOOKMARK_MENU_RECENT_BOOKMARKS), bookmark_mrb_load}, + { STR(LANG_BOOKMARK_MENU_CREATE), bookmark_create_menu}, + { STR(LANG_BOOKMARK_MENU_LIST), bookmark_load_menu}, + { STR(LANG_BOOKMARK_MENU_RECENT_BOOKMARKS), bookmark_mrb_load}, }; 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) bool result; struct menu_items items[] = { - { "Dump ROM contents", dbg_save_roms }, - { "View I/O ports", dbg_ports }, + { "Dump ROM contents", -1, dbg_save_roms }, + { "View I/O ports", -1, dbg_ports }, #ifdef HAVE_LCD_BITMAP #ifdef HAVE_RTC - { "View/clr RTC RAM", dbg_rtc }, + { "View/clr RTC RAM", -1, dbg_rtc }, #endif /* HAVE_RTC */ #endif /* HAVE_LCD_BITMAP */ - { "View OS stacks", dbg_os }, + { "View OS stacks", -1, dbg_os }, #ifdef HAVE_MAS3507D - { "View MAS info", dbg_mas_info }, + { "View MAS info", -1, dbg_mas_info }, #endif - { "View MAS regs", dbg_mas }, + { "View MAS regs", -1, dbg_mas }, #ifdef HAVE_MAS3587F - { "View MAS codec", dbg_mas_codec }, + { "View MAS codec", -1, dbg_mas_codec }, #endif #ifdef HAVE_LCD_BITMAP - { "View battery", view_battery }, + { "View battery", -1, view_battery }, #endif - { "View HW info", dbg_hw_info }, - { "View partitions", dbg_partitions }, - { "View disk info", dbg_disk_info }, + { "View HW info", -1, dbg_hw_info }, + { "View partitions", -1, dbg_partitions }, + { "View disk info", -1, dbg_disk_info }, #ifdef HAVE_LCD_BITMAP - { "View mpeg thread", dbg_mpeg_thread }, + { "View mpeg thread", -1, dbg_mpeg_thread }, #ifdef PM_DEBUG - { "pm histogram", peak_meter_histogram}, + { "pm histogram", -1, peak_meter_histogram}, #endif /* PM_DEBUG */ #endif /* HAVE_LCD_BITMAP */ - { "View runtime", view_runtime }, + { "View runtime", -1, view_runtime }, #ifdef HAVE_FMRADIO - { "FM Radio", dbg_fm_radio }, + { "FM Radio", -1, dbg_fm_radio }, #endif }; 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 @@ #include "rolo.h" #include "screens.h" #include "power.h" +#include "talk.h" char appsversion[]=APPSVERSION; @@ -208,6 +209,7 @@ void init(void) global_settings.avc, global_settings.channel_config ); mpeg_init(); + talk_init(); /* no auto-rolo on startup any more, but I leave it here for reference */ #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) /* recording menu */ struct menu_items items[] = { - { str(LANG_RECORDING_MENU), recording_screen }, - { str(LANG_RECORDING_SETTINGS), recording_settings}, + { STR(LANG_RECORDING_MENU), recording_screen }, + { STR(LANG_RECORDING_SETTINGS), recording_settings}, }; m=menu_init( items, sizeof items / sizeof(struct menu_items), NULL ); @@ -281,13 +281,13 @@ bool info_menu(void) /* info menu */ struct menu_items items[] = { - { str(LANG_MENU_SHOW_ID3_INFO), browse_id3 }, - { str(LANG_INFO_MENU), show_info }, - { str(LANG_VERSION), show_credits }, + { STR(LANG_MENU_SHOW_ID3_INFO), browse_id3 }, + { STR(LANG_INFO_MENU), show_info }, + { STR(LANG_VERSION), show_credits }, #ifndef SIMULATOR - { str(LANG_DEBUG), debug_menu }, + { STR(LANG_DEBUG), debug_menu }, #else - { str(LANG_USB), simulate_usb }, + { STR(LANG_USB), simulate_usb }, #endif }; @@ -308,33 +308,41 @@ bool main_menu(void) struct menu_items items[8]; items[i].desc = str(LANG_BOOKMARK_MENU); + items[i].voice_id = LANG_BOOKMARK_MENU; items[i++].function = bookmark_menu; items[i].desc = str(LANG_SOUND_SETTINGS); + items[i].voice_id = LANG_SOUND_SETTINGS; items[i++].function = sound_menu; items[i].desc = str(LANG_GENERAL_SETTINGS); + items[i].voice_id = LANG_GENERAL_SETTINGS; items[i++].function = settings_menu; #ifdef HAVE_FMRADIO if(radio_hardware_present()) { items[i].desc = str(LANG_FM_RADIO); + items[i].voice_id = LANG_FM_RADIO; items[i++].function = radio_screen; } #endif #ifdef HAVE_MAS3587F items[i].desc = str(LANG_RECORDING); + items[i].voice_id = LANG_RECORDING; items[i++].function = rec_menu; #endif items[i].desc = str(LANG_PLAYLIST_MENU); + items[i].voice_id = LANG_PLAYLIST_MENU; items[i++].function = playlist_menu; items[i].desc = str(LANG_PLUGINS); + items[i].voice_id = LANG_PLUGINS; items[i++].function = plugin_browse; items[i].desc = str(LANG_INFO); + items[i].voice_id = LANG_INFO; items[i++].function = info_menu; 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 @@ #include "settings.h" #include "status.h" #include "screens.h" +#include "talk.h" #ifdef HAVE_LCD_BITMAP #include "icons.h" @@ -216,6 +217,13 @@ static void put_cursor(int m, int target) lcd_update(); } + if (do_update) + { /* "say" the entry under the cursor */ + int voice_id = menus[m].items[menus[m].cursor].voice_id; + if (voice_id >= 0) /* valid ID given? */ + talk_id(voice_id, false); /* say it */ + } + } int menu_init(struct menu_items* mitems, int count, int (*callback)(int, int)) @@ -250,6 +258,7 @@ int menu_show(int m) { bool exit = false; int key; + int voice_id; #ifdef HAVE_LCD_BITMAP int fw, fh; int menu_lines; @@ -263,9 +272,16 @@ int menu_show(int m) menu_draw(m); + /* say current entry */ + voice_id = menus[m].items[menus[m].cursor].voice_id; + if (voice_id >= 0) /* valid ID given? */ + talk_id(voice_id, false); /* say it */ + while (!exit) { key = button_get_w_tmo(HZ/2); + + /* * "short-circuit" the default keypresses by running the callback function */ @@ -274,6 +290,7 @@ int menu_show(int m) key = menus[m].callback(key, m); /* make sure there's no match in the switch */ switch( key ) { + #ifdef HAVE_RECORDER_KEYPAD case BUTTON_UP: 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 @@ #include <stdbool.h> struct menu_items { - unsigned char *desc; + unsigned char *desc; /* string */ + int voice_id; /* the associated voice clip, -1 if none */ bool (*function) (void); /* return true if USB was connected */ }; +/* convenience macro to have both string and ID as arguments */ +#define STR(id) str(id), id + int menu_init(struct menu_items* items, int count, int (*callback) (int keycode, int menu)); void menu_exit(int menu); 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 @@ #include "settings.h" #include "status.h" #include "playlist_viewer.h" +#include "talk.h" #include "onplay.h" static char* selected_file = NULL; @@ -147,6 +148,7 @@ static bool playlist_options(void) if ((selected_file_attr & TREE_ATTR_MASK) == TREE_ATTR_M3U) { menu[i].desc = str(LANG_VIEW); + menu[i].voice_id = LANG_VIEW; menu[i].function = view_playlist; i++; pstart++; @@ -155,31 +157,37 @@ static bool playlist_options(void) if (mpeg_status() & MPEG_STATUS_PLAY) { menu[i].desc = str(LANG_INSERT); + menu[i].voice_id = LANG_INSERT; args[i].position = PLAYLIST_INSERT; args[i].queue = false; i++; menu[i].desc = str(LANG_INSERT_FIRST); + menu[i].voice_id = LANG_INSERT_FIRST; args[i].position = PLAYLIST_INSERT_FIRST; args[i].queue = false; i++; menu[i].desc = str(LANG_INSERT_LAST); + menu[i].voice_id = LANG_INSERT_LAST; args[i].position = PLAYLIST_INSERT_LAST; args[i].queue = false; i++; menu[i].desc = str(LANG_QUEUE); + menu[i].voice_id = LANG_QUEUE; args[i].position = PLAYLIST_INSERT; args[i].queue = true; i++; menu[i].desc = str(LANG_QUEUE_FIRST); + menu[i].voice_id = LANG_QUEUE_FIRST; args[i].position = PLAYLIST_INSERT_FIRST; args[i].queue = true; i++; menu[i].desc = str(LANG_QUEUE_LAST); + menu[i].voice_id = LANG_QUEUE_LAST; args[i].position = PLAYLIST_INSERT_LAST; args[i].queue = true; i++; @@ -188,6 +196,7 @@ static bool playlist_options(void) (selected_file_attr & ATTR_DIRECTORY)) { menu[i].desc = str(LANG_INSERT); + menu[i].voice_id = LANG_INSERT; args[i].position = PLAYLIST_INSERT; args[i].queue = false; i++; @@ -283,6 +292,8 @@ static int insert_data_in_file(char *fname, int fpos, char *buf, int num_bytes) int orig_fd, fd; char tmpname[MAX_PATH]; + talk_buffer_steal(); /* we use the mp3 buffer, need to tell */ + snprintf(tmpname, MAX_PATH, "%s.tmp", fname); orig_fd = open(fname, O_RDONLY); @@ -384,6 +395,8 @@ static bool vbr_fix(void) return onplay_result; } + talk_buffer_steal(); /* we use the mp3 buffer, need to tell */ + lcd_clear_display(); lcd_puts_scroll(0, 0, selected_file); lcd_update(); @@ -552,17 +565,20 @@ int onplay(char* file, int attr) ((attr & TREE_ATTR_MASK) == TREE_ATTR_M3U)) { menu[i].desc = str(LANG_PLAYINDICES_PLAYLIST); + menu[i].voice_id = LANG_PLAYINDICES_PLAYLIST; menu[i].function = playlist_options; i++; } menu[i].desc = str(LANG_RENAME); + menu[i].voice_id = LANG_RENAME; menu[i].function = rename_file; i++; if (!(attr & ATTR_DIRECTORY)) { menu[i].desc = str(LANG_DELETE); + menu[i].voice_id = LANG_DELETE; menu[i].function = delete_file; i++; } @@ -570,12 +586,14 @@ int onplay(char* file, int attr) if ((attr & TREE_ATTR_MASK) == TREE_ATTR_MPA) { menu[i].desc = str(LANG_VBRFIX); + menu[i].voice_id = LANG_VBRFIX; menu[i].function = vbr_fix; i++; } } menu[i].desc = str(LANG_CREATE_DIR); + menu[i].voice_id = LANG_CREATE_DIR; menu[i].function = create_dir; i++; 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 @@ #endif #include "lang.h" +#include "talk.h" #define PLAYLIST_CONTROL_FILE ROCKBOX_DIR "/.playlist_control" #define PLAYLIST_CONTROL_FILE_VERSION 2 @@ -337,6 +338,7 @@ static int add_indices_to_playlist(struct playlist_info* playlist, { /* use mp3 buffer for maximum load speed */ mpeg_stop(); + talk_buffer_steal(); /* we use the mp3 buffer, need to tell */ buffer = mp3buf; buflen = (mp3end - mp3buf); @@ -1192,6 +1194,7 @@ int playlist_resume(void) }; /* use mp3 buffer for maximum load speed */ + talk_buffer_steal(); /* we use the mp3 buffer, need to tell */ buflen = (mp3end - mp3buf); buffer = mp3buf; 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) bool result; struct menu_items items[] = { - { str(LANG_CREATE_PLAYLIST), create_playlist }, - { str(LANG_VIEW_DYNAMIC_PLAYLIST), playlist_viewer }, - { str(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist }, - { str(LANG_RECURSE_DIRECTORY), recurse_directory }, + { STR(LANG_CREATE_PLAYLIST), create_playlist }, + { STR(LANG_VIEW_DYNAMIC_PLAYLIST), playlist_viewer }, + { STR(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist }, + { STR(LANG_RECURSE_DIRECTORY), recurse_directory }, }; 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) bool current = (tracks[index].index == viewer.current_playing_track); menu[i].desc = str(LANG_REMOVE); + menu[i].voice_id = LANG_REMOVE; i++; menu[i].desc = str(LANG_MOVE); + menu[i].voice_id = LANG_MOVE; i++; menu[i].desc = str(LANG_FILE_OPTIONS); + menu[i].voice_id = LANG_FILE_OPTIONS; i++; m = menu_init(menu, i, NULL); @@ -757,10 +760,10 @@ static bool viewer_menu(void) bool result; struct menu_items items[] = { - { str(LANG_SHOW_ICONS), show_icons }, - { str(LANG_SHOW_INDICES), show_indices }, - { str(LANG_TRACK_DISPLAY), track_display }, - { str(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist }, + { STR(LANG_SHOW_ICONS), show_icons }, + { STR(LANG_SHOW_INDICES), show_indices }, + { STR(LANG_TRACK_DISPLAY), track_display }, + { STR(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist }, }; 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 @@ #include "mp3_playback.h" #include "backlight.h" #include "ata.h" +#include "talk.h" #ifdef HAVE_LCD_BITMAP #include "widgets.h" @@ -325,6 +326,7 @@ void* plugin_get_mp3_buffer(int* buffer_size) return buf; #else mpeg_stop(); + talk_buffer_steal(); /* we use the mp3 buffer, need to tell */ *buffer_size = mp3end - mp3buf; return mp3buf; #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) if(presets[i].frequency) { menu[num_presets].desc = presets[i].name; + menu[num_presets].voice_id = -1; /* We use the function pointer entry for the preset entry index */ menu[num_presets++].function = (void *)i; @@ -669,6 +670,7 @@ bool radio_delete_preset(void) if(presets[i].frequency) { menu[num_presets].desc = presets[i].name; + menu[num_presets].voice_id = -1; /* We use the function pointer entry for the preset entry index */ menu[num_presets++].function = (void *)i; @@ -715,10 +717,10 @@ static bool fm_recording_settings(void) bool radio_menu(void) { struct menu_items radio_menu_items[] = { - { str(LANG_FM_SAVE_PRESET), radio_add_preset }, - { str(LANG_FM_DELETE_PRESET), radio_delete_preset }, - { str(LANG_SOUND_SETTINGS), sound_menu }, - { str(LANG_RECORDING_SETTINGS), fm_recording_settings } + { STR(LANG_FM_SAVE_PRESET), radio_add_preset }, + { STR(LANG_FM_DELETE_PRESET), radio_delete_preset }, + { STR(LANG_SOUND_SETTINGS), sound_menu }, + { STR(LANG_RECORDING_SETTINGS), fm_recording_settings } }; int m; 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) bool result; struct menu_items items[] = { - { str(LANG_PM_RELEASE) , peak_meter_release }, - { str(LANG_PM_PEAK_HOLD), peak_meter_hold }, - { str(LANG_PM_CLIP_HOLD), peak_meter_clip_hold }, - { str(LANG_PM_PERFORMANCE), peak_meter_performance }, + { STR(LANG_PM_RELEASE) , peak_meter_release }, + { STR(LANG_PM_PEAK_HOLD), peak_meter_hold }, + { STR(LANG_PM_CLIP_HOLD), peak_meter_clip_hold }, + { STR(LANG_PM_PERFORMANCE), peak_meter_performance }, #ifdef PM_DEBUG - { "Refresh rate" , peak_meter_fps_menu }, + { "Refresh rate" , -1 , peak_meter_fps_menu }, #endif - { str(LANG_PM_SCALE) , peak_meter_scale }, - { str(LANG_PM_MIN) , peak_meter_min }, - { str(LANG_PM_MAX) , peak_meter_max }, + { STR(LANG_PM_SCALE) , peak_meter_scale }, + { STR(LANG_PM_MIN) , peak_meter_min }, + { STR(LANG_PM_MAX) , peak_meter_max }, }; m=menu_init( items, sizeof(items) / sizeof(*items), NULL ); @@ -791,8 +791,8 @@ static bool ff_rewind_settings_menu(void) bool result; struct menu_items items[] = { - { str(LANG_FFRW_STEP), ff_rewind_min_step }, - { str(LANG_FFRW_ACCEL), ff_rewind_accel }, + { STR(LANG_FFRW_STEP), ff_rewind_min_step }, + { STR(LANG_FFRW_ACCEL), ff_rewind_accel }, }; m=menu_init( items, sizeof(items) / sizeof(*items), NULL ); @@ -808,13 +808,13 @@ static bool playback_settings_menu(void) bool result; struct menu_items items[] = { - { str(LANG_SHUFFLE), shuffle }, - { str(LANG_REPEAT), repeat_mode }, - { str(LANG_PLAY_SELECTED), play_selected }, - { str(LANG_RESUME), resume }, - { str(LANG_WIND_MENU), ff_rewind_settings_menu }, - { str(LANG_MP3BUFFER_MARGIN), buffer_margin }, - { str(LANG_FADE_ON_STOP), set_fade_on_stop }, + { STR(LANG_SHUFFLE), shuffle }, + { STR(LANG_REPEAT), repeat_mode }, + { STR(LANG_PLAY_SELECTED), play_selected }, + { STR(LANG_RESUME), resume }, + { STR(LANG_WIND_MENU), ff_rewind_settings_menu }, + { STR(LANG_MP3BUFFER_MARGIN), buffer_margin }, + { STR(LANG_FADE_ON_STOP), set_fade_on_stop }, }; bool old_shuffle = global_settings.playlist_shuffle; @@ -843,9 +843,9 @@ static bool bookmark_settings_menu(void) bool result; struct menu_items items[] = { - { str(LANG_BOOKMARK_SETTINGS_AUTOCREATE), autocreatebookmark}, - { str(LANG_BOOKMARK_SETTINGS_AUTOLOAD), autoloadbookmark}, - { str(LANG_BOOKMARK_SETTINGS_MAINTAIN_RECENT_BOOKMARKS), useMRB}, + { STR(LANG_BOOKMARK_SETTINGS_AUTOCREATE), autocreatebookmark}, + { STR(LANG_BOOKMARK_SETTINGS_AUTOLOAD), autoloadbookmark}, + { STR(LANG_BOOKMARK_SETTINGS_MAINTAIN_RECENT_BOOKMARKS), useMRB}, }; m=menu_init( items, sizeof items / sizeof(struct menu_items), NULL ); @@ -910,10 +910,10 @@ static bool fileview_settings_menu(void) bool result; struct menu_items items[] = { - { str(LANG_CASE_MENU), sort_case }, - { str(LANG_FILTER), dir_filter }, - { str(LANG_FOLLOW), browse_current }, - { str(LANG_SHOW_ICONS), show_icons }, + { STR(LANG_CASE_MENU), sort_case }, + { STR(LANG_FILTER), dir_filter }, + { STR(LANG_FOLLOW), browse_current }, + { STR(LANG_SHOW_ICONS), show_icons }, }; m=menu_init( items, sizeof(items) / sizeof(*items), NULL ); @@ -929,15 +929,15 @@ static bool scroll_settings_menu(void) bool result; struct menu_items items[] = { - { str(LANG_SCROLL_SPEED), scroll_speed }, - { str(LANG_SCROLL_DELAY), scroll_delay }, + { STR(LANG_SCROLL_SPEED), scroll_speed }, + { STR(LANG_SCROLL_DELAY), scroll_delay }, #ifdef HAVE_LCD_BITMAP - { str(LANG_SCROLL_STEP), scroll_step }, + { STR(LANG_SCROLL_STEP), scroll_step }, #endif - { str(LANG_BIDIR_SCROLL), bidir_limit }, + { STR(LANG_BIDIR_SCROLL), bidir_limit }, #ifdef HAVE_LCD_CHARCELLS - { str(LANG_JUMP_SCROLL), jump_scroll }, - { str(LANG_JUMP_SCROLL_DELAY), jump_scroll_delay }, + { STR(LANG_JUMP_SCROLL), jump_scroll }, + { STR(LANG_JUMP_SCROLL_DELAY), jump_scroll_delay }, #endif }; @@ -953,14 +953,14 @@ static bool lcd_settings_menu(void) bool result; struct menu_items items[] = { - { str(LANG_BACKLIGHT), backlight_timer }, - { str(LANG_BACKLIGHT_ON_WHEN_CHARGING), backlight_on_when_charging }, - { str(LANG_CAPTION_BACKLIGHT), caption_backlight }, - { str(LANG_CONTRAST), contrast }, + { STR(LANG_BACKLIGHT), backlight_timer }, + { STR(LANG_BACKLIGHT_ON_WHEN_CHARGING), backlight_on_when_charging }, + { STR(LANG_CAPTION_BACKLIGHT), caption_backlight }, + { STR(LANG_CONTRAST), contrast }, #ifdef HAVE_LCD_BITMAP - { str(LANG_INVERT), invert }, - { str(LANG_FLIP_DISPLAY), flip_display }, - { str(LANG_INVERT_CURSOR), invert_cursor }, + { STR(LANG_INVERT), invert }, + { STR(LANG_FLIP_DISPLAY), flip_display }, + { STR(LANG_INVERT_CURSOR), invert_cursor }, #endif }; @@ -977,10 +977,10 @@ static bool bars_settings_menu(void) bool result; struct menu_items items[] = { - { str(LANG_SCROLL_BAR), scroll_bar }, - { str(LANG_STATUS_BAR), status_bar }, - { str(LANG_VOLUME_DISPLAY), volume_type }, - { str(LANG_BATTERY_DISPLAY), battery_type }, + { STR(LANG_SCROLL_BAR), scroll_bar }, + { STR(LANG_STATUS_BAR), status_bar }, + { STR(LANG_VOLUME_DISPLAY), volume_type }, + { STR(LANG_BATTERY_DISPLAY), battery_type }, }; m=menu_init( items, sizeof(items) / sizeof(*items), NULL ); @@ -998,14 +998,14 @@ static bool display_settings_menu(void) struct menu_items items[] = { #ifdef HAVE_LCD_BITMAP - { str(LANG_CUSTOM_FONT), font_browse }, + { STR(LANG_CUSTOM_FONT), font_browse }, #endif - { str(LANG_WHILE_PLAYING), custom_wps_browse }, - { str(LANG_LCD_MENU), lcd_settings_menu }, - { str(LANG_SCROLL_MENU), scroll_settings_menu }, + { STR(LANG_WHILE_PLAYING), custom_wps_browse }, + { STR(LANG_LCD_MENU), lcd_settings_menu }, + { STR(LANG_SCROLL_MENU), scroll_settings_menu }, #ifdef HAVE_LCD_BITMAP - { str(LANG_BARS_MENU), bars_settings_menu }, - { str(LANG_PM_MENU), peak_meter_menu }, + { STR(LANG_BARS_MENU), bars_settings_menu }, + { STR(LANG_PM_MENU), peak_meter_menu }, #endif }; @@ -1028,11 +1028,11 @@ static bool battery_settings_menu(void) struct menu_items items[] = { #ifdef HAVE_CHARGE_CTRL - { str(LANG_DISCHARGE), deep_discharge }, - { str(LANG_TRICKLE_CHARGE), trickle_charge }, + { STR(LANG_DISCHARGE), deep_discharge }, + { STR(LANG_TRICKLE_CHARGE), trickle_charge }, #endif #ifndef SIMULATOR - { str(LANG_BATTERY_CAPACITY), battery_capacity }, + { STR(LANG_BATTERY_CAPACITY), battery_capacity }, #endif }; @@ -1048,9 +1048,9 @@ static bool disk_settings_menu(void) bool result; struct menu_items items[] = { - { str(LANG_SPINDOWN), spindown }, + { STR(LANG_SPINDOWN), spindown }, #ifdef HAVE_ATA_POWER_OFF - { str(LANG_POWEROFF), poweroff }, + { STR(LANG_POWEROFF), poweroff }, #endif }; @@ -1067,8 +1067,8 @@ static bool time_settings_menu(void) bool result; struct menu_items items[] = { - { str(LANG_TIME), timedate_set }, - { str(LANG_TIMEFORMAT), timeformat_set }, + { STR(LANG_TIME), timedate_set }, + { STR(LANG_TIMEFORMAT), timeformat_set }, }; m=menu_init( items, sizeof(items) / sizeof(*items), NULL ); @@ -1084,10 +1084,10 @@ static bool manage_settings_menu(void) bool result; struct menu_items items[] = { - { str(LANG_CUSTOM_CFG), custom_cfg_browse }, - { str(LANG_FIRMWARE), firmware_browse }, - { str(LANG_RESET), reset_settings }, - { str(LANG_SAVE_SETTINGS), settings_save_config }, + { STR(LANG_CUSTOM_CFG), custom_cfg_browse }, + { STR(LANG_FIRMWARE), firmware_browse }, + { STR(LANG_RESET), reset_settings }, + { STR(LANG_SAVE_SETTINGS), settings_save_config }, }; m=menu_init( items, sizeof(items) / sizeof(*items), NULL ); @@ -1102,8 +1102,8 @@ static bool limits_settings_menu(void) bool result; struct menu_items items[] = { - { str(LANG_MAX_FILES_IN_DIR), max_files_in_dir }, - { str(LANG_MAX_FILES_IN_PLAYLIST), max_files_in_playlist }, + { STR(LANG_MAX_FILES_IN_DIR), max_files_in_dir }, + { STR(LANG_MAX_FILES_IN_PLAYLIST), max_files_in_playlist }, }; m=menu_init( items, sizeof(items) / sizeof(*items), NULL ); @@ -1119,22 +1119,22 @@ static bool system_settings_menu(void) bool result; struct menu_items items[] = { - { str(LANG_BATTERY_MENU), battery_settings_menu }, - { str(LANG_DISK_MENU), disk_settings_menu }, + { STR(LANG_BATTERY_MENU), battery_settings_menu }, + { STR(LANG_DISK_MENU), disk_settings_menu }, #ifdef HAVE_RTC - { str(LANG_TIME_MENU), time_settings_menu }, + { STR(LANG_TIME_MENU), time_settings_menu }, #endif - { str(LANG_POWEROFF_IDLE), poweroff_idle_timer }, - { str(LANG_SLEEP_TIMER), sleeptimer_screen }, + { STR(LANG_POWEROFF_IDLE), poweroff_idle_timer }, + { STR(LANG_SLEEP_TIMER), sleeptimer_screen }, #ifdef HAVE_ALARM_MOD - { str(LANG_ALARM_MOD_ALARM_MENU), alarm_screen }, + { STR(LANG_ALARM_MOD_ALARM_MENU), alarm_screen }, #endif - { str(LANG_LIMITS_MENU), limits_settings_menu }, + { STR(LANG_LIMITS_MENU), limits_settings_menu }, #ifdef HAVE_MAS3507D - { str(LANG_LINE_IN), line_in }, + { STR(LANG_LINE_IN), line_in }, #endif - { str(LANG_CAR_ADAPTER_MODE), car_adapter_mode }, - { str(LANG_MANAGE_MENU), manage_settings_menu }, + { STR(LANG_CAR_ADAPTER_MODE), car_adapter_mode }, + { STR(LANG_MANAGE_MENU), manage_settings_menu }, }; m=menu_init( items, sizeof(items) / sizeof(*items), NULL ); @@ -1149,12 +1149,12 @@ bool settings_menu(void) bool result; struct menu_items items[] = { - { str(LANG_PLAYBACK), playback_settings_menu }, - { str(LANG_FILE), fileview_settings_menu }, - { str(LANG_DISPLAY), display_settings_menu }, - { str(LANG_SYSTEM), system_settings_menu }, - { str(LANG_BOOKMARK_SETTINGS),bookmark_settings_menu }, - { str(LANG_LANGUAGE), language_browse }, + { STR(LANG_PLAYBACK), playback_settings_menu }, + { STR(LANG_FILE), fileview_settings_menu }, + { STR(LANG_DISPLAY), display_settings_menu }, + { STR(LANG_SYSTEM), system_settings_menu }, + { STR(LANG_BOOKMARK_SETTINGS),bookmark_settings_menu }, + { STR(LANG_LANGUAGE), language_browse }, }; 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) int m; bool result; struct menu_items items[] = { - { str(LANG_VOLUME), volume }, - { str(LANG_BASS), bass }, - { str(LANG_TREBLE), treble }, - { str(LANG_BALANCE), balance }, - { str(LANG_CHANNEL_MENU), chanconf }, + { STR(LANG_VOLUME), volume }, + { STR(LANG_BASS), bass }, + { STR(LANG_TREBLE), treble }, + { STR(LANG_BALANCE), balance }, + { STR(LANG_CHANNEL_MENU), chanconf }, #ifdef HAVE_MAS3587F - { str(LANG_LOUDNESS), loudness }, - { str(LANG_BBOOST), bass_boost }, - { str(LANG_AUTOVOL), avc } + { STR(LANG_LOUDNESS), loudness }, + { STR(LANG_BBOOST), bass_boost }, + { STR(LANG_AUTOVOL), avc } #endif }; @@ -323,22 +323,30 @@ bool recording_menu(bool no_source) bool result; menu[i].desc = str(LANG_RECORDING_QUALITY); + menu[i].voice_id = LANG_RECORDING_QUALITY; menu[i++].function = recquality; menu[i].desc = str(LANG_RECORDING_FREQUENCY); + menu[i].voice_id = LANG_RECORDING_FREQUENCY; menu[i++].function = recfrequency; if(!no_source) { menu[i].desc = str(LANG_RECORDING_SOURCE); + menu[i].voice_id = LANG_RECORDING_SOURCE; menu[i++].function = recsource; } menu[i].desc = str(LANG_RECORDING_CHANNELS); + menu[i].voice_id = LANG_RECORDING_CHANNELS; menu[i++].function = recchannels; menu[i].desc = str(LANG_RECORDING_EDITABLE); + menu[i].voice_id = LANG_RECORDING_EDITABLE; menu[i++].function = receditable; menu[i].desc = str(LANG_RECORD_TIMESPLIT); + menu[i].voice_id = LANG_RECORD_TIMESPLIT; menu[i++].function = rectimesplit; menu[i].desc = str(LANG_RECORD_PRERECORD_TIME); + menu[i].voice_id = LANG_RECORD_PRERECORD_TIME; menu[i++].function = recprerecord; menu[i].desc = str(LANG_RECORD_DIRECTORY); + menu[i].voice_id = LANG_RECORD_DIRECTORY; menu[i++].function = recdirectory; 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 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2004 Jörg Hohensohn + * + * This module collects the Talkbox and voice UI functions. + * (Talkbox reads directory names from mp3 clips called thumbnails, + * the voice UI lets menus and screens "talk" from a voicefont in memory. + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef __TALK_H__ +#define __TALK_H__ + +#include <stdbool.h> + +void talk_init(void); +int talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */ +int talk_id(int id, bool block); /* play a voice ID from voicefont */ +int talk_file(char* filename, bool block); /* play a thumbnail from file */ + +#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) recording_filename[MAX_PATH - 1] = 0; disable_xing_header = false; + talk_buffer_steal(); /* we use the mp3 buffer, need to tell */ queue_post(&mpeg_queue, MPEG_RECORD, NULL); } @@ -2148,6 +2149,7 @@ static void start_prerecording(void) prerecord_timeout = current_tick + HZ; memset(prerecord_buffer, 0, sizeof(prerecord_buffer)); reset_mp3_buffer(); + talk_buffer_steal(); /* we use the mp3 buffer, need to tell */ is_prerecording = true; @@ -2404,6 +2406,7 @@ void mpeg_play(int offset) #else is_playing = true; + talk_buffer_steal(); /* we use the mp3 buffer, need to tell */ queue_post(&mpeg_queue, MPEG_PLAY, (void*)offset); #endif /* #ifdef SIMULATOR */ 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 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2004 Jörg Hohensohn + * + * This module collects the Talkbox and voice UI functions. + * (Talkbox reads directory names from mp3 clips called thumbnails, + * the voice UI lets menus and screens "talk" from a voicefont in memory. + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include <stdio.h> +#include <stddef.h> +#include "file.h" +#include "buffer.h" +#include "kernel.h" +#include "mp3_playback.h" +#include "mpeg.h" +#include "talk.h" +extern void bitswap(unsigned char *data, int length); /* no header for this */ + +/***************** Constants *****************/ + +#define VOICEFONT_FILENAME "/.rockbox/voicefont" + + +/***************** Data types *****************/ + +struct clip_entry /* one entry of the index table */ +{ + int offset; /* offset from start of voicefont file */ + int size; /* size of the clip */ +}; + +struct voicefont /* file format of our "voicefont" */ +{ + int version; /* version of the voicefont */ + int headersize; /* size of the header, =offset to index */ + int id_max; /* number of clips contained */ + struct clip_entry index[]; /* followed by the index table */ + /* and finally the bitswapped mp3 clips, not visible here */ +}; + + +/***************** Globals *****************/ + +static unsigned char* p_thumbnail; /* buffer for thumbnail */ +static long size_for_thumbnail; /* leftover buffer size for it */ +static struct voicefont* p_voicefont; /* loaded voicefont */ +static bool has_voicefont; /* a voicefont file is present */ +static bool is_playing; /* we're currently playing */ + + + +/***************** Private implementation *****************/ + +static int load_voicefont(void) +{ + int fd; + int size; + + p_voicefont = NULL; /* indicate no voicefont if we fail below */ + + fd = open(VOICEFONT_FILENAME, O_RDONLY); + if (fd < 0) /* failed to open */ + { + p_voicefont = NULL; /* indicate no voicefont */ + has_voicefont = false; /* don't try again */ + return 0; + } + + size = read(fd, mp3buf, mp3end - mp3buf); + if (size > 1000 + && ((struct voicefont*)mp3buf)->headersize + == offsetof(struct voicefont, index)) + { + p_voicefont = (struct voicefont*)mp3buf; + + /* thumbnail buffer is the remaining space behind */ + p_thumbnail = mp3buf + size; + p_thumbnail += (int)p_thumbnail % 2; /* 16-bit align */ + size_for_thumbnail = mp3end - p_thumbnail; + + /* max. DMA size, fixme */ + if (size_for_thumbnail > 0xFFFF) + size_for_thumbnail = 0xFFFF; + } + else + { + has_voicefont = false; /* don't try again */ + } + close(fd); + + return size; +} + + +/* called in ISR context if mp3 data got consumed */ +void mp3_callback(unsigned char** start, int* size) +{ + (void)start; /* unused parameter, avoid warning */ + *size = 0; /* end of data */ + is_playing = false; + mp3_play_stop(); /* fixme: should be done by caller */ +} + +/***************** Public implementation *****************/ + +void talk_init(void) +{ + has_voicefont = true; /* unless we fail later, assume we have one */ + talk_buffer_steal(); +} + + +/* somebody else claims the mp3 buffer, e.g. for regular play/record */ +int talk_buffer_steal(void) +{ + p_voicefont = NULL; /* indicate no voicefont (trashed) */ + p_thumbnail = mp3buf; /* whole space for thumbnail */ + size_for_thumbnail = mp3end - mp3buf; + /* max. DMA size, fixme */ + if (size_for_thumbnail > 0xFFFF) + size_for_thumbnail = 0xFFFF; + return 0; +} + + +/* play a voice ID from voicefont */ +int talk_id(int id, bool block) +{ + int clipsize; + + if (mpeg_status()) /* busy, buffer in use */ + return -1; + + if (p_voicefont == NULL && has_voicefont) + load_voicefont(); /* reload needed */ + + if (p_voicefont == NULL) /* still no voices? */ + return -1; + + if (id >= p_voicefont->id_max) + return -1; + + clipsize = p_voicefont->index[id].size; + if (clipsize == 0) /* clip not included in voicefont */ + return -1; + + is_playing = true; + mp3_play_data(mp3buf + p_voicefont->index[id].offset, + clipsize, mp3_callback); + mp3_play_pause(true); /* kickoff audio */ + + while(block && is_playing) + sleep(1); + + return 0; +} + + +/* play a thumbnail from file */ +int talk_file(char* filename, bool block) +{ + int fd; + int size; + + if (mpeg_status()) /* busy, buffer in use */ + return -1; + + if (p_thumbnail == NULL || size_for_thumbnail <= 0) + return -1; + + fd = open(filename, O_RDONLY); + if (fd < 0) /* failed to open */ + { + return 0; + } + + size = read(fd, p_thumbnail, size_for_thumbnail); + close(fd); + + /* ToDo: find audio, skip ID headers and trailers */ + + if (size) + { + bitswap(p_thumbnail, size); + is_playing = true; + mp3_play_data(p_thumbnail, size, mp3_callback); + mp3_play_pause(true); /* kickoff audio */ + + while(block && is_playing) + sleep(1); + } + + return size; +} 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) { (void)yesno; } + +int talk_buffer_steal(void) +{ + return 0; +} + +int talk_id(int id, bool block) +{ + (void)id; + (void)block; + return 0; +} + +int talk_file(char* filename, bool block) +{ + (void)filename; + (void)block; + return 0; +} |