diff --git a/audio/dsp_filter.c b/audio/dsp_filter.c index 66606d233b..939c6ce455 100644 --- a/audio/dsp_filter.c +++ b/audio/dsp_filter.c @@ -225,12 +225,14 @@ extern const struct dspfilter_implementation *panning_dspfilter_get_implementati 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); +extern const struct dspfilter_implementation *wahwah_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, + wahwah_dspfilter_get_implementation, }; static bool append_plugs(rarch_dsp_filter_t *dsp) diff --git a/audio/filters/WahWah.dsp b/audio/filters/WahWah.dsp new file mode 100644 index 0000000000..a4590cc28a --- /dev/null +++ b/audio/filters/WahWah.dsp @@ -0,0 +1,10 @@ +filters = 1 +filter0 = wahwah + +# Defaults. +# lfo_freq = 1.5 +# lfo_start_phase = 0.0 +# freq_offset = 0.3 +# depth = 0.7 +# resonance = 2.5 + diff --git a/audio/filters/phaser.c b/audio/filters/phaser.c index 1ea41237a4..76262f56b7 100644 --- a/audio/filters/phaser.c +++ b/audio/filters/phaser.c @@ -22,6 +22,10 @@ #define phaserlfoshape 4.0 #define lfoskipsamples 20 +#ifndef M_PI +#define M_PI 3.1415926535897932384626433832795 +#endif + struct phaser_data { float freq; @@ -113,10 +117,6 @@ static void *phaser_init(const struct dspfilter_info *info, ph->phase = lfo_start_phase * M_PI / 180.0; return ph; - -error: - free(ph); - return NULL; } static const struct dspfilter_implementation phaser_plug = { diff --git a/audio/filters/wahwah.c b/audio/filters/wahwah.c new file mode 100644 index 0000000000..6d05ae8335 --- /dev/null +++ b/audio/filters/wahwah.c @@ -0,0 +1,139 @@ +/* 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 lfoskipsamples 30 + +#ifndef M_PI +#define M_PI 3.1415926535897932384626433832795 +#endif + +struct wahwah_data +{ + float phase; + float lfoskip; + float b0, b1, b2, a0, a1, a2; + float freq, startphase; + float depth, freqofs, res; + unsigned long skipcount; + + struct + { + float xn1, xn2, yn1, yn2; + } l, r; +}; + +static void wahwah_free(void *data) +{ + free(data); +} + +static void wahwah_process(void *data, struct dspfilter_output *output, + const struct dspfilter_input *input) +{ + unsigned i; + struct wahwah_data *wah = (struct wahwah_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] }; + + if ((wah->skipcount++ % lfoskipsamples) == 0) + { + float frequency = (1.0 + cos(wah->skipcount * wah->lfoskip + wah->phase)) / 2.0; + frequency = frequency * wah->depth * (1.0 - wah->freqofs) + wah->freqofs; + frequency = exp((frequency - 1.0) * 6.0); + + float omega = M_PI * frequency; + float sn = sin(omega); + float cs = cos(omega); + float alpha = sn / (2.0 * wah->res); + + wah->b0 = (1.0 - cs) / 2.0; + wah->b1 = 1.0 - cs; + wah->b2 = (1.0 - cs) / 2.0; + wah->a0 = 1.0 + alpha; + wah->a1 = -2.0 * cs; + wah->a2 = 1.0 - alpha; + } + + float out_l = (wah->b0 * in[0] + wah->b1 * wah->l.xn1 + wah->b2 * wah->l.xn2 - wah->a1 * wah->l.yn1 - wah->a2 * wah->l.yn2) / wah->a0; + float out_r = (wah->b0 * in[1] + wah->b1 * wah->r.xn1 + wah->b2 * wah->r.xn2 - wah->a1 * wah->r.yn1 - wah->a2 * wah->r.yn2) / wah->a0; + + wah->l.xn2 = wah->l.xn1; + wah->l.xn1 = in[0]; + wah->l.yn2 = wah->l.yn1; + wah->l.yn1 = out_l; + + wah->r.xn2 = wah->r.xn1; + wah->r.xn1 = in[1]; + wah->r.yn2 = wah->r.yn1; + wah->r.yn1 = out_r; + + out[0] = out_l; + out[1] = out_r; + } +} + +static void *wahwah_init(const struct dspfilter_info *info, + const struct dspfilter_config *config, void *userdata) +{ + struct wahwah_data *wah = (struct wahwah_data*)calloc(1, sizeof(*wah)); + if (!wah) + return NULL; + + config->get_float(userdata, "lfo_freq", &wah->freq, 1.5f); + config->get_float(userdata, "lfo_start_phase", &wah->startphase, 0.0f); + config->get_float(userdata, "freq_offset", &wah->freqofs, 0.3f); + config->get_float(userdata, "depth", &wah->depth, 0.7f); + config->get_float(userdata, "resonance", &wah->res, 2.5f); + + wah->lfoskip = wah->freq * 2.0 * M_PI / info->input_rate; + wah->phase = wah->startphase * M_PI / 180.0; + + return wah; +} + +static const struct dspfilter_implementation wahwah_plug = { + wahwah_init, + wahwah_process, + wahwah_free, + + DSPFILTER_API_VERSION, + "Wah-Wah", + "wahwah", +}; + +#ifdef HAVE_FILTERS_BUILTIN +#define dspfilter_get_implementation wahwah_dspfilter_get_implementation +#endif + +const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask) +{ + (void)mask; + return &wahwah_plug; +} + +#undef dspfilter_get_implementation +