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