Ticket #4708: mythmusic-intelligent-order.diff

File mythmusic-intelligent-order.diff, 7.2 KB (added by mythtv@…, 12 years ago)
  • 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    double totalWeights = 0;
     945    std::map<int,double> weights;
     946    int TotalWeight = RatingWeight + PlayCountWeight + LastPlayWeight;
     947    for (trackIt = songs.first(); trackIt; trackIt = songs.next())
     948    {
     949        if (!trackIt->getCDFlag())
     950        {
     951            int songId = trackIt->getValue();
     952            if (songId == 0)
     953            {
     954                VERBOSE(VB_IMPORTANT, "Song with ID of 0 in playlist, this "
     955                                      "shouldn't happen.");
     956            }
     957            if (songId > 0)
     958            {
     959                Metadata *tmpdata = all_available_music->getMetadata(songId);
     960                if (tmpdata && tmpdata->isVisible())
     961                {
     962                    int rating = tmpdata->Rating();
     963                    int playcount = tmpdata->PlayCount();
     964                    double lastplaydbl = tmpdata->LastPlay();
     965                    double ratingValue = (double)(rating) / 10;
     966                    double playcountValue, lastplayValue;
     967
     968                    if (playcountMax == playcountMin)
     969                        playcountValue = 0;
     970                    else
     971                        playcountValue = ((playcountMin - (double)playcount) / (playcountMax - playcountMin) + 1);
     972
     973                    if (lastplayMax == lastplayMin)
     974                        lastplayValue = 0;
     975                    else
     976                        lastplayValue = ((lastplayMin - lastplaydbl) / (lastplayMax - lastplayMin) + 1);
     977
     978                    double weight = (RatingWeight * ratingValue +
     979                                     PlayCountWeight * playcountValue +
     980                                     LastPlayWeight * lastplayValue) / TotalWeight;
     981                    weight *= weight; // reduce even more the low weights, keep higher weights high
     982                    weights[songId] = weight;
     983                    totalWeights += weight;
     984                }
     985            }
     986        }
     987    }
     988
     989    // then we get a random order, balanced with relative weights of remaining songs
     990    uint32_t orderCpt = 1;
     991    std::map<int,double>::iterator weightIt, weightEnd;
     992    while(weights.size() > 0)
     993    {
     994        double hit = totalWeights * (double)rand() / (double)RAND_MAX;
     995        weightEnd = weights.end();
     996        weightIt = weights.begin();
     997        double pos = 0;
     998        while(weightIt != weightEnd)
     999        {
     1000            pos += weightIt->second;
     1001            if(pos >= hit) break;
     1002            ++weightIt;
     1003        }
     1004        order[weightIt->first] = orderCpt;
     1005        totalWeights -= weightIt->second;
     1006        weights.erase(weightIt);
     1007        ++orderCpt;
     1008    }
     1009}
     1010
    9241011int Playlist::writeTree(GenericTree *tree_to_write_to, int a_counter)
    9251012{
    9261013    Track *it;
     
    10061093        count++;
    10071094    }
    10081095
    1009     int RatingWeight = 2;
    1010     int PlayCountWeight = 2;
    1011     int LastPlayWeight = 2;
    1012     int RandomWeight = 2;
     1096    std::map<int,uint32_t> intelliOrder;
     1097    computeIntelliOrder(songs, intelliOrder,
     1098                        playcountMin, playcountMax,
     1099                        lastplayMin, lastplayMax);
    10131100
    1014     parent->FillIntelliWeights(RatingWeight, PlayCountWeight, LastPlayWeight,
    1015                                RandomWeight);
    1016 
    10171101    for (it = songs.first(); it; it = songs.next())
    10181102    {
    10191103        if (!it->getCDFlag())
     
    10361120                    added_node->setAttribute(1, a_counter); //  regular order
    10371121                    added_node->setAttribute(2, rand()); //  random order
    10381122
    1039                     //
    1040                     //  Compute "intelligent" weighting
    1041                     //
     1123                    //  "intelligent" order
     1124                    added_node->setAttribute(3, intelliOrder[it->getValue()]);
    10421125
    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 
    10651126                    // "intellegent/album" order
    10661127                    uint32_t album_order;
    10671128                    album = tmpdata->Album();