| 946 | void 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 | |
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); |