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
|
#include <assert.h>
#include <stdarg.h>
#include <stdlib.h>
#include "sig.h"
/* This is to try ensure ctxt's alignment accomodates all the base type sizes,
* it may waste some space in sig_t but since the caller supplies just a size
* via the supplied sig_ops_t.size(), we know nothing of the alignment reqs.
*
* XXX: If callers start using other types like xmmintrinsics __m128, this
* struct will have to get those added.
*/
typedef union sig_context_t {
float f;
double d;
long double ld;
char c;
short s;
int i;
long l;
long long ll;
void *p;
} sig_context_t;
typedef struct sig_t {
const sig_ops_t *ops;
sig_context_t ctxt[];
} sig_t;
/* return a new signal generator of ops type, configured according to va_list */
sig_t * sig_new(const sig_ops_t *ops, ...)
{
static const sig_ops_t null_ops;
size_t ctxt_size = 0;
sig_t *sig;
va_list ap;
if (!ops)
ops = &null_ops;
va_start(ap, ops);
if (ops->size)
ctxt_size = ops->size(ap);
va_end(ap);
sig = calloc(1, sizeof(sig_t) + ctxt_size);
if (!sig)
return NULL;
va_start(ap, ops);
if (ops->init)
ops->init(&sig->ctxt, ap);
va_end(ap);
sig->ops = ops;
return sig;
}
/* free a signal generator, always returns NULL */
sig_t * sig_free(sig_t *sig)
{
if (sig) {
if (sig->ops->destroy)
sig->ops->destroy(&sig->ctxt);
free(sig);
}
return NULL;
}
/* produce the value for time ticks_ms from the supplied signal generator,
* the returned value should always be kept in the range 0-1.
*/
float sig_output(sig_t *sig, unsigned ticks_ms)
{
assert(sig);
assert(sig->ops);
if (sig->ops->output)
return sig->ops->output(sig->ctxt, ticks_ms);
return 0;
}
#ifdef TESTING
#include <stdio.h>
int main(int argc, char *argv[])
{
sig_t *sig;
sig = sig_new(NULL);
printf("null output=%f\n", sig_output(sig, 0));
sig = sig_free(sig);
sig = sig_new(&sig_ops_rand);
for (unsigned j = 0; j < 2; j++) {
for (unsigned i = 0; i < 10; i++)
printf("rand j=%u i=%u output=%f\n", j, i, sig_output(sig, i));
}
sig = sig_new(&sig_ops_sin, sig_new(&sig_ops_const, 2.f));
for (unsigned i = 0; i < 1000; i++)
printf("sin 2hz output %i=%f\n", i, sig_output(sig, i));
sig = sig_free(sig);
sig = sig_new(&sig_ops_mult,
sig_new(&sig_ops_sin, sig_new(&sig_ops_const, 1.f)), /* LFO @ 1hz */
sig_new(&sig_ops_sin, sig_new(&sig_ops_const, 100.f)) /* oscillator @ 100hz */
);
for (unsigned i = 0; i < 1000; i++)
printf("sin 100hz * 1hz output %i=%f\n", i, sig_output(sig, i));
sig = sig_free(sig);
sig = sig_new(&sig_ops_pow, /* raise an ... */
sig_new(&sig_ops_sin, /* oscillator ... */
sig_new(&sig_ops_const, 10.f)), /* @ 10hz, */
sig_new(&sig_ops_round, /* to a rounded .. */
sig_new(&sig_ops_mult, sig_new(&sig_ops_const, 50.f), /* 50 X ... */
sig_new(&sig_ops_sin, sig_new(&sig_ops_const, 1.f)) /* 1hz oscillator */
)
)
);
for (unsigned i = 0; i < 1000; i++)
printf("sin 10hz ^ (sin 1hz * 50) output %i=%f\n", i, sig_output(sig, i));
sig = sig_free(sig);
}
#endif
|