Added mixer module.
[aftubes.git] / mixer.c
blob92be4014f0cde4390d443495d9ea07131590bfe2
1 #include "modules.h"
2 #include "graph.h"
3 #include "errors.h"
4 #include "assert.h"
6 ///// Simple additive mixer /////
7 ///// TODO: handle different input formats /////
9 struct mixer {
10 bool format_is_set;
11 struct aformat af;
12 struct graphpin *out_pin;
13 int n_inputs;
16 static bool is_acceptable_input_format(struct graphnode *node, struct graphpin *pin, const struct aformat *af)
18 struct mixer *m = node->extra;
19 assert(pin != m->out_pin);
20 if (m->format_is_set){
21 return af->media == m->af.media
22 && af->srate == m->af.srate
23 && af->channels == m->af.channels;
24 } else {
25 return true;
29 static err_t get_output_format(struct graphnode *node, struct graphpin *pin, struct aformat *af)
31 struct mixer *m = node->extra;
32 assert(pin == m->out_pin);
34 if (m->format_is_set){
35 *af = m->af;
36 return EOK;
37 } else {
38 return make_error(ECANNOT_GUESS_FORMAT, node, "mixer module is not yet bound to a format");
42 static err_t set_buffer(struct graphnode *node, struct graphpin *pin, struct buffer *buf)
44 struct mixer *m = node->extra;
45 if (m->format_is_set){
46 if (buf->format.media == m->af.media
47 && buf->format.srate == m->af.srate
48 && buf->format.channels == m->af.channels){
49 return EOK;
50 } else {
51 return make_error(EBAD_FORMAT, node, "mixer module is being connected to a bad media format");
53 } else {
54 m->af = buf->format;
55 m->format_is_set = true;
56 return EOK;
60 static size_t longest_in_buf_len(struct graphnode *restrict node)
62 struct graphpin *in_pin;
63 size_t sz = 0;
65 for (in_pin=node->pins; in_pin; in_pin=in_pin->next){
66 if (in_pin->dir != DIR_IN){
67 continue;
69 if (in_pin->edge->buf.n_samples > sz){
70 sz = in_pin->edge->buf.n_samples;
73 return sz;
76 static err_t run(struct graphnode *node)
78 #define DO_MIX(T) { \
79 T *restrict s_ptr, *restrict d_ptr; \
80 register int i; \
81 /* clear the output buffer */ \
82 d_ptr = d_buf->data; \
83 for (i=sz; i; --i){ \
84 *d_ptr++ = 0; \
85 } \
87 for (in_pin=node->pins; in_pin; in_pin=in_pin->next){ \
88 s_ptr = in_pin->edge->buf.data; \
89 d_ptr = d_buf->data; \
90 for (i=sz; i; --i){ \
91 /* Mix! */ \
92 *d_ptr++ += *s_ptr++ / m->n_inputs; /* *boggle* */ \
93 } \
94 } \
95 return EOK; }
97 struct mixer *restrict m = node->extra;
98 struct graphpin *in_pin;
99 struct buffer *restrict d_buf = &m->out_pin->edge->buf;
100 size_t sz;
101 err_t err;
103 sz = longest_in_buf_len(node);
104 err = buffer_alloc(d_buf, sz);
105 if (err != EOK){
106 return err;
109 sz *= m->out_pin->edge->buf.format.channels;
111 switch (m->out_pin->edge->buf.format.media){
112 case MT_AUDIO_32F:
113 DO_MIX(float)
114 case MT_AUDIO_16I:
115 DO_MIX(short)
116 case MT_AUDIO_32I:
117 DO_MIX(int)
119 return make_error(ENOTIMPL, NULL, "mixing these media types is not implemented");
122 static const struct graphnode_functab functab = {
123 is_acceptable_input_format,
124 NULL, // get_ideal_input_format
125 get_output_format,
126 set_buffer,
127 run,
130 err_t mixer_create(struct graphnode **node_out, int n_inputs)
132 struct graphnode *node;
133 struct mixer *m;
134 struct graphpin *in_pin;
135 err_t err;
136 int i;
138 err = graphnode_create(&node, &functab, sizeof *m);
139 if (err != EOK){
140 return err;
142 m = node->extra;
144 m->n_inputs = n_inputs;
145 m->format_is_set = false;
147 // create output pin
148 err = graphnode_add_pin(node, &m->out_pin);
149 if (err != EOK){
150 return err;
152 m->out_pin->dir = DIR_OUT;
153 m->out_pin->name = "out";
155 // create input pins
156 for (i=0; i<n_inputs; ++i){
157 err = graphnode_add_pin(node, &in_pin);
158 if (err != EOK){
159 return err;
161 in_pin->dir = DIR_IN;
162 in_pin->name = "in"; // how original
165 *node_out = node;
166 return EOK;