1 /* Copyright (C) 2010-2020 The RetroArch team
3 * ---------------------------------------------------------------------------------------
4 * The following license statement only applies to this file (reverb.c).
5 * ---------------------------------------------------------------------------------------
7 * Permission is hereby granted, free of charge,
8 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #include <retro_inline.h>
28 #include <libretro_dspfilter.h>
49 static INLINE float comb_process(struct comb *c, float input)
51 float output = c->buffer[c->bufidx];
52 c->filterstore = (output * c->damp2) + (c->filterstore * c->damp1);
54 c->buffer[c->bufidx] = input + (c->filterstore * c->feedback);
57 if (c->bufidx >= c->bufsize)
63 static INLINE float allpass_process(struct allpass *a, float input)
65 float bufout = a->buffer[a->bufidx];
66 float output = -input + bufout;
67 a->buffer[a->bufidx] = input + bufout * a->feedback;
70 if (a->bufidx >= a->bufsize)
77 #define numallpasses 4
78 static const float muted = 0;
79 static const float fixedgain = 0.015f;
80 static const float scalewet = 3;
81 static const float scaledry = 2;
82 static const float scaledamp = 0.4f;
83 static const float scaleroom = 0.28f;
84 static const float offsetroom = 0.7f;
85 static const float initialroom = 0.5f;
86 static const float initialdamp = 0.5f;
87 static const float initialwet = 1.0f / 3.0f;
88 static const float initialdry = 0;
89 static const float initialwidth = 1;
90 static const float initialmode = 0;
91 static const float freezemode = 0.5f;
95 struct comb combL[numcombs];
96 struct allpass allpassL[numallpasses];
98 float *bufcomb[numcombs];
99 float *bufallpass[numallpasses];
102 float roomsize, roomsize1;
104 float wet, wet1, wet2;
110 static float revmodel_process(struct revmodel *rev, float in)
113 float mono_out = 0.0f;
115 float input = mono_in * rev->gain;
117 for (i = 0; i < numcombs; i++)
118 mono_out += comb_process(&rev->combL[i], input);
120 for (i = 0; i < numallpasses; i++)
121 mono_out = allpass_process(&rev->allpassL[i], mono_out);
123 return mono_in * rev->dry + mono_out * rev->wet1;
126 static void revmodel_update(struct revmodel *rev)
129 rev->wet1 = rev->wet * (rev->width / 2.0f + 0.5f);
131 if (rev->mode >= freezemode)
133 rev->roomsize1 = 1.0f;
139 rev->roomsize1 = rev->roomsize;
140 rev->damp1 = rev->damp;
141 rev->gain = fixedgain;
144 for (i = 0; i < numcombs; i++)
146 rev->combL[i].feedback = rev->roomsize1;
147 rev->combL[i].damp1 = rev->damp1;
148 rev->combL[i].damp2 = 1.0f - rev->damp1;
152 static void revmodel_setroomsize(struct revmodel *rev, float value)
154 rev->roomsize = value * scaleroom + offsetroom;
155 revmodel_update(rev);
158 static void revmodel_setdamp(struct revmodel *rev, float value)
160 rev->damp = value * scaledamp;
161 revmodel_update(rev);
164 static void revmodel_setwet(struct revmodel *rev, float value)
166 rev->wet = value * scalewet;
167 revmodel_update(rev);
170 static void revmodel_setdry(struct revmodel *rev, float value)
172 rev->dry = value * scaledry;
173 revmodel_update(rev);
176 static void revmodel_setwidth(struct revmodel *rev, float value)
179 revmodel_update(rev);
182 static void revmodel_setmode(struct revmodel *rev, float value)
185 revmodel_update(rev);
188 static void revmodel_init(struct revmodel *rev,int srate)
191 static const int comb_lengths[8] = { 1116,1188,1277,1356,1422,1491,1557,1617 };
192 static const int allpass_lengths[4] = { 225,341,441,556 };
193 double r = srate * (1 / 44100.0);
196 for (c = 0; c < numcombs; ++c)
198 rev->bufcomb[c] = malloc(r*comb_lengths[c]*sizeof(float));
199 rev->combL[c].buffer = rev->bufcomb[c];
200 memset(rev->combL[c].buffer,0,r*comb_lengths[c]*sizeof(float));
201 rev->combL[c].bufsize=r*comb_lengths[c];
204 for (c = 0; c < numallpasses; ++c)
206 rev->bufallpass[c] = malloc(r*allpass_lengths[c]*sizeof(float));
207 rev->allpassL[c].buffer = rev->bufallpass[c];
208 memset(rev->allpassL[c].buffer,0,r*allpass_lengths[c]*sizeof(float));
209 rev->allpassL[c].bufsize=r*allpass_lengths[c];
210 rev->allpassL[c].feedback = 0.5f;
213 revmodel_setwet(rev, initialwet);
214 revmodel_setroomsize(rev, initialroom);
215 revmodel_setdry(rev, initialdry);
216 revmodel_setdamp(rev, initialdamp);
217 revmodel_setwidth(rev, initialwidth);
218 revmodel_setmode(rev, initialmode);
223 struct revmodel left, right;
226 static void reverb_free(void *data)
228 struct reverb_data *rev = (struct reverb_data*)data;
231 for (i = 0; i < numcombs; i++) {
232 free(rev->left.bufcomb[i]);
233 free(rev->right.bufcomb[i]);
236 for (i = 0; i < numallpasses; i++) {
237 free(rev->left.bufallpass[i]);
238 free(rev->right.bufallpass[i]);
243 static void reverb_process(void *data, struct dspfilter_output *output,
244 const struct dspfilter_input *input)
248 struct reverb_data *rev = (struct reverb_data*)data;
250 output->samples = input->samples;
251 output->frames = input->frames;
252 out = output->samples;
254 for (i = 0; i < input->frames; i++, out += 2)
256 float in[2] = { out[0], out[1] };
258 out[0] = revmodel_process(&rev->left, in[0]);
259 out[1] = revmodel_process(&rev->right, in[1]);
263 static void *reverb_init(const struct dspfilter_info *info,
264 const struct dspfilter_config *config, void *userdata)
266 float drytime, wettime, damping, roomwidth, roomsize;
267 struct reverb_data *rev = (struct reverb_data*)
268 calloc(1, sizeof(*rev));
272 config->get_float(userdata, "drytime", &drytime, 0.43f);
273 config->get_float(userdata, "wettime", &wettime, 0.4f);
274 config->get_float(userdata, "damping", &damping, 0.8f);
275 config->get_float(userdata, "roomwidth", &roomwidth, 0.56f);
276 config->get_float(userdata, "roomsize", &roomsize, 0.56f);
278 revmodel_init(&rev->left,info->input_rate);
279 revmodel_init(&rev->right,info->input_rate);
281 revmodel_setdamp(&rev->left, damping);
282 revmodel_setdry(&rev->left, drytime);
283 revmodel_setwet(&rev->left, wettime);
284 revmodel_setwidth(&rev->left, roomwidth);
285 revmodel_setroomsize(&rev->left, roomsize);
287 revmodel_setdamp(&rev->right, damping);
288 revmodel_setdry(&rev->right, drytime);
289 revmodel_setwet(&rev->right, wettime);
290 revmodel_setwidth(&rev->right, roomwidth);
291 revmodel_setroomsize(&rev->right, roomsize);
296 static const struct dspfilter_implementation reverb_plug = {
301 DSPFILTER_API_VERSION,
306 #ifdef HAVE_FILTERS_BUILTIN
307 #define dspfilter_get_implementation reverb_dspfilter_get_implementation
310 const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
315 #undef dspfilter_get_implementation