aboutsummaryrefslogtreecommitdiff
path: root/runningmean/runningmean.c
blob: ac9a4ac24a598510459ee99f7dee8608cb369168 (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
141
142
143
144
/* runningmean.c MP 20080516 */
/* output the running mean of the input */
#include "m_pd.h"

/* We implement a circular buffer x_data of length x_n */
/* With each incoming value we sum the x_n values, then divide by */
/* x_n to get the mean value, x_mean. */

#define RUNNINGMEAN_MAX 128 /* a default value when no valid argument is supplied */

typedef struct _runningmean
{
    t_object        x_obj;
    int             x_in1;
    int             x_in2;
    int             x_in3;
    t_outlet        *x_out;
    t_inlet         *x_inlet2;
    int             x_n;
    int             x_originalsize;
    t_float         *x_data;
    t_float         x_mean;
    int             x_pointer;
} t_runningmean;

static t_class *runningmean_class;

void runningmean_setup(void);
static void *runningmean_new(t_floatarg f);
static void runningmean_free(t_runningmean *x);
static void runningmean_bang(t_runningmean *x);
static void runningmean_float(t_runningmean *x, t_float f);
static void runningmean_length(t_runningmean *x, t_float f);
static void runningmean_zero(t_runningmean *x, t_float f);

static void runningmean_float(t_runningmean *x, t_float f)
{
    float   *p = x->x_data;
    float   total = 0;
    int     i;

    if (x->x_n > 0)
    {
        /* add a float at the current location, overwriting the oldest data */
        x->x_data[x->x_pointer] = f;
        if (++x->x_pointer >= x->x_n) x->x_pointer = 0; /* wrap pointer */
        for (i = 0; i < x->x_n; ++i) total += *p++;
        x->x_mean = total/x->x_n;
        outlet_float(x->x_out, x->x_mean);
    }
    return;
}

static void runningmean_bang(t_runningmean *x)
{
    outlet_float(x->x_out, x->x_mean);
    return;
}

static void runningmean_length(t_runningmean *x, t_float f)
{

    if ((f >= 1) && ((int)f == f) && (f <= x->x_originalsize))
    {
        x->x_n = (int)f;
        runningmean_zero(x, x->x_mean); // set the entire new array to the old mean
    }
    else post("runningmean length must be an integer between 1 and %d.", x->x_originalsize);
    return;
}

static void runningmean_zero(t_runningmean *x, t_float f)
{
    float   *p = x->x_data;
    int     i;

    /* set the entire array to f */
    for (i = 0; i < x->x_n; ++i) *p++ = f;
    x->x_mean = f;
    x->x_pointer = 0;
    return;
}


static void runningmean_free(t_runningmean *x)
{
    freebytes(x->x_data, x->x_originalsize);
    x->x_originalsize = x->x_n = 0;
    x->x_data = NULL;
    return;
}

static void *runningmean_new(t_floatarg f)
{
    t_runningmean   *x;

    x = (t_runningmean *)pd_new(runningmean_class);
    if (x == NULL) return (x);
    x->x_out = outlet_new((t_object *)x, &s_float);
    x->x_inlet2 = inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("length"));
    if (!((f >= 1) && ((int)f == f)))
    {
        post("runningmean length %0.2f must be an integer greater than 1, using %d", f, RUNNINGMEAN_MAX);
        f = RUNNINGMEAN_MAX;
    }
    {
        x->x_n = (int)f;
        x->x_data = (t_float *)getbytes(sizeof(float)*x->x_n);
        if (x->x_data == NULL)
        {
            post("runningmean unable to allocate %lu bytes of memory, using %d", sizeof(float)*x->x_n, RUNNINGMEAN_MAX);
            x->x_n = RUNNINGMEAN_MAX;
            //x->x_data = (t_float *)getbytes(x->x_n);
            if (x->x_data == NULL)
            {
                post("runningmean unable to allocate %lu bytes of memory, using 0", x->x_n);
                x->x_n = 0;
            }
        }
        x->x_originalsize = x->x_n;
        runningmean_zero(x, 0);
    }
    return (x);
}

void runningmean_setup(void)
{
    runningmean_class = class_new
    (
        gensym("runningmean"),
        (t_newmethod)runningmean_new,
        (t_method)runningmean_free,
        sizeof(t_runningmean),
        CLASS_DEFAULT,
        A_DEFFLOAT,
        0
    ); /* one argument for length */
    class_addbang(runningmean_class, runningmean_bang);
    class_addfloat(runningmean_class, runningmean_float);
    class_addmethod(runningmean_class, (t_method)runningmean_length, gensym("length"), A_FLOAT, 0);
    class_addmethod(runningmean_class, (t_method)runningmean_zero, gensym("clear"), A_DEFFLOAT, 0);
}
/* end runningmean.c */