aboutsummaryrefslogtreecommitdiff
path: root/cyclone/hammer/drunk.c
blob: e08800dd928f60a65dda31f00066d077886606e4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/* 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 */
}