diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index c4164c3b4b..8718d730fb 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c @@ -741,7 +741,7 @@ void pcmbuf_start_track_change(enum pcm_track_change_type type) } } - if (auto_skip && global_settings.single_mode && !global_settings.party_mode) + if (auto_skip && global_settings.single_mode != SINGLE_MODE_OFF && !global_settings.party_mode) crossfade = false; if (crossfade) diff --git a/apps/playback.c b/apps/playback.c index 5d980b5634..4162d9b647 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -2367,6 +2367,31 @@ static void audio_on_handle_finished(int hid) } } +static inline char* single_mode_get_id3_tag(struct mp3entry *id3) +{ + struct mp3entry *valid_id3 = valid_mp3entry(id3); + if (valid_id3 == NULL) + return NULL; + + switch (global_settings.single_mode) + { + case SINGLE_MODE_ALBUM: + return valid_id3->album; + case SINGLE_MODE_ALBUM_ARTIST: + return valid_id3->albumartist; + case SINGLE_MODE_ARTIST: + return valid_id3->artist; + case SINGLE_MODE_COMPOSER: + return valid_id3->composer; + case SINGLE_MODE_GROUPING: + return valid_id3->grouping; + case SINGLE_MODE_GENRE: + return valid_id3->genre_string; + } + + return NULL; +} + /* Called to make an outstanding track skip the current track and to send the transition events */ static void audio_finalise_track_change(void) @@ -2422,15 +2447,27 @@ static void audio_finalise_track_change(void) track_id3 = bufgetid3(info.id3_hid); } - id3_write(PLAYING_ID3, track_id3); + 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 (global_settings.single_mode) - if ( ((skip_pending == TRACK_SKIP_AUTO) || (skip_pending == TRACK_SKIP_AUTO_NEW_PLAYLIST)) - && (global_settings.party_mode == 0) ) + if (single_mode_do_pause) { play_status = PLAY_PAUSED; pcmbuf_pause(true); } + } + + id3_write(PLAYING_ID3, track_id3); /* The skip is technically over */ skip_pending = TRACK_SKIP_NONE; diff --git a/apps/settings.h b/apps/settings.h index 79b47f6a0f..b3c31476e3 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -108,6 +108,18 @@ enum NUM_REPEAT_MODES }; +/* single mode options */ +enum { + SINGLE_MODE_OFF = 0, + SINGLE_MODE_TRACK, + SINGLE_MODE_ALBUM, + SINGLE_MODE_ALBUM_ARTIST, + SINGLE_MODE_ARTIST, + SINGLE_MODE_COMPOSER, + SINGLE_MODE_GROUPING, + SINGLE_MODE_GENRE +}; + enum { QUEUE_HIDE = 0, @@ -476,7 +488,8 @@ struct user_settings int default_codepage; /* set default codepage for tag conversion */ bool hold_lr_for_scroll_in_list; /* hold L/R scrolls the list left/right */ bool play_selected; /* Plays selected file even in shuffle mode */ - bool single_mode; /* single mode - stop after every track */ + int single_mode; /* single mode - stop after every track, album, album artist, + artist, composer, work, or genre */ bool party_mode; /* party mode - unstoppable music */ bool audioscrobbler; /* Audioscrobbler logging */ bool cuesheet; diff --git a/apps/settings_list.c b/apps/settings_list.c index f93b3c272a..982b483874 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c @@ -1243,7 +1243,18 @@ const struct settings_list settings[] = { #endif /* more playback */ OFFON_SETTING(0,play_selected,LANG_PLAY_SELECTED,true,"play selected",NULL), - OFFON_SETTING(0,single_mode,LANG_SINGLE_MODE,false,"single mode",NULL), + CHOICE_SETTING(0, single_mode, LANG_SINGLE_MODE, 0, + "single mode", + "off,track,album,album artist,artist,composer,work,genre", + NULL, 8, + ID2P(LANG_OFF), + ID2P(LANG_TRACK), + ID2P(LANG_ID3_ALBUM), + ID2P(LANG_ID3_ALBUMARTIST), + ID2P(LANG_ID3_ARTIST), + ID2P(LANG_ID3_COMPOSER), + ID2P(LANG_ID3_GROUPING), + ID2P(LANG_ID3_GENRE)), OFFON_SETTING(0,party_mode,LANG_PARTY_MODE,false,"party mode",NULL), OFFON_SETTING(0,fade_on_stop,LANG_FADE_ON_STOP,true,"volume fade",NULL), INT_SETTING(F_TIME_SETTING, ff_rewind_min_step, LANG_FFRW_STEP, 1, diff --git a/manual/appendix/config_file_options.tex b/manual/appendix/config_file_options.tex index 257a3bc48e..40945e6397 100644 --- a/manual/appendix/config_file_options.tex +++ b/manual/appendix/config_file_options.tex @@ -37,7 +37,8 @@ repeat & off, all, one, shuffle, ab & N/A\\ play selected & on, off & N/A\\ - single mode & on, off & N/A\\ + single mode & off, track, album, album artist, artist, composer, work, genre + & N/A\\ party mode & on, off & N/A\\ scan min step & 1, 2, 3, 4, 5, 6, 8, 10, 15, 20, 25, 30, 45, 60 & s\\ diff --git a/manual/configure_rockbox/playback_options.tex b/manual/configure_rockbox/playback_options.tex index f9f50593e6..6c8f5de316 100644 --- a/manual/configure_rockbox/playback_options.tex +++ b/manual/configure_rockbox/playback_options.tex @@ -83,9 +83,12 @@ you to configure settings related to audio playback. playback, and fade in when you resume playback. \section{Single Mode} - If the Single Mode option is set to \setting{Yes}, your music - will pause at every automatic track change. Crossfade on track - change will be ignored if this setting is enabled. + If the Single Mode option is set to \setting{Track}, your music + will pause at every automatic track change. + If it is set to \setting{Album}, \setting{Album Artist}, \setting{Artist}, + \setting{Composer}, \setting{Work}, or \setting{Genre}, + your music will pause at the next track change where this tag also + changes. Crossfade on track change will be ignored if this setting is enabled. \section{Party Mode} Enables unstoppable music playback. When new songs are