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