diff options
author | XANTRONIX Development | 2022-01-18 13:17:45 -0500 |
---|---|---|
committer | XANTRONIX Development | 2022-01-18 13:17:58 -0500 |
commit | 26c62832420553f6f82ec3daeef6df08326fc922 (patch) | |
tree | a61000324a75a5965bbfbc3ea3c76a93799f85a9 | |
parent | 9b6dd9f61ab0f627470a521d626b1d6c476fc7d7 (diff) | |
download | xas-26c62832420553f6f82ec3daeef6df08326fc922.tar.gz xas-26c62832420553f6f82ec3daeef6df08326fc922.tar.bz2 xas-26c62832420553f6f82ec3daeef6df08326fc922.zip |
It compiles! Beep! Beep!
-rw-r--r-- | include/xas/mixer.h | 46 | ||||
-rw-r--r-- | src/Makefile | 4 | ||||
-rw-r--r-- | src/mixer.c | 206 |
3 files changed, 254 insertions, 2 deletions
diff --git a/include/xas/mixer.h b/include/xas/mixer.h new file mode 100644 index 0000000..9fd77cb --- /dev/null +++ b/include/xas/mixer.h @@ -0,0 +1,46 @@ +#ifndef _XAS_MIXER_H +#define _XAS_MIXER_H + +#include <sys/types.h> + +#include <xas/audio.h> + +typedef struct _xas_mixer_input { + xas_audio_stream *stream; + + float gain, + bias_l, + bias_r; + + struct _xas_mixer_input *next; +} xas_mixer_input; + +typedef struct _xas_mixer { + xas_mixer_input *inputs, + *last; + + xas_audio_stream *output; + + void *buf; + size_t buffer_size; +} xas_mixer; + +xas_mixer *xas_mixer_new(size_t sample_size, + size_t sample_rate, + size_t channels, + size_t buffer_size); + +void xas_mixer_destroy(xas_mixer *mixer); + +xas_audio_stream *xas_mixer_output(xas_mixer *mixer); + +xas_mixer_input *xas_mixer_input_add(xas_mixer *mixer, + xas_audio_stream *stream, + float gain, + float pan); + +void xas_mixer_input_set_gain(xas_mixer_input *input, float gain); + +void xas_mixer_input_set_pan(xas_mixer_input *input, float pan); + +#endif /* _XAS_MIXER_H */ diff --git a/src/Makefile b/src/Makefile index 3046c70..d638619 100644 --- a/src/Makefile +++ b/src/Makefile @@ -7,9 +7,9 @@ CC = $(CROSS)cc CFLAGS += -I$(INCLUDE_PATH) LDFLAGS += -HEADERS = audio.h riff.h +HEADERS = audio.h mixer.h riff.h -OBJS = audio.o riff.o +OBJS = audio.o mixer.o riff.o VERSION_MAJOR = 0 VERSION_MINOR = 0.1 diff --git a/src/mixer.c b/src/mixer.c new file mode 100644 index 0000000..da822bf --- /dev/null +++ b/src/mixer.c @@ -0,0 +1,206 @@ +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <math.h> +#include <errno.h> + +#include <xas/audio.h> +#include <xas/mixer.h> + +static void mixer_apply_int16_t_mono(int16_t *dest, + int16_t *src, + size_t count, + float bias_l, + float bias_r) { + size_t i; + + for (i=0; i<count; i++) { + dest[i] += src[i]; + } +} + +static void mixer_apply_int16_t_stereo(int16_t *dest, + int16_t *src, + size_t count, + float bias_l, + float bias_r) { + size_t i; + + for (i=0; i<2*count; i+=2) { + dest[i] += (int16_t)roundf(src[i] * bias_l); + dest[i+1] += (int16_t)roundf(src[i+1] * bias_r); + } +} + +static ssize_t mixer_fill(xas_mixer *mixer, + void *samples, + size_t count, + xas_audio_stream *output) { + ssize_t ret = 0; + + xas_mixer_input *input = mixer->inputs; + + void (*mixer_apply)(int16_t *, + int16_t *, + size_t, + float, + float) = (output->channels == 2)? + mixer_apply_int16_t_stereo: + mixer_apply_int16_t_mono; + + memset(mixer->buf, + '\0', + output->sample_size * output->channels * output->buffer_size); + + while (input) { + xas_mixer_input *next = input->next; + + ssize_t readlen; + + if ((readlen = xas_audio_stream_read(input->stream, + mixer->buf, + count)) < 0) { + goto error_audio_read_stream; + } + + mixer_apply((int16_t *)mixer->buf, + (int16_t *)(input + 1), + readlen, + input->bias_l, + input->bias_r); + + if (ret < readlen) { + ret = readlen; + } + + input = next; + } + + return ret; + +error_audio_read_stream: + return -1; +} + +xas_mixer *xas_mixer_new(size_t sample_size, + size_t sample_rate, + size_t channels, + size_t buffer_size) { + xas_mixer *mixer; + + if ((mixer = malloc(sizeof(*mixer))) == NULL) { + goto error_malloc_mixer; + } + + if ((mixer->buf = malloc(sample_size * channels * buffer_size)) == NULL) { + goto error_malloc_buf; + } + + if ((mixer->output = xas_audio_stream_new_source((xas_audio_fill)mixer_fill, + NULL, + mixer, + sample_size, + sample_rate, + channels, + buffer_size)) == NULL) { + goto error_audio_stream_new_source; + } + + mixer->inputs = NULL; + mixer->last = NULL; + mixer->buffer_size = buffer_size; + + return mixer; + +error_audio_stream_new_source: + free(mixer->buf); + +error_malloc_buf: + free(mixer); + +error_malloc_mixer: + return NULL; +} + +void xas_mixer_destroy(xas_mixer *mixer) { + xas_mixer_input *input = mixer->inputs; + + while (input) { + xas_mixer_input *next = input; + + free(input); + + input = next; + } + + xas_audio_stream_destroy(mixer->output); + + free(mixer); +} + +static inline void input_set_pan(xas_mixer_input *input, float pan) { + float angle, + term, + cosf_angle, + sinf_angle; + + if (pan < -1.0 || pan > 1.0) { + return; + } + + angle = pan * (M_PI / 2.0f); + term = sqrtf(2.0f) / 2.0f; + cosf_angle = cosf(angle); + sinf_angle = sinf(angle); + + input->bias_l = term * (cosf_angle + sinf_angle); + input->bias_r = term * (cosf_angle - sinf_angle); +} + +xas_mixer_input *xas_mixer_input_add(xas_mixer *mixer, + xas_audio_stream *stream, + float gain, + float pan) { + xas_mixer_input *input; + + if (stream->sample_size != mixer->output->sample_size + || stream->sample_rate != mixer->output->sample_rate + || stream->channels != mixer->output->channels + || stream->buffer_size != mixer->buffer_size) { + errno = EINVAL; + + goto error_invalid_stream; + } + + if ((input = malloc(sizeof(*input))) == NULL) { + goto error_malloc_input; + } + + input->stream = stream; + input->gain = gain; + + input_set_pan(input, pan); + + if (mixer->inputs == NULL) { + mixer->inputs = input; + mixer->last = NULL; + } + + return input; + +error_malloc_input: +error_invalid_stream: + return NULL; +} + +void xas_mixer_input_set_gain(xas_mixer_input *input, float gain) { + if (gain < 0.0 || gain > 1.0) { + return; + } + + input->gain = gain; +} + +void xas_mixer_input_set_pan(xas_mixer_input *input, float pan) { + return input_set_pan(input, pan); +} |