Index: apps/lang/english.lang =================================================================== --- apps/lang/english.lang (revision 27817) +++ apps/lang/english.lang (working copy) @@ -12619,3 +12619,87 @@ *: "Update on Stop" + + id: LANG_TRACKONLY + desc: used in track x of y constructs + user: core + + *: "Track" + + + *: "Track" + + + *: "Track" + + + + id: LANG_VOICEINFO + desc: progressively voice information on the wps hotkey + user: core + + *: "Announce Information" + + + *: "Announce Information" + + + *: "Announce Information" + + + + id: LANG_ELAPSED + desc: prefix for elapsed playtime announcement + user: core + + *: "Elapsed" + + + *: "Elapsed" + + + *: "Elapsed" + + + + id: LANG_WPS_ANNOUNCEMENT_FORMAT + desc: format for wps hotkey announcement + user: core + + *: "WPS Announcement" + + + *: "WPS Announcement" + + + *: "WPS Announcement" + + + + id: LANG_REMAINING + desc: for constructs such as number of tracks remaining etc + user: core + + *: "Remaining" + + + *: "Remaining" + + + *: "Remaining" + + + + id: LANG_DATE + desc: for constructing time and date announcements + user: core + + *: "Date" + + + *: "Date" + + + *: "Date" + + Index: apps/onplay.c =================================================================== --- apps/onplay.c (revision 27817) +++ apps/onplay.c (working copy) @@ -64,6 +64,10 @@ #include "pitchscreen.h" #include "viewport.h" +#include "ctype.h" + +#include "powermgmt.h" + static int context; static char* selected_file = NULL; static int selected_file_attr = 0; @@ -1216,6 +1220,295 @@ return ONPLAY_RELOAD_DIR; } + + +#define ANNOUNCEMENT_TIMEOUT 10 + +static int target_info = 0; + +static int info_reset_timeout = 0; + + +static unsigned char* voice_info_group(unsigned char* current_token); + +static int voice_general_info(void) +{ + unsigned char* infotemplate = global_settings.wps_announcement_format; + + if (*infotemplate == 0) + { +#if CONFIG_RTC + /* announce the time */ + strcpy(infotemplate, "Ac"); +#else + /* announce elapsed play for this track */ + strcpy(infotemplate, "Be"); +#endif + } + + if (TIME_AFTER(current_tick, info_reset_timeout)) + { + target_info = 0; + } + + info_reset_timeout = current_tick + ANNOUNCEMENT_TIMEOUT * HZ; + + talk_shutup(); + + /* + Consume announcement groups until we hit the target group + */ + int test_info = 0; + + while (*infotemplate != 0 && test_info != target_info) + { + if (*infotemplate == '.') + { + test_info++; + } + + infotemplate++; + } + + + /* + On a match, voice the found group and move on to the next + */ + if (test_info == target_info) + { + infotemplate = voice_info_group(infotemplate); + + target_info++; + } + + /* + If this was the last group, reset to the start + */ + if (*infotemplate == 0) + { + target_info = 0; + } + + return ONPLAY_OK; +} + + +static unsigned char* voice_info_group(unsigned char* current_token) +{ + unsigned char current_char; + + while (*current_token != 0 && *current_token != '.') + { + current_char = toupper(*current_token); + if (current_char == 'A') + { + /* + Date and time functions + */ + current_token++; + + current_char = toupper(*current_token); + +#if CONFIG_RTC + struct tm *tm = get_time(); + + if (valid_time(tm)) + { + if (current_char == 'A') + { + talk_time(tm, true); + } + else if (current_char == 'B') + { + talk_date(tm, true); + } + else if (current_char == 'C') + { + /* Time xxx */ + (void)voice_info_group("SaAa"); + } + else if (current_char == 'D') + { + /* Date xxx */ + (void)voice_info_group("SbAb"); + } + else if (current_char == 'E') + { + /* Date Time */ + (void)voice_info_group("AbAa"); + } +#endif + + int sleep_remaining = get_sleep_timer(); + + if (current_char == 'F') + { + talk_value_decimal(sleep_remaining, UNIT_TIME, 0, true); + } + else if (current_char == 'G') + { + /* SLEEPTIMER sleeptimer remaining */ + (void)voice_info_group("ShDf"); + } + } + + } + else if (current_char == 'B') + { + /* + Current track information + */ + current_token++; + + current_char = toupper(*current_token); + + struct mp3entry* id3 = audio_current_track(); + + int elapsed_length = id3->elapsed / 1000; + int track_length = id3->length / 1000; + int track_remaining = track_length - elapsed_length; + + if (current_char == 'A') + { + talk_value_decimal(elapsed_length, UNIT_TIME, 0, true); + } + else if (current_char == 'B') + { + talk_value_decimal(track_length, UNIT_TIME, 0, true); + } + else if (current_char == 'C') + { + talk_value_decimal(track_remaining, UNIT_TIME, 0, true); + } + else if (current_char == 'D') + { + /* xxx elapsed yyy remaining */ + (void)voice_info_group("BaSdBcSe"); + } + else if (current_char == 'E') + { + /* xxx of yyy */ + (void)voice_info_group("BaSfBb"); + } + } + else if (current_char == 'C') + { + /* + Current playlist information + */ + current_token++; + + current_char = toupper(*current_token); + + int current_track = playlist_get_display_index(); + int total_tracks = playlist_amount(); + int remaining_tracks = total_tracks - current_track; + + if (current_char == 'A') + { + talk_number(current_track, true); + } + else if (current_char == 'B') + { + talk_number(total_tracks, true); + } + else if (current_char == 'C') + { + talk_number(remaining_tracks, true); + } + else if (current_char == 'D') + { + /* TRACK current track OF number of tracks */ + (void)voice_info_group("ScCaSfCb"); + } + } + else if (current_char == 'D') + { + /* + Battery, sleep timer and runtime + */ + current_token++; + + current_char = toupper(*current_token); + + if (current_char == 'A') + { + talk_id(TALK_ID(battery_level(), UNIT_PERCENT), true); + } + else if (current_char == 'B') + { + talk_id(TALK_ID(battery_time() * 60, UNIT_TIME), true); + } + else if (current_char == 'C') + { + /* BATTERY LEVEL battery level percent */ + (void)voice_info_group("SgDa"); + } + else if (current_char == 'D') + { + /* BATTERY LEVEL battery level in minutes */ + (void)voice_info_group("SgDb"); + } + + } + else if (current_char == 'S') + { + /* + Stock prefixes, suffixes and connectives + */ + current_token++; + + current_char = toupper(*current_token); + + if (current_char == 'A') + { + talk_id(LANG_TIME, true); + } + else if (current_char == 'B') + { + talk_id(LANG_DATE, true); + } + else if (current_char == 'C') + { + talk_id(LANG_TRACKONLY, true); + } + else if (current_char == 'D') + { + talk_id(LANG_ELAPSED, true); + } + else if (current_char == 'E') + { + talk_id(LANG_REMAINING, true); + } + else if (current_char == 'F') + { + talk_id(LANG_OF, true); + } + else if (current_char == 'G') + { + talk_id(LANG_BATTERY_TIME, true); + } + else if (current_char == 'H') + { + talk_id(LANG_SLEEP_TIMER, true); + } + } + else if (current_char == ' ') + { + /* + Catch your breath + */ + talk_id(VOICE_PAUSE, true); + } + + current_token++; + } + + return current_token; +} + + + struct hotkey_assignment { int action; /* hotkey_action */ int lang_id; /* Language ID */ @@ -1252,6 +1545,9 @@ { HOTKEY_INSERT_SHUFFLED, LANG_INSERT_SHUFFLED, HOTKEY_FUNC(playlist_insert_shuffled, NULL), ONPLAY_OK }, + { HOTKEY_VOICEINFO, LANG_VOICEINFO, + HOTKEY_FUNC(voice_general_info, NULL), + ONPLAY_OK }, #ifdef HAVE_PICTUREFLOW_INTEGRATION { HOTKEY_PICTUREFLOW, LANG_ONPLAY_PICTUREFLOW, HOTKEY_FUNC(NULL, NULL), Index: apps/settings.h =================================================================== --- apps/settings.h (revision 27817) +++ apps/settings.h (working copy) @@ -42,8 +42,8 @@ /** Setting values defines **/ #define MAX_FILENAME 32 +#define MAX_ANNOUNCE_WPS 32 - enum { BOOKMARK_NO = 0, BOOKMARK_YES, @@ -611,6 +611,8 @@ bool talk_filetype; /* say file type */ bool talk_battery_level; + unsigned char wps_announcement_format[MAX_ANNOUNCE_WPS+1]; /* format for wps hotkey announcement */ + /* file browser sorting */ bool sort_case; /* dir sort order: 0=case insensitive, 1=sensitive */ int sort_dir; /* 0=alpha, 1=date (old first), 2=date (new first) */ Index: apps/menus/settings_menu.c =================================================================== --- apps/menus/settings_menu.c (revision 27817) +++ apps/menus/settings_menu.c (working copy) @@ -388,13 +388,27 @@ } return action; } + + +void edit_wps_announce_format(void); + +void edit_wps_announce_format(void) +{ + kbd_input(global_settings.wps_announcement_format, MAX_ANNOUNCE_WPS); + + +} + MENUITEM_SETTING(talk_filetype_item, &global_settings.talk_filetype, NULL); MENUITEM_SETTING(talk_battery_level_item, &global_settings.talk_battery_level, NULL); +MENUITEM_FUNCTION(wps_announce_item, 0, ID2P(LANG_WPS_ANNOUNCEMENT_FORMAT), + (int(*)(void))edit_wps_announce_format, + NULL, NULL, Icon_NOICON); MAKE_MENU(voice_settings_menu, ID2P(LANG_VOICE), 0, Icon_Voice, &talk_menu_item, &talk_dir_item, &talk_dir_clip_item, &talk_file_item, &talk_file_clip_item, &talk_filetype_item, - &talk_battery_level_item); + &talk_battery_level_item, &wps_announce_item); /* VOICE MENU */ /***********************************/ Index: apps/onplay.h =================================================================== --- apps/onplay.h (revision 27817) +++ apps/onplay.h (working copy) @@ -44,6 +44,7 @@ HOTKEY_DELETE, HOTKEY_INSERT, HOTKEY_INSERT_SHUFFLED, + HOTKEY_VOICEINFO, HOTKEY_PICTUREFLOW, }; #endif Index: apps/settings_list.c =================================================================== --- apps/settings_list.c (revision 27817) +++ apps/settings_list.c (working copy) @@ -1078,6 +1078,7 @@ "talk filetype", NULL), OFFON_SETTING(F_TEMPVAR, talk_battery_level, LANG_TALK_BATTERY_LEVEL, false, "Announce Battery Level", NULL), + TEXT_SETTING(F_T_UCHARPTR, wps_announcement_format, "wps announcement format", "","", NULL), #ifdef HAVE_RECORDING /* recording */ @@ -1755,7 +1756,7 @@ #ifdef HAVE_HOTKEY TABLE_SETTING(F_ALLOW_ARBITRARY_VALS, hotkey_wps, LANG_HOTKEY_WPS, HOTKEY_VIEW_PLAYLIST, "hotkey wps", - "off,view playlist,show track info,pitchscreen,open with,delete" + "off,view playlist,show track info,pitchscreen,open with,delete,voiceinfo" #ifdef HAVE_PICTUREFLOW_INTEGRATION ",pictureflow" #endif @@ -1767,7 +1768,7 @@ #endif HOTKEY_OFF, HOTKEY_VIEW_PLAYLIST, HOTKEY_SHOW_TRACK_INFO, HOTKEY_PITCHSCREEN, - HOTKEY_OPEN_WITH, HOTKEY_DELETE + HOTKEY_OPEN_WITH, HOTKEY_DELETE,HOTKEY_VOICEINFO #ifdef HAVE_PICTUREFLOW_INTEGRATION , HOTKEY_PICTUREFLOW #endif