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

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

Adapted patch to apply and compile on current trunk.

  • mythmusic/playlist.h

     
    147147
    148148  private:
    149149    QString             removeDuplicateTracks(const QString &new_songlist);
     150    void    computeIntelliOrder(QList<Track*>&          songs,
     151                                std::map<int,uint32_t>& order,
     152                                int                     playcountMin,
     153                                int                     playcountMax,
     154                                double                  lastplayMin,
     155                                double                  lastplayMax);
     156
     157  private:
    150158    int                 playlistid;
    151159    QString             name;
    152160    QString             raw_songlist;
  • mythmusic/playlist.cpp

     
     1#include "playlist.h"
     2
     3#include <assert.h>
    14#include <unistd.h>
    25#include <inttypes.h>
    36#include <cstdlib>
     
    1114#include <QFileInfo>
    1215#include <q3process.h>
    1316
    14 #include "playlist.h"
    1517#include "playlistcontainer.h"
    1618#include "smartplaylist.h"
    1719
     
    847849    return songlist;
    848850}
    849851
     852void Playlist::computeIntelliOrder(QList<Track*>&          songs,
     853                                   std::map<int,uint32_t>& order,
     854                                   int                     playcountMin,
     855                                   int                     playcountMax,
     856                                   double                  lastplayMin,
     857                                   double                  lastplayMax)
     858{
     859    assert(order.empty());
     860
     861    int RatingWeight = 2;
     862    int PlayCountWeight = 2;
     863    int LastPlayWeight = 2;
     864    int RandomWeight = 2;
     865    parent->FillIntelliWeights(RatingWeight, PlayCountWeight, LastPlayWeight,
     866                               RandomWeight);
     867
     868    // first we compute all the weights
     869    std::map<int,double> weights;
     870    std::map<int,int> ratings;
     871    std::map<int,int> ratingCounts;
     872    int TotalWeight = RatingWeight + PlayCountWeight + LastPlayWeight;
     873    for (int trackItI = 0; trackItI < songs.size(); ++trackItI)
     874    {
     875        Track *trackIt = songs[trackItI];
     876        if (!trackIt->getCDFlag())
     877        {
     878            int songId = trackIt->getValue();
     879            if (songId == 0)
     880            {
     881                VERBOSE(VB_IMPORTANT, "Song with ID of 0 in playlist, this "
     882                                      "shouldn't happen.");
     883            }
     884            if (songId > 0)
     885            {
     886                Metadata *tmpdata = all_available_music->getMetadata(songId);
     887                if (tmpdata && tmpdata->isVisible())
     888                {
     889                    int rating = tmpdata->Rating();
     890                    int playcount = tmpdata->PlayCount();
     891                    double lastplaydbl = tmpdata->LastPlay();
     892                    double ratingValue = (double)(rating) / 10;
     893                    double playcountValue, lastplayValue;
     894
     895                    if (playcountMax == playcountMin)
     896                        playcountValue = 0;
     897                    else
     898                        playcountValue = ((playcountMin - (double)playcount) / (playcountMax - playcountMin) + 1);
     899
     900                    if (lastplayMax == lastplayMin)
     901                        lastplayValue = 0;
     902                    else
     903                        lastplayValue = ((lastplayMin - lastplaydbl) / (lastplayMax - lastplayMin) + 1);
     904
     905                    double weight = (RatingWeight * ratingValue +
     906                                     PlayCountWeight * playcountValue +
     907                                     LastPlayWeight * lastplayValue) / TotalWeight;
     908                    weights[songId] = weight;
     909                    ratings[songId] = rating;
     910                    ++ratingCounts[rating];
     911                }
     912            }
     913        }
     914    }
     915
     916    // then we divide weights with the number of songs in the rating class
     917    // (more songs in a class ==> lower weight, without affecting other classes)
     918    double totalWeights = 0;
     919    std::map<int,double>::iterator weightsIt, weightsEnd = weights.end();
     920    for(weightsIt = weights.begin() ; weightsIt != weightsEnd ; ++weightsIt)
     921    {
     922        weightsIt->second /= ratingCounts[ratings[weightsIt->first]];
     923        totalWeights += weightsIt->second;
     924    }
     925
     926    // then we get a random order, balanced with relative weights of remaining songs
     927    uint32_t orderCpt = 1;
     928    std::map<int,double>::iterator weightIt, weightEnd;
     929    while(weights.size() > 0)
     930    {
     931        double hit = totalWeights * (double)rand() / (double)RAND_MAX;
     932        weightEnd = weights.end();
     933        weightIt = weights.begin();
     934        double pos = 0;
     935        while(weightIt != weightEnd)
     936        {
     937            pos += weightIt->second;
     938            if(pos >= hit) break;
     939            ++weightIt;
     940        }
     941        order[weightIt->first] = orderCpt;
     942        totalWeights -= weightIt->second;
     943        weights.erase(weightIt);
     944        ++orderCpt;
     945    }
     946}
     947
    850948int Playlist::writeTree(GenericTree *tree_to_write_to, int a_counter)
    851949{
    852950    // compute max/min playcount,lastplay for this playlist
     
    9321030        count++;
    9331031    }
    9341032
    935     int RatingWeight = 2;
    936     int PlayCountWeight = 2;
    937     int LastPlayWeight = 2;
    938     int RandomWeight = 2;
     1033    std::map<int,uint32_t> intelliOrder;
     1034    computeIntelliOrder(songs, intelliOrder,
     1035                        playcountMin, playcountMax,
     1036                        lastplayMin, lastplayMax);
    9391037
    940     parent->FillIntelliWeights(RatingWeight, PlayCountWeight, LastPlayWeight,
    941                                RandomWeight);
    942 
    9431038    for (it = songs.begin(); it != songs.end(); ++it)
    9441039    {
    9451040        if (!(*it)->getCDFlag())
     
    9651060                    added_node->setAttribute(1, a_counter); //  regular order
    9661061                    added_node->setAttribute(2, rand()); //  random order
    9671062
    968                     //
    969                     //  Compute "intelligent" weighting
    970                     //
    971 
    972                     int rating = tmpdata->Rating();
    973                     int playcount = tmpdata->PlayCount();
    974                     double lastplaydbl = tmpdata->LastPlay();
    975                     double ratingValue = (double)(rating) / 10;
    976                     double playcountValue, lastplayValue;
    977 
    978                     if (playcountMax == playcountMin)
    979                         playcountValue = 0;
    980                     else
    981                         playcountValue = ((playcountMin - (double)playcount)
    982                                          / (playcountMax - playcountMin) + 1);
    983 
    984                     if (lastplayMax == lastplayMin)
    985                         lastplayValue = 0;
    986                     else
    987                         lastplayValue = ((lastplayMin - lastplaydbl)
    988                                         / (lastplayMax - lastplayMin) + 1);
    989 
    990                     double rating_value =  (RatingWeight * ratingValue +
    991                                             PlayCountWeight * playcountValue +
    992                                             LastPlayWeight * lastplayValue +
    993                                             RandomWeight * (double)rand() /
    994                                             (RAND_MAX + 1.0));
    995                     uint32_t integer_rating = (int) (4000001 -
    996                                                      rating_value * 10000);
    9971063                    //  "intelligent" order
    998                     added_node->setAttribute(3, integer_rating);
     1064                    added_node->setAttribute(3, intelliOrder[(*it)->getValue()]);
    9991065
    10001066                    // "intellegent/album" order
    10011067                    uint32_t album_order;