diff options
-rw-r--r-- | apps/lang/english.lang | 22 | ||||
-rw-r--r-- | apps/plugins/playing_time.c | 421 |
2 files changed, 303 insertions, 140 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 0635f7b569..ada1129a43 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang | |||
@@ -12614,16 +12614,16 @@ | |||
12614 | </phrase> | 12614 | </phrase> |
12615 | <phrase> | 12615 | <phrase> |
12616 | id: LANG_PLAYTIME_REMAINING | 12616 | id: LANG_PLAYTIME_REMAINING |
12617 | desc: playing time screen | 12617 | desc: deprecated |
12618 | user: core | 12618 | user: core |
12619 | <source> | 12619 | <source> |
12620 | *: "Playlist remaining:" | 12620 | *: "" |
12621 | </source> | 12621 | </source> |
12622 | <dest> | 12622 | <dest> |
12623 | *: "Playlist remaining:" | 12623 | *: "" |
12624 | </dest> | 12624 | </dest> |
12625 | <voice> | 12625 | <voice> |
12626 | *: "Playlist remaining" | 12626 | *: "" |
12627 | </voice> | 12627 | </voice> |
12628 | </phrase> | 12628 | </phrase> |
12629 | <phrase> | 12629 | <phrase> |
@@ -16500,3 +16500,17 @@ | |||
16500 | *: "Choose File" | 16500 | *: "Choose File" |
16501 | </voice> | 16501 | </voice> |
16502 | </phrase> | 16502 | </phrase> |
16503 | <phrase> | ||
16504 | id: LANG_REMAINING | ||
16505 | desc: Playing Time | ||
16506 | user: core | ||
16507 | <source> | ||
16508 | *: "Remaining" | ||
16509 | </source> | ||
16510 | <dest> | ||
16511 | *: "Remaining" | ||
16512 | </dest> | ||
16513 | <voice> | ||
16514 | *: "Remaining" | ||
16515 | </voice> | ||
16516 | </phrase> | ||
diff --git a/apps/plugins/playing_time.c b/apps/plugins/playing_time.c index 5916e4e58f..54752e987a 100644 --- a/apps/plugins/playing_time.c +++ b/apps/plugins/playing_time.c | |||
@@ -32,10 +32,10 @@ const unsigned char * const byte_units[] = | |||
32 | }; | 32 | }; |
33 | 33 | ||
34 | const int menu_items[] = { | 34 | const int menu_items[] = { |
35 | LANG_PLAYTIME_ELAPSED, | 35 | LANG_REMAINING, |
36 | LANG_PLAYTIME_REMAINING, | 36 | LANG_ELAPSED, |
37 | LANG_PLAYTIME_TRK_ELAPSED, | ||
38 | LANG_PLAYTIME_TRK_REMAINING, | 37 | LANG_PLAYTIME_TRK_REMAINING, |
38 | LANG_PLAYTIME_TRK_ELAPSED, | ||
39 | LANG_PLAYTIME_TRACK, | 39 | LANG_PLAYTIME_TRACK, |
40 | LANG_PLAYTIME_STORAGE, | 40 | LANG_PLAYTIME_STORAGE, |
41 | LANG_PLAYTIME_AVG_TRACK_SIZE, | 41 | LANG_PLAYTIME_AVG_TRACK_SIZE, |
@@ -54,14 +54,61 @@ enum ePT_SUM { | |||
54 | }; | 54 | }; |
55 | 55 | ||
56 | struct playing_time_info { | 56 | struct playing_time_info { |
57 | int nb_tracks; /* number of tracks in playlist */ | 57 | char single_mode_tag[MAX_PATH]; /* Relevant tag when single mode enabled */ |
58 | int curr_track_index; /* index of currently playing track in playlist */ | 58 | unsigned long long size[ePT_COUNT]; /* File size of tracks */ |
59 | int curr_display_index; /* display index of currently playing track */ | 59 | unsigned long long length[ePT_COUNT]; /* Length of tracks */ |
60 | unsigned long curr_track_length[ePT_COUNT]; /* current track length */ | 60 | unsigned long curr_track_length[ePT_COUNT]; /* Current track length */ |
61 | unsigned long long length[ePT_COUNT]; /* length of all tracks */ | 61 | int curr_track_index; /* Index of currently playing track in playlist */ |
62 | unsigned long long size[ePT_COUNT]; /* file size of all tracks */ | 62 | int curr_display_index; /* Display index of currently playing track */ |
63 | int actual_index; /* Display index in actually counted tracks */ | ||
64 | int counted; /* Number of tracks already added up */ | ||
65 | int nb_tracks; /* Number of tracks in playlist */ | ||
66 | int error_count; /* Number of tracks whose data couldn't be retrieved */ | ||
67 | bool remaining_only; /* Whether to ignore elapsed tracks */ | ||
63 | }; | 68 | }; |
64 | 69 | ||
70 | static int32_t single_mode_lang(void) | ||
71 | { | ||
72 | switch (rb->global_settings->single_mode) | ||
73 | { | ||
74 | case SINGLE_MODE_ALBUM: | ||
75 | return LANG_ID3_ALBUM; | ||
76 | case SINGLE_MODE_ALBUM_ARTIST: | ||
77 | return LANG_ID3_ALBUMARTIST; | ||
78 | case SINGLE_MODE_ARTIST: | ||
79 | return LANG_ID3_ARTIST; | ||
80 | case SINGLE_MODE_COMPOSER: | ||
81 | return LANG_ID3_COMPOSER; | ||
82 | case SINGLE_MODE_GROUPING: | ||
83 | return LANG_ID3_GROUPING; | ||
84 | case SINGLE_MODE_GENRE: | ||
85 | return LANG_ID3_GENRE; | ||
86 | case SINGLE_MODE_TRACK: | ||
87 | return LANG_TRACK; | ||
88 | } | ||
89 | return LANG_OFF; | ||
90 | } | ||
91 | |||
92 | static char* single_mode_id3_tag(struct mp3entry *id3) | ||
93 | { | ||
94 | switch (rb->global_settings->single_mode) | ||
95 | { | ||
96 | case SINGLE_MODE_ALBUM: | ||
97 | return id3->album; | ||
98 | case SINGLE_MODE_ALBUM_ARTIST: | ||
99 | return id3->albumartist; | ||
100 | case SINGLE_MODE_ARTIST: | ||
101 | return id3->artist; | ||
102 | case SINGLE_MODE_COMPOSER: | ||
103 | return id3->composer; | ||
104 | case SINGLE_MODE_GROUPING: | ||
105 | return id3->grouping; | ||
106 | case SINGLE_MODE_GENRE: | ||
107 | return id3->genre_string; | ||
108 | } | ||
109 | return NULL; | ||
110 | } | ||
111 | |||
65 | static char* get_percent_str(long percents) | 112 | static char* get_percent_str(long percents) |
66 | { | 113 | { |
67 | static char val[10]; | 114 | static char val[10]; |
@@ -97,7 +144,18 @@ static const char * pt_get_or_speak_info(int selected_item, void * data, | |||
97 | 144 | ||
98 | /* data */ | 145 | /* data */ |
99 | switch(info_no) { | 146 | switch(info_no) { |
100 | case 0: { /* elapsed and total time */ | 147 | case 0: { /* playlist remaining time */ |
148 | char timestr[25]; | ||
149 | rb->format_time_auto(timestr, sizeof(timestr), | ||
150 | pti->length[ePT_REMAINING], UNIT_SEC, false); | ||
151 | rb->snprintf(buf, buffer_len, "%s", timestr); | ||
152 | |||
153 | if (say_it) | ||
154 | rb_talk_ids(false, menu_name_id, | ||
155 | TALK_ID(pti->length[ePT_REMAINING], UNIT_TIME)); | ||
156 | break; | ||
157 | } | ||
158 | case 1: { /* elapsed and total time */ | ||
101 | char timestr1[25], timestr2[25]; | 159 | char timestr1[25], timestr2[25]; |
102 | rb->format_time_auto(timestr1, sizeof(timestr1), | 160 | rb->format_time_auto(timestr1, sizeof(timestr1), |
103 | pti->length[ePT_ELAPSED], UNIT_SEC, true); | 161 | pti->length[ePT_ELAPSED], UNIT_SEC, true); |
@@ -128,18 +186,18 @@ static const char * pt_get_or_speak_info(int selected_item, void * data, | |||
128 | TALK_ID(elapsed_pct, UNIT_PERCENT)); | 186 | TALK_ID(elapsed_pct, UNIT_PERCENT)); |
129 | break; | 187 | break; |
130 | } | 188 | } |
131 | case 1: { /* playlist remaining time */ | 189 | case 2: { /* track remaining time */ |
132 | char timestr[25]; | 190 | char timestr[25]; |
133 | rb->format_time_auto(timestr, sizeof(timestr), | 191 | rb->format_time_auto(timestr, sizeof(timestr), |
134 | pti->length[ePT_REMAINING], UNIT_SEC, false); | 192 | pti->curr_track_length[ePT_REMAINING], UNIT_SEC, false); |
135 | rb->snprintf(buf, buffer_len, "%s", timestr); | 193 | rb->snprintf(buf, buffer_len, "%s", timestr); |
136 | 194 | ||
137 | if (say_it) | 195 | if (say_it) |
138 | rb_talk_ids(false, menu_name_id, | 196 | rb_talk_ids(false, menu_name_id, |
139 | TALK_ID(pti->length[ePT_REMAINING], UNIT_TIME)); | 197 | TALK_ID(pti->curr_track_length[ePT_REMAINING], UNIT_TIME)); |
140 | break; | 198 | break; |
141 | } | 199 | } |
142 | case 2: { /* track elapsed and duration */ | 200 | case 3: { /* track elapsed and duration */ |
143 | char timestr1[25], timestr2[25]; | 201 | char timestr1[25], timestr2[25]; |
144 | 202 | ||
145 | rb->format_time_auto(timestr1, sizeof(timestr1), | 203 | rb->format_time_auto(timestr1, sizeof(timestr1), |
@@ -170,32 +228,21 @@ static const char * pt_get_or_speak_info(int selected_item, void * data, | |||
170 | TALK_ID(elapsed_pct, UNIT_PERCENT)); | 228 | TALK_ID(elapsed_pct, UNIT_PERCENT)); |
171 | break; | 229 | break; |
172 | } | 230 | } |
173 | case 3: { /* track remaining time */ | ||
174 | char timestr[25]; | ||
175 | rb->format_time_auto(timestr, sizeof(timestr), | ||
176 | pti->curr_track_length[ePT_REMAINING], UNIT_SEC, false); | ||
177 | rb->snprintf(buf, buffer_len, "%s", timestr); | ||
178 | |||
179 | if (say_it) | ||
180 | rb_talk_ids(false, menu_name_id, | ||
181 | TALK_ID(pti->curr_track_length[ePT_REMAINING], UNIT_TIME)); | ||
182 | break; | ||
183 | } | ||
184 | case 4: { /* track index */ | 231 | case 4: { /* track index */ |
185 | int track_pct = pti->curr_display_index * 100 / pti->nb_tracks; | 232 | int track_pct = pti->actual_index * 100 / pti->counted; |
186 | 233 | ||
187 | if (rb->lang_is_rtl()) | 234 | if (rb->lang_is_rtl()) |
188 | rb->snprintf(buf, buffer_len, "%s %d / %d", get_percent_str(track_pct), | 235 | rb->snprintf(buf, buffer_len, "%s %d / %d", get_percent_str(track_pct), |
189 | pti->nb_tracks, pti->curr_display_index); | 236 | pti->counted, pti->actual_index); |
190 | else | 237 | else |
191 | rb->snprintf(buf, buffer_len, "%d / %d %s", pti->curr_display_index, | 238 | rb->snprintf(buf, buffer_len, "%d / %d %s", pti->actual_index, |
192 | pti->nb_tracks, get_percent_str(track_pct)); | 239 | pti->counted, get_percent_str(track_pct)); |
193 | 240 | ||
194 | if (say_it) | 241 | if (say_it) |
195 | rb_talk_ids(false, menu_name_id, | 242 | rb_talk_ids(false, menu_name_id, |
196 | TALK_ID(pti->curr_display_index, UNIT_INT), | 243 | TALK_ID(pti->actual_index, UNIT_INT), |
197 | VOICE_OF, | 244 | VOICE_OF, |
198 | TALK_ID(pti->nb_tracks, UNIT_INT), | 245 | TALK_ID(pti->counted, UNIT_INT), |
199 | VOICE_PAUSE, | 246 | VOICE_PAUSE, |
200 | TALK_ID(track_pct, UNIT_PERCENT)); | 247 | TALK_ID(track_pct, UNIT_PERCENT)); |
201 | break; | 248 | break; |
@@ -215,7 +262,7 @@ static const char * pt_get_or_speak_info(int selected_item, void * data, | |||
215 | int32_t voice_ids[ePT_COUNT]; | 262 | int32_t voice_ids[ePT_COUNT]; |
216 | voice_ids[ePT_TOTAL] = menu_name_id; | 263 | voice_ids[ePT_TOTAL] = menu_name_id; |
217 | voice_ids[ePT_ELAPSED] = VOICE_PLAYTIME_DONE; | 264 | voice_ids[ePT_ELAPSED] = VOICE_PLAYTIME_DONE; |
218 | voice_ids[ePT_REMAINING] = LANG_PLAYTIME_REMAINING; | 265 | voice_ids[ePT_REMAINING] = LANG_REMAINING; |
219 | 266 | ||
220 | for (i = 0; i < ePT_COUNT; i++) | 267 | for (i = 0; i < ePT_COUNT; i++) |
221 | { | 268 | { |
@@ -227,7 +274,7 @@ static const char * pt_get_or_speak_info(int selected_item, void * data, | |||
227 | } | 274 | } |
228 | case 6: { /* Average track file size */ | 275 | case 6: { /* Average track file size */ |
229 | char str[20]; | 276 | char str[20]; |
230 | long avg_track_size = pti->size[ePT_TOTAL] / pti->nb_tracks; | 277 | long avg_track_size = pti->size[ePT_TOTAL] / pti->counted; |
231 | rb->output_dyn_value(str, sizeof(str), avg_track_size, kibyte_units, 3, true); | 278 | rb->output_dyn_value(str, sizeof(str), avg_track_size, kibyte_units, 3, true); |
232 | rb->snprintf(buf, buffer_len, "%s", str); | 279 | rb->snprintf(buf, buffer_len, "%s", str); |
233 | 280 | ||
@@ -266,138 +313,240 @@ static int pt_speak_info(int selected_item, void * data) | |||
266 | return 0; | 313 | return 0; |
267 | } | 314 | } |
268 | 315 | ||
269 | /* playing time screen: shows total and elapsed playlist duration and | 316 | static bool pt_display_stats(struct playing_time_info *pti) |
270 | other stats */ | ||
271 | static bool playing_time(void) | ||
272 | { | 317 | { |
273 | struct playing_time_info pti; | ||
274 | struct playlist_track_info pl_track; | ||
275 | struct mp3entry id3; | ||
276 | struct mp3entry *curr_id3; | ||
277 | struct gui_synclist pt_lists; | 318 | struct gui_synclist pt_lists; |
278 | unsigned long talked_tick = *rb->current_tick; | 319 | rb->gui_synclist_init(&pt_lists, &pt_get_info, pti, true, 2, NULL); |
279 | int action, i, index, section, error_count = 0; | 320 | if (rb->global_settings->talk_menu) |
321 | rb->gui_synclist_set_voice_callback(&pt_lists, pt_speak_info); | ||
322 | rb->gui_synclist_set_nb_items(&pt_lists, pti->remaining_only ? 2 : 8*2); | ||
323 | rb->gui_synclist_set_title(&pt_lists, *pti->single_mode_tag ? | ||
324 | rb->str(single_mode_lang()) : | ||
325 | rb->str(LANG_PLAYLIST), NOICON); | ||
326 | rb->gui_synclist_draw(&pt_lists); | ||
327 | rb->gui_synclist_speak_item(&pt_lists); | ||
328 | while (true) | ||
329 | { | ||
330 | int action = rb->get_action(CONTEXT_LIST, HZ/2); | ||
331 | if (rb->gui_synclist_do_button(&pt_lists, &action) == 0 | ||
332 | && action != ACTION_NONE && action != ACTION_UNKNOWN) | ||
333 | { | ||
334 | bool usb = rb->default_event_handler(action) == SYS_USB_CONNECTED; | ||
280 | 335 | ||
281 | pti.nb_tracks = rb->playlist_amount(); | 336 | if (!usb && IS_SYSEVENT(action)) |
282 | rb->playlist_get_resume_info(&pti.curr_track_index); | 337 | continue; |
283 | curr_id3 = rb->audio_current_track(); | ||
284 | 338 | ||
285 | if (pti.curr_track_index == -1 || !curr_id3) | 339 | rb->talk_force_shutup(); |
286 | return false; | 340 | return usb; |
341 | } | ||
342 | } | ||
343 | return false; | ||
344 | } | ||
287 | 345 | ||
288 | pti.curr_display_index = rb->playlist_get_display_index(); | 346 | static const char *pt_options_name(int selected_item, void * data, |
347 | char *buf, size_t buf_size) | ||
348 | { | ||
349 | (void) data; | ||
350 | (void) buf; | ||
351 | (void) buf_size; | ||
352 | return selected_item == 0 ? rb->str(LANG_ALL) : | ||
353 | selected_item == 1 ? rb->str(LANG_REMAINING) : | ||
354 | rb->str(single_mode_lang()); | ||
355 | } | ||
289 | 356 | ||
290 | pti.length[ePT_ELAPSED] = pti.curr_track_length[ePT_ELAPSED] | 357 | static int pt_options_speak(int selected_item, void * data) |
291 | = curr_id3->elapsed; | 358 | { |
292 | pti.length[ePT_REMAINING] = pti.curr_track_length[ePT_REMAINING] | 359 | (void) data; |
293 | = curr_id3->length - curr_id3->elapsed; | 360 | rb->talk_id(selected_item == 0 ? LANG_ALL : |
361 | selected_item == 1 ? LANG_REMAINING : | ||
362 | single_mode_lang(), false); | ||
363 | return 0; | ||
364 | } | ||
294 | 365 | ||
295 | pti.size[ePT_ELAPSED] = curr_id3->offset; | 366 | static int pt_options(struct playing_time_info *pti) |
296 | pti.size[ePT_REMAINING] = curr_id3->filesize - curr_id3->offset; | 367 | { |
368 | struct gui_synclist pt_options; | ||
369 | rb->gui_synclist_init(&pt_options, &pt_options_name, NULL, true, 1, NULL); | ||
370 | if (rb->global_settings->talk_menu) | ||
371 | rb->gui_synclist_set_voice_callback(&pt_options, pt_options_speak); | ||
372 | rb->gui_synclist_set_nb_items(&pt_options, *pti->single_mode_tag ? 3 : 2); | ||
373 | rb->gui_synclist_set_title(&pt_options, rb->str(LANG_PLAYING_TIME), NOICON); | ||
374 | rb->gui_synclist_draw(&pt_options); | ||
375 | rb->gui_synclist_speak_item(&pt_options); | ||
297 | 376 | ||
298 | rb->splash_progress_set_delay(HZ/2); | 377 | while(true) |
378 | { | ||
379 | int button = rb->get_action(CONTEXT_LIST, HZ); | ||
380 | if (rb->gui_synclist_do_button(&pt_options, &button)) | ||
381 | continue; | ||
382 | switch(button) | ||
383 | { | ||
384 | case ACTION_STD_OK: | ||
385 | { | ||
386 | int sel = rb->gui_synclist_get_sel_pos(&pt_options); | ||
387 | if (sel < 2) | ||
388 | *pti->single_mode_tag = 0; | ||
389 | if (sel == 1) | ||
390 | pti->remaining_only = true; | ||
391 | return -1; | ||
392 | } | ||
393 | case ACTION_STD_CANCEL: | ||
394 | return 0; | ||
395 | default: | ||
396 | if (rb->default_event_handler(button) == SYS_USB_CONNECTED) | ||
397 | return 1; | ||
398 | } | ||
399 | } | ||
400 | } | ||
299 | 401 | ||
300 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | 402 | static void pt_store_converted_totals(struct playing_time_info *pti) |
301 | rb->cpu_boost(true); | 403 | { |
302 | #endif | 404 | /* convert units from ms to s */ |
303 | /* Go through each file in the playlist and get its stats. For | 405 | pti->length[ePT_ELAPSED] /= 1000; |
304 | huge playlists this can take a while... The reference position | 406 | pti->length[ePT_REMAINING] /= 1000; |
305 | is the position at the moment this function was invoked, | 407 | pti->curr_track_length[ePT_ELAPSED] /= 1000; |
306 | although playback continues forward. */ | 408 | pti->curr_track_length[ePT_REMAINING] /= 1000; |
307 | index = rb->playlist_get_first_index(NULL); | 409 | /* convert units from Bytes to KiB */ |
308 | for (i = 0; i < pti.nb_tracks; i++, index++) { | 410 | pti->size[ePT_ELAPSED] >>= 10; |
411 | pti->size[ePT_REMAINING] >>= 10; | ||
309 | 412 | ||
310 | if (index == pti.nb_tracks) | 413 | pti->length[ePT_TOTAL] = pti->length[ePT_ELAPSED] + pti->length[ePT_REMAINING]; |
311 | index = 0; | 414 | pti->curr_track_length[ePT_TOTAL] = pti->curr_track_length[ePT_ELAPSED] |
415 | + pti->curr_track_length[ePT_REMAINING]; | ||
416 | pti->size[ePT_TOTAL] = pti->size[ePT_ELAPSED] + pti->size[ePT_REMAINING]; | ||
417 | } | ||
312 | 418 | ||
313 | rb->splash_progress(i, pti.nb_tracks, "%s (%s)", | 419 | static int pt_add_track(int i, enum ePT_SUM section, struct playing_time_info *pti) |
314 | rb->str(LANG_WAIT), rb->str(LANG_OFF_ABORT)); | 420 | { |
421 | struct mp3entry id3; | ||
422 | struct playlist_track_info pl_track; | ||
423 | static unsigned long talked_tick; | ||
424 | int progress_total = pti->remaining_only ? | ||
425 | pti->nb_tracks - pti->curr_display_index : | ||
426 | pti->nb_tracks; | ||
315 | 427 | ||
316 | if (TIME_AFTER(*rb->current_tick, talked_tick + HZ*5)) | 428 | rb->splash_progress(pti->counted, progress_total, "%s (%s)", |
317 | { | 429 | rb->str(LANG_WAIT), rb->str(LANG_OFF_ABORT)); |
318 | talked_tick = *rb->current_tick; | ||
319 | rb_talk_ids(false, LANG_LOADING_PERCENT, | ||
320 | TALK_ID(i * 100 / pti.nb_tracks, UNIT_PERCENT)); | ||
321 | } | ||
322 | if (rb->action_userabort(TIMEOUT_NOBLOCK)) | ||
323 | { | ||
324 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
325 | rb->cpu_boost(false); | ||
326 | #endif | ||
327 | goto exit; | ||
328 | } | ||
329 | 430 | ||
330 | if (index == pti.curr_track_index) | 431 | if (TIME_AFTER(*rb->current_tick, talked_tick + HZ*5)) |
331 | continue; | 432 | { |
433 | talked_tick = *rb->current_tick; | ||
434 | rb_talk_ids(false, LANG_LOADING_PERCENT, | ||
435 | TALK_ID(pti->counted * 100 / progress_total, | ||
436 | UNIT_PERCENT)); | ||
437 | } | ||
332 | 438 | ||
333 | if (rb->playlist_get_track_info(NULL, index, &pl_track) < 0 | 439 | if (rb->action_userabort(TIMEOUT_NOBLOCK)) |
334 | || !rb->get_metadata(&id3, -1, pl_track.filename)) | 440 | return -1; |
335 | { | 441 | else if (rb->playlist_get_track_info(NULL, i, &pl_track) < 0 |
336 | error_count++; | 442 | || !rb->get_metadata(&id3, -1, pl_track.filename)) |
337 | continue; | 443 | { |
338 | } | 444 | pti->error_count++; |
445 | return -2; | ||
446 | } | ||
447 | else if(*pti->single_mode_tag && /* single mode tag doesn't match */ | ||
448 | rb->strcmp(pti->single_mode_tag, single_mode_id3_tag(&id3) ?: "")) | ||
449 | return 1; | ||
450 | |||
451 | pti->length[section] += id3.length; | ||
452 | pti->size[section] += id3.filesize; | ||
453 | pti->counted++; | ||
454 | return 0; | ||
455 | } | ||
339 | 456 | ||
340 | section = pl_track.display_index < pti.curr_display_index ? | 457 | static bool pt_add_remaining(struct playing_time_info *pti) |
341 | ePT_ELAPSED : ePT_REMAINING; | 458 | { |
342 | pti.length[section] += id3.length; | 459 | int display_index = pti->curr_display_index + 1; |
343 | pti.size[section] += id3.filesize; | 460 | for (int i = pti->curr_track_index + 1; display_index <= pti->nb_tracks; i++, display_index++) |
461 | { | ||
462 | if (i == pti->nb_tracks) | ||
463 | i = 0; | ||
464 | |||
465 | int ret = pt_add_track(i, ePT_REMAINING, pti); | ||
466 | if (ret == 1) | ||
467 | break; | ||
468 | else if (ret == -1) | ||
469 | return false; | ||
344 | } | 470 | } |
345 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | 471 | return true; |
346 | rb->cpu_boost(false); | 472 | } |
347 | #endif | ||
348 | 473 | ||
349 | if (error_count > 0) | 474 | static bool pt_add_elapsed(struct playing_time_info *pti) |
350 | rb->splash(HZ, ID2P(LANG_PLAYTIME_ERROR)); | 475 | { |
476 | int display_index = pti->curr_display_index - 1; | ||
477 | for (int i = pti->curr_track_index - 1; display_index > 0; i--, display_index--) | ||
478 | { | ||
479 | if (i < 0) | ||
480 | i = pti->nb_tracks - 1; | ||
481 | |||
482 | int ret = pt_add_track(i, ePT_ELAPSED, pti); | ||
483 | if (ret == 1) | ||
484 | break; | ||
485 | else if (ret == -1) | ||
486 | return false; | ||
487 | else if (ret == 0) | ||
488 | pti->actual_index++; | ||
489 | } | ||
490 | return true; | ||
491 | } | ||
351 | 492 | ||
352 | pti.nb_tracks -= error_count; | 493 | static bool pt_add_curr_track(struct playing_time_info *pti) |
494 | { | ||
495 | struct mp3entry *curr_id3 = rb->audio_current_track(); | ||
496 | rb->playlist_get_resume_info(&pti->curr_track_index); | ||
353 | 497 | ||
354 | /* convert units from ms to s */ | 498 | if (pti->curr_track_index == -1 || !curr_id3) |
355 | pti.length[ePT_ELAPSED] /= 1000; | 499 | return false; |
356 | pti.length[ePT_REMAINING] /= 1000; | ||
357 | pti.curr_track_length[ePT_ELAPSED] /= 1000; | ||
358 | pti.curr_track_length[ePT_REMAINING] /= 1000; | ||
359 | /* convert units from Bytes to KiB */ | ||
360 | pti.size[ePT_ELAPSED] >>= 10; | ||
361 | pti.size[ePT_REMAINING] >>= 10; | ||
362 | 500 | ||
363 | /* calculate totals */ | 501 | pti->curr_display_index = rb->playlist_get_display_index(); |
364 | pti.length[ePT_TOTAL] = pti.length[ePT_ELAPSED] + pti.length[ePT_REMAINING]; | 502 | pti->length[ePT_ELAPSED] = pti->curr_track_length[ePT_ELAPSED] |
365 | pti.curr_track_length[ePT_TOTAL] = pti.curr_track_length[ePT_ELAPSED] | 503 | = curr_id3->elapsed; |
366 | + pti.curr_track_length[ePT_REMAINING]; | 504 | pti->length[ePT_REMAINING] = pti->curr_track_length[ePT_REMAINING] |
367 | pti.size[ePT_TOTAL] = pti.size[ePT_ELAPSED] + pti.size[ePT_REMAINING]; | 505 | = curr_id3->length - curr_id3->elapsed; |
506 | pti->size[ePT_ELAPSED] = curr_id3->offset; | ||
507 | pti->size[ePT_REMAINING] = curr_id3->filesize - curr_id3->offset; | ||
508 | pti->actual_index = pti->counted = 1; | ||
509 | rb->strlcpy(pti->single_mode_tag, single_mode_id3_tag(curr_id3) ?: "", | ||
510 | sizeof(pti->single_mode_tag)); | ||
511 | return true; | ||
512 | } | ||
368 | 513 | ||
369 | rb->gui_synclist_init(&pt_lists, &pt_get_info, &pti, true, 2, NULL); | 514 | /* playing time screen: shows total and elapsed playlist duration and |
370 | if (rb->global_settings->talk_menu) | 515 | other stats */ |
371 | rb->gui_synclist_set_voice_callback(&pt_lists, pt_speak_info); | 516 | static bool playing_time(void) |
372 | rb->gui_synclist_set_nb_items(&pt_lists, 16); | 517 | { |
373 | rb->gui_synclist_set_title(&pt_lists, rb->str(LANG_PLAYING_TIME), NOICON); | 518 | struct playing_time_info pti = {0}; |
374 | rb->gui_synclist_draw(&pt_lists); | ||
375 | rb->gui_synclist_speak_item(&pt_lists); | ||
376 | while (true) | ||
377 | { | ||
378 | action = rb->get_action(CONTEXT_LIST, HZ/2); | ||
379 | if (rb->gui_synclist_do_button(&pt_lists, &action) == 0 | ||
380 | && action != ACTION_NONE && action != ACTION_UNKNOWN) | ||
381 | { | ||
382 | bool usb = rb->default_event_handler(action) == SYS_USB_CONNECTED; | ||
383 | 519 | ||
384 | if (!usb && IS_SYSEVENT(action)) | 520 | if (!pt_add_curr_track(&pti)) |
385 | continue; | 521 | return false; |
386 | 522 | ||
387 | rb->talk_force_shutup(); | 523 | int opt = pt_options(&pti); |
388 | return usb; | 524 | if (opt > -1) |
389 | } | 525 | return opt; |
390 | } | 526 | |
391 | exit: | 527 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
392 | return false; | 528 | rb->cpu_boost(true); |
529 | #endif | ||
530 | rb->splash_progress_set_delay(HZ/2); | ||
531 | pti.nb_tracks = rb->playlist_amount(); | ||
532 | int success = (pti.remaining_only || pt_add_elapsed(&pti)) && pt_add_remaining(&pti); | ||
533 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
534 | rb->cpu_boost(false); | ||
535 | #endif | ||
536 | if (!success) | ||
537 | return false; | ||
538 | if (pti.error_count > 0) | ||
539 | rb->splash(HZ, ID2P(LANG_PLAYTIME_ERROR)); | ||
540 | |||
541 | pt_store_converted_totals(&pti); | ||
542 | return pt_display_stats(&pti); | ||
393 | } | 543 | } |
394 | 544 | ||
395 | /* this is the plugin entry point */ | 545 | /* this is the plugin entry point */ |
396 | enum plugin_status plugin_start(const void* parameter) | 546 | enum plugin_status plugin_start(const void* parameter) |
397 | { | 547 | { |
398 | enum plugin_status status = PLUGIN_OK; | ||
399 | |||
400 | (void)parameter; | 548 | (void)parameter; |
549 | enum plugin_status status = PLUGIN_OK; | ||
401 | 550 | ||
402 | if (!rb->audio_status()) | 551 | if (!rb->audio_status()) |
403 | { | 552 | { |