summaryrefslogtreecommitdiff
path: root/src/libs/sig/sig.c
blob: cd179e2882d0d5a86d7c4b2a8566408286268958 (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
#include <assert.h>
#include <stdarg.h>
#include <stdlib.h>

#include "sig.h"


typedef struct sig_t {
	const sig_ops_t	*ops;
	void		*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_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
© All Rights Reserved