server: Convert non-afs commands to lopsub.
[paraslash.git] / mood.c
diff --git a/mood.c b/mood.c
index d29c62c22b396ac685f140b9d936f041184ca5d3..79f47e5a3d20801832d5ad396bbd5b3b98aeed08 100644 (file)
--- a/mood.c
+++ b/mood.c
@@ -19,6 +19,7 @@
 #include "mm.h"
 #include "sideband.h"
 #include "mood.h"
+#include "sched.h"
 
 /**
  * Contains statistical data of the currently admissible audio files.
@@ -446,7 +447,7 @@ static int64_t normalized_value(int64_t x, int64_t n, int64_t sum, int64_t qd)
 {
        if (!n || !qd)
                return 0;
-       return 100 * (n * x - sum) / (int64_t)int_sqrt(n * qd);
+       return 100 * (n * x - sum) / (int64_t)int_sqrt(n) / (int64_t)int_sqrt(qd);
 }
 
 static long compute_score(struct afs_info *afsi, long mood_score)
@@ -460,7 +461,7 @@ static long compute_score(struct afs_info *afsi, long mood_score)
 
 static int add_afs_statistics(const struct osl_row *row)
 {
-       uint64_t n, x, s;
+       uint64_t n, x, s, q;
        struct afs_info afsi;
        int ret;
 
@@ -470,14 +471,18 @@ static int add_afs_statistics(const struct osl_row *row)
        n = statistics.num;
        x = afsi.last_played;
        s = statistics.last_played_sum;
-       if (n > 0)
-               statistics.last_played_qd += (x - s / n) * (x - s / n) * n / (n + 1);
+       if (n > 0) {
+               q = (x > s / n)? x - s / n : s / n - x;
+               statistics.last_played_qd += q * q * n / (n + 1);
+       }
        statistics.last_played_sum += x;
 
        x = afsi.num_played;
        s = statistics.num_played_sum;
-       if (n > 0)
-               statistics.num_played_qd += (x - s / n) * (x - s / n) * n / (n + 1);
+       if (n > 0) {
+               q = (x > s / n)? x - s / n : s / n - x;
+               statistics.num_played_qd += q * q * n / (n + 1);
+       }
        statistics.num_played_sum += x;
        statistics.num++;
        return 1;
@@ -604,7 +609,8 @@ static int add_if_admissible(struct osl_row *aft_row, void *data)
  * the last number a_n was replaced by b) may be computed in O(1) time in terms
  * of n, q, a_n, b, and S as
  *
- *     q' = q + d * s - (2 * S + d) * d / n,
+ *     q' = q + d * s - (2 * S + d) * d / n
+ *        = q + d * (s - 2 * S / n - d /n),
  *
  * where d = b - a_n, and s = b + a_n.
  *
@@ -621,7 +627,7 @@ _static_inline_ int64_t update_quadratic_deviation(int64_t n, int64_t old_qd,
 {
        int64_t delta = new_val - old_val;
        int64_t sigma = new_val + old_val;
-       return old_qd + delta * sigma - (2 * old_sum + delta) * delta / n;
+       return old_qd + delta * (sigma - 2 * old_sum / n - delta / n);
 }
 
 static int update_afs_statistics(struct afs_info *old_afsi, struct afs_info *new_afsi)
@@ -741,23 +747,34 @@ static int mood_update_audio_file(const struct osl_row *aft_row,
                percent = 100;
        else if (percent < 0)
                percent = 0;
-       PARA_DEBUG_LOG("moving from rank %u to %lu%%\n", rank, percent);
+       PARA_DEBUG_LOG("moving from rank %u to %li%%\n", rank, percent);
        return score_update(aft_row, percent);
 }
 
 static void log_statistics(void)
 {
        unsigned n = statistics.num;
+       int mean_days, sigma_days;
+       /*
+        * We can not use the "now" pointer from sched.c here because we are
+        * called before schedule(), which initializes "now".
+        */
+       struct timeval rnow;
 
+       assert(current_mood);
+       PARA_NOTICE_LOG("loaded mood %s\n", current_mood->name?
+               current_mood->name : "(dummy)");
        if (!n) {
-               PARA_NOTICE_LOG("no admissible files\n");
+               PARA_WARNING_LOG("no admissible files\n");
                return;
        }
-       PARA_INFO_LOG("last_played mean: %lli, last_played sigma: %llu\n",
-               (long long int)(statistics.last_played_sum / n),
-               (long long unsigned)int_sqrt(statistics.last_played_qd / n));
-       PARA_INFO_LOG("num_played mean: %lli, num_played sigma: %llu\n",
-               (long long int)statistics.num_played_sum / n,
+       PARA_NOTICE_LOG("%u admissible files\n", statistics.num);
+       clock_get_realtime(&rnow);
+       mean_days = (rnow.tv_sec - statistics.last_played_sum / n) / 3600 / 24;
+       sigma_days = int_sqrt(statistics.last_played_qd / n) / 3600 / 24;
+       PARA_NOTICE_LOG("last_played mean/sigma: %d/%d days\n", mean_days, sigma_days);
+       PARA_NOTICE_LOG("num_played mean/sigma: %llu/%llu\n",
+               (long long unsigned)statistics.num_played_sum / n,
                (long long unsigned)int_sqrt(statistics.num_played_qd / n));
 }
 
@@ -790,7 +807,7 @@ void close_current_mood(void)
  * \sa struct admissible_file_info, struct admissible_array, struct
  * afs_info::last_played, mood_close().
  */
-int change_current_mood(char *mood_name)
+int change_current_mood(const char *mood_name)
 {
        int i, ret;
        struct admissible_array aa = {
@@ -802,7 +819,7 @@ int change_current_mood(char *mood_name)
                struct mood *m;
                struct osl_row *row;
                struct osl_object obj = {
-                       .data = mood_name,
+                       .data = (char *)mood_name,
                        .size = strlen(mood_name) + 1
                };
                ret = osl(osl_get_row(moods_table, BLOBCOL_NAME, &obj, &row));
@@ -824,15 +841,13 @@ int change_current_mood(char *mood_name)
        ret = audio_file_loop(&aa, add_if_admissible);
        if (ret < 0)
                return ret;
-       log_statistics();
-       PARA_INFO_LOG("%d admissible files\n", statistics.num);
        for (i = 0; i < statistics.num; i++) {
                struct admissible_file_info *a = aa.array + i;
                ret = add_to_score_table(a->aft_row, a->score);
                if (ret < 0)
                        goto out;
        }
-       PARA_NOTICE_LOG("loaded mood %s\n", mood_name? mood_name : "(dummy)");
+       log_statistics();
        ret = statistics.num;
 out:
        free(aa.array);