diff --git a/audio/dsp_filter.c b/audio/dsp_filter.c
index d567720511..505e72cb28 100644
--- a/audio/dsp_filter.c
+++ b/audio/dsp_filter.c
@@ -222,9 +222,13 @@ static bool create_filter_graph(rarch_dsp_filter_t *dsp, float sample_rate)
#if defined(HAVE_FILTERS_BUILTIN)
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);
static const dspfilter_get_implementation_t dsp_plugs_builtin[] = {
panning_dspfilter_get_implementation,
+ iir_dspfilter_get_implementation,
+ echo_dspfilter_get_implementation,
};
static bool append_plugs(rarch_dsp_filter_t *dsp)
diff --git a/audio/filters/Echo.dsp b/audio/filters/Echo.dsp
new file mode 100644
index 0000000000..e26fdb666a
--- /dev/null
+++ b/audio/filters/Echo.dsp
@@ -0,0 +1,10 @@
+filters = 1
+filter0 = echo
+
+# Somewhat fancy Echo filter. Can take any number of echo channels with varying delays (ms) and feedback factors.
+# Echo output from all channels can be fed back into each other to create a somewhat reverb-like effect if desired.
+echo_delay = " 60 80 120 172 200 320 380"
+echo_feedback = "0.5 0.5 0.4 0.3 0.5 0.3 0.2"
+
+# Overall echo amplification. If too high, the echo becomes unstable due to feedback.
+echo_amp = "0.12"
diff --git a/audio/filters/echo.c b/audio/filters/echo.c
new file mode 100644
index 0000000000..4baf7f8fd5
--- /dev/null
+++ b/audio/filters/echo.c
@@ -0,0 +1,167 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
+ *
+ * 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
+
+#ifndef min
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+struct echo_channel
+{
+ float *buffer;
+ unsigned ptr;
+ unsigned frames;
+ float feedback;
+};
+
+struct echo_data
+{
+ struct echo_channel *channels;
+ unsigned num_channels;
+ float amp;
+};
+
+static void echo_free(void *data)
+{
+ unsigned i;
+ struct echo_data *echo = (struct echo_data*)data;
+
+ for (i = 0; i < echo->num_channels; i++)
+ free(echo->channels[i].buffer);
+ free(echo->channels);
+ free(echo);
+}
+
+static void echo_process(void *data, struct dspfilter_output *output,
+ const struct dspfilter_input *input)
+{
+ unsigned i, c;
+ struct echo_data *echo = (struct echo_data*)data;
+
+ output->samples = input->samples;
+ output->frames = input->frames;
+
+ float *out = output->samples;
+
+ for (i = 0; i < input->frames; i++, out += 2)
+ {
+ float echo_left = 0.0f;
+ float echo_right = 0.0f;
+
+ for (c = 0; c < echo->num_channels; c++)
+ {
+ echo_left += echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 0];
+ echo_right += echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 1];
+ }
+
+ echo_left *= echo->amp;
+ echo_right *= echo->amp;
+
+ float left = out[0] + echo_left;
+ float right = out[1] + echo_right;
+
+ for (c = 0; c < echo->num_channels; c++)
+ {
+ float feedback_left = out[0] + echo->channels[c].feedback * echo_left;
+ float feedback_right = out[1] + echo->channels[c].feedback * echo_right;
+
+ echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 0] = feedback_left;
+ echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 1] = feedback_right;
+
+ echo->channels[c].ptr = (echo->channels[c].ptr + 1) % echo->channels[c].frames;
+ }
+
+ out[0] = left;
+ out[1] = right;
+ }
+}
+
+static void *echo_init(const struct dspfilter_info *info,
+ const struct dspfilter_config *config, void *userdata)
+{
+ unsigned i;
+ struct echo_data *echo = (struct echo_data*)calloc(1, sizeof(*echo));
+ if (!echo)
+ return NULL;
+
+ float *delay = NULL, *feedback = NULL;
+ unsigned num_delay = 0, num_feedback = 0;
+
+ static const float default_delay[] = { 200.0f };
+ static const float default_feedback[] = { 0.5f };
+
+ config->get_float_array(userdata, "delay", &delay, &num_delay, default_delay, 1);
+ config->get_float_array(userdata, "feedback", &feedback, &num_feedback, default_feedback, 1);
+ config->get_float(userdata, "amp", &echo->amp, 0.2f);
+
+ unsigned channels = num_feedback = num_delay = min(num_delay, num_feedback);
+
+ echo->channels = (struct echo_channel*)calloc(channels, sizeof(*echo->channels));
+ if (!echo->channels)
+ goto error;
+
+ echo->num_channels = channels;
+
+ for (i = 0; i < channels; i++)
+ {
+ unsigned frames = (unsigned)(delay[i] * info->input_rate / 1000.0f + 0.5f);
+ if (!frames)
+ goto error;
+
+ echo->channels[i].buffer = (float*)calloc(frames, 2 * sizeof(float));
+ if (!echo->channels[i].buffer)
+ goto error;
+
+ echo->channels[i].frames = frames;
+ echo->channels[i].feedback = feedback[i];
+ }
+
+ config->free(delay);
+ config->free(feedback);
+ return echo;
+
+error:
+ config->free(delay);
+ config->free(feedback);
+ echo_free(echo);
+ return NULL;
+}
+
+
+static const struct dspfilter_implementation echo_plug = {
+ echo_init,
+ echo_process,
+ echo_free,
+
+ DSPFILTER_API_VERSION,
+ "Multi-Echo",
+ "echo",
+};
+
+#ifdef HAVE_FILTERS_BUILTIN
+#define dspfilter_get_implementation echo_dspfilter_get_implementation
+#endif
+
+const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
+{
+ (void)mask;
+ return &echo_plug;
+}
+
+#undef dspfilter_get_implementation
+
diff --git a/griffin/griffin.c b/griffin/griffin.c
index 0d32845dc4..bbea8c20e1 100644
--- a/griffin/griffin.c
+++ b/griffin/griffin.c
@@ -486,6 +486,8 @@ FILTERS
#include "../gfx/filters/phosphor2x.c"
#include "../audio/filters/panning.c"
+#include "../audio/filters/iir.c"
+#include "../audio/filters/echo.c"
#endif
/*============================================================
DYNAMIC