1 /*
2   ZynAddSubFX - a software synthesizer
3 
4   Distorsion.cpp - Distorsion effect
5   Copyright (C) 2002-2005 Nasca Octavian Paul
6   Author: Nasca Octavian Paul
7 
8   This program is free software; you can redistribute it and/or
9   modify it under the terms of the GNU General Public License
10   as published by the Free Software Foundation; either version 2
11   of the License, or (at your option) any later version.
12 */
13 
14 #include "Distorsion.h"
15 #include "../DSP/AnalogFilter.h"
16 #include "../Misc/WaveShapeSmps.h"
17 #include "../Misc/Allocator.h"
18 #include <cmath>
19 #include <rtosc/ports.h>
20 #include <rtosc/port-sugar.h>
21 
22 namespace zyn {
23 
24 #define rObject Distorsion
25 #define rBegin [](const char *msg, rtosc::RtData &d) {
26 #define rEnd }
27 
28 rtosc::Ports Distorsion::ports = {
29     {"preset::i", rProp(parameter)
30                   rOptions(Overdrive 1, Overdrive 2, A. Exciter 1, A. Exciter 2, Guitar Amp,
31                     Quantisize)
32                   rDoc("Instrument Presets"), 0,
33                   rBegin;
34                   rObject *o = (rObject*)d.obj;
35                   if(rtosc_narguments(msg))
36                       o->setpreset(rtosc_argument(msg, 0).i);
37                   else
38                       d.reply(d.loc, "i", o->Ppreset);
39                   rEnd},
40     rEffParVol(rDefault(127), rPresetsAt(2, 64, 64)),
41     rEffParPan(),
42     rEffPar(Plrcross, 2, rShort("l/r"), rDefault(35), "Left/Right Crossover"),
43     rEffPar(Pdrive,   3, rShort("drive"),
44             rLinear(0, 127), rPresets(56, 29, 75, 85, 63, 88),
45             "Input amplification"),
46     rEffPar(Plevel,   4, rShort("output"), rPresets(70, 75, 80, 62, 75, 75),
47             "Output amplification"),
48     rEffParOpt(Ptype,    5, rShort("type"),
49             rOptions(Arctangent, Asymmetric, Pow, Sine, Quantisize,
50                      Zigzag, Limiter, Upper Limiter, Lower Limiter,
51                      Inverse Limiter, Clip, Asym2, Pow2, Sigmoid, Tanh,
52                      Cubic, Square), rLinear(0,127),
53             rPresets(Arctangent, Asymmetric, Zigzag,
54                      Asymmetric, Pow, Quantisize),
55             "Distortion Shape"),
56     rEffParTF(Pnegate, 6, rShort("neg"), rDefault(false), "Negate Signal"),
57     rEffPar(Plpf, 7, rShort("lpf"),
58             rPreset(0, 96), rPreset(4, 55), rDefault(127), "Low Pass Cutoff"),
59     rEffPar(Phpf, 8, rShort("hpf"),
60             rPreset(2, 105), rPreset(3, 118), rDefault(0), "High Pass Cutoff"),
61     rEffParTF(Pstereo, 9, rShort("stereo"),
62               rPresets(false, false, true, true, false, true), "Stereo"),
63     rEffParTF(Pprefiltering, 10, rShort("p.filt"), rDefault(false),
64               "Filtering before/after non-linearity"),
65     rEffPar(Pfuncpar,   11, rShort("shape"), rDefault(32),
66             rLinear(0, 127), "Shape of the wave shaping function"),
67     rEffPar(Poffset,   12, rShort("offset"), rDefault(64),
68             rLinear(0, 127), "Input DC Offset"),
69     {"waveform:", 0, 0, [](const char *, rtosc::RtData &d)
__anon361cc80b0102() 70         {
71             Distorsion  &dd = *(Distorsion*)d.obj;
72             float        buffer[128], orig[128];
73             rtosc_arg_t  args[128];
74             char         arg_str[128+1] = {};
75 
76             for(int i=0; i<128; ++i)
77                 buffer[i] = 2*(i/128.0)-1;
78             memcpy(orig, buffer, sizeof(float_t)*128);
79 
80             waveShapeSmps(sizeof(buffer)/sizeof(buffer[0]), buffer,
81                     dd.Ptype + 1, dd.Pdrive, dd.Poffset, dd.Pfuncpar);
82 
83             for(int i=0; i<128; ++i) {
84                 arg_str[i] = 'f';
85                 args[i].f  = (dd.Pvolume * buffer[i] + (127 - dd.Pvolume) * orig[i]) / 127.0f;
86             }
87 
88             d.replyArray(d.loc, arg_str, args);
89         }},
90 };
91 #undef rBegin
92 #undef rEnd
93 #undef rObject
94 
Distorsion(EffectParams pars)95 Distorsion::Distorsion(EffectParams pars)
96     :Effect(pars),
97       Pvolume(50),
98       Pdrive(90),
99       Plevel(64),
100       Ptype(0),
101       Pnegate(0),
102       Plpf(127),
103       Phpf(0),
104       Pstereo(0),
105       Pprefiltering(0),
106       Pfuncpar(32),
107       Poffset(64)
108 {
109     lpfl = memory.alloc<AnalogFilter>(2, 22000, 1, 0, pars.srate, pars.bufsize);
110     lpfr = memory.alloc<AnalogFilter>(2, 22000, 1, 0, pars.srate, pars.bufsize);
111     hpfl = memory.alloc<AnalogFilter>(3, 20, 1, 0, pars.srate, pars.bufsize);
112     hpfr = memory.alloc<AnalogFilter>(3, 20, 1, 0, pars.srate, pars.bufsize);
113     setpreset(Ppreset);
114     cleanup();
115 }
116 
~Distorsion()117 Distorsion::~Distorsion()
118 {
119     memory.dealloc(lpfl);
120     memory.dealloc(lpfr);
121     memory.dealloc(hpfl);
122     memory.dealloc(hpfr);
123 }
124 
125 //Cleanup the effect
cleanup(void)126 void Distorsion::cleanup(void)
127 {
128     lpfl->cleanup();
129     hpfl->cleanup();
130     lpfr->cleanup();
131     hpfr->cleanup();
132 }
133 
134 
135 //Apply the filters
applyfilters(float * efxoutl,float * efxoutr)136 void Distorsion::applyfilters(float *efxoutl, float *efxoutr)
137 {
138     if(Plpf!=127) lpfl->filterout(efxoutl);
139     if(Phpf!=0) hpfl->filterout(efxoutl);
140     if(Pstereo != 0) { //stereo
141         if(Plpf!=127) lpfr->filterout(efxoutr);
142         if(Phpf!=0) hpfr->filterout(efxoutr);
143     }
144 }
145 
146 
147 //Effect output
out(const Stereo<float * > & smp)148 void Distorsion::out(const Stereo<float *> &smp)
149 {
150     float inputvol = powf(5.0f, (Pdrive - 32.0f) / 127.0f);
151     if(Pnegate)
152         inputvol *= -1.0f;
153 
154     if(Pstereo) //Stereo
155         for(int i = 0; i < buffersize; ++i) {
156             efxoutl[i] = smp.l[i] * inputvol * pangainL;
157             efxoutr[i] = smp.r[i] * inputvol * pangainR;
158         }
159     else //Mono
160         for(int i = 0; i < buffersize; ++i)
161             efxoutl[i] = (smp.l[i] * pangainL + smp.r[i] * pangainR) * inputvol;
162 
163     if(Pprefiltering)
164         applyfilters(efxoutl, efxoutr);
165 
166     waveShapeSmps(buffersize, efxoutl, Ptype + 1, Pdrive, Poffset, Pfuncpar);
167     if(Pstereo)
168         waveShapeSmps(buffersize, efxoutr, Ptype + 1, Pdrive, Poffset, Pfuncpar);
169 
170     if(!Pprefiltering)
171         applyfilters(efxoutl, efxoutr);
172 
173     if(!Pstereo)
174         memcpy(efxoutr, efxoutl, bufferbytes);
175 
176     float level = dB2rap(60.0f * Plevel / 127.0f - 40.0f);
177     for(int i = 0; i < buffersize; ++i) {
178         float lout = efxoutl[i];
179         float rout = efxoutr[i];
180         float l    = lout * (1.0f - lrcross) + rout * lrcross;
181         float r    = rout * (1.0f - lrcross) + lout * lrcross;
182         lout = l;
183         rout = r;
184 
185         efxoutl[i] = lout * 2.0f * level;
186         efxoutr[i] = rout * 2.0f * level;
187     }
188 }
189 
190 
191 //Parameter control
setvolume(unsigned char _Pvolume)192 void Distorsion::setvolume(unsigned char _Pvolume)
193 {
194     Pvolume = _Pvolume;
195 
196     if(insertion == 0) {
197         outvolume = powf(0.01f, (1.0f - Pvolume / 127.0f)) * 4.0f;
198         volume    = 1.0f;
199     }
200     else
201         volume = outvolume = Pvolume / 127.0f;
202     if(Pvolume == 0)
203         cleanup();
204 }
205 
setlpf(unsigned char _Plpf)206 void Distorsion::setlpf(unsigned char _Plpf)
207 {
208     Plpf = _Plpf;
209     float fr = expf(sqrtf(Plpf / 127.0f) * logf(25000.0f)) + 40.0f;
210     lpfl->setfreq(fr);
211     lpfr->setfreq(fr);
212 }
213 
sethpf(unsigned char _Phpf)214 void Distorsion::sethpf(unsigned char _Phpf)
215 {
216     Phpf = _Phpf;
217     float fr = expf(sqrtf(Phpf / 127.0f) * logf(25000.0f)) + 20.0f;
218     hpfl->setfreq(fr);
219     hpfr->setfreq(fr);
220 }
221 
getpresetpar(unsigned char npreset,unsigned int npar)222 unsigned char Distorsion::getpresetpar(unsigned char npreset, unsigned int npar)
223 {
224 #define	PRESET_SIZE 13
225 #define	NUM_PRESETS 6
226     static const unsigned char presets[NUM_PRESETS][PRESET_SIZE] = {
227         //Overdrive 1
228         {127, 64, 35, 56, 70, 0, 0, 96,  0,   0, 0, 32, 64},
229         //Overdrive 2
230         {127, 64, 35, 29, 75, 1, 0, 127, 0,   0, 0, 32, 64},
231         //A. Exciter 1
232         {64,  64, 35, 75, 80, 5, 0, 127, 105, 1, 0, 32, 64},
233         //A. Exciter 2
234         {64,  64, 35, 85, 62, 1, 0, 127, 118, 1, 0, 32, 64},
235         //Guitar Amp
236         {127, 64, 35, 63, 75, 2, 0, 55,  0,   0, 0, 32, 64},
237         //Quantisize
238         {127, 64, 35, 88, 75, 4, 0, 127, 0,   1, 0, 32, 64}
239     };
240     if(npreset < NUM_PRESETS && npar < PRESET_SIZE) {
241         if(npar == 0 && insertion == 0) {
242             /* lower the volume if this is system effect */
243             return (3 * presets[npreset][npar]) / 2;
244         }
245         return presets[npreset][npar];
246     }
247     return 0;
248 }
249 
setpreset(unsigned char npreset)250 void Distorsion::setpreset(unsigned char npreset)
251 {
252     if(npreset >= NUM_PRESETS)
253         npreset = NUM_PRESETS - 1;
254     for(int n = 0; n != 128; n++)
255         changepar(n, getpresetpar(npreset, n));
256     Ppreset = npreset;
257     cleanup();
258 }
259 
changepar(int npar,unsigned char value)260 void Distorsion::changepar(int npar, unsigned char value)
261 {
262     switch(npar) {
263         case 0:
264             setvolume(value);
265             break;
266         case 1:
267             setpanning(value);
268             break;
269         case 2:
270             setlrcross(value);
271             break;
272         case 3:
273             Pdrive = value;
274             break;
275         case 4:
276             Plevel = value;
277             break;
278         case 5:
279             if(value > 16)
280                 Ptype = 16;  //this must be increased if more distorsion types are added
281             else
282                 Ptype = value;
283             break;
284         case 6:
285             if(value > 1)
286                 Pnegate = 1;
287             else
288                 Pnegate = value;
289             break;
290         case 7:
291             setlpf(value);
292             break;
293         case 8:
294             sethpf(value);
295             break;
296         case 9:
297             Pstereo = (value > 1) ? 1 : value;
298             break;
299         case 10:
300             Pprefiltering = value;
301             break;
302         case 11:
303             Pfuncpar = value;
304             break;
305         case 12:
306             Poffset = value;
307             break;
308     }
309 }
310 
getpar(int npar) const311 unsigned char Distorsion::getpar(int npar) const
312 {
313     switch(npar) {
314         case 0:  return Pvolume;
315         case 1:  return Ppanning;
316         case 2:  return Plrcross;
317         case 3:  return Pdrive;
318         case 4:  return Plevel;
319         case 5:  return Ptype;
320         case 6:  return Pnegate;
321         case 7:  return Plpf;
322         case 8:  return Phpf;
323         case 9:  return Pstereo;
324         case 10: return Pprefiltering;
325         case 11: return Pfuncpar;
326         case 12: return Poffset;
327         default: return 0; //in case of bogus parameter number
328     }
329 }
330 
331 }
332