From faada59567f8cb252f4a909116595ce309ff5828 Mon Sep 17 00:00:00 2001 From: "N.N." Date: Fri, 23 May 2003 12:29:55 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r647, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/miXed/; revision=648 --- cyclone/hammer/prob.c | 312 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 312 insertions(+) create mode 100644 cyclone/hammer/prob.c (limited to 'cyclone/hammer/prob.c') diff --git a/cyclone/hammer/prob.c b/cyclone/hammer/prob.c new file mode 100644 index 0000000..5227870 --- /dev/null +++ b/cyclone/hammer/prob.c @@ -0,0 +1,312 @@ +/* Copyright (c) 2002-2003 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +#include +#include "m_pd.h" +#include "common/loud.h" +#include "common/rand.h" +#include "hammer/file.h" + +/* CHECKED: no preallocation. Apparently, it looks like if the new + state-entries were added to the list's head, and the new transition-entries + were added to the sublist's head. No sorting of any kind. */ + +#define PROB_DEBUG 0 + +typedef struct _probtrans +{ + int tr_value; /* state (if a header trans), or suffix value (otherwise) */ + int tr_count; /* (a total in case of a header trans) */ + struct _probtrans *tr_suffix; /* header trans of a suffix state */ + struct _probtrans *tr_nexttrans; /* next trans of this state */ + struct _probtrans *tr_nextstate; /* header trans of a next state */ +} t_probtrans; + +typedef struct _prob +{ + t_object x_ob; + t_probtrans *x_translist; + t_probtrans *x_state; + t_probtrans *x_default; + int x_embedmode; + int x_silent; + unsigned int x_seed; + t_outlet *x_bangout; + t_hammerfile *x_filehandle; +} t_prob; + +static t_class *prob_class; + +static t_probtrans *prob_findstate(t_prob *x, int value, int complain) +{ + t_probtrans *state; + for (state = x->x_translist; state; state = state->tr_nextstate) + if (state->tr_value == value) + break; + if (!state && complain && !x->x_silent) + loud_error((t_pd *)x, "no state %d", value); /* CHECKED */ + return (state); +} + +static void prob_reset(t_prob *x, t_floatarg f) +{ + int value = (int)f; /* CHECKED: float converted to int */ + t_probtrans *state = prob_findstate(x, value, 1); + if (state) /* CHECKED */ + { + x->x_default = state; + /* CHECKED (sort of): */ + if (!x->x_state->tr_nexttrans) + x->x_state = state; + } +} + +/* +CHECKED: embedmode off: +#N prob; +#P newobj ... prob; + +CHECKED: embedmode on, after clear: +#N prob; +#T embed 1; +#P newobj ... prob; + +CHECKED: embedmode on, filled: +#N prob; +#T +... +#T embed 1; +#T reset ; (if set) +#P newobj ... prob; +*/ +static void prob_embed(t_prob *x, t_floatarg f) +{ + x->x_embedmode = ((int)f != 0); + if (x->x_embedmode) + loud_incompatible(prob_class, "embedding not supported (yet)..."); +} + +static void prob_clear(t_prob *x) +{ + t_probtrans *state, *nextstate; + for (state = x->x_translist; state; state = nextstate) + { + t_probtrans *trans, *nexttrans; + for (trans = state->tr_nexttrans; trans; trans = nexttrans) + { + nexttrans = trans->tr_nexttrans; + freebytes(trans, sizeof(*trans)); + } + nextstate = state->tr_nextstate; + freebytes(state, sizeof(*state)); + } + x->x_translist = 0; + x->x_state = 0; + x->x_default = 0; /* CHECKED: default number is not kept */ + /* CHECKED embedmode is kept */ +} + +/* CHECKED */ +static void prob_dump(t_prob *x) +{ + t_probtrans *state; + post("transition probabilities:"); + for (state = x->x_translist; state; state = state->tr_nextstate) + { + t_probtrans *trans; + for (trans = state->tr_nexttrans; trans; trans = trans->tr_nexttrans) + post(" from %3d to %3d: %d", + state->tr_value, trans->tr_value, trans->tr_count); + /* CHECKED: dead-ends are reported */ + post("total weights for state %d: %d", + state->tr_value, state->tr_count); + } +} + +static void prob_bang(t_prob *x) +{ + if (x->x_state) /* CHECKED: no output after clear */ + { + int rnd = rand_int(&x->x_seed, x->x_state->tr_count); + t_probtrans *trans = x->x_state->tr_nexttrans; + if (trans) + { + for (trans = x->x_state->tr_nexttrans; trans; + trans = trans->tr_nexttrans) + if ((rnd -= trans->tr_count) < 0) + break; + if (trans) + { + t_probtrans *nextstate = trans->tr_suffix; + if (nextstate) + { + outlet_float(((t_object *)x)->ob_outlet, + nextstate->tr_value); + x->x_state = nextstate; + } + else bug("prob_bang: void suffix"); + } + else bug("prob_bang: search overflow"); + } + else + { + outlet_bang(x->x_bangout); + if (x->x_default) /* CHECKED: stays at dead-end if no default */ + x->x_state = x->x_default; + } + } +} + +static void prob_float(t_prob *x, t_float f) +{ + int value; + if (loud_checkint((t_pd *)x, f, &value, &s_float)) /* CHECKED */ + { + t_probtrans *state = prob_findstate(x, value, 1); + if (state) /* CHECKED */ + x->x_state = state; + } +} + +static void prob_list(t_prob *x, t_symbol *s, int ac, t_atom *av) +{ + int prefval, suffval, count; + if (ac == 3 && av->a_type == A_FLOAT + && av[1].a_type == A_FLOAT && av[2].a_type == A_FLOAT + && (prefval = (int)av->a_w.w_float) == av->a_w.w_float + && (suffval = (int)av[1].a_w.w_float) == av[1].a_w.w_float + && (count = (int)av[2].a_w.w_float) == av[2].a_w.w_float) + { + t_probtrans *prefix = prob_findstate(x, prefval, 0); + t_probtrans *suffix = prob_findstate(x, suffval, 0); + t_probtrans *trans; + if (prefix && suffix) + { + for (trans = prefix->tr_nexttrans; trans; + trans = trans->tr_nexttrans) + if (trans->tr_suffix == suffix) + break; + if (trans) + { + /* the transition already exists... */ + prefix->tr_count += (count - trans->tr_count); + trans->tr_count = count; + return; + } + } + if (!prefix) + { + if (!(prefix = getbytes(sizeof(*prefix)))) + return; + prefix->tr_value = prefval; + prefix->tr_count = 0; + prefix->tr_suffix = 0; + prefix->tr_nexttrans = 0; + prefix->tr_nextstate = x->x_translist; + x->x_translist = prefix; + if (suffval == prefval) + suffix = prefix; + } + if (!suffix) + { + if (!(suffix = getbytes(sizeof(*suffix)))) + return; + suffix->tr_value = suffval; + suffix->tr_count = 0; + suffix->tr_suffix = 0; + suffix->tr_nexttrans = 0; + suffix->tr_nextstate = x->x_translist; + x->x_translist = suffix; + } + if (trans = getbytes(sizeof(*trans))) + { + trans->tr_value = suffval; + trans->tr_count = count; + trans->tr_suffix = suffix; + trans->tr_nexttrans = prefix->tr_nexttrans; + trans->tr_nextstate = prefix->tr_nextstate; + prefix->tr_count += count; + prefix->tr_nexttrans = trans; + } + if (!x->x_state) /* CHECKED */ + x->x_state = prefix; /* CHECKED */ + } + else loud_error((t_pd *)x, "bad list message format"); /* CHECKED */ +} + +static void prob_silent(t_prob *x) +{ + if (!x->x_silent) + { + loud_incompatible(prob_class, "no 'silent' message in max"); + x->x_silent = 1; + } +} + +static void prob_click(t_prob *x, t_floatarg xpos, t_floatarg ypos, + t_floatarg shift, t_floatarg ctrl, t_floatarg alt) +{ + t_probtrans *state; + char buf[64]; + hammereditor_open(x->x_filehandle, "prob"); + for (state = x->x_translist; state; state = state->tr_nextstate) + { + t_probtrans *trans; + for (trans = state->tr_nexttrans; trans; trans = trans->tr_nexttrans) + { + sprintf(buf, "%d %d %d\n", + state->tr_value, trans->tr_value, trans->tr_count); + hammereditor_append(x->x_filehandle, buf); + } + } +} + +static void prob_free(t_prob *x) +{ + prob_clear(x); + hammerfile_free(x->x_filehandle); +} + +static void *prob_new(void) +{ + t_prob *x = (t_prob *)pd_new(prob_class); + x->x_translist = 0; + x->x_state = 0; + x->x_default = 0; + x->x_embedmode = 0; /* CHECKED */ + x->x_silent = 0; + rand_seed(&x->x_seed, 0); + outlet_new((t_object *)x, &s_float); + x->x_bangout = outlet_new((t_object *)x, &s_bang); + x->x_filehandle = hammerfile_new((t_pd *)x, 0, 0, 0, 0); + return (x); +} + +void prob_setup(void) +{ + prob_class = class_new(gensym("prob"), + (t_newmethod)prob_new, + (t_method)prob_free, + sizeof(t_prob), 0, 0); + class_addbang(prob_class, prob_bang); + class_addfloat(prob_class, prob_float); + class_addlist(prob_class, prob_list); + class_addmethod(prob_class, (t_method)prob_embed, + gensym("embed"), A_FLOAT, 0); + class_addmethod(prob_class, (t_method)prob_reset, + gensym("reset"), A_FLOAT, 0); + class_addmethod(prob_class, (t_method)prob_clear, + gensym("clear"), 0); + class_addmethod(prob_class, (t_method)prob_dump, + gensym("dump"), 0); + /* CHECKED: doesn't understand "seed" */ + + /* below are the incompatible extensions... */ + class_addmethod(prob_class, (t_method)prob_silent, + gensym("silent"), 0); + class_addmethod(prob_class, (t_method)prob_click, + gensym("click"), + A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); + hammerfile_setup(prob_class, 0); /* LATER embedding (, 1) */ +} -- cgit v1.2.1