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
141
142
143
144
145
146
147
148
|
/* 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. */
/* LATER think again about avoiding memory allocation overhead in run-time.
One would need to use a creation argument greater than any future right
inlet value. But this is incompatible (max uses a `static', max-size
array), and should be put somewhere in the docs... */
#include "m_pd.h"
#include "common/loud.h"
#include "common/rand.h"
#include "common/grow.h"
#define URN_INISIZE 128 /* LATER rethink */
#define URN_C74MAXSIZE 4096 /* CHECKED */
#define URN_MAXSIZE 65536 /* LATER use USHRT_MAX */
typedef struct _urn
{
t_object x_ob;
int x_count;
int x_size; /* as allocated (in bytes) */
int x_range; /* as used */
unsigned short *x_urn;
unsigned short x_urnini[URN_INISIZE];
unsigned int x_seed;
t_outlet *x_bangout;
} t_urn;
static t_class *urn_class;
static int urn_resize(t_urn *x, t_float f, int init)
{
int maxmax = URN_C74MAXSIZE;
int range = (int)f; /* CHECKED silent truncation */
if (init)
{
maxmax--; /* CHECKED: max 4095 here (a bug, sort of) */
/* CHECKED in the constructor this is silent
(also > maxmax clipped without complaining) */
if (range < 1)
range = 1;
}
else if (range < 1)
{
/* CHECKED (the same for > maxmax) */
loud_error((t_pd *)x, "illegal size %d", f);
return (0);
}
if (range > URN_MAXSIZE)
{
loud_warning((t_pd *)x,
"requested size (%d) clipped -- effective size is %d",
range, URN_MAXSIZE);
range = URN_MAXSIZE;
}
if (range > maxmax)
loud_incompatible_max(urn_class, maxmax, "elements");
x->x_range = range;
if (range > x->x_size)
x->x_urn = grow_nodata(&x->x_range, &x->x_size, x->x_urn,
URN_INISIZE, x->x_urnini,
sizeof(*x->x_urn));
return (1);
}
static void urn_bang(t_urn *x)
{
if (x->x_count)
{
int ndx = rand_int(&x->x_seed, x->x_count);
unsigned short pick = x->x_urn[ndx];
x->x_urn[ndx] = x->x_urn[--x->x_count];
outlet_float(((t_object *)x)->ob_outlet, pick);
}
/* CHECKED: start banging when the first bang is input
into an empty urn (and not when the last value is output).
CHECKED: keep banging until cleared. */
else outlet_bang(x->x_bangout);
}
static void urn_clear(t_urn *x)
{
int i;
x->x_count = x->x_range;
for (i = 0; i < x->x_count; i++) x->x_urn[i] = i;
}
static void urn_float(t_urn *x, t_float f)
{
/* CHECKED: float loudly rejected, int (any value) same as bang */
int i;
if (loud_checkint((t_pd *)x, f, &i, &s_float))
urn_bang(x);
}
static void urn_ft1(t_urn *x, t_floatarg f)
{
if (urn_resize(x, f, 0)) /* CHECKED cleared only if a legal resize */
urn_clear(x);
}
static void urn_seed(t_urn *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 urn_free(t_urn *x)
{
if (x->x_urn != x->x_urnini)
freebytes(x->x_urn, x->x_size * sizeof(*x->x_urn));
}
static void *urn_new(t_floatarg f1, t_floatarg f2)
{
t_urn *x = (t_urn *)pd_new(urn_class);
x->x_size = URN_INISIZE;
x->x_urn = x->x_urnini;
urn_resize(x, f1, 1);
urn_seed(x, f2); /* CHECKME */
inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
outlet_new((t_object *)x, &s_float);
x->x_bangout = outlet_new((t_object *)x, &s_bang);
urn_clear(x);
return (x);
}
void urn_setup(void)
{
urn_class = class_new(gensym("urn"),
(t_newmethod)urn_new,
(t_method)urn_free,
sizeof(t_urn), 0,
A_DEFFLOAT, A_DEFFLOAT, 0);
class_addbang(urn_class, urn_bang);
class_addfloat(urn_class, urn_float);
class_addmethod(urn_class, (t_method)urn_ft1,
gensym("ft1"), A_FLOAT, 0);
/* CHECKED list is auto-unfolded */
class_addmethod(urn_class, (t_method)urn_seed,
gensym("seed"), A_FLOAT, 0); /* CHECKED arg obligatory */
class_addmethod(urn_class, (t_method)urn_clear,
gensym("clear"), 0);
}
|