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 /*
25  * This envelope follower will track the input signal to extract an amplitude
26  * envelope from it. It will track the rectified signal.
27  */
28 
29 #include <math.h>
30 
31 #include "bristol.h"
32 #include "follower.h"
33 
34 #define OPNAME "Envelope Follower"
35 #define OPDESCRIPTION "Mono envelope follower"
36 #define PCOUNT 1
37 #define IOCOUNT 2
38 
39 #define GAIN 0
40 
41 #define FOLLOWER_LIN_IND 0
42 #define FOLLOWER_LOUT_IND 1
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 	return(0);
57 }
58 
59 /*
60  * This is called by the frontend when a parameter is changed.
61 static int param(param, value)
62  */
param(bristolOP * operator,bristolOPParams * param,unsigned char index,float value)63 static int param(bristolOP *operator, bristolOPParams *param,
64 	unsigned char index, float value)
65 {
66 #ifdef DEBUG
67 	printf("checkParams(%f)\n", value);
68 #endif
69 
70 	param->param[index].float_val = value;
71 
72 	if (index == 0)
73 	{
74 		int offset = (value * (CONTROLLER_RANGE - 1)) + 1;
75 		/*
76 		 * This will be used to control the tracking rate. Attack should be
77 		 * quite a lot faster than decay.
78 		 */
79 		param->param[1].float_val = gainTable[offset].rate;
80 		param->param[2].float_val = 1/(gainTable[offset].rate * 4);
81 	}
82 	return(0);
83 }
84 
85 /*
86  * Reset any local memory information.
87  */
reset(bristolOP * operator,bristolOPParams * param)88 static int reset(bristolOP *operator, bristolOPParams *param)
89 {
90 #ifdef BRISTOL_DBG
91 	printf("reset(%x)\n", operator);
92 #endif
93 
94 	param->param[0].float_val = 0;
95 	return(0);
96 }
97 
operate(bristolOP * operator,bristolVoice * voice,bristolOPParams * param,void * lcl)98 static int operate(bristolOP *operator,
99 	bristolVoice *voice,
100 	bristolOPParams *param,
101 	void *lcl)
102 {
103 	bristolFOLLOWER *specs;
104 	register float *source, *dest, envelope, signal, attack, decay;
105 	register int count, i;
106 
107 	specs = (bristolFOLLOWER *) operator->specs;
108 
109 	count = specs->spec.io[FOLLOWER_LOUT_IND].samplecount;
110 	source = specs->spec.io[FOLLOWER_LIN_IND].buf;
111 	dest = specs->spec.io[FOLLOWER_LOUT_IND].buf;
112 
113 	envelope = ((bristolFOLLOWERlocal *) lcl)->envelope;
114 
115 	attack = param->param[1].float_val;
116 	decay = param->param[2].float_val;
117 
118 #ifdef DEBUG
119 	printf("follower()\n");
120 #endif
121 
122 	/*
123 	 * This should be something like a VU meter, and a root mean square with a
124 	 * gentle average function might fit the bill but could be quite intensive.
125 	 * Alternatively a rectifier and smoother would also work, but the single
126 	 * available parameter would really have to be the smoothing rate rather
127 	 * than overall gain - not an issue as the typical source would be the input
128 	 * signal that will already have gone through a preamp.
129 	 */
130 	for (i = 0; i < count; i++) {
131 		if ((signal = *source++) < 0)
132 			signal = -signal;
133 
134 		if (signal > envelope)
135 			envelope *= attack;
136 		else if (signal < envelope)
137 			envelope *= decay;
138 
139 		*dest++ = envelope;
140 	}
141 
142 	((bristolFOLLOWERlocal *) lcl)->envelope = envelope;
143 	return(0);
144 }
145 
146 /*
147  * Setup any variables in our OP structure, in our IO structures, and malloc
148  * any memory we need.
149  */
150 bristolOP *
followerinit(bristolOP ** operator,int index,int samplerate,int samplecount)151 followerinit(bristolOP **operator, int index, int samplerate, int samplecount)
152 {
153 	bristolFOLLOWER *specs;
154 
155 	*operator = bristolOPinit(operator, index, samplecount);
156 
157 #ifdef BRISTOL_DBG
158 	printf("followerinit(%x(%x), %i, %i, %i)\n",
159 		operator, *operator, index, samplerate, samplecount);
160 #endif
161 
162 	/*
163 	 * Then the local parameters specific to this operator. These will be
164 	 * the same for each operator, but must be inited in the local code.
165 	 */
166 	(*operator)->operate = operate;
167 	(*operator)->destroy = destroy;
168 	(*operator)->reset = reset;
169 	(*operator)->param = param;
170 	(*operator)->flags |= BRISTOL_FX_STEREO;
171 
172 	specs = (bristolFOLLOWER *) bristolmalloc0(sizeof(bristolFOLLOWER));
173 	(*operator)->specs = (bristolOPSpec *) specs;
174 	(*operator)->size = sizeof(bristolFOLLOWER);
175 
176 	/*
177 	 * These are specific to this operator, and will need to be altered for
178 	 * each operator.
179 	 */
180 	specs->spec.opname = OPNAME;
181 	specs->spec.description = OPDESCRIPTION;
182 	specs->spec.pcount = PCOUNT;
183 	specs->spec.iocount = IOCOUNT;
184 	specs->spec.localsize = sizeof(bristolFOLLOWERlocal);
185 
186 	/*
187 	 * Now fill in the specs for this operator.
188 	 */
189 	specs->spec.param[0].pname = "rate";
190 	specs->spec.param[0].description= "follower envelope attack and decay rate";
191 	specs->spec.param[0].type = BRISTOL_FLOAT;
192 	specs->spec.param[0].low = 0;
193 	specs->spec.param[0].high = 1;
194 	specs->spec.param[0].flags = BRISTOL_ROTARY|BRISTOL_SLIDER;
195 
196 	/*
197 	 * Now fill in the IO specs.
198 	 */
199 	specs->spec.io[0].ioname = "input buffer";
200 	specs->spec.io[0].description = "input signal";
201 	specs->spec.io[0].samplerate = samplerate;
202 	specs->spec.io[0].samplecount = samplecount;
203 	specs->spec.io[0].flags = BRISTOL_AC|BRISTOL_INPUT;
204 
205 	specs->spec.io[1].ioname = "output buffer";
206 	specs->spec.io[1].description = "output signal";
207 	specs->spec.io[1].samplerate = samplerate;
208 	specs->spec.io[1].samplecount = samplecount;
209 	specs->spec.io[1].flags = BRISTOL_AC|BRISTOL_INPUT;
210 
211 	return(*operator);
212 }
213 
214