Jamoma API  0.6.0.a19
j.stats.cpp
Go to the documentation of this file.
1 /** @file
2  *
3  * @ingroup implementationMaxExternals
4  *
5  * @brief j.stats : Calculate running statistical values
6  *
7  * @details
8  *
9  * @authors Trond Lossius, Nils Peters
10  *
11  * @copyright © 2001-06 by Trond Lossius @n
12  * This code is licensed under the terms of the "New BSD License" @n
13  * http://creativecommons.org/licenses/BSD/
14  */
15 
16 
17 #include "JamomaForMax.h"
18 
19 typedef struct _stats{ // Data structure for this object
20  struct object ob; // Must always be the first field; used by Max
21  double sumOfValues; // Sum of values
22  double sumOfSquaredValues; // Sum of squared values
23  unsigned long maxWindowSize; // Maximum window size
24  unsigned long windowSize; // Actual window size
25  long attr_windowed; // ATTRIBUTE: Flag indicating if we calculating windowed statistics
26  unsigned long valueCount; // Number of floats counted so far
27  double *values; // Pointer to array of values
28  double min; // Min value recorded (within the window)
29  double max; // Max value recorded (within the window)
30  unsigned long index; // Next value goes at this index in array
31  void *outlet; // Pointer to outlet. Need one for each outlet. This is for mean
32  void *outlet2; // This is for standard deviation
33  void *outlet3; // This is for counter
34  void *outlet4; // This is for min value
35  void *outlet5; // This is for max value
36 } t_stats;
37 
38 
39 
40 // Prototypes for methods: need a method for each incoming message
41 void *stats_new(t_symbol *s, long argc, t_atom *argv);
42 void stats_free(t_stats *x);
43 void stats_setwindowed(t_stats *x, void *attr, long argc, t_atom *argv);
44 void stats_bang(t_stats *x);
45 void stats_int(t_stats *x, long n);
46 void stats_float(t_stats *x, double f);
47 void stats_clear(t_stats *x);
48 void stats_window(t_stats *x, long n);
49 void stats_set(t_stats *x, double f);
50 void stats_assist(t_stats *x, void *b, long msg, long arg, char *dst);
51 
52 
53 // Globals
54 t_class *this_class; // Required. Global pointing to this class
55 
56 
57 /************************************************************************************/
58 // Main() Function
59 
60 int JAMOMA_EXPORT_MAXOBJ main(void)
61 {
62  long attrflags = 0;
63  t_class *c;
64  t_object *attr;
65 
66  common_symbols_init();
67 
68  // Define our class
69  c = class_new("j.stats",(method)stats_new, (method)stats_free, sizeof(t_stats), (method)0L, A_GIMME, 0);
70 
71  // Make methods accessible for our class:
72 
73  class_addmethod(c, (method)stats_bang, "bang", 0);
74  class_addmethod(c, (method)stats_int, "int", A_LONG, 0);
75  class_addmethod(c, (method)stats_float, "float", A_FLOAT, 0);
76  class_addmethod(c, (method)stats_assist, "assist", A_CANT, 0);
77  class_addmethod(c, (method)stats_set, "set", A_FLOAT, 0);
78  class_addmethod(c, (method)stats_window, "window_size", A_LONG, 0);
79  class_addmethod(c, (method)stats_clear, "clear", 0);
80  class_addmethod(c, (method)object_obex_dumpout, "dumpout", A_CANT, 0);
81 
82  // ATTRIBUTE: windowed
83  attr = attr_offset_new("windowed", _sym_long, attrflags,
84  (method)0, (method)stats_setwindowed, calcoffset(t_stats, attr_windowed));
85  class_addattr(c, attr);
86 
87  // Finalize our class
88  class_register(CLASS_BOX, c);
89  this_class = c;
90  return 0;
91 }
92 
93 
94 /************************************************************************************/
95 // Object Life
96 
97 void *stats_new(t_symbol *s, long argc, t_atom *argv)
98 {
99  t_stats *x;
100 
101 
102  x = (t_stats *)object_alloc(this_class); // create the new instance and return a pointer to it
103  if (x) {
104  long attrstart = attr_args_offset(argc, argv);
105 
106  // Create outlets
107  object_obex_store((void *)x, _sym_dumpout, (object *)outlet_new(x,NULL)); // dumpout
108  x->outlet5 = floatout(x); // 5th outlet: standard deviation
109  x->outlet4 = floatout(x); // 4th outlet: mean
110  x->outlet3 = floatout(x); // 3rd outlet: maximum
111  x->outlet2 = floatout(x); // 2nd outlet: minimum
112  x->outlet = intout(x); // 1st outlet: counter
113 
114  // Setting max window size and actual window size
115  x->maxWindowSize = 0;
116  x->windowSize = 0;
117  if (attrstart && argv)
118  x->maxWindowSize = atom_getlong(argv);
119 
120  if ((attrstart==2) && argv)
121  x->windowSize = atom_getlong(argv+1);
122  if (x->maxWindowSize <= 0)
123  x->maxWindowSize = 500; // changing to default value
124  if (x->windowSize <= 0)
125  x->windowSize = x->maxWindowSize; // changing to default value
126  if (x->windowSize > x->maxWindowSize)
127  x->windowSize = x->maxWindowSize; // making sure we do not read outside array
128 
129  // allocate memory for array
130  x->values = (double *)sysmem_newptr(sizeof(double) * x->maxWindowSize);
131  if (x->values == NULL) {
132  error("j.stats: memory allocation error"); // whoops, out of memory...
133  return 0;
134  }
135 
136  x->attr_windowed = 1; // set default
137  attr_args_process(x, argc, argv); // handle attribute args
138 
139  stats_clear(x); // initilaize instance
140  return (x); // return the pointer to our new instantiation
141  }
142  else
143  return 0;
144 }
145 
146 
147 void stats_free(t_stats *x)
148 {
149  sysmem_freeptr(x->values);
150 }
151 
152 
153 /************************************************************************************/
154 // Methods bound to input/inlets
155 
156 
157 // ATTRIBUT: set_windowed
158 void stats_setwindowed(t_stats *x, void *attr, long argc, t_atom *argv)
159 {
160  x->attr_windowed = atom_getlong(argv);
161  stats_clear(x);
162 }
163 
164 // BANG input
165 void stats_bang(t_stats *x)
166 {
167  double mean, standardDeviation;
168 
169 /* if (x->valueCount < 0)
170  mean = 0;
171  else
172  mean = x->sumOfValues / x->valueCount;
173  if (x->valueCount > 1)
174  standardDeviation = sqrt((x->sumOfSquaredValues - ((x->sumOfValues*x->sumOfValues) / x->valueCount)) / (x->valueCount - 1));
175  else
176  standardDeviation = 0;*/
177 
178 /////small optimization by Nils Peters////
179 
180  if (x->valueCount >= 0)
181  mean = x->sumOfValues / x->valueCount;
182  else
183  mean = 0;
184  if (x->valueCount > 1)
185  standardDeviation = sqrt((x->sumOfSquaredValues - (x->sumOfValues*mean)) / (x->valueCount - 1)); /* i just simplified the equation by using the mean which was already calculated before*/
186  else
187  standardDeviation = 0;
188 ///// end of small optimization by Nils Peters////
189  outlet_float(x->outlet5, standardDeviation);
190  outlet_float(x->outlet4, mean);
191  outlet_float(x->outlet3, x->max);
192  outlet_float(x->outlet2, x->min);
193  outlet_int(x->outlet, x->valueCount);
194 }
195 
196 
197 // INT input
198 void stats_int(t_stats *x, long n)
199 {
200  stats_set(x,(double)n);
201  stats_bang(x);
202 }
203 
204 
205 // FLOAT input
206 void stats_float(t_stats *x, double f)
207 {
208  stats_set(x, f);
209  stats_bang(x);
210 }
211 
212 
213 
214 // SET input
215 void stats_set(t_stats *x, double f)
216 {
217  double old, temp;
218  unsigned long i;
219 
220  // Calculating windowed statistics
221  if (x->attr_windowed) {
222  if (x->valueCount < x->windowSize)
223  x->valueCount++;
224 
225  // Remove oldest value
226  old = x->values[x->index];
227  x->sumOfValues -= old;
228  x->sumOfSquaredValues -= old*old;
229 
230  // Insert new value
231  x->values[x->index] = f;
232  x->sumOfValues += f;
233  x->sumOfSquaredValues += f*f;
234  x->index++;
235 
236  // Do we need to update min or max?
237  if (x->valueCount == 1) {
238  x->min = f;
239  x->max = f;
240  }
241  else {
242  // Check new value
243  if (f<x->min)
244  x->min = f;
245  if (f>x->max)
246  x->max = f;
247  // Do we need to update min or max because we are leaving current record holder behind?
248  if (old==x->min) {
249  temp = x->values[0];
250  for (i=1; i< x->valueCount ; i++)
251  if (x->values[i] < temp)
252  temp = x->values[i];
253  x->min = temp;
254  }
255 
256  // Do we need to update min or max?
257  if (old==x->max) {
258  temp = x->values[0];
259  for (i=1; i<x->valueCount ; i++)
260  if (x->values[i] > temp)
261  temp = x->values[i];
262  x->max = temp;
263  }
264  }
265 
266  // Wrap around at end of window
267  if (x->index >= x->windowSize)
268  x->index = 0;
269  }
270 
271  // Calculating for infinite series
272  else {
273  x->valueCount++;
274  x->sumOfValues += f;
275  x->sumOfSquaredValues += f*f;
276  if (x->valueCount == 1) {
277  x->min = f;
278  x->max = f;
279  }
280  else {
281  if (f<x->min)
282  x->min = f;
283  if (f>x->max)
284  x->max = f;
285  }
286  }
287 }
288 
289 
290 void stats_window(t_stats *x, long n)
291 {
292  x->windowSize = n;
293 
294  if (x->windowSize <= 0)
295  x->windowSize = x->maxWindowSize;
296  if (x->windowSize > x->maxWindowSize)
297  x->windowSize = x->maxWindowSize;
298  stats_clear(x);
299 }
300 
301 
302 // CLEAR input
303 void stats_clear(t_stats *x)
304 {
305  unsigned long i;
306 
307  x->sumOfValues = 0;
308  x->sumOfSquaredValues = 0;
309  x->valueCount = 0;
310  x->index = 0;
311  for (i=0; i<x->windowSize; i++)
312  x->values[i] = 0;
313  x->min = 0;
314  x->max = 0;
315 }
316 
317 
318 // Method for Assistance Messages
319 void stats_assist(t_stats *x, void *b, long msg, long arg, char *dst) // Display assistance messages
320 {
321  if (msg==1) {
322  strcpy(dst, "(int/float) function value");
323  }
324  else if (msg==2) {
325  if (arg==0)
326  strcpy(dst, "(int) counter");
327  else if (arg==1)
328  strcpy(dst, "(float) minimum");
329  else if (arg==2)
330  strcpy(dst, "(float) maximum");
331  else if (arg==3)
332  strcpy(dst, "(float) mean");
333  else if (arg==4)
334  strcpy(dst, "(float) standard deviation");
335  else
336  strcpy(dst, "dumpout");
337  }
338 }
int JAMOMA_EXPORT_MAXOBJ main(void)
Set up this class as a Max external the first time an object of this kind is instantiated.
Definition: j.stats.cpp:60
Various utilities for interfacing with Max that are not specific to JamomaModular as such...
t_class * this_class
Required. Global pointing to this class.
Definition: j.envexp.cpp:108