@@ -2077,29 +2077,47 @@ void Playlist::ReloadItems(const QList<int> &rows) {
20772077
20782078}
20792079
2080- void Playlist::Shuffle () {
2081-
2082- PlaylistItemPtrList new_items (items_);
2080+ void Playlist::Shuffle (const PlaylistSequence::ShuffleMode shuffle_mode) {
20832081
2082+ QList<int > index_items;
20842083 int begin = 0 ;
2084+ int exclude_index = -1 ;
2085+
20852086 if (current_item_index_.isValid ()) {
20862087 if (dynamic_playlist_) {
2087- // Keep the history and the current track fixed; only shuffle the future region (mirrors sort()).
2088- begin = current_item_index_.row () + 1 ;
2088+ begin += current_item_index_.row () + 1 ;
20892089 }
2090- else {
2091- if (new_items[0 ] != new_items[current_item_index_.row ()]) {
2092- std::swap (new_items[0 ], new_items[current_item_index_.row ()]);
2093- }
2094- begin = 1 ;
2090+ else if (shuffle_mode == PlaylistSequence::ShuffleMode::All) {
2091+ // I keep the current track on the first place only when I shuffle all the tracks
2092+ exclude_index = current_item_index_.row ();
20952093 }
20962094 }
20972095
20982096 const int count = static_cast <int >(items_.count ());
20992097 for (int i = begin; i < count; ++i) {
2100- const int new_pos = i + (rand () % (count - i));
2098+ if (exclude_index == i) {
2099+ continue ;
2100+ }
2101+ index_items.push_back (i);
2102+ }
2103+
2104+ ReshuffleIndices (index_items, shuffle_mode, begin, true );
21012105
2102- std::swap (new_items[i], new_items[new_pos]);
2106+ PlaylistItemPtrList new_items;
2107+
2108+ if (exclude_index >= 0 ) {
2109+ // Here I want to keep the current track fixed
2110+ new_items.push_back (items_[exclude_index]);
2111+ }
2112+ else if (begin > 0 ) {
2113+ // Here I want to keep the history and the current track fixed
2114+ for (int i = 0 ; i < begin; ++i) {
2115+ new_items.push_back (items_[i]);
2116+ }
2117+ }
2118+ // Then, I shuffle the remaining «future» tracks to read
2119+ for (int idx_shuffle : std::as_const (index_items)) {
2120+ new_items.push_back (items_[idx_shuffle]);
21032121 }
21042122
21052123 undo_stack_->push (new PlaylistUndoCommandShuffleItems (this , new_items));
@@ -2113,7 +2131,29 @@ bool AlbumShuffleComparator(const QHash<QString, int> &album_key_positions, cons
21132131 const int left_pos = album_key_positions[album_keys[left]];
21142132 const int right_pos = album_key_positions[album_keys[right]];
21152133
2134+ // With this return, I keep the tracks in the order they have in the playlist
21162135 if (left_pos == right_pos) return left < right;
2136+
2137+ // Sort the albums by their position in the playlist
2138+ return left_pos < right_pos;
2139+
2140+ }
2141+
2142+ // to the contrary of the function upper, I will keep the tracks in the order of their position in the album
2143+ // not with the position they have in the playlist
2144+ bool AlbumShuffleComparatorTrackOrder (const QHash<QString, int > &album_key_positions, const QHash<int , QString> &album_keys, const PlaylistItemPtrList &items, const int left, const int right) {
2145+
2146+ const int left_pos = album_key_positions[album_keys[left]];
2147+ const int right_pos = album_key_positions[album_keys[right]];
2148+
2149+ if (left_pos == right_pos) {
2150+ auto &&left_song = items[left]->EffectiveMetadata ();
2151+ auto &&right_song = items[right]->EffectiveMetadata ();
2152+
2153+ if (left_song.disc () == right_song.disc ()) return left_song.track () < right_song.track ();
2154+
2155+ return left_song.disc () < right_song.disc ();
2156+ }
21172157 return left_pos < right_pos;
21182158
21192159}
@@ -2122,18 +2162,38 @@ bool AlbumShuffleComparator(const QHash<QString, int> &album_key_positions, cons
21222162
21232163void Playlist::ReshuffleIndices () {
21242164
2125- const PlaylistSequence::ShuffleMode shuffle_mode = ShuffleMode ();
2165+ // First, cancel the replay position
2166+ // TODO : uncomment the code below when the branch «Grouped tracks are considered as single track» will be merged
2167+ // next_song_after_queued_ = -1;
2168+
2169+ current_virtual_index_ = ReshuffleIndices (virtual_items_, ShuffleMode (), 0 , false );
2170+
2171+ }
2172+
2173+ int Playlist::ReshuffleIndices (QList<int >& virtual_items, const PlaylistSequence::ShuffleMode shuffle_mode, const int base_reference, const bool album_keep_track_order) {
2174+
2175+ static std::mt19937 rng{std::random_device{}()};
2176+
21262177 switch (shuffle_mode) {
21272178 case PlaylistSequence::ShuffleMode::Off:{
21282179 // No shuffling - sort the virtual item list normally.
2129- std::sort (virtual_items_ .begin (), virtual_items_ .end ());
2180+ std::sort (virtual_items .begin (), virtual_items .end ());
21302181 break ;
21312182 }
21322183
21332184 case PlaylistSequence::ShuffleMode::All:
21342185 case PlaylistSequence::ShuffleMode::InsideAlbum:{
2135- std::random_device rd;
2136- std::shuffle (virtual_items_.begin (), virtual_items_.end (), std::mt19937 (rd ()));
2186+ std::shuffle (virtual_items.begin (), virtual_items.end (), rng);
2187+
2188+ // If the user is currently playing a song, force its track to be first
2189+ // Also check last_played_row() for cases where current_row() hasn't been set yet (e.g., on app startup)
2190+ int reference_row = current_row ();
2191+ if (reference_row == -1 && last_played_row () != -1 ) {
2192+ reference_row = last_played_row ();
2193+ }
2194+ if (reference_row > base_reference) {
2195+ std::swap (virtual_items[0 ], virtual_items[reference_row - base_reference]);
2196+ }
21372197 break ;
21382198 }
21392199
@@ -2142,15 +2202,14 @@ void Playlist::ReshuffleIndices() {
21422202 QSet<QString> album_key_set; // unique keys
21432203
21442204 // Find all the unique albums in the playlist
2145- for (QList<int >::const_iterator it = virtual_items_ .constBegin (); it != virtual_items_ .constEnd (); ++it) {
2205+ for (QList<int >::const_iterator it = virtual_items .constBegin (); it != virtual_items .constEnd (); ++it) {
21462206 const int index = *it;
21472207 const QString key = items_[index]->EffectiveMetadata ().AlbumKey ();
21482208 album_keys[index] = key;
21492209 album_key_set << key;
21502210 }
21512211
21522212 // Shuffle them
2153- static std::mt19937 rng{std::random_device{}()};
21542213 QStringList shuffled_album_keys = album_key_set.values ();
21552214 std::shuffle (shuffled_album_keys.begin (), shuffled_album_keys.end (), rng);
21562215
@@ -2163,8 +2222,8 @@ void Playlist::ReshuffleIndices() {
21632222 if (reference_row != -1 ) {
21642223 const QString key = items_[reference_row]->EffectiveMetadata ().AlbumKey ();
21652224 const qint64 pos = shuffled_album_keys.indexOf (key);
2166- if (pos >= 1 ) {
2167- std::swap (shuffled_album_keys[0 ], shuffled_album_keys[pos]);
2225+ if (pos > base_reference ) {
2226+ std::swap (shuffled_album_keys[0 ], shuffled_album_keys[pos - base_reference ]);
21682227 }
21692228 }
21702229
@@ -2174,8 +2233,18 @@ void Playlist::ReshuffleIndices() {
21742233 album_key_positions[shuffled_album_keys[i]] = i;
21752234 }
21762235
2236+ if (album_keep_track_order) {
2237+ // Sort the virtual items : use AlbumShuffleComparator with a cheap-to-copy lambda comparator
2238+ // force the track order to be the album one
2239+ std::stable_sort (virtual_items.begin (), virtual_items.end (), [&album_key_positions, &album_keys, this ](const int lhs, const int rhs) {
2240+ return AlbumShuffleComparatorTrackOrder (album_key_positions, album_keys, items_, lhs, rhs);
2241+ });
2242+
2243+ break ;
2244+ }
21772245 // Sort the virtual items : use AlbumShuffleComparator with a cheap-to-copy lambda comparator
2178- std::stable_sort (virtual_items_.begin (), virtual_items_.end (), [&album_key_positions, &album_keys](const int lhs, const int rhs) {
2246+ // keep the track order they have in the playlist
2247+ std::stable_sort (virtual_items.begin (), virtual_items.end (), [&album_key_positions, &album_keys](const int lhs, const int rhs) {
21792248 return AlbumShuffleComparator (album_key_positions, album_keys, lhs, rhs);
21802249 });
21812250
@@ -2186,15 +2255,14 @@ void Playlist::ReshuffleIndices() {
21862255 QSet<QString> grouping_key_set; // unique keys
21872256
21882257 // Find all the unique grouping keys in the playlist
2189- for (QList<int >::const_iterator it = virtual_items_ .constBegin (); it != virtual_items_ .constEnd (); ++it) {
2258+ for (QList<int >::const_iterator it = virtual_items .constBegin (); it != virtual_items .constEnd (); ++it) {
21902259 const int index = *it;
21912260 const QString key = items_[index]->EffectiveMetadata ().GroupingKey ();
21922261 grouping_keys[index] = key;
21932262 grouping_key_set << key;
21942263 }
21952264
21962265 // Shuffle them
2197- static std::mt19937 rng{std::random_device{}()};
21982266 QStringList shuffled_grouping_keys = grouping_key_set.values ();
21992267 std::shuffle (shuffled_grouping_keys.begin (), shuffled_grouping_keys.end (), rng);
22002268
@@ -2207,8 +2275,8 @@ void Playlist::ReshuffleIndices() {
22072275 if (reference_row != -1 ) {
22082276 const QString key = items_[reference_row]->EffectiveMetadata ().GroupingKey ();
22092277 const qint64 pos = shuffled_grouping_keys.indexOf (key);
2210- if (pos >= 1 ) {
2211- std::swap (shuffled_grouping_keys[0 ], shuffled_grouping_keys[pos]);
2278+ if (pos > base_reference ) {
2279+ std::swap (shuffled_grouping_keys[0 ], shuffled_grouping_keys[pos - base_reference ]);
22122280 }
22132281 }
22142282
@@ -2218,22 +2286,23 @@ void Playlist::ReshuffleIndices() {
22182286 grouping_key_positions[shuffled_grouping_keys[i]] = i;
22192287 }
22202288
2221- // Sort the virtual items: use AlbumShuffleComparator as a grouping-key comparator with a cheap-to-copy lambda
2222- std::stable_sort (virtual_items_.begin (), virtual_items_.end (), [&grouping_key_positions, &grouping_keys](const int lhs, const int rhs) {
2223- return AlbumShuffleComparator (grouping_key_positions, grouping_keys, lhs, rhs);
2289+ // Sort the virtual items: use AlbumShuffleComparatorTrackOrder as a grouping-key comparator with a cheap-to-copy lambda
2290+ // This sort method will keep the track number order so important in the grouped read
2291+ std::stable_sort (virtual_items.begin (), virtual_items.end (), [&grouping_key_positions, &grouping_keys, this ](const int lhs, const int rhs) {
2292+ return AlbumShuffleComparatorTrackOrder (grouping_key_positions, grouping_keys, items_, lhs, rhs);
22242293 });
22252294 break ;
22262295 }
22272296 }
22282297
2229- // Update current virtual index
2298+ // I keep the computation of the virtual index because it is only return, if you want to ignore it, you can
2299+ // besides, it will be usefull in the cases I want to use the updated method
22302300 if (current_item_index_.isValid ()) {
2231- current_virtual_index_ = static_cast <int >(virtual_items_.indexOf (current_item_index_.row ()));
2232- }
2233- else {
2234- current_virtual_index_ = -1 ;
2301+ return static_cast <int >(virtual_items.indexOf (current_item_index_.row ()));
22352302 }
22362303
2304+ return -1 ;
2305+
22372306}
22382307
22392308void Playlist::set_sequence (PlaylistSequence *v) {
0 commit comments