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
|
#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);
}
#endif
|