Warning, file /multimedia/amarok/src/dynamic/BiasSolver.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /**************************************************************************************** 0002 * Copyright (c) 2008 Daniel Caleb Jones <danielcjones@gmail.com> * 0003 * Copyright (c) 2010, 2013 Ralf Engels <ralf-engels@gmx.de> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify it under * 0006 * the terms of the GNU General Public License as published by the Free Software * 0007 * Foundation; either version 2 of the License, or (at your option) version 3 or * 0008 * any later version accepted by the membership of KDE e.V. (or its successor approved * 0009 * by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of * 0010 * version 3 of the license. * 0011 * * 0012 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0013 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0014 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0015 * * 0016 * You should have received a copy of the GNU General Public License along with * 0017 * this program. If not, see <http://www.gnu.org/licenses/>. * 0018 ****************************************************************************************/ 0019 0020 #ifndef AMAROK_BIASSOLVER_H 0021 #define AMAROK_BIASSOLVER_H 0022 0023 #include "Bias.h" 0024 #include "core/meta/forward_declarations.h" 0025 #include "dynamic/TrackSet.h" 0026 0027 #include <QDateTime> 0028 #include <QMutex> 0029 #include <QWaitCondition> 0030 0031 #include <ThreadWeaver/Job> 0032 0033 namespace Dynamic 0034 { 0035 0036 /** A playlist helper class 0037 */ 0038 class SolverList; 0039 0040 /** 0041 * A class to implement the optimization algorithm used to generate 0042 * playlists from a set of biases. The method used here is slightly 0043 * complicated. It uses a a combination of heuristics, genetic algorithms, 0044 * and simulated annealing. The steps involved are documented in the source 0045 * code of BiasSolver::run. 0046 0047 The whole operation is a little bit tricky since the bias solver runs as 0048 separate job without it's own event queue. 0049 0050 The signals and slots are all handled via the UI threads event queue. 0051 Since the BiasSolver and all biases are created from the UI thread this 0052 is also the event queue of all objects. 0053 Bottom line: don't create objects in the bias solver that use signals. 0054 0055 0056 * Playlist generation is now done by adding tracks until we run out of time 0057 * or out of candidates. 0058 * We are back stepping a couple of times in such a case. 0059 * 0060 * The old bias solver that tried different optimization solutions is 0061 * not longer used. If you want to see the old code and/or re-use parts 0062 * of it see Amarok 2.7 0063 * 0064 * To use the solver: 0065 * Create an instance 0066 * enqueue the job. When the job is finished, call solution to get the 0067 * playlist produced. 0068 */ 0069 class BiasSolver : public QObject, public ThreadWeaver::Job 0070 { 0071 Q_OBJECT 0072 0073 public: 0074 0075 /** 0076 * Create and prepare the solver. The constructor returns 0077 * 0078 * @param n The size of the playlist to generate. 0079 * @param bias The system of biases being applied. 0080 * @param context The tracks (if any) that precede the playlist 0081 * being generated. 0082 */ 0083 BiasSolver( int n, const BiasPtr &bias, const Meta::TrackList &context ); 0084 0085 ~BiasSolver() override; 0086 0087 /// Returns the playlist generated after the job has finished. 0088 Meta::TrackList solution(); 0089 0090 /// Politely asks the thread to give up and finish ASAP. 0091 void requestAbort() override; 0092 0093 /** 0094 * Returns true if the solver was successful, false if it was 0095 * aborted or encountered some other error. 0096 */ 0097 bool success() const override; 0098 0099 /** 0100 * Choose whether the BiasSolver instance should delete itself after the query. 0101 * By passing true the instance will delete itself after emitting done, failed. 0102 * Otherwise it is the responsibility of the owner to delete the instance 0103 * when it is not needed anymore. 0104 * 0105 * Defaults to false, i.e. the BiasSolver instance will not delete itself. 0106 */ 0107 void setAutoDelete( bool autoDelete ); 0108 0109 /** 0110 * Return the universe set (a list of the uid of every track being 0111 * considered) being used. 0112 */ 0113 static const QList<QByteArray>& universe(); 0114 0115 /** 0116 * Mark the universe set as out of date (i.e. it needs to be 0117 * updated). 0118 */ 0119 static void outdateUniverse(); 0120 0121 protected: 0122 void run(ThreadWeaver::JobPointer self = QSharedPointer<ThreadWeaver::Job>(), ThreadWeaver::Thread *thread = nullptr) override; 0123 void defaultBegin(const ThreadWeaver::JobPointer& job, ThreadWeaver::Thread *thread) override; 0124 void defaultEnd(const ThreadWeaver::JobPointer& job, ThreadWeaver::Thread *thread) override; 0125 0126 Q_SIGNALS: 0127 /** a job must implement the following signals for the progress bar 0128 BiasedPlaylist set's us as progress sender in startSolver. 0129 */ 0130 0131 /** Sets the total steps for the progress bar (which is always 100 for the bias solver). 0132 This signal is never emitted as the BiasedPlaylist already registers us with 0133 100 steps. */ 0134 void totalSteps( int ); 0135 void incrementProgress(); 0136 void endProgressOperation( QObject * ); 0137 0138 /** This signal is emitted when this job is being processed by a thread. */ 0139 void started(ThreadWeaver::JobPointer); 0140 /** This signal is emitted when the job has been finished (no matter if it succeeded or not). */ 0141 void done(ThreadWeaver::JobPointer); 0142 /** This job has failed. 0143 * This signal is emitted when success() returns false after the job is executed. */ 0144 void failed(ThreadWeaver::JobPointer); 0145 0146 private Q_SLOTS: 0147 void biasResultReady( const Dynamic::TrackSet &set ); 0148 0149 void trackCollectionResultsReady( const QStringList &); 0150 void trackCollectionDone(); 0151 0152 0153 private: 0154 /** Returns the TrackSet that would match the end of the given playlist 0155 The function blocks until the result is received */ 0156 TrackSet matchingTracks( const Meta::TrackList& playlist ) const; 0157 0158 /** Query for the universe set (the set of all tracks in the collection being considered. 0159 This function needs to be called from a thread with an event loop. 0160 */ 0161 void getTrackCollection(); 0162 0163 /** Try to recursive add tracks to the current solver list up to m_n tracks. 0164 * The function will return with partly filled lists. 0165 */ 0166 void addTracks( SolverList *list ); 0167 0168 /** 0169 * Get the track referenced by the uid stored in the given 0170 * QByteArray. 0171 * @param uid The uid 0172 */ 0173 Meta::TrackPtr trackForUid( const QString& uid ) const; 0174 0175 /** 0176 * Return a random track from the domain. 0177 */ 0178 Meta::TrackPtr getMutation(); 0179 0180 /** 0181 * Return a random track from the given subset. 0182 * @param subset A list (representing a set) of uids stored in 0183 * QByteArrays. 0184 */ 0185 Meta::TrackPtr getRandomTrack( const TrackSet& subset ) const; 0186 0187 /** Returns a TrackSet with all duplicates removed (except the one at "position") 0188 This helper function can be used in special cases if needed and 0189 AmarokConfig::dynamicDuplicates() == false 0190 Normally the BiasSolver will call it at for the top most bias. 0191 */ 0192 static TrackSet withoutDuplicate( int position, 0193 const Meta::TrackList& playlist, 0194 const Dynamic::TrackSet& oldSet ); 0195 0196 /** Emits the required progress signals */ 0197 void updateProgress( const SolverList* list ); 0198 0199 int m_n; //!< size of playlist to generate 0200 Dynamic::BiasPtr m_bias; // bias used to determine tracks. not owned by solver 0201 Meta::TrackList m_context; //!< tracks that precede the playlist 0202 0203 Meta::TrackList m_solution; 0204 0205 bool m_abortRequested; //!< flag set when the thread is aborted 0206 0207 QDateTime m_startTime; 0208 0209 mutable QMutex m_biasResultsMutex; 0210 mutable QWaitCondition m_biasResultsReady; 0211 mutable Dynamic::TrackSet m_tracks; // tracks just received from the bias. 0212 0213 mutable QMutex m_collectionResultsMutex; 0214 mutable QWaitCondition m_collectionResultsReady; 0215 0216 /** All uids of all the tracks in the collection */ 0217 QStringList m_collectionUids; 0218 TrackCollectionPtr m_trackCollection; 0219 0220 bool m_allowDuplicates; 0221 0222 int m_currentProgress; 0223 0224 /** The maximum time we should try to spend generating the playlist */ 0225 static const int MAX_TIME_MS = 5000; 0226 }; 0227 } 0228 0229 #endif