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