diff --git a/audio/filters/Makefile b/audio/filters/Makefile index 2495bb2b13..dfb74a35c7 100644 --- a/audio/filters/Makefile +++ b/audio/filters/Makefile @@ -1,58 +1,58 @@ compiler := gcc extra_flags := use_neon := 0 -release := release -DYLIB := so +build = release +DYLIB := so ifeq ($(platform),) -platform = unix -ifeq ($(shell uname -a),) - platform = win -else ifneq ($(findstring MINGW,$(shell uname -a)),) - platform = win -else ifneq ($(findstring Darwin,$(shell uname -a)),) - platform = osx - arch = intel -ifeq ($(shell uname -p),powerpc) - arch = ppc -endif -else ifneq ($(findstring win,$(shell uname -a)),) - platform = win -endif + platform = unix + ifeq ($(shell uname -a),) + platform = win + else ifneq ($(findstring MINGW,$(shell uname -a)),) + platform = win + else ifneq ($(findstring Darwin,$(shell uname -a)),) + platform = osx + arch = intel + ifeq ($(shell uname -p),powerpc) + arch = ppc + endif + else ifneq ($(findstring win,$(shell uname -a)),) + platform = win + endif endif ifeq ($(platform),gcc) -extra_rules_gcc := $(shell $(compiler) -dumpmachine) + extra_rules_gcc := $(shell $(compiler) -dumpmachine) endif ifneq (,$(findstring armv7,$(extra_rules_gcc))) -extra_flags += -mcpu=cortex-a9 -mtune=cortex-a9 -mfpu=neon -use_neon := 1 + extra_flags += -mcpu=cortex-a9 -mtune=cortex-a9 -mfpu=neon + use_neon := 1 endif ifneq (,$(findstring hardfloat,$(extra_rules_gcc))) -extra_flags += -mfloat-abi=hard + extra_flags += -mfloat-abi=hard endif ifeq (release,$(build)) -extra_flags += -O2 + extra_flags += -O2 endif ifeq (debug,$(build)) -extra_flags += -O0 -g + extra_flags += -O0 -g endif -ldflags := -shared -Wl,--version-script=link.T +ldflags := -shared -lm -Wl,--version-script=link.T ifeq ($(platform), unix) -DYLIB = so + DYLIB = so else ifeq ($(platform), osx) -compiler := $(CC) -DYLIB = dylib -ldflags := -dynamiclib + compiler := $(CC) + DYLIB = dylib + ldflags := -dynamiclib else -extra_flags += -static-libgcc -static-libstdc++ -DYLIB = dll + extra_flags += -static-libgcc -static-libstdc++ + DYLIB = dll endif CC := $(compiler) @@ -60,15 +60,15 @@ CXX := $(subst CC,++,$(compiler)) -std=gnu++0x flags := -fPIC $(extra_flags) asflags := -fPIC $(extra_flags) objects := -flags += -std=c99 - ifeq (1,$(use_neon)) -ASMFLAGS := -INEON/asm -asflags += -mfpu=neon + ASMFLAGS := -INEON/asm + asflags += -mfpu=neon endif - -objects += echo.$(DYLIB) eq.$(DYLIB) iir.$(DYLIB) phaser.$(DYLIB) reverb.$(DYLIB) volume.$(DYLIB) wah.$(DYLIB) + +plugs := $(wildcard *.c) +objects := $(plugs:.c=.o) +targets := $(objects:.o=.$(DYLIB)) all: build; @@ -81,7 +81,7 @@ all: build; %.$(DYLIB): %.o $(CC) -o $@ $(ldflags) $(flags) $^ -build: $(objects) +build: $(targets) clean: rm -f *.o diff --git a/audio/filters/Panning.dsp b/audio/filters/Panning.dsp new file mode 100644 index 0000000000..f8d6afd62e --- /dev/null +++ b/audio/filters/Panning.dsp @@ -0,0 +1,20 @@ +filters = 1 +filter0 = panning + +# Gains are linear. + +# The default. Left and right channels map to each other. +panning_left_mix = "1.0 0.0" +panning_right_mix = "0.0 1.0" + + +# Some examples: +# +# Mono: +# panning_left_mix = "0.5 0.5" +# panning_right_mix = "0.5 0.5" + +# Swap left and right channels: +# panning_left_mix = "0.0 1.0" +# panning_right_mix = "1.0 0.0" + diff --git a/audio/filters/dspfilter.h b/audio/filters/dspfilter.h index a28c42252f..6ed686044f 100644 --- a/audio/filters/dspfilter.h +++ b/audio/filters/dspfilter.h @@ -57,12 +57,11 @@ struct dspfilter_info struct dspfilter_output { - // The DSP plugin has to provide the buffering for the output samples. - // This is for performance reasons to avoid redundant copying of data. + // The DSP plugin has to provide the buffering for the output samples or reuse the input buffer directly. // The samples are laid out in interleaving order: LRLRLRLR // The range of the samples are [-1.0, 1.0]. - // This range cannot be exceeded without horrible audio glitches. - const float *samples; + // It is not necessary to manually clip values. + float *samples; // Frames which the DSP plugin outputted for the current process. // One frame is here defined as a combined sample of @@ -75,7 +74,11 @@ struct dspfilter_output struct dspfilter_input { // Input data for the DSP. The samples are interleaved in order: LRLRLRLR - const float *samples; + // It is valid for a DSP plug to use this buffer for output as long as the output size is less or equal to the input. + // This is useful for filters which can output one sample for each input sample and do not need to maintain its own buffers. + // Block based filters must provide their own buffering scheme. + // The input size is not bound, but it can be safely assumed that it will not exceed ~100ms worth of audio at a time. + float *samples; // Number of frames for input data. // One frame is here defined as a combined sample of @@ -101,7 +104,7 @@ typedef int (*dspfilter_config_get_int_array_t)(void *userdata, const char *key, typedef int (*dspfilter_config_get_string_t)(void *userdata, const char *key, char **output, const char *default_output); // Calls free() in host runtime. Sometimes needed on Windows. free() on NULL is fine. -typedef void (*dspfilter_config_free_t)(void *userdata, void *ptr); +typedef void (*dspfilter_config_free_t)(void *ptr); struct dspfilter_config { diff --git a/audio/filters/link.T b/audio/filters/link.T index ea0000d6f6..bd9ad7918c 100644 --- a/audio/filters/link.T +++ b/audio/filters/link.T @@ -1,4 +1,4 @@ { - global: rarch_dsp_*; + global: dspfilter_get_implementation; local: *; }; diff --git a/audio/filters/panning.c b/audio/filters/panning.c new file mode 100644 index 0000000000..259930abfa --- /dev/null +++ b/audio/filters/panning.c @@ -0,0 +1,79 @@ +#include "dspfilter.h" +#include +#include +#include + +struct panning_data +{ + float left[2]; + float right[2]; +}; + +static void panning_free(void *data) +{ + free(data); +} + +static void panning_process(void *data, struct dspfilter_output *output, + const struct dspfilter_input *input) +{ + unsigned i; + struct panning_data *pan = (struct panning_data*)data; + + output->samples = input->samples; + output->frames = input->frames; + + float *out = output->samples; + + for (i = 0; i < input->frames; i++, out += 2) + { + float left = out[0]; + float right = out[1]; + out[0] = left * pan->left[0] + right * pan->left[1]; + out[1] = left * pan->right[0] + right * pan->right[1]; + } +} + +static void *panning_init(const struct dspfilter_info *info, + const struct dspfilter_config *config, void *userdata) +{ + struct panning_data *pan = (struct panning_data*)calloc(1, sizeof(*pan)); + if (!pan) + return NULL; + + float *left = NULL, *right = NULL; + unsigned num_left = 0, num_right = 0; + + static const float default_left[] = { 1.0f, 0.0f }; + static const float default_right[] = { 0.0f, 1.0f }; + + config->get_float_array(userdata, "left_mix", &left, &num_left, default_left, 2); + config->get_float_array(userdata, "right_mix", &right, &num_right, default_right, 2); + + if (num_left == 2) + memcpy(pan->left, left, sizeof(pan->left)); + if (num_right == 2) + memcpy(pan->right, right, sizeof(pan->right)); + + config->free(left); + config->free(right); + + return pan; +} + +static const struct dspfilter_implementation panning = { + panning_init, + panning_process, + panning_free, + + DSPFILTER_API_VERSION, + "Panning", + "panning", +}; + +const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask) +{ + (void)mask; + return &panning; +} +