7 ///// Simple additive mixer /////
8 ///// TODO: handle different input formats /////
13 struct graphpin
*out_pin
;
17 static bool is_acceptable_input_format(struct graphnode
*node
, struct graphpin
*pin
, const struct aformat
*af
)
19 struct mixer
*m
= node
->extra
;
20 assert(pin
!= m
->out_pin
);
21 if (m
->format_is_set
){
22 return af
->media
== m
->af
.media
23 && af
->srate
== m
->af
.srate
24 && af
->channels
== m
->af
.channels
;
30 static err_t
get_output_format(struct graphnode
*node
, struct graphpin
*pin
, struct aformat
*af
)
32 struct mixer
*m
= node
->extra
;
33 assert(pin
== m
->out_pin
);
35 if (m
->format_is_set
){
39 return make_error(ECANNOT_GUESS_FORMAT
, node
, "mixer module is not yet bound to a format");
43 static err_t
another_in_pin(struct graphnode
*node
, struct mixer
*m
)
45 // create a new input pin
46 struct graphpin
*new_pin
;
48 char *new_name
= NULL
;
50 err
= graphnode_add_pin(node
, &new_pin
);
54 asprintf(&new_name
, "in%d", m
->n_inputs
);
55 new_pin
->name
= new_name
;
56 new_pin
->dir
= DIR_IN
;
61 static err_t
set_buffer(struct graphnode
*node
, struct graphpin
*pin
, struct buffer
*buf
)
63 struct mixer
*m
= node
->extra
;
64 if (m
->format_is_set
){
65 if (buf
->format
.media
== m
->af
.media
66 && buf
->format
.srate
== m
->af
.srate
67 && buf
->format
.channels
== m
->af
.channels
){
68 return another_in_pin(node
, m
);
70 return make_error(EBAD_FORMAT
, node
, "mixer module is being connected to a bad media format");
74 m
->format_is_set
= true;
75 return another_in_pin(node
, m
);
79 static size_t longest_in_buf_len(struct graphnode
*restrict node
)
81 struct graphpin
*in_pin
;
84 for (in_pin
=node
->pins
; in_pin
; in_pin
=in_pin
->next
){
85 if (in_pin
->dir
!= DIR_IN
|| !in_pin
->edge
){
88 if (in_pin
->edge
->buf
.n_samples
> sz
){
89 sz
= in_pin
->edge
->buf
.n_samples
;
95 static err_t
run(struct graphnode
*node
)
98 T *restrict s_ptr, *restrict d_ptr; \
100 /* clear the output buffer */ \
101 d_ptr = d_buf->data; \
102 for (i=sz; i; --i){ \
106 for (in_pin=node->pins; in_pin; in_pin=in_pin->next){ \
107 if (in_pin->dir != DIR_IN || !in_pin->edge){ \
110 s_ptr = in_pin->edge->buf.data; \
111 d_ptr = d_buf->data; \
112 for (i=sz; i; --i){ \
114 *d_ptr++ += *s_ptr++ / m->n_inputs; /* *boggle* */ \
119 struct mixer
*restrict m
= node
->extra
;
120 struct graphpin
*in_pin
;
121 struct buffer
*restrict d_buf
= &m
->out_pin
->edge
->buf
;
125 sz
= longest_in_buf_len(node
);
126 err
= buffer_alloc(d_buf
, sz
);
131 sz
*= m
->out_pin
->edge
->buf
.format
.channels
;
133 switch (m
->out_pin
->edge
->buf
.format
.media
){
141 return make_error(ENOTIMPL
, NULL
, "mixing these media types is not implemented");
144 static const struct graphnode_functab functab
= {
145 is_acceptable_input_format
,
146 NULL
, // get_ideal_input_format
152 err_t
mixer_create(struct graphnode
**node_out
)
154 struct graphnode
*node
;
156 struct graphpin
*in_pin
;
159 err
= graphnode_create(&node
, &functab
, sizeof *m
);
166 m
->format_is_set
= false;
169 err
= graphnode_add_pin(node
, &m
->out_pin
);
173 m
->out_pin
->dir
= DIR_OUT
;
174 m
->out_pin
->name
= "out";
177 err
= graphnode_add_pin(node
, &in_pin
);
181 in_pin
->dir
= DIR_IN
;
182 in_pin
->name
= "in0"; // how original