void option_talk_value(const struct settings_list *setting, int value, bool enqueue) { if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING) { bool val = (value==1); talk_id(val? setting->bool_setting->lang_yes : setting->bool_setting->lang_no, enqueue); } #if 0 /* probably dont need this one */ else if ((setting->flags & F_FILENAME) == F_FILENAME) { } #endif else if (((setting->flags & F_INT_SETTING) == F_INT_SETTING) || ((setting->flags & F_TABLE_SETTING) == F_TABLE_SETTING)) { const struct int_setting *int_info = setting->int_setting; const struct table_setting *tbl_info = setting->table_setting; int unit; int32_t (*get_talk_id)(int, int); if ((setting->flags & F_INT_SETTING) == F_INT_SETTING) { unit = int_info->unit; get_talk_id = int_info->get_talk_id; } else { unit = tbl_info->unit; get_talk_id = tbl_info->get_talk_id; } if (get_talk_id) talk_id(get_talk_id(value, unit), enqueue); else talk_value(value, unit, enqueue); } else if ((setting->flags & F_T_SOUND) == F_T_SOUND) { int talkunit = UNIT_INT; const char *unit = sound_unit(setting->sound_setting->setting); if (!strcmp(unit, "dB")) talkunit = UNIT_DB; else if (!strcmp(unit, "%")) talkunit = UNIT_PERCENT; else if (!strcmp(unit, "Hz")) talkunit = UNIT_HERTZ; talk_value(value, talkunit, false); } else if ((setting->flags & F_CHOICE_SETTING) == F_CHOICE_SETTING) { if (setting->flags & F_CHOICETALKS) { talk_id(setting->choice_setting->talks[value], enqueue); } else { talk_id(P2ID(setting->choice_setting->desc[value]), enqueue); } } }
static void init_tagcache(void) { bool clear = false; #if CONFIG_CODEC == SWCODEC long talked_tick = 0; #endif tagcache_init(); while (!tagcache_is_initialized()) { int ret = tagcache_get_commit_step(); if (ret > 0) { #if CONFIG_CODEC == SWCODEC /* hwcodec can't use voice here, as the database commit * uses the audio buffer. */ if(global_settings.talk_menu && (talked_tick == 0 || TIME_AFTER(current_tick, talked_tick+7*HZ))) { talked_tick = current_tick; talk_id(LANG_TAGCACHE_INIT, false); talk_number(ret, true); talk_id(VOICE_OF, true); talk_number(tagcache_get_max_commit_step(), true); } #endif #ifdef HAVE_LCD_BITMAP if (lang_is_rtl()) { splashf(0, "[%d/%d] %s", ret, tagcache_get_max_commit_step(), str(LANG_TAGCACHE_INIT)); } else { splashf(0, "%s [%d/%d]", str(LANG_TAGCACHE_INIT), ret, tagcache_get_max_commit_step()); } #else lcd_double_height(false); lcd_putsf(0, 1, " DB [%d/%d]", ret, tagcache_get_max_commit_step()); lcd_update(); #endif clear = true; } sleep(HZ/4); } tagtree_init(); if (clear) { backlight_on(); show_logo(); } }
/* ------------------------------------------------------------------------*/ static void say_bookmark(const char* bookmark, int bookmark_id, bool show_playlist_name) { if (!parse_bookmark(bookmark, true)) { talk_id(LANG_BOOKMARK_INVALID, false); return; } talk_number(bookmark_id + 1, false); #if CONFIG_CODEC == SWCODEC bool is_dir = (global_temp_buffer[0] && global_temp_buffer[strlen(global_temp_buffer)-1] == '/'); /* HWCODEC cannot enqueue voice file entries and .talk thumbnails together, because there is no guarantee that the same mp3 parameters are used. */ if(show_playlist_name) { /* It's useful to know which playlist this is */ if(is_dir) talk_dir_or_spell(global_temp_buffer, TALK_IDARRAY(VOICE_DIR), true); else talk_file_or_spell(NULL, global_temp_buffer, TALK_IDARRAY(LANG_PLAYLIST), true); } #else (void)show_playlist_name; #endif if(bm.shuffle) talk_id(LANG_SHUFFLE, true); talk_id(VOICE_BOOKMARK_SELECT_INDEX_TEXT, true); talk_number(bm.resume_index + 1, true); talk_id(LANG_TIME, true); talk_value(bm.resume_time / 1000, UNIT_TIME, true); #if CONFIG_CODEC == SWCODEC /* Track filename */ if(is_dir) talk_file_or_spell(global_temp_buffer, global_filename, TALK_IDARRAY(VOICE_FILE), true); else { /* Unfortunately if this is a playlist, we do not know in which directory the file is and therefore cannot find the track's .talk file. */ talk_id(VOICE_FILE, true); talk_spell(global_filename, true); } #endif }
static int playlist_callback_voice(int selected_item, void *data) { struct playlist_viewer *local_viewer = (struct playlist_viewer *)data; int track_num = get_track_num(local_viewer, selected_item); struct playlist_entry *track = playlist_buffer_get_track(&(local_viewer->buffer), track_num); bool enqueue = false; if (global_settings.talk_file_clip || global_settings.talk_file == 2) { if (global_settings.playlist_viewer_indices) { talk_number(track->display_index, false); enqueue = true; } talk_file_or_spell(NULL, track->name, NULL, enqueue); } else if (global_settings.talk_file == 1) /* as numbers */ { talk_id(VOICE_FILE, false); talk_number(track->display_index, true); } return 0; }
/* have to do this manually because the setting screen doesnt handle variable item count */ static int alarm_setting(void) { struct opt_items items[ALARM_START_COUNT]; int i = 0; items[i].string = str(LANG_RESUME_PLAYBACK); items[i].voice_id = LANG_RESUME_PLAYBACK; i++; #if CONFIG_TUNER if (radio_hardware_present()) { items[i].string = str(LANG_FM_RADIO); items[i].voice_id = LANG_FM_RADIO; i++; } #endif #ifdef HAVE_RECORDING items[i].string = str(LANG_RECORDING); items[i].voice_id = LANG_RECORDING; i++; #endif return set_option(str(LANG_ALARM_WAKEUP_SCREEN), &global_settings.alarm_wake_up_screen, INT, items, i, NULL); } MENUITEM_FUNCTION(alarm_wake_up_screen, 0, ID2P(LANG_ALARM_WAKEUP_SCREEN), alarm_setting, NULL, alarm_callback, Icon_Menu_setting); #endif /* CONFIG_TUNER || defined(HAVE_RECORDING) */ #endif /* HAVE_RTC_ALARM */ static void talk_timedate(void) { struct tm *tm = get_time(); if (!global_settings.talk_menu) return; talk_id(VOICE_CURRENT_TIME, false); if (valid_time(tm)) { talk_time(tm, true); talk_date(get_time(), true); } else { talk_id(LANG_UNKNOWN, true); } }
static int gainitem_speak_item(int selected_item, void *data) { (void)data; talk_number(global_settings.eq_band_settings[selected_item].cutoff, false); talk_id(LANG_EQUALIZER_GAIN_ITEM, true); return 0; }
static void talk_qs_option(const struct settings_list *opt, bool enqueue) { if (global_settings.talk_menu) { if (!enqueue) talk_shutup(); talk_id(opt->lang_id, true); option_talk_value(opt, option_value_as_int(opt), true); } }
/* Speak a frequency. */ void talk_freq(int freq, bool enqueue) { freq /= 10000; talk_number(freq / 100, enqueue); talk_id(LANG_POINT, true); talk_number(freq % 100 / 10, true); if (freq % 10) talk_number(freq % 10, true); }
static int advancedmenu_speak_item(int selected_item, void *data) { (void)data; int band; int item; int lang = -1; selection_to_banditem(selected_item, *(intptr_t*)data, &band, &item); switch (item) { case 0: /* Band title */ if (band == 0) lang = LANG_EQUALIZER_BAND_LOW_SHELF; else if (band == EQ_NUM_BANDS - 1) lang = LANG_EQUALIZER_BAND_HIGH_SHELF; else { talk_id(LANG_EQUALIZER_BAND_PEAK, false); talk_number(band, true); return -1; } break; case 1: /* cutoff */ if (band == 0) lang = LANG_EQUALIZER_BAND_CUTOFF; else if (band == EQ_NUM_BANDS - 1) lang = LANG_EQUALIZER_BAND_CUTOFF; else lang = LANG_EQUALIZER_BAND_CENTER; break; case 2: /* Q */ lang = LANG_EQUALIZER_BAND_Q; break; case 3: /* Gain */ lang = LANG_GAIN; break; } talk_id(lang, true); return -1; }
static void say_filetype(int attr) { /* try to find a voice ID for the extension, if known */ int j; attr &= FILE_ATTR_MASK; /* file type */ for (j=0; j<filetypes_count; j++) if (attr == filetypes[j].tree_attr) { talk_id(filetypes[j].voiceclip, true); return; } }
/* display number of tracks inserted into playlists. Used for directory insert */ static void display_insert_count(int count) { static long talked_tick = 0; if(global_settings.talk_menu && count && (talked_tick == 0 || TIME_AFTER(current_tick, talked_tick+5*HZ))) { talked_tick = current_tick; talk_number(count, false); talk_id(LANG_PLAYLIST_INSERT_COUNT, true); } splashf(0, str(LANG_PLAYLIST_INSERT_COUNT), count, str(LANG_OFF_ABORT)); }
static int bookmark_list_voice_cb(int list_index, void* data) { struct bookmark_list* bookmarks = (struct bookmark_list*) data; int index = list_index / 2; if (bookmarks->show_dont_resume) { if (index == 0) return talk_id(LANG_BOOKMARK_DONT_RESUME, false); index--; } say_bookmark(bookmarks->items[index - bookmarks->start], index, bookmarks->show_playlist_name); return 0; }
/* * Move the cursor to a particular id, * target: where you want it to be */ static void put_cursor(int m, int target) { int voice_id; menus[m].cursor = target; menu_draw(m); /* "say" the entry under the cursor */ if(global_settings.talk_menu) { voice_id = P2ID(menus[m].items[menus[m].cursor].desc); if (voice_id >= 0) /* valid ID given? */ talk_id(voice_id, false); /* say it */ } }
static void talk_text_message(const struct text_message * message, bool enqueue) { int line; if(message) { for(line=0; line<message->nb_lines; line++) { long id = P2ID((unsigned char *)message->message_lines[line]); if(id>=0) { talk_id(id, enqueue); enqueue = true; } } } }
static int ft_play_dirname(char* name) { #if CONFIG_CODEC != SWCODEC if (audio_status() & AUDIO_STATUS_PLAY) return 0; #endif if(talk_file(tc.currdir, name, dir_thumbnail_name, NULL, NULL, false)) { if(global_settings.talk_filetype) talk_id(VOICE_DIR, true); return 1; } else return -1; }
static int browser(void* param) { int ret_val; #ifdef HAVE_TAGCACHE struct tree_context* tc = tree_get_context(); #endif int filter = SHOW_SUPPORTED; char folder[MAX_PATH] = "/"; /* stuff needed to remember position in file browser */ static char last_folder[MAX_PATH] = "/"; /* and stuff for the database browser */ #ifdef HAVE_TAGCACHE static int last_db_dirlevel = 0, last_db_selection = 0; #endif switch ((intptr_t)param) { case GO_TO_FILEBROWSER: filter = global_settings.dirfilter; if (global_settings.browse_current && last_screen == GO_TO_WPS && current_track_path[0]) { strcpy(folder, current_track_path); } else if (!strcmp(last_folder, "/")) { strcpy(folder, global_settings.start_directory); } else { #ifdef HAVE_HOTSWAP bool in_hotswap = false; /* handle entering an ejected drive */ int i; for (i = 0; i < NUM_VOLUMES; i++) { char vol_string[VOL_ENUM_POS + 8]; if (!storage_removable(i)) continue; /* VOL_NAMES contains a %d */ snprintf(vol_string, sizeof(vol_string), "/"VOL_NAMES, i); /* test whether we would browse the external card */ if (!storage_present(i) && (strstr(last_folder, vol_string) #ifdef HAVE_HOTSWAP_STORAGE_AS_MAIN || (i == 0) #endif )) { /* leave folder as "/" to avoid crash when trying * to access an ejected drive */ strcpy(folder, "/"); in_hotswap = true; break; } } if (!in_hotswap) #endif strcpy(folder, last_folder); } break; #ifdef HAVE_TAGCACHE case GO_TO_DBBROWSER: if (!tagcache_is_usable()) { bool reinit_attempted = false; /* Now display progress until it's ready or the user exits */ while(!tagcache_is_usable()) { struct tagcache_stat *stat = tagcache_get_stat(); /* Allow user to exit */ if (action_userabort(HZ/2)) break; /* Maybe just needs to reboot due to delayed commit */ if (stat->commit_delayed) { splash(HZ*2, ID2P(LANG_PLEASE_REBOOT)); break; } /* Check if ready status is known */ if (!stat->readyvalid) { splash(0, str(LANG_TAGCACHE_BUSY)); continue; } /* Re-init if required */ if (!reinit_attempted && !stat->ready && stat->processed_entries == 0 && stat->commit_step == 0) { /* Prompt the user */ reinit_attempted = true; static const char *lines[]={ ID2P(LANG_TAGCACHE_BUSY), ID2P(LANG_TAGCACHE_FORCE_UPDATE)}; static const struct text_message message={lines, 2}; if(gui_syncyesno_run(&message, NULL, NULL) == YESNO_NO) break; int i; FOR_NB_SCREENS(i) screens[i].clear_display(); /* Start initialisation */ tagcache_rebuild(); } /* Display building progress */ static long talked_tick = 0; if(global_settings.talk_menu && (talked_tick == 0 || TIME_AFTER(current_tick, talked_tick+7*HZ))) { talked_tick = current_tick; if (stat->commit_step > 0) { talk_id(LANG_TAGCACHE_INIT, false); talk_number(stat->commit_step, true); talk_id(VOICE_OF, true); talk_number(tagcache_get_max_commit_step(), true); } else if(stat->processed_entries) { talk_number(stat->processed_entries, false); talk_id(LANG_BUILDING_DATABASE, true); } } if (stat->commit_step > 0) { if (lang_is_rtl()) { splashf(0, "[%d/%d] %s", stat->commit_step, tagcache_get_max_commit_step(), str(LANG_TAGCACHE_INIT)); } else { splashf(0, "%s [%d/%d]", str(LANG_TAGCACHE_INIT), stat->commit_step, tagcache_get_max_commit_step()); } } else { splashf(0, str(LANG_BUILDING_DATABASE), stat->processed_entries); } } } if (!tagcache_is_usable()) return GO_TO_PREVIOUS; filter = SHOW_ID3DB; tc->dirlevel = last_db_dirlevel; tc->selected_item = last_db_selection; break; #endif case GO_TO_BROWSEPLUGINS: filter = SHOW_PLUGINS; strlcpy(folder, PLUGIN_DIR, MAX_PATH); break; } ret_val = rockbox_browse(folder, filter); switch ((intptr_t)param) { case GO_TO_FILEBROWSER: if (!get_current_file(last_folder, MAX_PATH) || (!strchr(&last_folder[1], '/') && global_settings.start_directory[1] != '\0')) { last_folder[0] = '/'; last_folder[1] = '\0'; } break; #ifdef HAVE_TAGCACHE case GO_TO_DBBROWSER: last_db_dirlevel = tc->dirlevel; last_db_selection = tc->selected_item; break; #endif } return ret_val; }
bool alarm_screen(void) { int h, m; bool done = false; struct tm *tm; int togo; int button; bool update = true; bool hour_wrapped = false; struct viewport vp[NB_SCREENS]; rtc_get_alarm(&h, &m); /* After a battery change the RTC values are out of range */ if (m > 60 || h > 24) { m = 0; h = 12; } else { m = m / 5 * 5; /* 5 min accuracy should be enough */ } FOR_NB_SCREENS(i) { viewport_set_defaults(&vp[i], i); } while(!done) { if(update) { FOR_NB_SCREENS(i) { screens[i].set_viewport(&vp[i]); screens[i].clear_viewport(); screens[i].puts(0, 4, str(LANG_ALARM_MOD_KEYS)); } /* Talk when entering the wakeup screen */ speak_time(h, m, true, true); update = false; } FOR_NB_SCREENS(i) { screens[i].set_viewport(&vp[i]); screens[i].putsf(0, 1, str(LANG_ALARM_MOD_TIME)); screens[i].putsf(0, 2, "%02d:%02d", h, m); screens[i].update_viewport(); screens[i].set_viewport(NULL); } button = get_action(CONTEXT_SETTINGS,HZ); switch(button) { case ACTION_STD_OK: /* prevent that an alarm occurs in the shutdown procedure */ /* accept alarms only if they are in 2 minutes or more */ tm = get_time(); togo = (m + h * 60 - tm->tm_min - tm->tm_hour * 60 + 1440) % 1440; if (togo > 1) { rtc_init(); rtc_set_alarm(h,m); rtc_enable_alarm(true); if (global_settings.talk_menu) { talk_id(LANG_ALARM_MOD_TIME_TO_GO, true); talk_value(togo / 60, UNIT_HOUR, true); talk_value(togo % 60, UNIT_MIN, true); talk_force_enqueue_next(); } splashf(HZ*2, str(LANG_ALARM_MOD_TIME_TO_GO), togo / 60, togo % 60); done = true; } else { splash(HZ, ID2P(LANG_ALARM_MOD_ERROR)); update = true; } break; /* inc(m) */ case ACTION_SETTINGS_INC: case ACTION_SETTINGS_INCREPEAT: m += 5; if (m == 60) { h += 1; m = 0; hour_wrapped = true; } if (h == 24) h = 0; speak_time(h, m, hour_wrapped, false); break; /* dec(m) */ case ACTION_SETTINGS_DEC: case ACTION_SETTINGS_DECREPEAT: m -= 5; if (m == -5) { h -= 1; m = 55; hour_wrapped = true; } if (h == -1) h = 23; speak_time(h, m, hour_wrapped, false); break; /* inc(h) */ case ACTION_STD_NEXT: case ACTION_STD_NEXTREPEAT: h = (h+1) % 24; if (global_settings.talk_menu) talk_value(h, UNIT_HOUR, false); break; /* dec(h) */ case ACTION_STD_PREV: case ACTION_STD_PREVREPEAT: h = (h+23) % 24; if (global_settings.talk_menu) talk_value(h, UNIT_HOUR, false); break; case ACTION_STD_CANCEL: rtc_enable_alarm(false); splash(HZ*2, ID2P(LANG_ALARM_MOD_DISABLE)); done = true; break; case ACTION_NONE: hour_wrapped = false; break; default: if(default_event_handler(button) == SYS_USB_CONNECTED) { rtc_enable_alarm(false); return true; } break; } } return false; }
static int tree_voice_cb(int selected_item, void * data) { struct tree_context * local_tc=(struct tree_context *)data; char *name; int attr=0; #ifdef HAVE_TAGCACHE bool id3db = *(local_tc->dirfilter) == SHOW_ID3DB; char buf[AVERAGE_FILENAME_LENGTH*2]; if (id3db) { attr = tagtree_get_attr(local_tc); name = tagtree_get_entry_name(local_tc, selected_item, buf, sizeof(buf)); } else #endif { struct entry* e = tree_get_entry_at(local_tc, selected_item); name = e->name; attr = e->attr; } bool is_dir = (attr & ATTR_DIRECTORY); bool did_clip = false; /* First the .talk clip case */ if(is_dir) { if(global_settings.talk_dir_clip) { did_clip = true; if(ft_play_dirname(name) <0) /* failed, not existing */ did_clip = false; } } else { /* it's a file */ if (global_settings.talk_file_clip && (attr & FILE_ATTR_THUMBNAIL)) { did_clip = true; ft_play_filename(local_tc->currdir, name); } } if(!did_clip) { /* say the number or spell if required or as a fallback */ switch (is_dir ? global_settings.talk_dir : global_settings.talk_file) { case 1: /* as numbers */ talk_id(is_dir ? VOICE_DIR : VOICE_FILE, false); talk_number(selected_item+1 - (is_dir ? 0 : local_tc->dirsindir), true); if(global_settings.talk_filetype && !is_dir && *local_tc->dirfilter < NUM_FILTER_MODES) say_filetype(attr); break; case 2: /* spelled */ talk_shutup(); if(global_settings.talk_filetype) { if(is_dir) talk_id(VOICE_DIR, true); else if(*local_tc->dirfilter < NUM_FILTER_MODES) say_filetype(attr); } talk_spell(name, true); break; } } return 0; }
static bool clean_shutdown(void (*callback)(void *), void *parameter) { #ifdef SIMULATOR (void)callback; (void)parameter; bookmark_autobookmark(); call_storage_idle_notifys(true); exit(0); #else long msg_id = -1; int i; scrobbler_poweroff(); #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING) if(!charger_inserted()) #endif { bool batt_safe = battery_level_safe(); int audio_stat = audio_status(); FOR_NB_SCREENS(i) { screens[i].clear_display(); screens[i].update(); } if (batt_safe) { #ifdef HAVE_TAGCACHE if (!tagcache_prepare_shutdown()) { cancel_shutdown(); splash(HZ, ID2P(LANG_TAGCACHE_BUSY)); return false; } #endif if (battery_level() > 10) splash(0, str(LANG_SHUTTINGDOWN)); else { msg_id = LANG_WARNING_BATTERY_LOW; splashf(0, "%s %s", str(LANG_WARNING_BATTERY_LOW), str(LANG_SHUTTINGDOWN)); } } else { msg_id = LANG_WARNING_BATTERY_EMPTY; splashf(0, "%s %s", str(LANG_WARNING_BATTERY_EMPTY), str(LANG_SHUTTINGDOWN)); } if (global_settings.fade_on_stop && (audio_stat & AUDIO_STATUS_PLAY)) { fade(false, false); } if (batt_safe) /* do not save on critical battery */ { #if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC if (audio_stat & AUDIO_STATUS_RECORD) { rec_command(RECORDING_CMD_STOP); /* wait for stop to complete */ while (audio_status() & AUDIO_STATUS_RECORD) sleep(1); } #endif bookmark_autobookmark(); /* audio_stop_recording == audio_stop for HWCODEC */ audio_stop(); if (callback != NULL) callback(parameter); #if CONFIG_CODEC != SWCODEC /* wait for audio_stop or audio_stop_recording to complete */ while (audio_status()) sleep(1); #endif #if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC audio_close_recording(); #endif if(global_settings.talk_menu) { bool enqueue = false; if(msg_id != -1) { talk_id(msg_id, enqueue); enqueue = true; } talk_id(LANG_SHUTTINGDOWN, enqueue); #if CONFIG_CODEC == SWCODEC voice_wait(); #endif } system_flush(); #ifdef HAVE_EEPROM_SETTINGS if (firmware_settings.initialized) { firmware_settings.disk_clean = true; firmware_settings.bl_version = 0; eeprom_settings_store(); } #endif } #ifdef HAVE_DIRCACHE else dircache_disable(); #endif shutdown_hw(); }