/* 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. */ /* The first version of this code was written by Nicola Bernardini. It was entirely reimplemented in the hope of adapting it to the cyclone's guidelines. */ #include "m_pd.h" #include "common/rand.h" #define DRUNK_DEFMAXVALUE 128 #define DRUNK_DEFMAXSTEP 2 typedef struct _drunk { t_object x_ob; int x_value; int x_maxvalue; int x_maxstep; int x_minstep; unsigned int x_seed; unsigned int x_bitseed; } t_drunk; static t_class *drunk_class; static void drunk_set(t_drunk *x, t_floatarg f) { int i = (int)f; /* CHECKED float silently truncated */ if (i > x->x_maxvalue) x->x_value = x->x_maxvalue; /* CHECKED */ else if (i < 0) x->x_value = 0; /* CHECKED */ else x->x_value = i; } /* CHECKED: this is a superposition of two rngs -- the random bit generator, and the random integer generator, which is the same (CHECKED) as the one used in the 'random' class (quite lame: period 35730773, nonuniform for large ranges, so I would rather not RE it...) */ #define RBIT1 1 #define RBIT2 2 #define RBIT5 16 #define RBIT18 131072 #define RBIT_MASK (RBIT1 + RBIT2 + RBIT5) static void drunk_bang(t_drunk *x) { int rnd = rand_int(&x->x_seed, x->x_maxstep) + x->x_minstep; int val; if (x->x_bitseed & RBIT18) { x->x_bitseed = ((x->x_bitseed ^ RBIT_MASK) << 1) | RBIT1; if ((val = x->x_value + rnd) > x->x_maxvalue) val = x->x_value - rnd; /* CHECKED */ if (val < 0) val = 0; /* CHECKED (needed for maxstep > maxvalue) */ } else { x->x_bitseed <<= 1; if ((val = x->x_value - rnd) < 0) val = x->x_value + rnd; /* CHECKED */ if (val > x->x_maxvalue) val = x->x_maxvalue; /* CHECKED (needed for maxstep > maxvalue) */ } outlet_float(((t_object *)x)->ob_outlet, x->x_value = val); } static void drunk_float(t_drunk *x, t_float f) { drunk_set(x, f); outlet_float(((t_object *)x)->ob_outlet, x->x_value); } static void drunk_ft1(t_drunk *x, t_floatarg f) { int i = (int)f; /* CHECKED float silently truncated */ x->x_maxvalue = (i < 0 ? 1 : i); /* CHECKED zero allowed */ /* CHECKED maxstep not updated */ } static void drunk_ft2(t_drunk *x, t_floatarg f) { int i = (int)f; /* CHECKED float silently truncated */ if (i < 0) { x->x_minstep = 1; i = -i; } else x->x_minstep = 0; /* CHECKED maxstep not clipped to the maxvalue */ x->x_maxstep = (x->x_minstep ? i - 1 : i); /* CHECKED zero allowed */ } /* apparently, bitseed cannot be controlled, but LATER recheck */ static void drunk_seed(t_drunk *x, t_floatarg f) { int i = (int)f; /* CHECKED */ if (i < 0) i = 1; /* CHECKED */ rand_seed(&x->x_seed, (unsigned int)i); } static void *drunk_new(t_floatarg f1, t_floatarg f2) { t_drunk *x = (t_drunk *)pd_new(drunk_class); x->x_maxvalue = ((int)f1 > 0 ? (int)f1 : 128); /* CHECKED */ x->x_maxstep = 2; x->x_minstep = 0; if ((int)f2) /* CHECKED */ drunk_ft2(x, f2); x->x_value = x->x_maxvalue / 2; /* CHECKED */ rand_seed(&x->x_seed, 0); /* CHECKED third arg silently ignored */ x->x_bitseed = 123456789; /* FIXME */ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1")); inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft2")); outlet_new((t_object *)x, &s_float); return (x); } void drunk_setup(void) { drunk_class = class_new(gensym("drunk"), (t_newmethod)drunk_new, 0, sizeof(t_drunk), 0, A_DEFFLOAT, A_DEFFLOAT, 0); class_addbang(drunk_class, drunk_bang); class_addfloat(drunk_class, drunk_float); class_addmethod(drunk_class, (t_method)drunk_ft1, gensym("ft1"), A_FLOAT, 0); class_addmethod(drunk_class, (t_method)drunk_ft2, gensym("ft2"), A_FLOAT, 0); /* CHECKED list is auto-unfolded */ class_addmethod(drunk_class, (t_method)drunk_seed, gensym("seed"), A_FLOAT, 0); /* CHECKED arg obligatory */ class_addmethod(drunk_class, (t_method)drunk_set, gensym("set"), A_FLOAT, 0); /* CHECKED arg obligatory */ }