| 926 | void 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 | |
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 | | |