From b5fa628c9f9d5452e151a9709b600f9d3f4a57b7 Mon Sep 17 00:00:00 2001 From: Joshua Phillips Date: Thu, 1 Jan 2009 17:04:53 +0000 Subject: [PATCH] Added mixer module. Number of inputs are specified when creating the mixer. --- SConscript | 2 +- convert.c | 2 +- graph.h | 2 + main.c | 28 +++++++---- mixer.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ modules.h | 1 + 6 files changed, 189 insertions(+), 13 deletions(-) create mode 100644 mixer.c diff --git a/SConscript b/SConscript index 64644b7..ff9b427 100644 --- a/SConscript +++ b/SConscript @@ -4,7 +4,7 @@ Import(['env']) programs = { 'main': [ 'main.c', 'wavefile.c', 'soundout.c', 'aformat.c', 'sound-ioctl.c', 'graph.c', 'errors.c', 'wavesource.c', 'playsink.c', 'buffer.c', - 'ringmod.c', 'convert.c'], + 'ringmod.c', 'convert.c', 'mixer.c'], } objects = {} diff --git a/convert.c b/convert.c index c4b8998..d92e99c 100644 --- a/convert.c +++ b/convert.c @@ -59,7 +59,7 @@ static err_t run(struct graphnode *node) DO_CONVERT(int, short, << 16) } } - return make_error(ENOTIMPL, node, "conversion between these media types is not implemented"); + return make_error(ENOTIMPL, NULL, "conversion between these media types is not implemented"); } static const struct graphnode_functab functab = { diff --git a/graph.h b/graph.h index 3a60fa2..7e5b7c1 100644 --- a/graph.h +++ b/graph.h @@ -10,6 +10,7 @@ enum { EUNCONNECTED, // there are unconnected pins ENO_AGREEABLE_FORMAT, // no format that both nodes will agree on ECANNOT_GUESS_FORMAT, // cannot guess a node's output format + EBAD_FORMAT, // bad format }; enum direction { @@ -60,6 +61,7 @@ struct graph { *sorted_nodes; }; +struct graphpin *graphnode_get_pin(struct graphnode *node, enum direction dir); // return the first pin of direction 'dir' err_t graphnode_add_pin(struct graphnode *node, struct graphpin **pin_out); // create a new pin for the node void graphnode_remove_pin(struct graphnode *node, struct graphpin *pin); // remove a pin from this node diff --git a/main.c b/main.c index 551ebe4..2ac130a 100644 --- a/main.c +++ b/main.c @@ -25,7 +25,7 @@ void moan(err_t err) int main(int argc, char **argv) { struct graph _graph, *graph = &_graph; - struct graphnode *node, *node_1, *node_2, *node_3; + struct graphnode *node, *source_1, *source_2, *mixer, *sink; err_t err; if (graph_create(graph)){ @@ -33,27 +33,33 @@ int main(int argc, char **argv) return 1; } - //moan(wavesource_create(&node, "/home/aoe/reflections.wav")); - moan(wavesource_create(&node, "/home/aoe/logout.wav")); + moan(wavesource_create(&node, "/home/aoe/reflections.wav")); assert(node); moan(graph_add_node(graph, node)); - node->name = "source"; - node_1 = node; + node->name = "source_1"; + source_1 = node; + + moan(wavesource_create(&node, "/home/aoe/horizon.wav")); + assert(node); + moan(graph_add_node(graph, node)); + node->name = "source_2"; + source_2 = node; moan(playsink_create(&node)); assert(node); moan(graph_add_node(graph, node)); node->name = "sink"; - node_2 = node; + sink = node; - moan(ringmod_create(&node)); + moan(mixer_create(&node, 2)); assert(node); moan(graph_add_node(graph, node)); - node->name = "ringmod"; - node_3 = node; + node->name = "mixer"; + mixer = node; - moan(graph_connect(graph, node_1->pins, node_3->pins)); - moan(graph_connect(graph, node_3->pins->next, node_2->pins)); + moan(graph_connect(graph, source_1->pins, mixer->pins->next)); + moan(graph_connect(graph, source_2->pins, mixer->pins->next->next)); + moan(graph_connect(graph, mixer->pins, sink->pins)); moan(graph_sort(graph)); { diff --git a/mixer.c b/mixer.c new file mode 100644 index 0000000..92be401 --- /dev/null +++ b/mixer.c @@ -0,0 +1,167 @@ +#include "modules.h" +#include "graph.h" +#include "errors.h" +#include "assert.h" + +///// Simple additive mixer ///// +///// TODO: handle different input formats ///// + +struct mixer { + bool format_is_set; + struct aformat af; + struct graphpin *out_pin; + int n_inputs; +}; + +static bool is_acceptable_input_format(struct graphnode *node, struct graphpin *pin, const struct aformat *af) +{ + struct mixer *m = node->extra; + assert(pin != m->out_pin); + if (m->format_is_set){ + return af->media == m->af.media + && af->srate == m->af.srate + && af->channels == m->af.channels; + } else { + return true; + } +} + +static err_t get_output_format(struct graphnode *node, struct graphpin *pin, struct aformat *af) +{ + struct mixer *m = node->extra; + assert(pin == m->out_pin); + + if (m->format_is_set){ + *af = m->af; + return EOK; + } else { + return make_error(ECANNOT_GUESS_FORMAT, node, "mixer module is not yet bound to a format"); + } +} + +static err_t set_buffer(struct graphnode *node, struct graphpin *pin, struct buffer *buf) +{ + struct mixer *m = node->extra; + if (m->format_is_set){ + if (buf->format.media == m->af.media + && buf->format.srate == m->af.srate + && buf->format.channels == m->af.channels){ + return EOK; + } else { + return make_error(EBAD_FORMAT, node, "mixer module is being connected to a bad media format"); + } + } else { + m->af = buf->format; + m->format_is_set = true; + return EOK; + } +} + +static size_t longest_in_buf_len(struct graphnode *restrict node) +{ + struct graphpin *in_pin; + size_t sz = 0; + + for (in_pin=node->pins; in_pin; in_pin=in_pin->next){ + if (in_pin->dir != DIR_IN){ + continue; + } + if (in_pin->edge->buf.n_samples > sz){ + sz = in_pin->edge->buf.n_samples; + } + } + return sz; +} + +static err_t run(struct graphnode *node) +{ +#define DO_MIX(T) { \ + T *restrict s_ptr, *restrict d_ptr; \ + register int i; \ + /* clear the output buffer */ \ + d_ptr = d_buf->data; \ + for (i=sz; i; --i){ \ + *d_ptr++ = 0; \ + } \ + \ + for (in_pin=node->pins; in_pin; in_pin=in_pin->next){ \ + s_ptr = in_pin->edge->buf.data; \ + d_ptr = d_buf->data; \ + for (i=sz; i; --i){ \ + /* Mix! */ \ + *d_ptr++ += *s_ptr++ / m->n_inputs; /* *boggle* */ \ + } \ + } \ + return EOK; } + + struct mixer *restrict m = node->extra; + struct graphpin *in_pin; + struct buffer *restrict d_buf = &m->out_pin->edge->buf; + size_t sz; + err_t err; + + sz = longest_in_buf_len(node); + err = buffer_alloc(d_buf, sz); + if (err != EOK){ + return err; + } + + sz *= m->out_pin->edge->buf.format.channels; + + switch (m->out_pin->edge->buf.format.media){ + case MT_AUDIO_32F: + DO_MIX(float) + case MT_AUDIO_16I: + DO_MIX(short) + case MT_AUDIO_32I: + DO_MIX(int) + } + return make_error(ENOTIMPL, NULL, "mixing these media types is not implemented"); +} + +static const struct graphnode_functab functab = { + is_acceptable_input_format, + NULL, // get_ideal_input_format + get_output_format, + set_buffer, + run, +}; + +err_t mixer_create(struct graphnode **node_out, int n_inputs) +{ + struct graphnode *node; + struct mixer *m; + struct graphpin *in_pin; + err_t err; + int i; + + err = graphnode_create(&node, &functab, sizeof *m); + if (err != EOK){ + return err; + } + m = node->extra; + + m->n_inputs = n_inputs; + m->format_is_set = false; + + // create output pin + err = graphnode_add_pin(node, &m->out_pin); + if (err != EOK){ + return err; + } + m->out_pin->dir = DIR_OUT; + m->out_pin->name = "out"; + + // create input pins + for (i=0; idir = DIR_IN; + in_pin->name = "in"; // how original + } + + *node_out = node; + return EOK; +} diff --git a/modules.h b/modules.h index 82518c2..b066edb 100644 --- a/modules.h +++ b/modules.h @@ -8,5 +8,6 @@ err_t wavesource_create(struct graphnode **node_out, const char *filename); err_t playsink_create(struct graphnode **node_out); err_t ringmod_create(struct graphnode **node_out); err_t audio_converter_create(struct graphnode **node_out, struct aformat *src_af, struct aformat *dest_af); +err_t mixer_create(struct graphnode **node_out, int n_inputs); #endif -- 2.11.4.GIT