From ffe2df2e92cbdeb507a49279a85ac88cac2fbe4f Mon Sep 17 00:00:00 2001 From: "roman.artiukhin" Date: Sat, 5 Nov 2022 20:51:02 +0200 Subject: Implement Rewind across tracks functionality Useful feature for audiobooks. To rewind from the end of the previous track - press rewind at the very beginning of the current track. So if you are in the middle of the track - first rewind till beginning then release and press rewind button again (Playback Settings -> Rewind Across Tracks option should be enabled) Fixes FS#13290 Change-Id: I5d7f06f64ad76d1e8f7827fe594ccca5f621769d --- apps/gui/wps.c | 57 ++++++++++++++++++--------- apps/lang/english.lang | 14 +++++++ apps/menus/playback_menu.c | 2 + apps/settings.h | 3 +- apps/settings_list.c | 2 +- docs/CREDITS | 1 + manual/appendix/config_file_options.tex | 2 + manual/configure_rockbox/playback_options.tex | 5 +++ 8 files changed, 66 insertions(+), 20 deletions(-) diff --git a/apps/gui/wps.c b/apps/gui/wps.c index 9d7a4c96f3..05a64370ac 100644 --- a/apps/gui/wps.c +++ b/apps/gui/wps.c @@ -202,7 +202,7 @@ static int skintouch_to_wps(struct wps_data *data) } #endif /* HAVE_TOUCHSCREEN */ -static bool ffwd_rew(int button) +static bool ffwd_rew(int button, bool seek_from_end) { unsigned int step = 0; /* current ff/rewind step */ unsigned int max_step = 0; /* maximum ff/rewind step */ @@ -213,6 +213,7 @@ static bool ffwd_rew(int button) bool ff_rewind = false; const long ff_rw_accel = (global_settings.ff_rewind_accel + 3); struct wps_state *gstate = get_wps_state(); + struct mp3entry *old_id3 = gstate->id3; if (button == ACTION_NONE) { @@ -221,6 +222,16 @@ static bool ffwd_rew(int button) } while (!exit) { + struct mp3entry *id3 = gstate->id3; + if (id3 != old_id3) + { + ff_rewind = false; + ff_rewind_count = 0; + old_id3 = id3; + } + if (id3 && seek_from_end) + id3->elapsed = id3->length; + switch ( button ) { case ACTION_WPS_SEEKFWD: @@ -232,16 +243,16 @@ static bool ffwd_rew(int button) if (direction == 1) { /* fast forwarding, calc max step relative to end */ - max_step = (gstate->id3->length - - (gstate->id3->elapsed + + max_step = (id3->length - + (id3->elapsed + ff_rewind_count)) * FF_REWIND_MAX_PERCENT / 100; } else { /* rewinding, calc max step relative to start */ - max_step = (gstate->id3->elapsed + ff_rewind_count) * - FF_REWIND_MAX_PERCENT / 100; + max_step = (id3->elapsed + ff_rewind_count) * + FF_REWIND_MAX_PERCENT / 100; } max_step = MAX(max_step, MIN_FF_REWIND_STEP); @@ -256,8 +267,7 @@ static bool ffwd_rew(int button) } else { - if ( (audio_status() & AUDIO_STATUS_PLAY) && - gstate->id3 && gstate->id3->length ) + if ((audio_status() & AUDIO_STATUS_PLAY) && id3 && id3->length ) { audio_pre_ff_rewind(); if (direction > 0) @@ -274,12 +284,12 @@ static bool ffwd_rew(int button) } if (direction > 0) { - if ((gstate->id3->elapsed + ff_rewind_count) > gstate->id3->length) - ff_rewind_count = gstate->id3->length - gstate->id3->elapsed; + if ((id3->elapsed + ff_rewind_count) > id3->length) + ff_rewind_count = id3->length - id3->elapsed; } else { - if ((int)(gstate->id3->elapsed + ff_rewind_count) < 0) - ff_rewind_count = -gstate->id3->elapsed; + if ((int)(id3->elapsed + ff_rewind_count) < 0) + ff_rewind_count = -id3->elapsed; } /* set the wps state ff_rewind_count so the progess info @@ -296,8 +306,8 @@ static bool ffwd_rew(int button) break; case ACTION_WPS_STOPSEEK: - gstate->id3->elapsed = gstate->id3->elapsed+ff_rewind_count; - audio_ff_rewind(gstate->id3->elapsed); + id3->elapsed = id3->elapsed + ff_rewind_count; + audio_ff_rewind(id3->elapsed); gstate->ff_rewind_count = 0; ff_rewind = false; status_set_ffmode(0); @@ -319,8 +329,9 @@ static bool ffwd_rew(int button) if (button == ACTION_TOUCHSCREEN) button = skintouch_to_wps(skin_get_gwps(WPS, SCREEN_MAIN)->data); #endif - if (button != ACTION_WPS_SEEKFWD && - button != ACTION_WPS_SEEKBACK) + if (button != ACTION_WPS_SEEKFWD + && button != ACTION_WPS_SEEKBACK + && button != 0) button = ACTION_WPS_STOPSEEK; } } @@ -733,7 +744,7 @@ long gui_wps_show(void) } } else - ffwd_rew(ACTION_WPS_SEEKFWD); + ffwd_rew(ACTION_WPS_SEEKFWD, false); last_right = last_left = 0; break; /* fast rewind @@ -752,9 +763,19 @@ long gui_wps_show(void) { change_dir(-1); } + } else if (global_settings.rewind_across_tracks + && get_wps_state()->id3->elapsed < DEFAULT_SKIP_THRESH + && playlist_check(-1)) + { + if (!audio_paused) + audio_pause(); + audio_prev(); + ffwd_rew(ACTION_WPS_SEEKBACK, true); + if (!audio_paused) + audio_resume(); } else - ffwd_rew(ACTION_WPS_SEEKBACK); + ffwd_rew(ACTION_WPS_SEEKBACK, false); last_left = last_right = 0; break; @@ -926,7 +947,7 @@ long gui_wps_show(void) break; case ACTION_NONE: /* Timeout, do a partial update */ update = true; - ffwd_rew(button); /* hopefully fix the ffw/rwd bug */ + ffwd_rew(button, false); /* hopefully fix the ffw/rwd bug */ break; #ifdef HAVE_RECORDING case ACTION_WPS_REC: diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 31090aa861..29a2527bec 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -16388,3 +16388,17 @@ clear_settings_on_hold, iriverh10: "Clear settings when reset button is held during startup" + + id: LANG_REWIND_ACROSS_TRACKS + desc: in playback settings menu + user: core + + *: "Rewind Across Tracks" + + + *: "Rewind Across Tracks" + + + *: "Rewind across tracks" + + diff --git a/apps/menus/playback_menu.c b/apps/menus/playback_menu.c index 881a4b5a99..e4945be0b5 100644 --- a/apps/menus/playback_menu.c +++ b/apps/menus/playback_menu.c @@ -174,6 +174,7 @@ MAKE_MENU(unplug_menu, ID2P(LANG_HEADPHONE_UNPLUG), 0, Icon_NOICON, MENUITEM_SETTING(skip_length, &global_settings.skip_length, NULL); MENUITEM_SETTING(prevent_skip, &global_settings.prevent_skip, NULL); +MENUITEM_SETTING(rewind_across_tracks, &global_settings.rewind_across_tracks, NULL); MENUITEM_SETTING(resume_rewind, &global_settings.resume_rewind, NULL); MENUITEM_SETTING(pause_rewind, &global_settings.pause_rewind, NULL); #ifdef HAVE_PLAY_FREQ @@ -226,6 +227,7 @@ MAKE_MENU(playback_settings,ID2P(LANG_PLAYBACK),0, ,&unplug_menu #endif ,&skip_length, &prevent_skip + ,&rewind_across_tracks ,&resume_rewind ,&pause_rewind diff --git a/apps/settings.h b/apps/settings.h index 092c04a76b..37e546f6fc 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -613,7 +613,8 @@ struct user_settings #ifdef HAVE_ALBUMART int album_art; /* switch off album art display or choose preferred source */ #endif - + bool rewind_across_tracks; + /* playlist viewer settings */ bool playlist_viewer_icons; /* display icons on viewer */ bool playlist_viewer_indices; /* display playlist indices on viewer */ diff --git a/apps/settings_list.c b/apps/settings_list.c index 6d01f5c6fc..f54738163a 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c @@ -2061,7 +2061,7 @@ const struct settings_list settings[] = { tsc_is_changed, tsc_set_default), #endif OFFON_SETTING(0, prevent_skip, LANG_PREVENT_SKIPPING, false, "prevent track skip", NULL), - + OFFON_SETTING(0, rewind_across_tracks, LANG_REWIND_ACROSS_TRACKS, false, "rewind across tracks", NULL), #ifdef HAVE_PITCHCONTROL OFFON_SETTING(0, pitch_mode_semitone, LANG_SEMITONE, false, "Semitone pitch change", NULL), diff --git a/docs/CREDITS b/docs/CREDITS index 86e009c8a8..c2422e2367 100644 --- a/docs/CREDITS +++ b/docs/CREDITS @@ -712,6 +712,7 @@ Selami Dinçer Matej Golian James Le Cuirot Michael Landherr +Roman Artiukhin The libmad team The wavpack team diff --git a/manual/appendix/config_file_options.tex b/manual/appendix/config_file_options.tex index bf231de46c..dc186e2d26 100644 --- a/manual/appendix/config_file_options.tex +++ b/manual/appendix/config_file_options.tex @@ -174,6 +174,8 @@ 90s, 2min, 3min, 5min, 10min, 15min & N/A\\ prevent track skip & on, off & N/A\\ + rewind across tracks + & on, off & N/A\\ start in screen & previous, root, files, dB, wps, menu, \opt{recording}{recording, } \opt{radio}{radio, } diff --git a/manual/configure_rockbox/playback_options.tex b/manual/configure_rockbox/playback_options.tex index a2337439db..0c75315214 100644 --- a/manual/configure_rockbox/playback_options.tex +++ b/manual/configure_rockbox/playback_options.tex @@ -287,6 +287,11 @@ you to configure settings related to audio playback. if a track ends, which can be achieved by combining this option with \setting{Repeat} set to \setting{One} +\section{Rewind Across Tracks}\index{Rewind Across Tracks} + Enables rewinding to the end of the previous track. When enabled pressing rewind + at the very beginning of the current track (first 3 seconds) skips to the end of + the previous track. + \section{Rewind Before Resume}\index{Rewind Before Resume} When restarting a track or a bookmark, a short rewind can be done before the playback is started. This can be useful when listening to speech material, -- cgit v1.2.3