Ticket #4708: mythmusic-intelligent-order-trunk-19938.diff

File mythmusic-intelligent-order-trunk-19938.diff, 7.8 KB (added by mythtv@…, 11 years ago)

Updated patch: apply cleanly on current trunk.

  • mythmusic/mythmusic/playlist.h

     
    135135    int CreateCDAudio(void);
    136136
    137137  private:
    138     QString             removeDuplicateTracks(const QString &new_songlist);
     138    void    computeIntelliOrder(QPtrList<Track>&        songs,
     139                                std::map<int,uint32_t>& order,
     140                                int                     playcountMin,
     141                                int                     playcountMax,
     142                                double                  lastplayMin,
     143                                double                  lastplayMax);
     144    QString removeDuplicateTracks(const QString &new_songlist);
     145
     146  private:
    139147    int                 playlistid;
    140148    QString             name;
    141149    QString             raw_songlist;
  • mythmusic/mythmusic/playlist.cpp

     
     1#include "playlist.h"
     2
     3#include <assert.h>
    14#include <unistd.h>
    25#include <inttypes.h>
    36#include <cstdlib>
     
    58#include <map>
    69
    710using namespace std;
    8 #include "playlist.h"
    911#include "qdatetime.h"
    1012//Added by qt3to4:
    1113#include <Q3PtrList>
     
    941943    return songlist;
    942944}
    943945
     946void Playlist::computeIntelliOrder(QPtrList<Track>&        songs,
     947                                   std::map<int,uint32_t>& order,
     948                                   int                     playcountMin,
     949                                   int                     playcountMax,
     950                                   double                  lastplayMin,
     951                                   double                  lastplayMax)
     952{
     953    assert(order.empty());
     954
     955    int RatingWeight = 2;
     956    int PlayCountWeight = 2;
     957    int LastPlayWeight = 2;
     958    int RandomWeight = 2;
     959    parent->FillIntelliWeights(RatingWeight, PlayCountWeight, LastPlayWeight,
     960                               RandomWeight);
     961
     962    // first we compute all the weights
     963    Track *trackIt;
     964    std::map<int,double> weights;
     965    std::map<int,int> ratings;
     966    std::map<int,int> ratingCounts;
     967    int TotalWeight = RatingWeight + PlayCountWeight + LastPlayWeight;
     968    for (trackIt = songs.first(); trackIt; trackIt = songs.next())
     969    {
     970        if (!trackIt->getCDFlag())
     971        {
     972            int songId = trackIt->getValue();
     973            if (songId == 0)
     974            {
     975                VERBOSE(VB_IMPORTANT, "Song with ID of 0 in playlist, this "
     976                                      "shouldn't happen.");
     977            }
     978            if (songId > 0)
     979            {
     980                Metadata *tmpdata = all_available_music->getMetadata(songId);
     981                if (tmpdata && tmpdata->isVisible())
     982                {
     983                    int rating = tmpdata->Rating();
     984                    int playcount = tmpdata->PlayCount();
     985                    double lastplaydbl = tmpdata->LastPlay();
     986                    double ratingValue = (double)(rating) / 10;
     987                    double playcountValue, lastplayValue;
     988
     989                    if (playcountMax == playcountMin)
     990                        playcountValue = 0;
     991                    else
     992                        playcountValue = ((playcountMin - (double)playcount) / (playcountMax - playcountMin) + 1);
     993
     994                    if (lastplayMax == lastplayMin)
     995                        lastplayValue = 0;
     996                    else
     997                        lastplayValue = ((lastplayMin - lastplaydbl) / (lastplayMax - lastplayMin) + 1);
     998
     999                    double weight = (RatingWeight * ratingValue +
     1000                                     PlayCountWeight * playcountValue +
     1001                                     LastPlayWeight * lastplayValue) / TotalWeight;
     1002                    weights[songId] = weight;
     1003                    ratings[songId] = rating;
     1004                    ++ratingCounts[rating];
     1005                }
     1006            }
     1007        }
     1008    }
     1009   
     1010    // then we divide weights with the number of songs in the rating class
     1011    // (more songs in a class ==> lower weight, without affecting other classes)
     1012    double totalWeights = 0;
     1013    std::map<int,double>::iterator weightsIt, weightsEnd = weights.end();
     1014    for(weightsIt = weights.begin() ; weightsIt != weightsEnd ; ++weightsIt)
     1015    {
     1016        weightsIt->second /= ratingCounts[ratings[weightsIt->first]];
     1017        totalWeights += weightsIt->second;
     1018    }
     1019
     1020    // then we get a random order, balanced with relative weights of remaining songs
     1021    uint32_t orderCpt = 1;
     1022    std::map<int,double>::iterator weightIt, weightEnd;
     1023    while(weights.size() > 0)
     1024    {
     1025        double hit = totalWeights * (double)rand() / (double)RAND_MAX;
     1026        weightEnd = weights.end();
     1027        weightIt = weights.begin();
     1028        double pos = 0;
     1029        while(weightIt != weightEnd)
     1030        {
     1031            pos += weightIt->second;
     1032            if(pos >= hit) break;
     1033            ++weightIt;
     1034        }
     1035        order[weightIt->first] = orderCpt;
     1036        totalWeights -= weightIt->second;
     1037        weights.erase(weightIt);
     1038        ++orderCpt;
     1039    }
     1040}
     1041
    9441042int Playlist::writeTree(GenericTree *tree_to_write_to, int a_counter)
    9451043{
    9461044    Track *it;
     
    10261124        count++;
    10271125    }
    10281126
    1029     int RatingWeight = 2;
    1030     int PlayCountWeight = 2;
    1031     int LastPlayWeight = 2;
    1032     int RandomWeight = 2;
     1127    std::map<int,uint32_t> intelliOrder;
     1128    computeIntelliOrder(songs, intelliOrder,
     1129                        playcountMin, playcountMax,
     1130                        lastplayMin, lastplayMax);
    10331131
    1034     parent->FillIntelliWeights(RatingWeight, PlayCountWeight, LastPlayWeight,
    1035                                RandomWeight);
    1036 
    10371132    for (it = songs.first(); it; it = songs.next())
    10381133    {
    10391134        if (!it->getCDFlag())
     
    10591154                    added_node->setAttribute(1, a_counter); //  regular order
    10601155                    added_node->setAttribute(2, rand()); //  random order
    10611156
    1062                     //
    1063                     //  Compute "intelligent" weighting
    1064                     //
    1065 
    1066                     int rating = tmpdata->Rating();
    1067                     int playcount = tmpdata->PlayCount();
    1068                     double lastplaydbl = tmpdata->LastPlay();
    1069                     double ratingValue = (double)(rating) / 10;
    1070                     double playcountValue, lastplayValue;
    1071 
    1072                     if (playcountMax == playcountMin)
    1073                         playcountValue = 0;
    1074                     else
    1075                         playcountValue = ((playcountMin - (double)playcount)
    1076                                          / (playcountMax - playcountMin) + 1);
    1077 
    1078                     if (lastplayMax == lastplayMin)
    1079                         lastplayValue = 0;
    1080                     else
    1081                         lastplayValue = ((lastplayMin - lastplaydbl)
    1082                                         / (lastplayMax - lastplayMin) + 1);
    1083 
    1084                     double rating_value =  (RatingWeight * ratingValue +
    1085                                             PlayCountWeight * playcountValue +
    1086                                             LastPlayWeight * lastplayValue +
    1087                                             RandomWeight * (double)rand() /
    1088                                             (RAND_MAX + 1.0));
    1089                     uint32_t integer_rating = (int) (4000001 -
    1090                                                      rating_value * 10000);
    10911157                    //  "intelligent" order
    1092                     added_node->setAttribute(3, integer_rating);
     1158                    added_node->setAttribute(3, intelliOrder[it->getValue()]);
    10931159
    10941160                    // "intellegent/album" order
    10951161                    uint32_t album_order;