From 828552d1119d8f7130adaa8cfe4ca8ac62a25192 Mon Sep 17 00:00:00 2001 From: Themaister Date: Sun, 25 May 2014 13:54:20 +0200 Subject: [PATCH] Add phaser. --- audio/dsp_filter.c | 2 + audio/filters/Phaser.dsp | 11 +++ audio/filters/phaser.c | 143 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 audio/filters/Phaser.dsp create mode 100644 audio/filters/phaser.c diff --git a/audio/dsp_filter.c b/audio/dsp_filter.c index 505e72cb28..66606d233b 100644 --- a/audio/dsp_filter.c +++ b/audio/dsp_filter.c @@ -224,11 +224,13 @@ static bool create_filter_graph(rarch_dsp_filter_t *dsp, float sample_rate) extern const struct dspfilter_implementation *panning_dspfilter_get_implementation(dspfilter_simd_mask_t mask); extern const struct dspfilter_implementation *iir_dspfilter_get_implementation(dspfilter_simd_mask_t mask); extern const struct dspfilter_implementation *echo_dspfilter_get_implementation(dspfilter_simd_mask_t mask); +extern const struct dspfilter_implementation *phaser_dspfilter_get_implementation(dspfilter_simd_mask_t mask); static const dspfilter_get_implementation_t dsp_plugs_builtin[] = { panning_dspfilter_get_implementation, iir_dspfilter_get_implementation, echo_dspfilter_get_implementation, + phaser_dspfilter_get_implementation, }; static bool append_plugs(rarch_dsp_filter_t *dsp) diff --git a/audio/filters/Phaser.dsp b/audio/filters/Phaser.dsp new file mode 100644 index 0000000000..6dfdfd8d0e --- /dev/null +++ b/audio/filters/Phaser.dsp @@ -0,0 +1,11 @@ +filters = 1 +filter0 = phaser + +# Defaults. +# lfo_freq = 0.4 +# lfo_start_phase = 0.0 +# feedback = 0.0 +# depth = 0.4 +# dry_wet = 0.5 +# stages = 2 + diff --git a/audio/filters/phaser.c b/audio/filters/phaser.c new file mode 100644 index 0000000000..1ea41237a4 --- /dev/null +++ b/audio/filters/phaser.c @@ -0,0 +1,143 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2014 - Brad Miller + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include "dspfilter.h" +#include +#include +#include + +#define phaserlfoshape 4.0 +#define lfoskipsamples 20 + +struct phaser_data +{ + float freq; + float startphase; + float fb; + float depth; + float drywet; + float old[2][24]; + float gain; + float fbout[2]; + float lfoskip; + float phase; + + int stages; + unsigned long skipcount; +}; + +static void phaser_free(void *data) +{ + free(data); +} + +static void phaser_process(void *data, struct dspfilter_output *output, + const struct dspfilter_input *input) +{ + unsigned i, c; + int s; + float m[2], tmp[2]; + struct phaser_data *ph = (struct phaser_data*)data; + + output->samples = input->samples; + output->frames = input->frames; + float *out = output->samples; + + for (i = 0; i < input->frames; i++, out += 2) + { + float in[2] = { out[0], out[1] }; + + for (c = 0; c < 2; c++) + m[c] = in[c] + ph->fbout[c] * ph->fb * 0.01f; + + if ((ph->skipcount++ % lfoskipsamples) == 0) + { + ph->gain = 0.5 * (1.0 + cos(ph->skipcount * ph->lfoskip + ph->phase)); + ph->gain = (exp(ph->gain * phaserlfoshape) - 1.0) / (exp(phaserlfoshape) - 1); + ph->gain = 1.0 - ph->gain * ph->depth; + } + + for (s = 0; s < ph->stages; s++) + { + for (c = 0; c < 2; c++) + { + tmp[c] = ph->old[c][s]; + ph->old[c][s] = ph->gain * tmp[c] + m[c]; + m[c] = tmp[c] - ph->gain * ph->old[c][s]; + } + } + + for (c = 0; c < 2; c++) + { + ph->fbout[c] = m[c]; + out[c] = m[c] * ph->drywet + in[c] * (1.0f - ph->drywet); + } + } +} + +static void *phaser_init(const struct dspfilter_info *info, + const struct dspfilter_config *config, void *userdata) +{ + struct phaser_data *ph = (struct phaser_data*)calloc(1, sizeof(*ph)); + if (!ph) + return NULL; + + float lfo_freq, lfo_start_phase; + + config->get_float(userdata, "lfo_freq", &lfo_freq, 0.4f); + config->get_float(userdata, "lfo_start_phase", &lfo_start_phase, 0.0f); + config->get_float(userdata, "feedback", &ph->fb, 0.0f); + config->get_float(userdata, "depth", &ph->depth, 0.4f); + config->get_float(userdata, "dry_wet", &ph->drywet, 0.5f); + config->get_int(userdata, "stages", &ph->stages, 2); + + if (ph->stages < 1) + ph->stages = 1; + else if (ph->stages > 24) + ph->stages = 24; + + ph->lfoskip = lfo_freq * 2.0 * M_PI / info->input_rate; + ph->phase = lfo_start_phase * M_PI / 180.0; + + return ph; + +error: + free(ph); + return NULL; +} + +static const struct dspfilter_implementation phaser_plug = { + phaser_init, + phaser_process, + phaser_free, + + DSPFILTER_API_VERSION, + "Phaser", + "phaser", +}; + +#ifdef HAVE_FILTERS_BUILTIN +#define dspfilter_get_implementation phaser_dspfilter_get_implementation +#endif + +const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask) +{ + (void)mask; + return &phaser_plug; +} + +#undef dspfilter_get_implementation +