From fe5375a6cb8761e6af33ac1c2cddbe0c76200d91 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Wed, 24 Jan 2024 10:57:17 +0200 Subject: Improve Crossfade handling in Single Mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Crossfade (see Playback Settings -> Crossfade) now works between songs in Single Mode (see Playback Settings -> Single Mode) unless it’s the last song to be played. Change-Id: Icfe3d48459bb35bbc050f237a68b27e793ab9152 --- apps/pcmbuf.c | 3 -- apps/playback.c | 160 ++++++++++++++++++++++++++++++-------------------------- 2 files changed, 86 insertions(+), 77 deletions(-) (limited to 'apps') diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index 8718d730fb..773e97cce0 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c @@ -741,9 +741,6 @@ void pcmbuf_start_track_change(enum pcm_track_change_type type) } } - if (auto_skip && global_settings.single_mode != SINGLE_MODE_OFF && !global_settings.party_mode) - crossfade = false; - if (crossfade) { logf("crossfade track change"); diff --git a/apps/playback.c b/apps/playback.c index 8a30af5199..a284a1858d 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -2494,6 +2494,23 @@ static inline char* single_mode_get_id3_tag(struct mp3entry *id3) return NULL; } +static bool single_mode_do_pause(int id3_hid) +{ + if (global_settings.single_mode != SINGLE_MODE_OFF && global_settings.party_mode == 0 && + ((skip_pending == TRACK_SKIP_AUTO) || (skip_pending == TRACK_SKIP_AUTO_NEW_PLAYLIST))) { + + if (global_settings.single_mode == SINGLE_MODE_TRACK) + return true; + + char *previous_tag = single_mode_get_id3_tag(id3_get(PLAYING_ID3)); + char *new_tag = single_mode_get_id3_tag(bufgetid3(id3_hid)); + return previous_tag == NULL || + new_tag == NULL || + strcmp(previous_tag, new_tag) != 0; + } + return false; +} + /* Called to make an outstanding track skip the current track and to send the transition events */ static void audio_finalise_track_change(void) @@ -2540,43 +2557,28 @@ static void audio_finalise_track_change(void) bool have_info = track_list_current(0, &info); struct mp3entry *track_id3 = NULL; - id3_mutex_lock(); - /* Update the current cuesheet if any and enabled */ if (have_info) { buf_read_cuesheet(info.cuesheet_hid); track_id3 = bufgetid3(info.id3_hid); - } - - if (SINGLE_MODE_OFF != global_settings.single_mode && global_settings.party_mode == 0 && - ((skip_pending == TRACK_SKIP_AUTO) || (skip_pending == TRACK_SKIP_AUTO_NEW_PLAYLIST))) - { - bool single_mode_do_pause = true; - if (SINGLE_MODE_TRACK != global_settings.single_mode) - { - char *previous_tag = single_mode_get_id3_tag(id3_get(PLAYING_ID3)); - char *new_tag = single_mode_get_id3_tag(track_id3); - single_mode_do_pause = previous_tag == NULL || - new_tag == NULL || - strcmp(previous_tag, new_tag) != 0; - } - if (single_mode_do_pause) + if (single_mode_do_pause(info.id3_hid)) { play_status = PLAY_PAUSED; pcmbuf_pause(true); } } + /* Sync the next track information */ + have_info = track_list_current(1, &info); + + id3_mutex_lock(); id3_write(PLAYING_ID3, track_id3); /* The skip is technically over */ skip_pending = TRACK_SKIP_NONE; - /* Sync the next track information */ - have_info = track_list_current(1, &info); - id3_write(NEXTTRACK_ID3, have_info ? bufgetid3(info.id3_hid) : id3_get(UNBUFFERED_ID3)); @@ -2641,54 +2643,12 @@ static void audio_monitor_end_of_playlist(void) pcmbuf_start_track_change(TRACK_CHANGE_END_OF_DATA); } -/* Codec has completed decoding the track - (usually Q_AUDIO_CODEC_COMPLETE) */ -static void audio_on_codec_complete(int status) +/* Does this track have an entry allocated? */ +static bool audio_can_change_track(int *trackstat, int *id3_hid) { - logf("%s(%d)", __func__, status); - - if (play_status == PLAY_STOPPED) - return; - - /* If it didn't notify us first, don't expect "seek complete" message - since the codec can't post it now - do things like it would have - done */ - audio_complete_codec_seek(); - - if (play_status == PLAY_PAUSED || skip_pending != TRACK_SKIP_NONE) - { - /* Old-hay on the ip-skay - codec has completed decoding - - Paused: We're not sounding it, so just remember that it happened - and the resume will begin the transition - - Skipping: There was already a skip in progress, remember it and - allow no further progress until the PCM from the previous - song has finished - - This function will be reentered upon completing the existing - transition in order to do the one that was just tried (below) - */ - codec_skip_pending = true; - codec_skip_status = status; - - /* PCM buffer must know; audio could still be filling and hasn't - yet reached the play watermark */ - pcmbuf_start_track_change(TRACK_CHANGE_AUTO_PILEUP); - return; - } - - codec_skip_pending = false; - - int trackstat = LOAD_TRACK_OK; - - track_event_flags = TEF_AUTO_SKIP; - skip_pending = TRACK_SKIP_AUTO; - - /* Does this track have an entry allocated? */ struct track_info info; bool have_track = track_list_advance_current(1, &info); - + *id3_hid = info.id3_hid; if (!have_track || info.audio_hid < 0) { bool end_of_playlist = false; @@ -2697,8 +2657,8 @@ static void audio_on_codec_complete(int status) { if (filling == STATE_STOPPED) { - audio_begin_track_change(TRACK_CHANGE_END_OF_DATA, trackstat); - return; + audio_begin_track_change(TRACK_CHANGE_END_OF_DATA, *trackstat); + return false; } /* Track load is not complete - it might have stopped on a @@ -2719,8 +2679,7 @@ static void audio_on_codec_complete(int status) { /* Continue filling after this track */ audio_reset_and_rebuffer(TRACK_LIST_KEEP_CURRENT, 1); - audio_begin_track_change(TRACK_CHANGE_AUTO, trackstat); - return; + return true; } /* else rebuffer at this track; status applies to the track we want */ @@ -2736,10 +2695,10 @@ static void audio_on_codec_complete(int status) if (!end_of_playlist) { - trackstat = audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL, - skip_pending == TRACK_SKIP_AUTO ? 0 : -1); + *trackstat = audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL, + skip_pending == TRACK_SKIP_AUTO ? 0 : -1); - if (trackstat == LOAD_TRACK_ERR_NO_MORE) + if (*trackstat == LOAD_TRACK_ERR_NO_MORE) { /* Failed to find anything after all - do playlist switchover instead */ @@ -2751,11 +2710,64 @@ static void audio_on_codec_complete(int status) if (end_of_playlist) { audio_monitor_end_of_playlist(); - return; + return false; } } + return true; +} + +/* Codec has completed decoding the track + (usually Q_AUDIO_CODEC_COMPLETE) */ +static void audio_on_codec_complete(int status) +{ + logf("%s(%d)", __func__, status); - audio_begin_track_change(TRACK_CHANGE_AUTO, trackstat); + if (play_status == PLAY_STOPPED) + return; + + /* If it didn't notify us first, don't expect "seek complete" message + since the codec can't post it now - do things like it would have + done */ + audio_complete_codec_seek(); + + if (play_status == PLAY_PAUSED || skip_pending != TRACK_SKIP_NONE) + { + /* Old-hay on the ip-skay - codec has completed decoding + + Paused: We're not sounding it, so just remember that it happened + and the resume will begin the transition + + Skipping: There was already a skip in progress, remember it and + allow no further progress until the PCM from the previous + song has finished + + This function will be reentered upon completing the existing + transition in order to do the one that was just tried (below) + */ + codec_skip_pending = true; + codec_skip_status = status; + + /* PCM buffer must know; audio could still be filling and hasn't + yet reached the play watermark */ + pcmbuf_start_track_change(TRACK_CHANGE_AUTO_PILEUP); + return; + } + + codec_skip_pending = false; + + int trackstat = LOAD_TRACK_OK; + + track_event_flags = TEF_AUTO_SKIP; + skip_pending = TRACK_SKIP_AUTO; + + int id3_hid = 0; + if (audio_can_change_track(&trackstat, &id3_hid)) + { + audio_begin_track_change( + single_mode_do_pause(id3_hid) + ? TRACK_CHANGE_END_OF_DATA + : TRACK_CHANGE_AUTO, trackstat); + } } /* Called when codec completes seek operation -- cgit v1.2.3