File indexing completed on 2024-05-19 04:49:50

0001 /****************************************************************************************
0002  * Copyright (c) 2008 Seb Ruiz <ruiz@kde.org>                                           *
0003  * Copyright (c) 2008 Soren Harward <stharward@gmail.com>                               *
0004  * Copyright (c) 2008 Nikolaj Hald Nielsen <nhn@kde.org>                                *
0005  * Copyright (c) 2009 Téo Mrnjavac <teo@kde.org>                                        *
0006  * Copyright (c) 2010 Nanno Langstraat <langstr@gmail.com>                              *
0007  * Copyright (c) 2013 Daniel Schmitz <daniel.schmitz@gmx.info>                          *
0008  *                                                                                      *
0009  * This program is free software; you can redistribute it and/or modify it under        *
0010  * the terms of the GNU General Public License as published by the Free Software        *
0011  * Foundation; either version 2 of the License, or (at your option) version 3 or        *
0012  * any later version accepted by the membership of KDE e.V. (or its successor approved  *
0013  * by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of  *
0014  * version 3 of the license.                                                            *
0015  *                                                                                      *
0016  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0017  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0018  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0019  *                                                                                      *
0020  * You should have received a copy of the GNU General Public License along with         *
0021  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0022  ****************************************************************************************/
0023 
0024 #define DEBUG_PREFIX "Playlist::RandomTrackNavigator"
0025 
0026 #include "RandomTrackNavigator.h"
0027 
0028 #include "core/support/Debug.h"
0029 
0030 #include <QDateTime>
0031 #include <QRandomGenerator> // For 'QRandomGenerator::global()->generate()'
0032 
0033 #include <cmath> // For 'round()'
0034 
0035 Playlist::RandomTrackNavigator::RandomTrackNavigator()
0036 {
0037     loadFromSourceModel();
0038 }
0039 
0040 void
0041 Playlist::RandomTrackNavigator::planOne()
0042 {
0043     DEBUG_BLOCK
0044 
0045     if ( m_plannedItems.isEmpty() )
0046     {
0047         if ( !allItemsList().isEmpty() )
0048         {
0049             quint64 chosenItem;
0050 
0051             int avoidRecentlyPlayedSize = AVOID_RECENTLY_PLAYED_MAX;    // Start with being very picky.
0052 
0053             // Don't over-constrain ourself:
0054             //   - Keep enough headroom to be unpredictable.
0055             //   - Make sure that 'chooseRandomItem()' doesn't need to find a needle in a haystack.
0056             avoidRecentlyPlayedSize = qMin( avoidRecentlyPlayedSize, allItemsList().size() / 2 );
0057 
0058             QSet<quint64> avoidSet = getRecentHistory( avoidRecentlyPlayedSize );
0059             chosenItem = chooseRandomItem( avoidSet );
0060 
0061             m_plannedItems.append( chosenItem );
0062         }
0063     }
0064 }
0065 
0066 QSet<quint64>
0067 Playlist::RandomTrackNavigator::getRecentHistory( int size )
0068 {
0069     QList<quint64> allHistory = historyItems();
0070     QSet<quint64> recentHistory;
0071 
0072     if ( size > 0 ) {    // If '== 0', we even need to consider playing the same item again.
0073         recentHistory.insert( currentItem() );    // Might be '0'
0074         size--;
0075     }
0076 
0077     for ( int i = allHistory.size() - 1; ( i >= 0 ) && ( i >= allHistory.size() - size ); i-- )
0078         recentHistory.insert( allHistory.at( i ) );
0079 
0080     return recentHistory;
0081 }
0082 
0083 quint64
0084 Playlist::RandomTrackNavigator::chooseRandomItem( const QSet<quint64> &avoidSet )
0085 {
0086     quint64 chosenItem;
0087 
0088     do
0089     {
0090         int maxPosition = allItemsList().size() - 1;
0091         int randomPosition = round( ( QRandomGenerator::global()->generate() / (float)RAND_MAX ) * maxPosition );
0092         chosenItem = allItemsList().at( randomPosition );
0093     } while ( avoidSet.contains( chosenItem ) );
0094 
0095     return chosenItem;
0096 }