1
2 /*
3 * Diverse Bristol audio routines.
4 * Copyright (c) by Nick Copeland <nickycopeland@hotmail.com> 1996,2012
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 /*#define DEBUG */
23
24 #include <math.h>
25
26 #include "bristol.h"
27 #include "aksreverb.h"
28
29 #define DELAY 0
30 #define FEEDBACK 1
31 #define CROSSOVER 2
32 #define WETDRY 3
33 #define LINE1 4
34
35 #define OPNAME "AKS Reverb"
36 #define OPDESCRIPTION "Stereo input/output reverb"
37 #define PCOUNT 6
38 #define IOCOUNT 3
39
40 #define AKSREVERB_IN_IND 0
41 #define AKSREVERB_MOD_IND 1
42 #define AKSREVERB_OUT_IND 2
43
44 /*
45 * Reset any local memory information.
46 */
destroy(bristolOP * operator)47 static int destroy(bristolOP *operator)
48 {
49 #ifdef BRISTOL_DBG
50 printf("destroy(%x)\n", operator);
51 #endif
52
53 bristolfree(operator->specs);
54
55 cleanup(operator);
56
57 return(0);
58 }
59
60 /*
61 * This is called by the frontend when a parameter is changed.
62 static int param(param, value)
63 */
param(bristolOP * operator,bristolOPParams * param,unsigned char index,float value)64 static int param(bristolOP *operator, bristolOPParams *param,
65 unsigned char index, float value)
66 {
67 #ifdef DEBUG
68 printf("checkParams(%f)\n", value);
69 #endif
70
71 param->param[index].float_val = value;
72
73 return(0);
74 }
75
76 /*
77 * Reset any local memory information.
78 */
reset(bristolOP * operator,bristolOPParams * param)79 static int reset(bristolOP *operator, bristolOPParams *param)
80 {
81 #ifdef BRISTOL_DBG
82 printf("reset(%x)\n", operator);
83 #endif
84
85 if (param->param[0].mem)
86 bristolfree(param->param[0].mem);
87 if (param->param[1].mem)
88 bristolfree(param->param[1].mem);
89
90 param->param[0].mem = bristolmalloc0(sizeof(float) * HISTSIZE);
91 param->param[1].mem = bristolmalloc0(sizeof(float) * HISTSIZE);
92
93 param->param[0].float_val = 0.2;
94 param->param[1].float_val = 0.3;
95 param->param[2].float_val = 0.3;
96 param->param[3].float_val = 0.3;
97 param->param[4].float_val = 1.0;
98 param->param[5].float_val = 1.0;
99
100 return(0);
101 }
102
103 /*
104 * This is going to be a mono reverb with two delay lines. The delay lines
105 * will be sized to approximate the 25 and 28 ms delay lines from the original
106 * although we should allow it to go outside of that range. Should consider
107 * implementing a high pass filter to try and cut down on booming from the low
108 * end.
109 */
operate(bristolOP * operator,bristolVoice * voice,bristolOPParams * param,void * lcl)110 static int operate(bristolOP *operator,
111 bristolVoice *voice,
112 bristolOPParams *param,
113 void *lcl)
114 {
115 bristolAKSREVERB *specs;
116 bristolAKSREVERBlocal *local = (bristolAKSREVERBlocal *) lcl;
117 register float *source, *dest, *lhistory, *rhistory;
118 register int count, i, histin1, histin2, delay1, delay2;
119 register float crossover, feedback, line1, *mod, fb, co;
120
121 specs = (bristolAKSREVERB *) operator->specs;
122
123 count = specs->spec.io[AKSREVERB_OUT_IND].samplecount;
124 source = specs->spec.io[AKSREVERB_IN_IND].buf;
125 dest = specs->spec.io[AKSREVERB_OUT_IND].buf;
126 mod = specs->spec.io[AKSREVERB_MOD_IND].buf;
127
128 /*
129 * operational parameters. Speed should be a function of depth, ie, if
130 * depth changes, speed should be adjusted to maintain scan rate.
131 *
132 * Let speed be 10 seconds require to reach the given depth. That can be
133 * calculated as 441000 samples, so we divide speed by depth * 44100;
134 depth = param->param[DEPTH].float_val * 1024;
135 speed = param->param[SPEED].float_val * 0.0002 * depth;
136 */
137 /*
138 * Let scan be ten seconds to reach gain
139 gain = param->param[GAIN].float_val * 1.5;
140 scan = param->param[SCAN].float_val * 0.0005 * gain;
141 */
142 delay1 = param->param[DELAY].float_val * HISTSIZE;
143 delay2 = delay1 * 25 / 28;
144 fb = 0.5 - param->param[FEEDBACK].float_val;
145 co = 0.5 - param->param[CROSSOVER].float_val;
146 line1 = param->param[LINE1].float_val;
147
148 lhistory = param->param[0].mem;
149 rhistory = param->param[1].mem;
150
151 #ifdef DEBUG
152 printf("reverb()\n");
153 #endif
154
155 histin1 = local->histin1;
156 histin2 = local->histin2;
157
158 for (i = 0; i < count; i++) {
159 feedback = fb * *mod;
160 crossover = co * *mod++;
161 /*
162 * Save our current signal into the history buffers. This should
163 * include a component of feedback and crossover for echo/reverb effect.
164 * It also needs to go through a HPF.
165 */
166 lhistory[histin1] =
167 lhistory[histin1] * feedback
168 + rhistory[histin2] * crossover
169 + *source;
170 rhistory[histin2] =
171 rhistory[histin2] * feedback
172 + lhistory[histin1] * crossover
173 + *source++;
174
175 /*
176 * for testing just make the output be the input with delay.
177 */
178 if (++histin1 >= delay1)
179 histin1 = 0;
180 if (++histin2 >= delay2)
181 histin2 = 0;
182
183 *dest++ = (lhistory[histin1] + rhistory[histin2]) * line1;
184 }
185
186 local->histin1 = histin1;
187 local->histin2 = histin2;
188
189 return(0);
190 }
191
192 /*
193 * Setup any variables in our OP structure, in our IO structures, and malloc
194 * any memory we need.
195 */
196 bristolOP *
aksreverbinit(bristolOP ** operator,int index,int samplerate,int samplecount)197 aksreverbinit(bristolOP **operator, int index, int samplerate, int samplecount)
198 {
199 bristolAKSREVERB *specs;
200
201 *operator = bristolOPinit(operator, index, samplecount);
202
203 #ifdef BRISTOL_DBG
204 printf("reverbinit(%x(%x), %i, %i, %i)\n",
205 operator, *operator, index, samplerate, samplecount);
206 #endif
207
208 /*
209 * Then the local parameters specific to this operator. These will be
210 * the same for each operator, but must be inited in the local code.
211 */
212 (*operator)->operate = operate;
213 (*operator)->destroy = destroy;
214 (*operator)->reset = reset;
215 (*operator)->param = param;
216 (*operator)->flags |= BRISTOL_FX_STEREO;
217
218 specs = (bristolAKSREVERB *) bristolmalloc0(sizeof(bristolAKSREVERB));
219 (*operator)->specs = (bristolOPSpec *) specs;
220 (*operator)->size = sizeof(bristolAKSREVERB);
221
222 /*
223 * These are specific to this operator, and will need to be altered for
224 * each operator.
225 */
226 specs->spec.opname = OPNAME;
227 specs->spec.description = OPDESCRIPTION;
228 specs->spec.pcount = PCOUNT;
229 specs->spec.iocount = IOCOUNT;
230 specs->spec.localsize = sizeof(bristolAKSREVERBlocal);
231
232 /*
233 * Now fill in the specs for this operator.
234 */
235 specs->spec.param[0].pname = "delay";
236 specs->spec.param[0].description= "reverb delay line depth";
237 specs->spec.param[0].type = BRISTOL_FLOAT;
238 specs->spec.param[0].low = 0;
239 specs->spec.param[0].high = 1;
240 specs->spec.param[0].flags = BRISTOL_ROTARY|BRISTOL_SLIDER;
241
242 specs->spec.param[1].pname = "feedback";
243 specs->spec.param[1].description = "depth of mono feedback";
244 specs->spec.param[1].type = BRISTOL_FLOAT;
245 specs->spec.param[1].low = 0;
246 specs->spec.param[1].high = 1;
247 specs->spec.param[1].flags = BRISTOL_ROTARY|BRISTOL_SLIDER;
248
249 specs->spec.param[2].pname = "crossfade";
250 specs->spec.param[2].description = "depth of stereo feedback signal";
251 specs->spec.param[2].type = BRISTOL_FLOAT;
252 specs->spec.param[2].low = 0;
253 specs->spec.param[2].high = 1;
254 specs->spec.param[2].flags = BRISTOL_ROTARY|BRISTOL_SLIDER;
255
256 specs->spec.param[3].pname = "depth";
257 specs->spec.param[3].description = "wet/dry mix";
258 specs->spec.param[3].type = BRISTOL_FLOAT;
259 specs->spec.param[3].low = 0;
260 specs->spec.param[3].high = 1;
261 specs->spec.param[3].flags = BRISTOL_ROTARY|BRISTOL_SLIDER;
262
263 specs->spec.param[4].pname = "line1 gain";
264 specs->spec.param[4].description = "mix";
265 specs->spec.param[4].type = BRISTOL_FLOAT;
266 specs->spec.param[4].low = 0;
267 specs->spec.param[4].high = 1;
268 specs->spec.param[4].flags = BRISTOL_ROTARY|BRISTOL_SLIDER;
269
270 /*
271 * Now fill in the IO specs.
272 */
273 specs->spec.io[0].ioname = "input buffer";
274 specs->spec.io[0].description = "input signal";
275 specs->spec.io[0].samplerate = samplerate;
276 specs->spec.io[0].samplecount = samplecount;
277 specs->spec.io[0].flags = BRISTOL_AC|BRISTOL_INPUT;
278
279 specs->spec.io[1].ioname = "output buffer";
280 specs->spec.io[1].description = "input signal";
281 specs->spec.io[1].samplerate = samplerate;
282 specs->spec.io[1].samplecount = samplecount;
283 specs->spec.io[1].flags = BRISTOL_AC|BRISTOL_INPUT;
284
285 specs->spec.io[2].ioname = "mod buffer";
286 specs->spec.io[2].description = "input signal";
287 specs->spec.io[2].samplerate = samplerate;
288 specs->spec.io[2].samplecount = samplecount;
289 specs->spec.io[2].flags = BRISTOL_AC|BRISTOL_INPUT;
290
291 return(*operator);
292 }
293
294