Ticket #4708: mythmusic-intelligent-order-v2.diff

File mythmusic-intelligent-order-v2.diff, 7.7 KB (added by mythtv@…, 12 years ago)

Normalized weights using the number of songs having the same rating

  • 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>
     
    47#include <iostream>
    58#include <map>
    69using namespace std;
    7 #include "playlist.h"
    810#include "qdatetime.h"
    911#include <mythtv/mythcontext.h>
    1012#include "smartplaylist.h"
     
    921923    return songlist;
    922924}
    923925
     926void Playlist::computeIntelliOrder(QPtrList<Track>&        songs,
     927                                   std::map<int,uint32_t>& order,
     928                                   int                     playcountMin,
     929                                   int                     playcountMax,
     930                                   double                  lastplayMin,
     931                                   double                  lastplayMax)
     932{
     933    assert(order.empty());
     934
     935    int RatingWeight = 2;
     936    int PlayCountWeight = 2;
     937    int LastPlayWeight = 2;
     938    int RandomWeight = 2;
     939    parent->FillIntelliWeights(RatingWeight, PlayCountWeight, LastPlayWeight,
     940                               RandomWeight);
     941
     942    // first we compute all the weights
     943    Track *trackIt;
     944    std::map<int,double> weights;
     945    std::map<int,int> ratings;
     946    std::map<int,int> ratingCounts;
     947    int TotalWeight = RatingWeight + PlayCountWeight + LastPlayWeight;
     948    for (trackIt = songs.first(); trackIt; trackIt = songs.next())
     949    {
     950        if (!trackIt->getCDFlag())
     951        {
     952            int songId = trackIt->getValue();
     953            if (songId == 0)
     954            {
     955                VERBOSE(VB_IMPORTANT, "Song with ID of 0 in playlist, this "
     956                                      "shouldn't happen.");
     957            }
     958            if (songId > 0)
     959            {
     960                Metadata *tmpdata = all_available_music->getMetadata(songId);
     961                if (tmpdata && tmpdata->isVisible())
     962                {
     963                    int rating = tmpdata->Rating();
     964                    int playcount = tmpdata->PlayCount();
     965                    double lastplaydbl = tmpdata->LastPlay();
     966                    double ratingValue = (double)(rating) / 10;
     967                    double playcountValue, lastplayValue;
     968
     969                    if (playcountMax == playcountMin)
     970                        playcountValue = 0;
     971                    else
     972                        playcountValue = ((playcountMin - (double)playcount) / (playcountMax - playcountMin) + 1);
     973
     974                    if (lastplayMax == lastplayMin)
     975                        lastplayValue = 0;
     976                    else
     977                        lastplayValue = ((lastplayMin - lastplaydbl) / (lastplayMax - lastplayMin) + 1);
     978
     979                    double weight = (RatingWeight * ratingValue +
     980                                     PlayCountWeight * playcountValue +
     981                                     LastPlayWeight * lastplayValue) / TotalWeight;
     982                    weights[songId] = weight;
     983                    ratings[songId] = rating;
     984                    ++ratingCounts[rating];
     985                }
     986            }
     987        }
     988    }
     989   
     990    // then we divide weights with the number of songs in the rating class
     991    // (more songs in a class ==> lower weight, without affecting other classes)
     992    double totalWeights = 0;
     993    std::map<int,double>::iterator weightsIt, weightsEnd = weights.end();
     994    for(weightsIt = weights.begin() ; weightsIt != weightsEnd ; ++weightsIt)
     995    {
     996        weightsIt->second /= ratingCounts[ratings[weightsIt->first]];
     997        totalWeights += weightsIt->second;
     998    }
     999
     1000    // then we get a random order, balanced with relative weights of remaining songs
     1001    uint32_t orderCpt = 1;
     1002    std::map<int,double>::iterator weightIt, weightEnd;
     1003    while(weights.size() > 0)
     1004    {
     1005        double hit = totalWeights * (double)rand() / (double)RAND_MAX;
     1006        weightEnd = weights.end();
     1007        weightIt = weights.begin();
     1008        double pos = 0;
     1009        while(weightIt != weightEnd)
     1010        {
     1011            pos += weightIt->second;
     1012            if(pos >= hit) break;
     1013            ++weightIt;
     1014        }
     1015        order[weightIt->first] = orderCpt;
     1016        totalWeights -= weightIt->second;
     1017        weights.erase(weightIt);
     1018        ++orderCpt;
     1019    }
     1020}
     1021
    9241022int Playlist::writeTree(GenericTree *tree_to_write_to, int a_counter)
    9251023{
    9261024    Track *it;
     
    10061104        count++;
    10071105    }
    10081106
    1009     int RatingWeight = 2;
    1010     int PlayCountWeight = 2;
    1011     int LastPlayWeight = 2;
    1012     int RandomWeight = 2;
     1107    std::map<int,uint32_t> intelliOrder;
     1108    computeIntelliOrder(songs, intelliOrder,
     1109                        playcountMin, playcountMax,
     1110                        lastplayMin, lastplayMax);
    10131111
    1014     parent->FillIntelliWeights(RatingWeight, PlayCountWeight, LastPlayWeight,
    1015                                RandomWeight);
    1016 
    10171112    for (it = songs.first(); it; it = songs.next())
    10181113    {
    10191114        if (!it->getCDFlag())
     
    10361131                    added_node->setAttribute(1, a_counter); //  regular order
    10371132                    added_node->setAttribute(2, rand()); //  random order
    10381133
    1039                     //
    1040                     //  Compute "intelligent" weighting
    1041                     //
     1134                    //  "intelligent" order
     1135                    added_node->setAttribute(3, intelliOrder[it->getValue()]);
    10421136
    1043                     int rating = tmpdata->Rating();
    1044                     int playcount = tmpdata->PlayCount();
    1045                     double lastplaydbl = tmpdata->LastPlay();
    1046                     double ratingValue = (double)(rating) / 10;
    1047                     double playcountValue, lastplayValue;
    1048 
    1049                     if (playcountMax == playcountMin)
    1050                         playcountValue = 0;
    1051                     else
    1052                         playcountValue = ((playcountMin - (double)playcount) / (playcountMax - playcountMin) + 1);
    1053 
    1054                     if (lastplayMax == lastplayMin)
    1055                         lastplayValue = 0;
    1056                     else
    1057                         lastplayValue = ((lastplayMin - lastplaydbl) / (lastplayMax - lastplayMin) + 1);
    1058 
    1059                     double rating_value =  (RatingWeight * ratingValue + PlayCountWeight * playcountValue +
    1060                                             LastPlayWeight * lastplayValue + RandomWeight * (double)rand() /
    1061                                             (RAND_MAX + 1.0));
    1062                     uint32_t integer_rating = (int) (4000001 - rating_value * 10000);
    1063                     added_node->setAttribute(3, integer_rating); //  "intelligent" order
    1064 
    10651137                    // "intellegent/album" order
    10661138                    uint32_t album_order;
    10671139                    album = tmpdata->Album();