1 /*
2   rakarrack - a guitar effects software
3 
4  Opticaltrem.C  -  Optical tremolo effect
5 
6   Copyright (C) 2008-2010 Ryan Billing
7   Author: Josep Andreu
8 
9 
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of version 2 of the GNU General Public License
12  as published by the Free Software Foundation.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  GNU General Public License (version 2) for more details.
18 
19  You should have received a copy of the GNU General Public License
20  (version2)  along with this program; if not, write to the Free Software
21  Foundation,
22  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
23 
24 */
25 
26 #include <math.h>
27 #include "Opticaltrem.h"
28 
Opticaltrem(float * efxoutl_,float * efxoutr_,double sample_rate)29 Opticaltrem::Opticaltrem (float * efxoutl_, float * efxoutr_, double sample_rate)
30 {
31     efxoutl = efxoutl_;
32     efxoutr = efxoutr_;
33     cSAMPLE_RATE = 1.0f/sample_rate;
34 
35     R1 = 2700.0f;	   //tremolo circuit series resistance
36     Ra = 1000000.0f;  //Cds cell dark resistance.
37     Ra = logf(Ra);		//this is done for clarity
38     Rb = 300.0f;         //Cds cell full illumination
39     Rp = 100000.0f;      //Resistor in parallel with Cds cell
40     b = exp(Ra/logf(Rb)) - CNST_E;
41     dTC = 0.03f;
42     dRCl = dTC;
43     dRCr = dTC;   //Right & left channel dynamic time contsants
44     minTC = logf(0.005f/dTC);
45     alphal = 1.0f - cSAMPLE_RATE/(dRCl + cSAMPLE_RATE);
46     alphar = alphal;
47     lstep = 0.0f;
48     rstep = 0.0f;
49     Pdepth = 127;
50     Ppanning = 64;
51     lpanning = 1.0f;
52     rpanning = 1.0f;
53     fdepth = 1.0f;
54     Pinvert = 0;
55     oldgl = 0.0f;
56     oldgr = 0.0f;
57     gl = 0.0f;
58     gr = 0.0f;
59 
60     lfo = new EffectLFO(sample_rate);
61     PERIOD = 256;//best guess until better info comes
62 
63 }
64 
~Opticaltrem()65 Opticaltrem::~Opticaltrem ()
66 {
67 	delete lfo;
68 }
69 
70 
71 void
cleanup()72 Opticaltrem::cleanup ()
73 {
74 
75 
76 };
77 
78 void
out(float * smpsl,float * smpsr,uint32_t period)79 Opticaltrem::out (float *smpsl, float *smpsr, uint32_t period)
80 {
81 
82     unsigned int i;
83     float lfol, lfor, xl, xr, fxl, fxr;
84     float rdiff, ldiff;
85     lfo->effectlfoout (&lfol, &lfor);
86 
87     if(Pinvert) {
88     lfol = lfol*fdepth;
89     lfor = lfor*fdepth;
90     } else {
91     lfor = 1.0f - lfor*fdepth;
92     lfol = 1.0f - lfol*fdepth;
93     }
94 
95     if (lfol > 1.0f)
96         lfol = 1.0f;
97     else if (lfol < 0.0f)
98         lfol = 0.0f;
99     if (lfor > 1.0f)
100         lfor = 1.0f;
101     else if (lfor < 0.0f)
102         lfor = 0.0f;
103 
104     lfor = powf(lfor, 1.9f);
105     lfol = powf(lfol, 1.9f);  //emulate lamp turn on/off characteristic
106 
107     //lfo interpolation
108     rdiff = (lfor - oldgr)/(float)period;
109     ldiff = (lfol - oldgl)/(float)period;
110     gr = lfor;
111     gl = lfol;
112     oldgr = lfor;
113     oldgl = lfol;
114 
115     for (i = 0; i < period; i++) {
116         //Left Cds
117         stepl = gl*(1.0f - alphal) + alphal*oldstepl;
118         oldstepl = stepl;
119         dRCl = dTC*f_exp(stepl*minTC);
120         alphal = 1.0f - cSAMPLE_RATE/(dRCl + cSAMPLE_RATE);
121         xl = CNST_E + stepl*b;
122         fxl = f_exp(Ra/logf(xl));
123         if(Pinvert) {
124         fxl = fxl*Rp/(fxl + Rp); //Parallel resistance
125         fxl = fxl/(fxl + R1);
126         }
127         else fxl = R1/(fxl + R1);
128 
129         //Right Cds
130         stepr = gr*(1.0f - alphar) + alphar*oldstepr;
131         oldstepr = stepr;
132         dRCr = dTC*f_exp(stepr*minTC);
133         alphar = 1.0f - cSAMPLE_RATE/(dRCr + cSAMPLE_RATE);
134         xr = CNST_E + stepr*b;
135         fxr = f_exp(Ra/logf(xr));
136         if(Pinvert) {
137         fxr = fxr*Rp/(fxr + Rp); //Parallel resistance
138         fxr = fxr/(fxr + R1);
139         }
140         else fxr = R1/(fxr + R1);
141 
142         //Modulate input signal
143         efxoutl[i] = lpanning*fxl*smpsl[i];
144         efxoutr[i] = rpanning*fxr*smpsr[i];
145 
146         gl += ldiff;
147         gr += rdiff;  //linear interpolation of LFO
148 
149     };
150 
151 
152 };
153 
154 void
setpanning(int value)155 Opticaltrem::setpanning (int value)
156 {
157     Ppanning = value;
158     rpanning = ((float)Ppanning) / 64.0f;
159     lpanning = 2.0f - rpanning;
160     lpanning = 10.0f * powf(lpanning, 4);
161     rpanning = 10.0f * powf(rpanning, 4);
162     lpanning = 1.0f - 1.0f/(lpanning + 1.0f);
163     rpanning = 1.0f - 1.0f/(rpanning + 1.0f);
164 
165     if(Pinvert) {
166     rpanning *= 2.0f;
167     lpanning *= 2.0f;
168     } else {
169     rpanning *= 1.3f;
170     lpanning *= 1.3f;
171     }
172 
173 };
174 
175 void
setpreset(int npreset)176 Opticaltrem::setpreset (int npreset)
177 {
178     const int PRESET_SIZE = 7;
179     const int NUM_PRESETS = 6;
180     int pdata[PRESET_SIZE];
181     int presets[NUM_PRESETS][PRESET_SIZE] = {
182         //Fast
183         {127, 260, 10, 0, 64, 64, 0},
184         //trem2
185         {45, 140, 10, 0, 64, 64, 0},
186         //hard pan
187         {127, 120, 10, 5, 0, 64, 0},
188         //soft pan
189         {45, 240, 10, 1, 16, 64, 0},
190         //ramp down
191         {65, 200, 0, 3, 32, 64, 0},
192         //hard ramp
193         {127, 480, 0, 3, 32, 64, 0}
194 
195     };
196 
197     if(npreset>NUM_PRESETS-1) {
198         Fpre->ReadPreset(44,npreset-NUM_PRESETS+1, pdata);
199         for (int n = 0; n < PRESET_SIZE; n++)
200             changepar (n, pdata[n]);
201     } else {
202         for (int n = 0; n < PRESET_SIZE; n++)
203             changepar (n, presets[npreset][n]);
204     }
205 
206 };
207 
208 void
changepar(int npar,int value)209 Opticaltrem::changepar (int npar, int value)
210 {
211 
212     switch (npar) {
213 
214     case 0:
215         Pdepth = value;
216         fdepth = 0.5f + ((float) Pdepth)/254.0f;
217         break;
218     case 1:
219         lfo->Pfreq = value;
220         lfo->updateparams (PERIOD);
221         break;
222     case 2:
223         lfo->Prandomness = value;
224         lfo->updateparams (PERIOD);
225         break;
226     case 3:
227         lfo->PLFOtype = value;
228         lfo->updateparams (PERIOD);
229         break;
230     case 4:
231         lfo->Pstereo = value;
232         lfo->updateparams (PERIOD);
233         break;
234     case 5: // pan
235         Ppanning = value;
236         setpanning(value);
237         break;
238     case 6: //Invert
239         Pinvert = value;
240         if(Pinvert) {
241           R1 = 68000.0f;   //tremolo circuit series resistance
242           Ra = 500000.0f;  //Cds cell dark resistance.
243         } else {
244           R1 = 2700.0f;	   //tremolo circuit series resistance
245           Ra = 1000000.0f;  //Cds cell dark resistance.
246         }
247         setpanning(Ppanning);
248 
249         Ra = logf(Ra);		//this is done for clarity
250         Rb = 300.0f;         //Cds cell full illumination
251         b = exp(Ra/logf(Rb)) - CNST_E;
252            break;
253    }
254 
255 };
256 
257 int
getpar(int npar)258 Opticaltrem::getpar (int npar)
259 {
260 
261     switch (npar)
262 
263     {
264     case 0:
265         return (Pdepth);
266         break;
267     case 1:
268         return (lfo->Pfreq);
269         break;
270     case 2:
271         return (lfo->Prandomness);
272         break;
273     case 3:
274         return (lfo->PLFOtype);
275         break;
276     case 4:
277         return (lfo->Pstereo);
278         break;
279     case 5:
280         return (Ppanning); //pan
281         break;
282     case 6:
283         return (Pinvert); //pan
284         break;
285 
286     }
287 
288     return (0);
289 
290 };
291 
292 
293