diff --git a/audio/filters/Makefile b/audio/filters/Makefile index dfb74a35c7..0e4fbddd86 100644 --- a/audio/filters/Makefile +++ b/audio/filters/Makefile @@ -55,8 +55,8 @@ else DYLIB = dll endif -CC := $(compiler) -CXX := $(subst CC,++,$(compiler)) -std=gnu++0x +CC := $(compiler) -Wall +CXX := $(subst CC,++,$(compiler)) -std=gnu++0x -Wall flags := -fPIC $(extra_flags) asflags := -fPIC $(extra_flags) objects := diff --git a/audio/filters/Phaser.dsp b/audio/filters/Phaser.dsp index 6dfdfd8d0e..80b209deaa 100644 --- a/audio/filters/Phaser.dsp +++ b/audio/filters/Phaser.dsp @@ -2,10 +2,10 @@ 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 +# phaser_lfo_freq = 0.4 +# phaser_lfo_start_phase = 0.0 +# phaser_feedback = 0.0 +# phaser_depth = 0.4 +# phaser_dry_wet = 0.5 +# phaser_stages = 2 diff --git a/audio/filters/Reverb.dsp b/audio/filters/Reverb.dsp new file mode 100644 index 0000000000..0f0d53f4a8 --- /dev/null +++ b/audio/filters/Reverb.dsp @@ -0,0 +1,10 @@ +filters = 1 +filter0 = reverb + +# Defaults. +# reverb_drytime = 0.43 +# reverb_wettime = 0.4 +# reverb_damping = 0.8 +# reverb_roomwidth = 0.56 +# reverb_roomsize = 0.56 + diff --git a/audio/filters/WahWah.dsp b/audio/filters/WahWah.dsp index a4590cc28a..4d5bceb094 100644 --- a/audio/filters/WahWah.dsp +++ b/audio/filters/WahWah.dsp @@ -2,9 +2,9 @@ filters = 1 filter0 = wahwah # Defaults. -# lfo_freq = 1.5 -# lfo_start_phase = 0.0 -# freq_offset = 0.3 -# depth = 0.7 -# resonance = 2.5 +# wahwah_lfo_freq = 1.5 +# wahwah_lfo_start_phase = 0.0 +# wahwah_freq_offset = 0.3 +# wahwah_depth = 0.7 +# wahwah_resonance = 2.5 diff --git a/audio/filters/reverb.c b/audio/filters/reverb.c new file mode 100644 index 0000000000..229a39b7dd --- /dev/null +++ b/audio/filters/reverb.c @@ -0,0 +1,315 @@ +/* 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 + +struct comb +{ + float *buffer; + unsigned bufsize; + unsigned bufidx; + + float feedback; + float filterstore; + float damp1, damp2; +}; + +static inline float comb_process(struct comb *c, float input) +{ + float output = c->buffer[c->bufidx]; + c->filterstore = (output * c->damp2) + (c->filterstore * c->damp1); + + c->buffer[c->bufidx] = input + (c->filterstore * c->feedback); + + c->bufidx++; + if (c->bufidx >= c->bufsize) + c->bufidx = 0; + + return output; +} + +struct allpass +{ + float *buffer; + float feedback; + unsigned bufsize; + unsigned bufidx; +}; + +static inline float allpass_process(struct allpass *a, float input) +{ + float bufout = a->buffer[a->bufidx]; + float output = -input + bufout; + a->buffer[a->bufidx] = input + bufout * a->feedback; + + a->bufidx++; + if (a->bufidx >= a->bufsize) + a->bufidx = 0; + + return output; +} + +#define numcombs 8 +#define numallpasses 4 +static const float muted = 0; +static const float fixedgain = 0.015f; +static const float scalewet = 3; +static const float scaledry = 2; +static const float scaledamp = 0.4f; +static const float scaleroom = 0.28f; +static const float offsetroom = 0.7f; +static const float initialroom = 0.5f; +static const float initialdamp = 0.5f; +static const float initialwet = 1.0f / 3.0f; +static const float initialdry = 0; +static const float initialwidth = 1; +static const float initialmode = 0; +static const float freezemode = 0.5f; + +#define combtuningL1 1116 +#define combtuningL2 1188 +#define combtuningL3 1277 +#define combtuningL4 1356 +#define combtuningL5 1422 +#define combtuningL6 1491 +#define combtuningL7 1557 +#define combtuningL8 1617 +#define allpasstuningL1 556 +#define allpasstuningL2 441 +#define allpasstuningL3 341 +#define allpasstuningL4 225 + +struct revmodel +{ + struct comb combL[numcombs]; + struct allpass allpassL[numallpasses]; + + float bufcombL1[combtuningL1]; + float bufcombL2[combtuningL2]; + float bufcombL3[combtuningL3]; + float bufcombL4[combtuningL4]; + float bufcombL5[combtuningL5]; + float bufcombL6[combtuningL6]; + float bufcombL7[combtuningL7]; + float bufcombL8[combtuningL8]; + + float bufallpassL1[allpasstuningL1]; + float bufallpassL2[allpasstuningL2]; + float bufallpassL3[allpasstuningL3]; + float bufallpassL4[allpasstuningL4]; + + float gain; + float roomsize, roomsize1; + float damp, damp1; + float wet, wet1, wet2; + float dry; + float width; + float mode; +}; + +static float revmodel_process(struct revmodel *rev, float in) +{ + int i; + float mono_out = 0.0f; + float mono_in = in; + float input = mono_in * rev->gain; + for (i = 0; i < numcombs; i++) + mono_out += comb_process(&rev->combL[i], input); + + for (i = 0; i < numallpasses; i++) + mono_out = allpass_process(&rev->allpassL[i], mono_out); + + return mono_in * rev->dry + mono_out * rev->wet1; +} + +static void revmodel_update(struct revmodel *rev) +{ + int i; + rev->wet1 = rev->wet * (rev->width / 2.0f + 0.5f); + + if (rev->mode >= freezemode) + { + rev->roomsize1 = 1.0f; + rev->damp1 = 0.0f; + rev->gain = muted; + } + else + { + rev->roomsize1 = rev->roomsize; + rev->damp1 = rev->damp; + rev->gain = fixedgain; + } + + for (i = 0; i < numcombs; i++) + { + rev->combL[i].feedback = rev->roomsize1; + rev->combL[i].damp1 = rev->damp1; + rev->combL[i].damp2 = 1.0f - rev->damp1; + } +} + +static void revmodel_setroomsize(struct revmodel *rev, float value) +{ + rev->roomsize = value * scaleroom + offsetroom; + revmodel_update(rev); +} + +static void revmodel_setdamp(struct revmodel *rev, float value) +{ + rev->damp = value * scaledamp; + revmodel_update(rev); +} + +static void revmodel_setwet(struct revmodel *rev, float value) +{ + rev->wet = value * scalewet; + revmodel_update(rev); +} + +static void revmodel_setdry(struct revmodel *rev, float value) +{ + rev->dry = value * scaledry; + revmodel_update(rev); +} + +static void revmodel_setwidth(struct revmodel *rev, float value) +{ + rev->width = value; + revmodel_update(rev); +} + +static void revmodel_setmode(struct revmodel *rev, float value) +{ + rev->mode = value; + revmodel_update(rev); +} + +static void revmodel_init(struct revmodel *rev) +{ + rev->combL[0].buffer = rev->bufcombL1; rev->combL[0].bufsize = combtuningL1; + rev->combL[1].buffer = rev->bufcombL2; rev->combL[1].bufsize = combtuningL2; + rev->combL[2].buffer = rev->bufcombL3; rev->combL[2].bufsize = combtuningL3; + rev->combL[3].buffer = rev->bufcombL4; rev->combL[3].bufsize = combtuningL4; + rev->combL[4].buffer = rev->bufcombL5; rev->combL[4].bufsize = combtuningL5; + rev->combL[5].buffer = rev->bufcombL6; rev->combL[5].bufsize = combtuningL6; + rev->combL[6].buffer = rev->bufcombL7; rev->combL[6].bufsize = combtuningL7; + rev->combL[7].buffer = rev->bufcombL8; rev->combL[7].bufsize = combtuningL8; + + rev->allpassL[0].buffer = rev->bufallpassL1; rev->allpassL[0].bufsize = allpasstuningL1; + rev->allpassL[1].buffer = rev->bufallpassL2; rev->allpassL[1].bufsize = allpasstuningL2; + rev->allpassL[2].buffer = rev->bufallpassL3; rev->allpassL[2].bufsize = allpasstuningL3; + rev->allpassL[3].buffer = rev->bufallpassL4; rev->allpassL[3].bufsize = allpasstuningL4; + + rev->allpassL[0].feedback = 0.5f; + rev->allpassL[1].feedback = 0.5f; + rev->allpassL[2].feedback = 0.5f; + rev->allpassL[3].feedback = 0.5f; + + revmodel_setwet(rev, initialwet); + revmodel_setroomsize(rev, initialroom); + revmodel_setdry(rev, initialdry); + revmodel_setdamp(rev, initialdamp); + revmodel_setwidth(rev, initialwidth); + revmodel_setmode(rev, initialmode); +} + +struct reverb_data +{ + struct revmodel left, right; +}; + +static void reverb_free(void *data) +{ + free(data); +} + +static void reverb_process(void *data, struct dspfilter_output *output, + const struct dspfilter_input *input) +{ + unsigned i; + struct reverb_data *rev = (struct reverb_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] }; + + out[0] = revmodel_process(&rev->left, in[0]); + out[1] = revmodel_process(&rev->right, in[1]); + } +} + +static void *reverb_init(const struct dspfilter_info *info, + const struct dspfilter_config *config, void *userdata) +{ + struct reverb_data *rev = (struct reverb_data*)calloc(1, sizeof(*rev)); + if (!rev) + return NULL; + + float drytime, wettime, damping, roomwidth, roomsize; + config->get_float(userdata, "drytime", &drytime, 0.43f); + config->get_float(userdata, "wettime", &wettime, 0.4f); + config->get_float(userdata, "damping", &damping, 0.8f); + config->get_float(userdata, "roomwidth", &roomwidth, 0.56f); + config->get_float(userdata, "roomsize", &roomsize, 0.56f); + + revmodel_init(&rev->left); + revmodel_init(&rev->right); + + revmodel_setdamp(&rev->left, damping); + revmodel_setdry(&rev->left, drytime); + revmodel_setwet(&rev->left, wettime); + revmodel_setwidth(&rev->left, roomwidth); + revmodel_setroomsize(&rev->left, roomsize); + + revmodel_setdamp(&rev->right, damping); + revmodel_setdry(&rev->right, drytime); + revmodel_setwet(&rev->right, wettime); + revmodel_setwidth(&rev->right, roomwidth); + revmodel_setroomsize(&rev->right, roomsize); + + return rev; +} + +static const struct dspfilter_implementation reverb_plug = { + reverb_init, + reverb_process, + reverb_free, + + DSPFILTER_API_VERSION, + "Reverb", + "reverb", +}; + +#ifdef HAVE_FILTERS_BUILTIN +#define dspfilter_get_implementation reverb_dspfilter_get_implementation +#endif + +const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask) +{ + (void)mask; + return &reverb_plug; +} + +#undef dspfilter_get_implementation + +