Index: apps/playlist.c =================================================================== --- apps/playlist.c (revision 16012) +++ apps/playlist.c (working copy) @@ -2719,6 +2719,67 @@ return playlist_amount_ex(NULL); } +/* move to first track of next directory within a playlist */ +int playlist_next_album(void) +{ + struct playlist_info* playlist = ¤t_playlist; + const char* currfullpath; + int dirlen = 0; + int i; + struct playlist_track_info info; + + /* get current track's path */ + currfullpath = audio_current_track()->path; + dirlen = strrchr(currfullpath, '/') - currfullpath + 1; + + /* find the dir, and compare with current dir */ + for (i=playlist->index; i < playlist->amount; i++) + { + if (playlist_get_track_info(playlist, i, &info) == -1) + return -1; + + if (strncmp(currfullpath, info.filename, dirlen) != 0) + { /* we found the next dir */ + playlist_start(i, 0); + return 0; + } + } + + /* fell off the bottom of playlist. do nothing */ + return 0; +} + +/* move to first track of current directory */ +int playlist_prev_album(void) +{ + struct playlist_info* playlist = ¤t_playlist; + const char* currfullpath; + int dirlen = 0; + int i; + struct playlist_track_info info; + + /* get current track's path */ + currfullpath = audio_current_track()->path; + dirlen = strrchr(currfullpath, '/') - currfullpath + 1; + + /* find the dir, and compare with current dir */ + for (i=playlist->index-1; i >= 0; i--) + { + if (playlist_get_track_info(playlist, i, &info) == -1) + return -1; + + if (strncmp(currfullpath, info.filename, dirlen) != 0) + { /* we found the prev dir */ + playlist_start(i+1, 0); + return 0; + } + } + + /* fell off the top of the playlist, plays first track */ + playlist_start(0, 0); + return 0; +} + /* * Create a new playlist If playlist is not NULL then we're loading a * playlist off disk for viewing/editing. The index_buffer is used to store Index: apps/playlist.h =================================================================== --- apps/playlist.h (revision 16012) +++ apps/playlist.h (working copy) @@ -127,6 +127,8 @@ int playlist_update_resume_info(const struct mp3entry* id3); int playlist_get_display_index(void); int playlist_amount(void); +int playlist_next_album(void); +int playlist_prev_album(void); /* Exported functions for all playlists. Pass NULL for playlist_info structure to work with current playlist. */ Index: apps/lang/english.lang =================================================================== --- apps/lang/english.lang (revision 16012) +++ apps/lang/english.lang (working copy) @@ -2108,6 +2108,34 @@ + id: LANG_DIR_SKIP + desc: in playback settings menu. + user: + + *: "Directory Skip by Keypress" + + + *: "Directory Skip by Keypress" + + + *: "Directory Skip by Keypress" + + + + id: LANG_WITHIN_PLAYLIST + desc: in directory skip in playback settings menu. + user: + + *: "Within Playlist" + + + *: "Within Playlist" + + + *: "Within Playlist" + + + id: LANG_AUDIOSCROBBLER desc: "Last.fm Log" in the playback menu user: Index: apps/gui/gwps.c =================================================================== --- apps/gui/gwps.c (revision 16012) +++ apps/gui/gwps.c (working copy) @@ -332,30 +332,28 @@ } } break; - /* fast forward - OR next dir if this is straight after ACTION_WPS_SKIPNEXT */ + /* fast forward */ case ACTION_WPS_SEEKFWD: if (global_settings.party_mode) break; - if (current_tick -last_right < HZ) - { - if (cuesheet_is_enabled() && wps_state.id3->cuesheet_type) - { - audio_next(); - } - else - { - audio_next_dir(); - } - } - else ffwd_rew(ACTION_WPS_SEEKFWD); - last_right = 0; + ffwd_rew(ACTION_WPS_SEEKFWD); + last_right = current_tick; break; - /* fast rewind - OR prev dir if this is straight after ACTION_WPS_SKIPPREV */ + /* fast rewind */ case ACTION_WPS_SEEKBACK: if (global_settings.party_mode) break; + ffwd_rew(ACTION_WPS_SEEKBACK); + last_left = current_tick; + break; + + /* prev / restart + OR prev dir if this is straight after ACTION_WPS_SEEKBACK */ + case ACTION_WPS_SKIPPREV: + if (global_settings.party_mode) + break; + + update_track = true; if (current_tick -last_left < HZ) { if (cuesheet_is_enabled() && wps_state.id3->cuesheet_type) @@ -370,102 +368,120 @@ } else { - audio_prev_dir(); + /* if Directory Skip is set to 'Within Playlist', + move to first song of the current-playing-track's album */ + if (global_settings.directory_skip == 0) + playlist_prev_album(); + else if (global_settings.directory_skip == 1) + audio_prev_dir(); } } - else ffwd_rew(ACTION_WPS_SEEKBACK); - last_left = 0; - break; - - /* prev / restart */ - case ACTION_WPS_SKIPPREV: - if (global_settings.party_mode) - break; - last_left = current_tick; - update_track = true; - + else + { #ifdef AB_REPEAT_ENABLE - /* if we're in A/B repeat mode and the current position - is past the A marker, jump back to the A marker... */ - if ( ab_repeat_mode_enabled() ) - { - if ( ab_after_A_marker(wps_state.id3->elapsed) ) + /* if we're in A/B repeat mode and the current position + is past the A marker, jump back to the A marker... */ + if ( ab_repeat_mode_enabled() ) { - ab_jump_to_A_marker(); - break; + if ( ab_after_A_marker(wps_state.id3->elapsed) ) + { + ab_jump_to_A_marker(); + break; #if (AB_REPEAT_ENABLE == 2) - } else { - ab_reset_markers(); + } else { + ab_reset_markers(); #endif + } } - } - /* ...otherwise, do it normally */ + /* ...otherwise, do it normally */ #endif - if (!wps_state.id3 || (wps_state.id3->elapsed < 3*1000)) { - audio_prev(); - } - else { - - if (cuesheet_is_enabled() && wps_state.id3->cuesheet_type) - { - curr_cuesheet_skip(-1, wps_state.id3->elapsed); - break; + if (!wps_state.id3 || (wps_state.id3->elapsed < 3*1000)) { + audio_prev(); } + else { - if (!wps_state.paused) + if (cuesheet_is_enabled() && wps_state.id3->cuesheet_type) + { + curr_cuesheet_skip(-1, wps_state.id3->elapsed); + break; + } + + if (!wps_state.paused) #if (CONFIG_CODEC == SWCODEC) - audio_pre_ff_rewind(); + audio_pre_ff_rewind(); #else - audio_pause(); + audio_pause(); #endif - audio_ff_rewind(0); + audio_ff_rewind(0); #if (CONFIG_CODEC != SWCODEC) - if (!wps_state.paused) - audio_resume(); + if (!wps_state.paused) + audio_resume(); #endif + } } + last_left = 0; break; - /* next */ + /* next + OR next dir if this is straight after ACTION_WPS_SEEKFWD */ case ACTION_WPS_SKIPNEXT: if (global_settings.party_mode) break; - last_right = current_tick; + update_track = true; - -#ifdef AB_REPEAT_ENABLE - /* if we're in A/B repeat mode and the current position is - before the A marker, jump to the A marker... */ - if ( ab_repeat_mode_enabled() ) + if (current_tick -last_right < HZ) { - if ( ab_before_A_marker(wps_state.id3->elapsed) ) + if (cuesheet_is_enabled() && wps_state.id3->cuesheet_type) { - ab_jump_to_A_marker(); - break; + audio_next(); + } + else + { + /* if Directory Skip is set to 'Within Playlist', + skip to next album in the current playlist. */ + if (global_settings.directory_skip == 0) + playlist_next_album(); + else if (global_settings.directory_skip == 1) + audio_next_dir(); + } + } + else + { +#ifdef AB_REPEAT_ENABLE + /* if we're in A/B repeat mode and the current position is + before the A marker, jump to the A marker... */ + if ( ab_repeat_mode_enabled() ) + { + if ( ab_before_A_marker(wps_state.id3->elapsed) ) + { + ab_jump_to_A_marker(); + break; #if (AB_REPEAT_ENABLE == 2) - } else { - ab_reset_markers(); + } else { + ab_reset_markers(); #endif + } } - } - /* ...otherwise, do it normally */ + /* ...otherwise, do it normally */ #endif - /* take care of if we're playing a cuesheet */ - if (cuesheet_is_enabled() && wps_state.id3->cuesheet_type) - { - if (curr_cuesheet_skip(1, wps_state.id3->elapsed)) + /* take care of if we're playing a cuesheet */ + if (cuesheet_is_enabled() && wps_state.id3->cuesheet_type) { - /* if the result was false, then we really want - to skip to the next track */ - break; + if (curr_cuesheet_skip(1, wps_state.id3->elapsed)) + { + /* if the result was false, then we really want + to skip to the next track */ + break; + } } + + audio_next(); } - - audio_next(); + last_right = 0; break; /* next / prev directories */ /* and set A-B markers if in a-b mode */ Index: apps/settings.h =================================================================== --- apps/settings.h (revision 16012) +++ apps/settings.h (working copy) @@ -545,6 +545,7 @@ #endif /* HAVE_REMOTE_LCD */ int next_folder; /* move to next folder */ + int directory_skip; bool runtimedb; /* runtime database active? */ #if CONFIG_CODEC == SWCODEC Index: apps/menus/playback_menu.c =================================================================== --- apps/menus/playback_menu.c (revision 16012) +++ apps/menus/playback_menu.c (working copy) @@ -130,6 +130,7 @@ MENUITEM_SETTING(spdif_enable, &global_settings.spdif_enable, NULL); #endif MENUITEM_SETTING(next_folder, &global_settings.next_folder, NULL); +MENUITEM_SETTING(directory_skip, &global_settings.directory_skip, NULL); int audioscrobbler_callback(int action,const struct menu_item_ex *this_item) { (void)this_item; @@ -186,7 +187,7 @@ #ifdef HAVE_SPDIF_POWER &spdif_enable, #endif - &next_folder, &audioscrobbler, &cuesheet + &next_folder, &directory_skip, &audioscrobbler, &cuesheet #ifdef HAVE_HEADPHONE_DETECTION ,&unplug_menu #endif Index: apps/settings_list.c =================================================================== --- apps/settings_list.c (revision 16012) +++ apps/settings_list.c (working copy) @@ -852,6 +852,9 @@ CHOICE_SETTING(0, next_folder, LANG_NEXT_FOLDER, FOLDER_ADVANCE_OFF, "folder navigation", "off,on,random",NULL ,3, ID2P(LANG_SET_BOOL_NO), ID2P(LANG_SET_BOOL_YES), ID2P(LANG_RANDOM)), + CHOICE_SETTING(0, directory_skip, LANG_DIR_SKIP, 0, + "dirskip mode", "within pl,normal,never",NULL ,3, + ID2P(LANG_WITHIN_PLAYLIST), ID2P(LANG_NORMAL), ID2P(LANG_NEVER)), OFFON_SETTING(0,runtimedb,LANG_RUNTIMEDB_ACTIVE,false,"gather runtime data",NULL), #if CONFIG_CODEC == SWCODEC