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
This commit is contained in:
roman.artiukhin 2022-11-05 20:51:02 +02:00 committed by Aidan MacDonald
parent 30ec10c790
commit ffe2df2e92
8 changed files with 66 additions and 20 deletions

View file

@ -202,7 +202,7 @@ static int skintouch_to_wps(struct wps_data *data)
} }
#endif /* HAVE_TOUCHSCREEN */ #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 step = 0; /* current ff/rewind step */
unsigned int max_step = 0; /* maximum 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; bool ff_rewind = false;
const long ff_rw_accel = (global_settings.ff_rewind_accel + 3); const long ff_rw_accel = (global_settings.ff_rewind_accel + 3);
struct wps_state *gstate = get_wps_state(); struct wps_state *gstate = get_wps_state();
struct mp3entry *old_id3 = gstate->id3;
if (button == ACTION_NONE) if (button == ACTION_NONE)
{ {
@ -221,6 +222,16 @@ static bool ffwd_rew(int button)
} }
while (!exit) 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 ) switch ( button )
{ {
case ACTION_WPS_SEEKFWD: case ACTION_WPS_SEEKFWD:
@ -232,16 +243,16 @@ static bool ffwd_rew(int button)
if (direction == 1) if (direction == 1)
{ {
/* fast forwarding, calc max step relative to end */ /* fast forwarding, calc max step relative to end */
max_step = (gstate->id3->length - max_step = (id3->length -
(gstate->id3->elapsed + (id3->elapsed +
ff_rewind_count)) * ff_rewind_count)) *
FF_REWIND_MAX_PERCENT / 100; FF_REWIND_MAX_PERCENT / 100;
} }
else else
{ {
/* rewinding, calc max step relative to start */ /* rewinding, calc max step relative to start */
max_step = (gstate->id3->elapsed + ff_rewind_count) * max_step = (id3->elapsed + ff_rewind_count) *
FF_REWIND_MAX_PERCENT / 100; FF_REWIND_MAX_PERCENT / 100;
} }
max_step = MAX(max_step, MIN_FF_REWIND_STEP); max_step = MAX(max_step, MIN_FF_REWIND_STEP);
@ -256,8 +267,7 @@ static bool ffwd_rew(int button)
} }
else else
{ {
if ( (audio_status() & AUDIO_STATUS_PLAY) && if ((audio_status() & AUDIO_STATUS_PLAY) && id3 && id3->length )
gstate->id3 && gstate->id3->length )
{ {
audio_pre_ff_rewind(); audio_pre_ff_rewind();
if (direction > 0) if (direction > 0)
@ -274,12 +284,12 @@ static bool ffwd_rew(int button)
} }
if (direction > 0) { if (direction > 0) {
if ((gstate->id3->elapsed + ff_rewind_count) > gstate->id3->length) if ((id3->elapsed + ff_rewind_count) > id3->length)
ff_rewind_count = gstate->id3->length - gstate->id3->elapsed; ff_rewind_count = id3->length - id3->elapsed;
} }
else { else {
if ((int)(gstate->id3->elapsed + ff_rewind_count) < 0) if ((int)(id3->elapsed + ff_rewind_count) < 0)
ff_rewind_count = -gstate->id3->elapsed; ff_rewind_count = -id3->elapsed;
} }
/* set the wps state ff_rewind_count so the progess info /* set the wps state ff_rewind_count so the progess info
@ -296,8 +306,8 @@ static bool ffwd_rew(int button)
break; break;
case ACTION_WPS_STOPSEEK: case ACTION_WPS_STOPSEEK:
gstate->id3->elapsed = gstate->id3->elapsed+ff_rewind_count; id3->elapsed = id3->elapsed + ff_rewind_count;
audio_ff_rewind(gstate->id3->elapsed); audio_ff_rewind(id3->elapsed);
gstate->ff_rewind_count = 0; gstate->ff_rewind_count = 0;
ff_rewind = false; ff_rewind = false;
status_set_ffmode(0); status_set_ffmode(0);
@ -319,8 +329,9 @@ static bool ffwd_rew(int button)
if (button == ACTION_TOUCHSCREEN) if (button == ACTION_TOUCHSCREEN)
button = skintouch_to_wps(skin_get_gwps(WPS, SCREEN_MAIN)->data); button = skintouch_to_wps(skin_get_gwps(WPS, SCREEN_MAIN)->data);
#endif #endif
if (button != ACTION_WPS_SEEKFWD && if (button != ACTION_WPS_SEEKFWD
button != ACTION_WPS_SEEKBACK) && button != ACTION_WPS_SEEKBACK
&& button != 0)
button = ACTION_WPS_STOPSEEK; button = ACTION_WPS_STOPSEEK;
} }
} }
@ -733,7 +744,7 @@ long gui_wps_show(void)
} }
} }
else else
ffwd_rew(ACTION_WPS_SEEKFWD); ffwd_rew(ACTION_WPS_SEEKFWD, false);
last_right = last_left = 0; last_right = last_left = 0;
break; break;
/* fast rewind /* fast rewind
@ -752,9 +763,19 @@ long gui_wps_show(void)
{ {
change_dir(-1); 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 else
ffwd_rew(ACTION_WPS_SEEKBACK); ffwd_rew(ACTION_WPS_SEEKBACK, false);
last_left = last_right = 0; last_left = last_right = 0;
break; break;
@ -926,7 +947,7 @@ long gui_wps_show(void)
break; break;
case ACTION_NONE: /* Timeout, do a partial update */ case ACTION_NONE: /* Timeout, do a partial update */
update = true; update = true;
ffwd_rew(button); /* hopefully fix the ffw/rwd bug */ ffwd_rew(button, false); /* hopefully fix the ffw/rwd bug */
break; break;
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
case ACTION_WPS_REC: case ACTION_WPS_REC:

View file

@ -16388,3 +16388,17 @@
clear_settings_on_hold, iriverh10: "Clear settings when reset button is held during startup" clear_settings_on_hold, iriverh10: "Clear settings when reset button is held during startup"
</voice> </voice>
</phrase> </phrase>
<phrase>
id: LANG_REWIND_ACROSS_TRACKS
desc: in playback settings menu
user: core
<source>
*: "Rewind Across Tracks"
</source>
<dest>
*: "Rewind Across Tracks"
</dest>
<voice>
*: "Rewind across tracks"
</voice>
</phrase>

View file

@ -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(skip_length, &global_settings.skip_length, NULL);
MENUITEM_SETTING(prevent_skip, &global_settings.prevent_skip, 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(resume_rewind, &global_settings.resume_rewind, NULL);
MENUITEM_SETTING(pause_rewind, &global_settings.pause_rewind, NULL); MENUITEM_SETTING(pause_rewind, &global_settings.pause_rewind, NULL);
#ifdef HAVE_PLAY_FREQ #ifdef HAVE_PLAY_FREQ
@ -226,6 +227,7 @@ MAKE_MENU(playback_settings,ID2P(LANG_PLAYBACK),0,
,&unplug_menu ,&unplug_menu
#endif #endif
,&skip_length, &prevent_skip ,&skip_length, &prevent_skip
,&rewind_across_tracks
,&resume_rewind ,&resume_rewind
,&pause_rewind ,&pause_rewind

View file

@ -613,7 +613,8 @@ struct user_settings
#ifdef HAVE_ALBUMART #ifdef HAVE_ALBUMART
int album_art; /* switch off album art display or choose preferred source */ int album_art; /* switch off album art display or choose preferred source */
#endif #endif
bool rewind_across_tracks;
/* playlist viewer settings */ /* playlist viewer settings */
bool playlist_viewer_icons; /* display icons on viewer */ bool playlist_viewer_icons; /* display icons on viewer */
bool playlist_viewer_indices; /* display playlist indices on viewer */ bool playlist_viewer_indices; /* display playlist indices on viewer */

View file

@ -2061,7 +2061,7 @@ const struct settings_list settings[] = {
tsc_is_changed, tsc_set_default), tsc_is_changed, tsc_set_default),
#endif #endif
OFFON_SETTING(0, prevent_skip, LANG_PREVENT_SKIPPING, false, "prevent track skip", NULL), 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 #ifdef HAVE_PITCHCONTROL
OFFON_SETTING(0, pitch_mode_semitone, LANG_SEMITONE, false, OFFON_SETTING(0, pitch_mode_semitone, LANG_SEMITONE, false,
"Semitone pitch change", NULL), "Semitone pitch change", NULL),

View file

@ -712,6 +712,7 @@ Selami Dinçer
Matej Golian Matej Golian
James Le Cuirot James Le Cuirot
Michael Landherr Michael Landherr
Roman Artiukhin
The libmad team The libmad team
The wavpack team The wavpack team

View file

@ -174,6 +174,8 @@
90s, 2min, 3min, 5min, 10min, 15min & N/A\\ 90s, 2min, 3min, 5min, 10min, 15min & N/A\\
prevent track skip prevent track skip
& on, off & N/A\\ & on, off & N/A\\
rewind across tracks
& on, off & N/A\\
start in screen & previous, root, files, dB, wps, menu, start in screen & previous, root, files, dB, wps, menu,
\opt{recording}{recording, } \opt{recording}{recording, }
\opt{radio}{radio, } \opt{radio}{radio, }

View file

@ -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 if a track ends, which can be achieved by combining this option with
\setting{Repeat} set to \setting{One} \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} \section{Rewind Before Resume}\index{Rewind Before Resume}
When restarting a track or a bookmark, a short rewind can be done before the 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, playback is started. This can be useful when listening to speech material,