1 /* Copyright  (C) 2010-2020 The RetroArch team
2  *
3  * ---------------------------------------------------------------------------------------
4  * The following license statement only applies to this file (reverb.c).
5  * ---------------------------------------------------------------------------------------
6  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14  *
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.
21  */
22 
23 #include <math.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include <retro_inline.h>
28 #include <libretro_dspfilter.h>
29 
30 struct comb
31 {
32    float *buffer;
33    unsigned bufsize;
34    unsigned bufidx;
35 
36    float feedback;
37    float filterstore;
38    float damp1, damp2;
39 };
40 
41 struct allpass
42 {
43    float *buffer;
44    float feedback;
45    unsigned bufsize;
46    unsigned bufidx;
47 };
48 
comb_process(struct comb * c,float input)49 static INLINE float comb_process(struct comb *c, float input)
50 {
51    float output         = c->buffer[c->bufidx];
52    c->filterstore       = (output * c->damp2) + (c->filterstore * c->damp1);
53 
54    c->buffer[c->bufidx] = input + (c->filterstore * c->feedback);
55 
56    c->bufidx++;
57    if (c->bufidx >= c->bufsize)
58       c->bufidx = 0;
59 
60    return output;
61 }
62 
allpass_process(struct allpass * a,float input)63 static INLINE float allpass_process(struct allpass *a, float input)
64 {
65    float bufout         = a->buffer[a->bufidx];
66    float output         = -input + bufout;
67    a->buffer[a->bufidx] = input + bufout * a->feedback;
68 
69    a->bufidx++;
70    if (a->bufidx >= a->bufsize)
71       a->bufidx = 0;
72 
73    return output;
74 }
75 
76 #define numcombs 8
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;
92 
93 struct revmodel
94 {
95    struct comb combL[numcombs];
96    struct allpass allpassL[numallpasses];
97 
98    float *bufcomb[numcombs];
99    float *bufallpass[numallpasses];
100 
101    float gain;
102    float roomsize, roomsize1;
103    float damp, damp1;
104    float wet, wet1, wet2;
105    float dry;
106    float width;
107    float mode;
108 };
109 
revmodel_process(struct revmodel * rev,float in)110 static float revmodel_process(struct revmodel *rev, float in)
111 {
112    int i;
113    float mono_out = 0.0f;
114    float mono_in  = in;
115    float input    = mono_in * rev->gain;
116 
117    for (i = 0; i < numcombs; i++)
118       mono_out += comb_process(&rev->combL[i], input);
119 
120    for (i = 0; i < numallpasses; i++)
121       mono_out = allpass_process(&rev->allpassL[i], mono_out);
122 
123    return mono_in * rev->dry + mono_out * rev->wet1;
124 }
125 
revmodel_update(struct revmodel * rev)126 static void revmodel_update(struct revmodel *rev)
127 {
128    int i;
129    rev->wet1 = rev->wet * (rev->width / 2.0f + 0.5f);
130 
131    if (rev->mode >= freezemode)
132    {
133       rev->roomsize1 = 1.0f;
134       rev->damp1 = 0.0f;
135       rev->gain = muted;
136    }
137    else
138    {
139       rev->roomsize1 = rev->roomsize;
140       rev->damp1 = rev->damp;
141       rev->gain = fixedgain;
142    }
143 
144    for (i = 0; i < numcombs; i++)
145    {
146       rev->combL[i].feedback = rev->roomsize1;
147       rev->combL[i].damp1 = rev->damp1;
148       rev->combL[i].damp2 = 1.0f - rev->damp1;
149    }
150 }
151 
revmodel_setroomsize(struct revmodel * rev,float value)152 static void revmodel_setroomsize(struct revmodel *rev, float value)
153 {
154    rev->roomsize = value * scaleroom + offsetroom;
155    revmodel_update(rev);
156 }
157 
revmodel_setdamp(struct revmodel * rev,float value)158 static void revmodel_setdamp(struct revmodel *rev, float value)
159 {
160    rev->damp = value * scaledamp;
161    revmodel_update(rev);
162 }
163 
revmodel_setwet(struct revmodel * rev,float value)164 static void revmodel_setwet(struct revmodel *rev, float value)
165 {
166    rev->wet = value * scalewet;
167    revmodel_update(rev);
168 }
169 
revmodel_setdry(struct revmodel * rev,float value)170 static void revmodel_setdry(struct revmodel *rev, float value)
171 {
172    rev->dry = value * scaledry;
173    revmodel_update(rev);
174 }
175 
revmodel_setwidth(struct revmodel * rev,float value)176 static void revmodel_setwidth(struct revmodel *rev, float value)
177 {
178    rev->width = value;
179    revmodel_update(rev);
180 }
181 
revmodel_setmode(struct revmodel * rev,float value)182 static void revmodel_setmode(struct revmodel *rev, float value)
183 {
184    rev->mode = value;
185    revmodel_update(rev);
186 }
187 
revmodel_init(struct revmodel * rev,int srate)188 static void revmodel_init(struct revmodel *rev,int srate)
189 {
190 
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);
194   unsigned c;
195 
196    for (c = 0; c < numcombs; ++c)
197    {
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];
202   }
203 
204    for (c = 0; c < numallpasses; ++c)
205    {
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;
211   }
212 
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);
219 }
220 
221 struct reverb_data
222 {
223    struct revmodel left, right;
224 };
225 
reverb_free(void * data)226 static void reverb_free(void *data)
227 {
228    struct reverb_data *rev = (struct reverb_data*)data;
229    unsigned i;
230 
231    for (i = 0; i < numcombs; i++) {
232    free(rev->left.bufcomb[i]);
233    free(rev->right.bufcomb[i]);
234    }
235 
236    for (i = 0; i < numallpasses; i++) {
237    free(rev->left.bufallpass[i]);
238    free(rev->right.bufallpass[i]);
239    }
240    free(data);
241 }
242 
reverb_process(void * data,struct dspfilter_output * output,const struct dspfilter_input * input)243 static void reverb_process(void *data, struct dspfilter_output *output,
244       const struct dspfilter_input *input)
245 {
246    unsigned i;
247    float *out;
248    struct reverb_data *rev = (struct reverb_data*)data;
249 
250    output->samples         = input->samples;
251    output->frames          = input->frames;
252    out                     = output->samples;
253 
254    for (i = 0; i < input->frames; i++, out += 2)
255    {
256       float in[2] = { out[0], out[1] };
257 
258       out[0] = revmodel_process(&rev->left, in[0]);
259       out[1] = revmodel_process(&rev->right, in[1]);
260    }
261 }
262 
reverb_init(const struct dspfilter_info * info,const struct dspfilter_config * config,void * userdata)263 static void *reverb_init(const struct dspfilter_info *info,
264       const struct dspfilter_config *config, void *userdata)
265 {
266    float drytime, wettime, damping, roomwidth, roomsize;
267    struct reverb_data *rev = (struct reverb_data*)
268       calloc(1, sizeof(*rev));
269    if (!rev)
270       return NULL;
271 
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);
277 
278    revmodel_init(&rev->left,info->input_rate);
279    revmodel_init(&rev->right,info->input_rate);
280 
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);
286 
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);
292 
293    return rev;
294 }
295 
296 static const struct dspfilter_implementation reverb_plug = {
297    reverb_init,
298    reverb_process,
299    reverb_free,
300 
301    DSPFILTER_API_VERSION,
302    "Reverb",
303    "reverb",
304 };
305 
306 #ifdef HAVE_FILTERS_BUILTIN
307 #define dspfilter_get_implementation reverb_dspfilter_get_implementation
308 #endif
309 
dspfilter_get_implementation(dspfilter_simd_mask_t mask)310 const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
311 {
312    (void)mask;
313    return &reverb_plug;
314 }
315 
316 #undef dspfilter_get_implementation
317