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