+++ /dev/null
-/* Copyright (C) 2007 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
-
-/** \file mm.c Paraslash's mood methods. */
-
-#include <regex.h>
-#include <fnmatch.h>
-#include <osl.h>
-#include <lopsub.h>
-
-#include "para.h"
-#include "error.h"
-#include "string.h"
-#include "afh.h"
-#include "afs.h"
-#include "mm.h"
-
-/** The comparators for numeric mood methods (year, bitrate, ...). */
-#define MOOD_COMPARATORS \
- MC(LESS, <) \
- MC(LESS_OR_EQUAL, <=) \
- MC(EQUAL, =) \
- MC(EQUAL2, ==) \
- MC(NOT_EQUAL, !=) \
- MC(NOT_EQUAL2, <>) \
- MC(GREATER, >) \
- MC(GREATER_OR_EQUAL, >=) \
-
-/** Prefix mood comparator name with "_MC", example: MC_LESS. */
-#define MC(a, b) MC_ ## a,
-/** Each mood comparator is identified by an integer of this type. */
-enum mood_comparator_id {MOOD_COMPARATORS NUM_MOOD_COMPARATORS};
-#undef MC
-/** Stringfied mood comparator, example: "<". */
-#define MC(a, b) # b,
-/** Array of mood comparators represented as C strings ("<", "<=", ...). */
-static const char *mood_comparators[] = {MOOD_COMPARATORS};
-#undef MC
-
-static int parse_mood_comparator(const char *word)
-{
- int i;
-
- for (i = 0; i < NUM_MOOD_COMPARATORS; i++)
- if (!strcmp(word, mood_comparators[i]))
- return i;
- return -E_MOOD_SYNTAX;
-}
-
-struct mm_compare_num_data {
- /** <, <=, =, !=, >=, or >. */
- enum mood_comparator_id id;
- /** The value given at the mood line. */
- int32_t arg;
-};
-
-static int mm_compare_num_score_function(int32_t val,
- const struct mm_compare_num_data *cnd)
-{
- int res;
- int32_t arg = cnd->arg;
-
- switch (cnd->id) {
- case MC_LESS:
- res = val < arg; break;
- case MC_LESS_OR_EQUAL:
- res = val <= arg; break;
- case MC_EQUAL:
- case MC_EQUAL2:
- res = val == arg; break;
- case MC_NOT_EQUAL:
- case MC_NOT_EQUAL2:
- res = val != arg; break;
- case MC_GREATER:
- res = val > arg; break;
- case MC_GREATER_OR_EQUAL:
- res = val >= arg; break;
- default:
- PARA_EMERG_LOG("BUG: invalid mood comparator\n");
- exit(EXIT_FAILURE);
- }
- return res? 100 : -100;
-}
-
-static int mm_compare_num_parser(int argc, char **argv, void **private)
-{
- int ret;
- enum mood_comparator_id id;
- int32_t arg;
- struct mm_compare_num_data *cnd;
- if (argc != 2)
- return -E_MOOD_SYNTAX;
- ret = parse_mood_comparator(argv[1]);
- if (ret < 0)
- return ret;
- id = ret;
- ret = para_atoi32(argv[2], &arg);
- if (ret < 0)
- return ret;
- cnd = para_malloc(sizeof(struct mm_compare_num_data));
- cnd->id = id;
- cnd->arg = arg;
- *private = cnd;
- return 1;
-}
-
-static int mm_regex_parser(int argc, char **argv, void **private)
-{
- regex_t *preg;
- int ret;
-
- if (argc != 1)
- return -E_MOOD_SYNTAX;
- preg = para_malloc(sizeof(*preg));
- ret = para_regcomp(preg, argv[1], REG_EXTENDED | REG_NOSUB);
- if (ret < 0) {
- free(preg);
- return ret;
- }
- *private = preg;
- return 1;
-}
-
-static int mm_regex_score_function(const regex_t *preg, const char *pattern)
-{
- return regexec(preg, pattern, 0, NULL, 0) == 0? 100 : -100;
-}
-
-static void mm_regex_cleanup(void *private)
-{
- regex_t *preg = private;
- regfree(preg);
- free(preg);
-}
-
-static int mm_artist_matches_score_function(__a_unused const char *path,
- __a_unused const struct afs_info *afsi,
- const struct afh_info *afhi,
- const void *private)
-{
- return mm_regex_score_function(private, afhi->tags.artist);
-}
-
-static int mm_title_matches_score_function(__a_unused const char *path,
- __a_unused const struct afs_info *afsi,
- const struct afh_info *afhi,
- const void *private)
-{
- return mm_regex_score_function(private, afhi->tags.title);
-}
-
-static int mm_album_matches_score_function(__a_unused const char *path,
- __a_unused const struct afs_info *afsi,
- const struct afh_info *afhi,
- const void *private)
-{
- return mm_regex_score_function(private, afhi->tags.album);
-}
-
-static int mm_comment_matches_score_function(__a_unused const char *path,
- __a_unused const struct afs_info *afsi,
- const struct afh_info *afhi,
- const void *private)
-{
- return mm_regex_score_function(private, afhi->tags.comment);
-}
-
-static int mm_bitrate_score_function(__a_unused const char *path,
- __a_unused const struct afs_info *afsi,
- const struct afh_info *afhi,
- const void *private)
-{
- return mm_compare_num_score_function(afhi->bitrate, private);
-}
-
-static int mm_frequency_score_function(__a_unused const char *path,
- __a_unused const struct afs_info *afsi,
- const struct afh_info *afhi,
- const void *private)
-{
- return mm_compare_num_score_function(afhi->frequency, private);
-}
-
-static int mm_channels_score_function(__a_unused const char *path,
- __a_unused const struct afs_info *afsi,
- const struct afh_info *afhi,
- const void *private)
-{
- return mm_compare_num_score_function(afhi->channels, private);
-}
-
-static int mm_image_id_score_function(__a_unused const char *path,
- const struct afs_info *afsi,
- __a_unused const struct afh_info *afhi,
- const void *private)
-{
- return mm_compare_num_score_function(afsi->image_id, private);
-}
-
-static int mm_lyrics_id_score_function(__a_unused const char *path,
- const struct afs_info *afsi,
- __a_unused const struct afh_info *afhi,
- const void *private)
-{
- return mm_compare_num_score_function(afsi->lyrics_id, private);
-}
-
-static int mm_num_played_score_function(__a_unused const char *path,
- const struct afs_info *afsi,
- __a_unused const struct afh_info *afhi,
- const void *private)
-{
- return mm_compare_num_score_function(afsi->num_played, private);
-}
-
-struct mm_year_data {
- /** Comparator and year given at the mood line. */
- struct mm_compare_num_data *cnd;
- /** Used to detect Y2K issues. */
- int32_t current_year;
-};
-
-static int mm_year_parser(int argc, char **argv, void **private)
-{
- int ret;
- struct mm_year_data *mmyd = para_malloc(sizeof(*mmyd));
- time_t current_time;
- struct tm *gmt;
-
- ret = mm_compare_num_parser(argc, argv, (void **)&mmyd->cnd);
- if (ret < 0)
- goto err;
- current_time = time(NULL);
- gmt = gmtime(¤t_time);
- /* tm_year is the number of years since 1900 */
- mmyd->current_year = gmt->tm_year + 1900;
- *private = mmyd;
- return 1;
-err:
- free(mmyd);
- return ret;
-}
-
-static int mm_year_score_function(__a_unused const char *path,
- __a_unused const struct afs_info *afsi,
- const struct afh_info *afhi,
- const void *private)
-{
- const struct mm_year_data *mmyd = private;
- int32_t tag_year;
- int ret = para_atoi32(afhi->tags.year, &tag_year);
-
- if (ret < 0) /* year tag not present or not a number */
- return -100;
- if (tag_year < 0)
- return -100;
- /* try to work around Y2K issues */
- if (tag_year < 100) {
- tag_year += 1900;
- if (tag_year + 100 <= mmyd->current_year)
- tag_year += 100; /* assume tag_year >= 2000 */
- }
- return mm_compare_num_score_function(tag_year, mmyd->cnd);
-}
-
-static void mm_year_cleanup(void *private)
-{
- struct mm_year_data *mmyd = private;
-
- free(mmyd->cnd);
- free(mmyd);
-}
-
-static int mm_no_attributes_set_parser(int argc, __a_unused char **argv,
- __a_unused void **ignored)
-{
- return argc? -E_MOOD_SYNTAX : 1;
-}
-
-static int mm_no_attributes_set_score_function(__a_unused const char *path,
- const struct afs_info *afsi,
- __a_unused const struct afh_info *afhi,
- __a_unused const void *data)
-{
- if (!afsi->attributes)
- return 100;
- return -100;
-}
-
-static int mm_path_matches_score_function(const char *path,
- __a_unused const struct afs_info *afsi,
- __a_unused const struct afh_info *afhi,
- const void *data)
-{
- if (fnmatch(data, path, 0))
- return -100;
- return 100;
-}
-
-static int mm_path_matches_parser(int argc, char **argv, void **data)
-{
- if (argc != 1)
- return -E_MOOD_SYNTAX;
- *data = para_strdup(argv[1]);
- return 1;
-}
-
-static void mm_path_matches_cleanup(void *data)
-{
- free(data);
-}
-
-static int mm_is_set_parser(int argc, char **argv, void **bitnum)
-{
- int ret;
- unsigned char c, *res;
-
- if (argc != 1)
- return -E_MOOD_SYNTAX;
- ret = get_attribute_bitnum_by_name(argv[1], &c);
- if (ret < 0)
- return ret;
- res = para_malloc(1);
- *res = c;
- *bitnum = res;
- return 1;
-}
-
-static int mm_is_set_score_function(__a_unused const char *path,
- __a_unused const struct afs_info *afsi,
- __a_unused const struct afh_info *afhi,
- const void *data)
-{
- const unsigned char *bn = data;
- if (afsi->attributes & (1ULL << *bn))
- return 100;
- return -100;
-}
-
-#define DEFINE_MOOD_METHOD(_name) \
-.parser = mm_ ## _name ## _parser, \
-.score_function = mm_ ## _name ## _score_function, \
-.name = #_name
-
-#define DEFINE_MOOD_METHOD_WITH_CLEANUP(_name) \
- DEFINE_MOOD_METHOD(_name), \
- .cleanup = mm_ ## _name ## _cleanup
-
-#define DEFINE_REGEX_MOOD_METHOD(_name) \
- .name = #_name, \
- .parser = mm_regex_parser, \
- .score_function = mm_ ## _name ## _score_function, \
- .cleanup = mm_regex_cleanup
-
-#define DEFINE_COMPARE_NUM_MOOD_METHOD(_name) \
- .name = #_name, \
- .parser = mm_compare_num_parser, \
- .score_function = mm_ ## _name ## _score_function
-
-const struct mood_method mood_methods[] = {
- {DEFINE_MOOD_METHOD(no_attributes_set)},
- {DEFINE_MOOD_METHOD(is_set)},
- {DEFINE_MOOD_METHOD_WITH_CLEANUP(path_matches)},
- {DEFINE_MOOD_METHOD_WITH_CLEANUP(year)},
- {DEFINE_REGEX_MOOD_METHOD(artist_matches)},
- {DEFINE_REGEX_MOOD_METHOD(title_matches)},
- {DEFINE_REGEX_MOOD_METHOD(album_matches)},
- {DEFINE_REGEX_MOOD_METHOD(comment_matches)},
- {DEFINE_COMPARE_NUM_MOOD_METHOD(bitrate)},
- {DEFINE_COMPARE_NUM_MOOD_METHOD(frequency)},
- {DEFINE_COMPARE_NUM_MOOD_METHOD(channels)},
- {DEFINE_COMPARE_NUM_MOOD_METHOD(num_played)},
- {DEFINE_COMPARE_NUM_MOOD_METHOD(image_id)},
- {DEFINE_COMPARE_NUM_MOOD_METHOD(lyrics_id)},
- {.parser = NULL}
-};
#include "afh.h"
#include "afs.h"
#include "list.h"
-#include "mm.h"
#include "mood.h"
/*
};
static struct afs_statistics statistics;
-/**
- * Each line of the current mood corresponds to a mood_item.
- */
-struct mood_item {
- /** The method this line is referring to. */
- const struct mood_method *method;
- /** The data structure computed by the mood parser. */
- void *parser_data;
- /** The given score value, or zero if none was given. */
- int32_t score_arg;
- /** Non-zero if random scoring was requested. */
- int random_score;
- /** Whether the "not" keyword was given in the mood line. */
- int logical_not;
- /** The position in the list of items. */
- struct list_head mood_item_node;
-};
-
-/*
- * Created from the mood definition by \ref change_current_mood().
- *
- * When a mood is opened, each line of its definition is investigated, and a
- * corresponding mood item is produced. Each mood line starts with accept,
- * deny, or score which determines the type of the mood line. For each such
- * type a linked list is maintained whose entries are the mood items.
- */
struct mood {
/** The name of this mood. */
char *name;
- /** The list of mood items of type \p accept. */
- struct list_head accept_list;
- /** The list of mood items of type \p deny. */
- struct list_head deny_list;
- /** The list of mood items of type \p score. */
- struct list_head score_list;
- /* Only used for version 2 moods. */
+ /** Info for the bison parser. */
struct mp_context *parser_context;
};
return res;
}
-/*
- * Returns true if row matches, false if it does not match. In any case score
- * and score_arg_sum are set/increased accordingly.
- */
-static bool get_item_score(struct mood_item *item, const struct afs_info *afsi,
- const struct afh_info *afhi, const char *path, long *score,
- long *score_arg_sum)
-{
- int ret;
- bool match = true;
-
- *score_arg_sum += item->random_score? 100 : PARA_ABS(item->score_arg);
- ret = 100;
- if (item->method) {
- ret = item->method->score_function(path, afsi, afhi,
- item->parser_data);
- if ((ret < 0 && !item->logical_not) || (ret >= 0 && item->logical_not))
- match = false;
- }
- if (item->random_score)
- *score = PARA_ABS(ret) * para_random(100);
- else
- *score = PARA_ABS(ret) * item->score_arg;
- return match;
-}
-
/* returns 1 if row admissible, 0 if not, negative on errors */
-static int row_is_admissible(const struct osl_row *aft_row, struct mood *m,
- long *scorep)
+static int row_is_admissible(const struct osl_row *aft_row, struct mood *m)
{
- struct mood_item *item;
- int ret;
- bool match;
- long score_arg_sum = 0, score = 0, item_score;
- struct afs_info afsi;
- struct afh_info afhi;
- char *path;
-
if (!m)
return -E_NO_MOOD;
- if (m->parser_context) {
- *scorep = 0;
- return mp_eval_row(aft_row, m->parser_context);
- }
- ret = get_afsi_of_row(aft_row, &afsi);
- if (ret < 0)
- return ret;
- ret = get_afhi_of_row(aft_row, &afhi);
- if (ret < 0)
- return ret;
- ret = get_audio_file_path_of_row(aft_row, &path);
- if (ret < 0)
- return ret;
- /* reject audio file if it matches any entry in the deny list */
- list_for_each_entry(item, &m->deny_list, mood_item_node) {
- match = get_item_score(item, &afsi, &afhi, path, &item_score,
- &score_arg_sum);
- if (match) /* not admissible */
- return 0;
- score += item_score;
- }
- match = false;
- list_for_each_entry(item, &m->accept_list, mood_item_node) {
- ret = get_item_score(item, &afsi, &afhi, path, &item_score,
- &score_arg_sum);
- if (ret == 0)
- continue;
- match = true;
- score += item_score;
- }
- /* reject if there is no matching entry in the accept list */
- if (!match && !list_empty(&m->accept_list))
- return 0;
- list_for_each_entry(item, &m->score_list, mood_item_node) {
- match = get_item_score(item, &afsi, &afhi, path, &item_score,
- &score_arg_sum);
- if (match)
- score += item_score;
- }
- if (score_arg_sum)
- score /= score_arg_sum;
- *scorep = score;
- return 1;
-}
-
-static void cleanup_list_entry(struct mood_item *item)
-{
- if (item->method && item->method->cleanup)
- item->method->cleanup(item->parser_data);
- else
- free(item->parser_data);
- list_del(&item->mood_item_node);
- free(item);
+ return mp_eval_row(aft_row, m->parser_context);
}
static void destroy_mood(struct mood *m)
{
- struct mood_item *tmp, *item;
-
if (!m)
return;
- list_for_each_entry_safe(item, tmp, &m->accept_list, mood_item_node)
- cleanup_list_entry(item);
- list_for_each_entry_safe(item, tmp, &m->deny_list, mood_item_node)
- cleanup_list_entry(item);
- list_for_each_entry_safe(item, tmp, &m->score_list, mood_item_node)
- cleanup_list_entry(item);
- free(m->name);
mp_shutdown(m->parser_context);
+ free(m->name);
free(m);
}
struct mood *m = para_calloc(sizeof(struct mood));
if (name)
m->name = para_strdup(name);
- INIT_LIST_HEAD(&m->accept_list);
- INIT_LIST_HEAD(&m->deny_list);
- INIT_LIST_HEAD(&m->score_list);
return m;
}
-/** The different types of a mood line. */
-enum mood_line_type {
- /** Invalid. */
- ML_INVALID,
- /** Accept line. */
- ML_ACCEPT,
- /** Deny line. */
- ML_DENY,
- /** Score line. */
- ML_SCORE
-};
-
-/** Data passed to the parser of a mood line. */
-struct mood_line_parser_data {
- /** The mood this mood line belongs to. */
- struct mood *m;
- /** The line number in the mood definition. */
- unsigned line_num;
-};
-
-/*
- * <accept [with score <score>] | deny [with score <score>] | score <score>>
- * [if] [not] <mood_method> [options]
- * <score> is either an integer or "random" which assigns a random score to
- * all matching files
- */
-static int parse_mood_line(char *mood_line, void *data)
-{
- struct mood_line_parser_data *mlpd = data;
- char **argv;
- unsigned num_words;
- char **w;
- int i, ret;
- enum mood_line_type mlt = ML_INVALID;
- struct mood_item *mi = NULL;
-
- mlpd->line_num++;
- ret = create_argv(mood_line, " \t", &argv);
- if (ret < 0)
- return ret;
- num_words = ret;
- if (!num_words) /* empty line */
- goto out;
- w = argv;
- if (**w == '#') /* comment */
- goto out;
- if (!strcmp(*w, "accept"))
- mlt = ML_ACCEPT;
- else if (!strcmp(*w, "deny"))
- mlt = ML_DENY;
- else if (!strcmp(*w, "score"))
- mlt = ML_SCORE;
- ret = -E_MOOD_SYNTAX;
- if (mlt == ML_INVALID)
- goto out;
- mi = para_calloc(sizeof(struct mood_item));
- if (mlt != ML_SCORE) {
- ret = -E_MOOD_SYNTAX;
- w++;
- if (!*w)
- goto out;
- if (strcmp(*w, "with"))
- goto check_for_if;
- w++;
- if (!*w)
- goto out;
- if (strcmp(*w, "score"))
- goto out;
- }
- if (mlt == ML_SCORE || !strcmp(*w, "score")) {
- ret = -E_MOOD_SYNTAX;
- w++;
- if (!*w)
- goto out;
- if (strcmp(*w, "random")) {
- mi->random_score = 0;
- ret = para_atoi32(*w, &mi->score_arg);
- if (ret < 0)
- goto out;
- } else {
- mi->random_score = 1;
- if (!*(w + 1))
- goto success; /* the line "score random" is valid */
- }
- } else
- mi->score_arg = 0;
- ret = -E_MOOD_SYNTAX;
- w++;
- if (!*w)
- goto out;
-check_for_if:
- if (!strcmp(*w, "if")) {
- ret = -E_MOOD_SYNTAX;
- w++;
- if (!*w)
- goto out;
- }
- if (!strcmp(*w, "not")) {
- ret = -E_MOOD_SYNTAX;
- w++;
- if (!*w)
- goto out;
- mi->logical_not = 1;
- } else
- mi->logical_not = 0;
- for (i = 0; mood_methods[i].parser; i++) {
- if (strcmp(*w, mood_methods[i].name))
- continue;
- break;
- }
- ret = -E_MOOD_SYNTAX;
- if (!mood_methods[i].parser)
- goto out;
- ret = mood_methods[i].parser(num_words - 1 - (w - argv), w,
- &mi->parser_data);
- if (ret < 0)
- goto out;
- mi->method = &mood_methods[i];
-success:
- if (mlpd->m) {
- if (mlt == ML_ACCEPT)
- para_list_add(&mi->mood_item_node, &mlpd->m->accept_list);
- else if (mlt == ML_DENY)
- para_list_add(&mi->mood_item_node, &mlpd->m->deny_list);
- else
- para_list_add(&mi->mood_item_node, &mlpd->m->score_list);
- }
- PARA_DEBUG_LOG("%s entry added, method: %p\n", mlt == ML_ACCEPT? "accept" :
- (mlt == ML_DENY? "deny" : "score"), mi->method);
- ret = 1;
-out:
- free_argv(argv);
- if (mi && (ret < 0 || !mlpd->m)) { /* mi was not added to any list */
- free(mi->parser_data);
- free(mi);
- }
- return ret;
-}
-
static int load_mood(const struct osl_row *mood_row, struct mood **m,
char **errmsg)
{
char *mood_name;
struct osl_object mood_def;
- struct mood_line_parser_data mlpd = {.line_num = 0};
int ret;
- *m = NULL;
ret = mood_get_name_and_def_by_row(mood_row, &mood_name, &mood_def);
if (ret < 0) {
if (errmsg)
return ret;
}
assert(*mood_name);
- mlpd.m = alloc_new_mood(mood_name);
- ret = for_each_line(FELF_READ_ONLY, mood_def.data, mood_def.size,
- parse_mood_line, &mlpd);
- if (ret < 0) {
- PARA_INFO_LOG("opening version 2 mood %s\n", mlpd.m->name);
- ret = mp_init(mood_def.data, mood_def.size, &mlpd.m->parser_context,
- errmsg);
- if (ret < 0)
- destroy_mood(mlpd.m);
- } else {
- PARA_WARNING_LOG("loaded version 1 mood %s\n", mlpd.m->name);
- PARA_WARNING_LOG("please convert to version 2\n");
- ret = 1;
- }
+ *m = alloc_new_mood(mood_name);
+ PARA_INFO_LOG("opening mood %s\n", mood_name);
+ ret = mp_init(mood_def.data, mood_def.size, &(*m)->parser_context, errmsg);
osl_close_disk_object(&mood_def);
- if (ret >= 0)
- *m = mlpd.m;
return ret;
}
static int check_mood(struct osl_row *mood_row, void *data)
{
struct para_buffer *pb = data;
- char *mood_name;
+ char *mood_name, *errmsg;
struct osl_object mood_def;
- struct mood_line_parser_data mlpd = {.line_num = 0};
-
+ struct mood *m;
int ret = mood_get_name_and_def_by_row(mood_row, &mood_name, &mood_def);
if (ret < 0) {
}
if (!*mood_name) /* ignore dummy row */
goto out;
- ret = for_each_line(FELF_READ_ONLY, mood_def.data, mood_def.size,
- parse_mood_line, &mlpd);
+ m = alloc_new_mood("check");
+ ret = mp_init(mood_def.data, mood_def.size, &m->parser_context,
+ &errmsg);
if (ret < 0) {
- char *errmsg;
- struct mood *m = alloc_new_mood("check");
- ret = mp_init(mood_def.data, mood_def.size, &m->parser_context,
- &errmsg);
- if (ret < 0) {
- para_printf(pb, "%s: %s\n", mood_name, errmsg);
- free(errmsg);
- para_printf(pb, "%s\n", para_strerror(-ret));
- } else
- destroy_mood(m);
- } else {
- para_printf(pb, "%s: v1 mood, please convert to v2\n",
- mood_name);
-
- }
+ para_printf(pb, "%s: %s\n", mood_name, errmsg);
+ free(errmsg);
+ para_printf(pb, "%s\n", para_strerror(-ret));
+ } else
+ destroy_mood(m);
ret = 1; /* don't fail the loop on invalid mood definitions */
out:
osl_close_disk_object(&mood_def);
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)
+static long compute_score(struct afs_info *afsi)
{
- mood_score -= normalized_value(afsi->num_played, statistics.num,
+ long score = -normalized_value(afsi->num_played, statistics.num,
statistics.num_played_sum, statistics.num_played_qd);
- mood_score -= normalized_value(afsi->last_played, statistics.num,
+ score -= normalized_value(afsi->last_played, statistics.num,
statistics.last_played_sum, statistics.last_played_qd);
- return mood_score / 3;
+ return score / 2;
}
static int add_afs_statistics(const struct osl_row *row)
/*
* At mood open time we determine the set of admissible files for the given
- * mood. The mood score of each admissible file is computed by adding up all
- * mood item scores. Next, we update the afs statistics and append a struct
- * admissible_file_info to a temporary array.
- *
- * When all files have been processed in this way, the final score of each
- * admissible file is computed by adding the dynamic score (which depends on
- * the afs_statistics and the current time) to the mood score. Finally, all
- * audio files in the temporary array are added to the score table and the
- * array is freed.
+ * 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
+ * this way, the score of each admissible file is computed and the (row, score)
+ * pair is added to the score table. This has to be done in a second pass
+ * since the score depends on the statistics. Finally, the array is freed.
*/
-struct admissible_file_info
-{
- /** The admissible audio file. */
- struct osl_row *aft_row;
- /** Its score. */
- long score;
-};
-
-/** The temporary array of admissible files. */
struct admissible_array {
/** Files are admissible wrt. this mood. */
struct mood *m;
/** The size of the array */
unsigned size;
/** Pointer to the array of admissible files. */
- struct admissible_file_info *array;
+ struct osl_row **array;
};
-/**
- * Add an entry to the array of admissible files.
- *
- * \param aft_row The audio file to be added.
- * \param private_data Pointer to a struct admissible_file_info.
- *
- * \return 1 if row admissible, 0 if not, negative on errors.
+/*
+ * Check whether the given audio file is admissible. If it is, add it to array
+ * of admissible files.
*/
static int add_if_admissible(struct osl_row *aft_row, void *data)
{
struct admissible_array *aa = data;
int ret;
- long score = 0;
- ret = row_is_admissible(aft_row, aa->m, &score);
+ ret = row_is_admissible(aft_row, aa->m);
if (ret <= 0)
return ret;
if (statistics.num >= aa->size) {
aa->size *= 2;
aa->size += 100;
aa->array = para_realloc(aa->array,
- aa->size * sizeof(struct admissible_file_info));
+ aa->size * sizeof(struct osl_row *));
}
- aa->array[statistics.num].aft_row = aft_row;
- aa->array[statistics.num].score = score;
- ret = add_afs_statistics(aft_row);
- if (ret < 0)
- return ret;
- return 1;
+ aa->array[statistics.num] = aft_row;
+ return add_afs_statistics(aft_row);
}
/**
return 1;
}
-static int add_to_score_table(const struct osl_row *aft_row, long mood_score)
+static int add_to_score_table(const struct osl_row *aft_row)
{
long score;
struct afs_info afsi;
if (ret < 0)
return ret;
- score = compute_score(&afsi, mood_score);
+ score = compute_score(&afsi);
return score_add(aft_row, score);
}
if (ret < 0)
return ret;
was_admissible = ret;
- ret = row_is_admissible(aft_row, current_mood, &score);
+ ret = row_is_admissible(aft_row, current_mood);
if (ret < 0)
return ret;
is_admissible = (ret > 0);
ret = add_afs_statistics(aft_row);
if (ret < 0)
return ret;
- return add_to_score_table(aft_row, score);
+ return add_to_score_table(aft_row);
}
/* update score */
ret = get_afsi_of_row(aft_row, &afsi);
if (ret < 0)
return ret;
}
- score = compute_score(&afsi, score);
+ score = compute_score(&afsi);
PARA_DEBUG_LOG("score: %li\n", score);
percent = (score + 100) / 3;
if (percent > 100)
return ret;
}
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);
+ ret = add_to_score_table(aa.array[i]);
if (ret < 0) {
if (errmsg)
*errmsg = make_message(