]> git.tuebingen.mpg.de Git - paraslash.git/blobdiff - mood.c
Rename mood_switch(), mood_close(), playlist_{open/close}.
[paraslash.git] / mood.c
diff --git a/mood.c b/mood.c
index 66024db6add623716b428edd0263847705bc80e9..50a67793ea6c6ccaeceb4298b0beb028c8926286 100644 (file)
--- a/mood.c
+++ b/mood.c
@@ -48,11 +48,11 @@ struct afs_statistics {
 };
 
 /**
- * Stores an instance of an open mood (parser and statistics).
+ * Stores an instance of a loaded mood (parser and statistics).
  *
- * A structure of this type is allocated and initialized at mood open time.
+ * A structure of this type is allocated and initialized when a mood is loaded.
  */
-struct mood {
+struct mood_instance {
        /** NULL means that this is the "dummy" mood. */
        char *name;
        /** Bison's abstract syntax tree, used to determine admissibility. */
@@ -62,13 +62,13 @@ struct mood {
 };
 
 /*
- * If current_mood is NULL then no mood is currently open. If
- * current_mood->name is NULL, the dummy mood is currently open.
+ * If current_mood is NULL then no mood is currently loaded. If
+ * current_mood->name is NULL, the current mood is the dummy mood.
  *
  * The statistics are adjusted dynamically through this pointer as files are
  * added, removed or played.
  */
-static struct mood *current_mood;
+static struct mood_instance *current_mood;
 
 /*
  * Find the position of the most-significant set bit.
@@ -127,7 +127,7 @@ __a_const static uint64_t int_sqrt(uint64_t x)
        return res;
 }
 
-static void destroy_mood(struct mood *m)
+static void destroy_mood(struct mood_instance *m)
 {
        if (!m)
                return;
@@ -136,16 +136,18 @@ static void destroy_mood(struct mood *m)
        free(m);
 }
 
-static struct mood *alloc_new_mood(const char *name)
+static struct mood_instance *alloc_new_mood(const char *name)
 {
-       struct mood *m = zalloc(sizeof(struct mood));
+       struct mood_instance *m = zalloc(sizeof(*m));
+
        if (name)
                m->name = para_strdup(name);
        m->stats.normalization_divisor = 1;
        return m;
 }
 
-static int init_mood_parser(const char *mood_name, struct mood **m, char **err)
+static int init_mood_parser(const char *mood_name, struct mood_instance **m,
+               char **err)
 {
        struct osl_object mood_def;
        int ret;
@@ -162,7 +164,7 @@ static int init_mood_parser(const char *mood_name, struct mood **m, char **err)
                return ret;
        }
        *m = alloc_new_mood(mood_name);
-       PARA_INFO_LOG("opening mood %s\n", mood_name);
+       PARA_INFO_LOG("loading mood %s\n", mood_name);
        ret = mp_init(mood_def.data, mood_def.size, &(*m)->parser_context, err);
        osl_close_disk_object(&mood_def);
        if (ret < 0)
@@ -175,7 +177,7 @@ static int check_mood(struct osl_row *mood_row, void *data)
        struct para_buffer *pb = data;
        char *mood_name, *errmsg;
        struct osl_object mood_def;
-       struct mood *m;
+       struct mood_instance *m;
        int ret = mood_get_name_and_def_by_row(mood_row, &mood_name, &mood_def);
 
        if (ret < 0) {
@@ -336,7 +338,7 @@ static int del_afs_statistics(const struct osl_row *row)
 }
 
 /*
- * At mood open time we determine the set of admissible files for the given
+ * At mood load time we determine the set of admissible files for the given
  * mood where each file is identified by a pointer to a row of the audio file
  * table. In the first pass the pointers are added to a temporary array and
  * statistics are computed. When all admissible files have been processed in
@@ -346,7 +348,7 @@ static int del_afs_statistics(const struct osl_row *row)
  */
 struct admissible_array {
        /** Files are admissible wrt. this mood. */
-       struct mood *m;
+       struct mood_instance *m;
        /** The size of the array */
        unsigned size;
        /** Pointer to the array of admissible files. */
@@ -521,36 +523,28 @@ static int mood_update_audio_file(const struct osl_row *aft_row,
 }
 
 /* sse: seconds since epoch. */
-static void log_statistics(struct afs_statistics *stats, int64_t sse)
+static char *get_statistics(struct mood_instance *m, int64_t sse)
 {
-       unsigned n = stats->num;
+       unsigned n = m->stats.num;
        int mean_days, sigma_days;
 
-       if (!n) {
-               PARA_WARNING_LOG("no admissible files\n");
-               return;
-       }
-       PARA_NOTICE_LOG("%u admissible files\n", stats->num);
-       mean_days = (sse - stats->last_played_sum / n) / 3600 / 24;
-       sigma_days = int_sqrt(stats->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: %" PRId64 "/%" PRIu64 "\n",
-               stats->num_played_sum / n,
-               int_sqrt(stats->num_played_qd / n));
-       PARA_NOTICE_LOG("num_played correction factor: %" PRId64 "\n",
-               stats->num_played_correction);
-       PARA_NOTICE_LOG("last_played correction factor: %" PRId64 "\n",
-               stats->last_played_correction);
-       PARA_NOTICE_LOG("normalization divisor: %" PRId64 "\n",
-               stats->normalization_divisor);
+       mean_days = (sse - m->stats.last_played_sum / n) / 3600 / 24;
+       sigma_days = int_sqrt(m->stats.last_played_qd / n) / 3600 / 24;
+       return make_message(
+               "loaded mood %s (%u files)\n"
+               "last_played mean/sigma: %d/%d days\n"
+               "num_played mean/sigma: %" PRId64 "/%" PRIu64 "\n"
+       ,
+               m->name? m->name : "(dummy)",
+               n,
+               mean_days, sigma_days,
+               m->stats.num_played_sum / n,
+                       int_sqrt(m->stats.num_played_qd / n)
+       );
 }
 
-/**
- * Close the current mood.
- *
- * Frees all resources of the current mood.
- */
-void close_current_mood(void)
+/** Free all resources of the current mood, if any. */
+void mood_unload(void)
 {
        destroy_mood(current_mood);
        current_mood = NULL;
@@ -575,22 +569,21 @@ static void compute_correction_factors(int64_t sse, struct afs_statistics *s)
 /**
  * Change the current mood.
  *
- * \param mood_name The name of the mood to open.
- * \param errmsg Error description is returned here.
+ * \param mood_name The name of the mood to load.
+ * \param msg Error message or mood info is returned here.
  *
  * If \a mood_name is \a NULL, load the dummy mood that accepts every audio file
  * and uses a scoring method based only on the \a last_played information.
  *
- * The errmsg pointer may be NULL, in which case no error message will be
- * returned. If a non-NULL pointer is given, the caller must free *errmsg.
- *
- * If there is already an open mood, it will be closed first.
+ * If the message pointer is not NULL, a suitable message is returned there in
+ * all cases. The caller must free this string.
  *
- * \return Positive on success, negative on errors.
+ * \return The number of admissible files on success, negative on errors. It is
+ * not considered an error if no files are admissible.
  *
  * \sa struct \ref afs_info::last_played, \ref mp_eval_row().
  */
-int mood_switch(const char *mood_name, char **errmsg)
+int mood_load(const char *mood_name, char **msg)
 {
        int i, ret;
        struct admissible_array aa = {.size = 0};
@@ -601,7 +594,7 @@ int mood_switch(const char *mood_name, char **errmsg)
        struct timeval rnow;
 
        if (mood_name) {
-               ret = init_mood_parser(mood_name, &aa.m, errmsg);
+               ret = init_mood_parser(mood_name, &aa.m, msg);
                if (ret < 0)
                        return ret;
        } else /* load dummy mood */
@@ -609,27 +602,33 @@ int mood_switch(const char *mood_name, char **errmsg)
        PARA_NOTICE_LOG("computing statistics of admissible files\n");
        ret = audio_file_loop(&aa, add_if_admissible);
        if (ret < 0) {
-               if (errmsg)
-                       *errmsg = make_message("audio file loop failed");
+               if (msg) /* false if we are called via the event handler */
+                       *msg = make_message("audio file loop failed\n");
                goto out;
        }
        clock_get_realtime(&rnow);
        compute_correction_factors(rnow.tv_sec, &aa.m->stats);
-       log_statistics(&aa.m->stats, rnow.tv_sec);
+       if (aa.m->stats.num == 0) {
+               if (msg)
+                       *msg = make_message("no admissible files\n");
+               ret = 0;
+               goto out;
+       }
        for (i = 0; i < aa.m->stats.num; i++) {
                ret = add_to_score_table(aa.array[i], &aa.m->stats);
                if (ret < 0) {
-                       if (errmsg)
-                               *errmsg = make_message(
-                                       "could not add row to score table");
+                       if (msg)
+                               *msg = make_message(
+                                       "could not add row to score table\n");
                        goto out;
                }
        }
        /* success */
-       close_current_mood();
-       current_mood = aa.m;
-       PARA_NOTICE_LOG("loaded mood %s\n", mood_name? mood_name : "(dummy)");
+       if (msg)
+               *msg = get_statistics(aa.m, rnow.tv_sec);
        ret = aa.m->stats.num;
+       mood_unload();
+       current_mood = aa.m;
 out:
        free(aa.array);
        if (ret < 0)
@@ -638,7 +637,7 @@ out:
 }
 
 /*
- * Close and re-open the current mood.
+ * Empty the score table and start over.
  *
  * This function is called on events which render the current list of
  * admissible files useless, for example if an attribute is removed from the
@@ -650,15 +649,13 @@ static int reload_current_mood(void)
        char *mood_name = NULL;
 
        assert(current_mood);
-       ret = clear_score_table();
-       if (ret < 0)
-               return ret;
+       score_clear();
        PARA_NOTICE_LOG("reloading %s\n", current_mood->name?
                current_mood->name : "(dummy)");
        if (current_mood->name)
                mood_name = para_strdup(current_mood->name);
-       close_current_mood();
-       ret = mood_switch(mood_name, NULL);
+       mood_unload();
+       ret = mood_load(mood_name, NULL);
        free(mood_name);
        return ret;
 }