make /distorsion/waveform reflect the Pvolume par
[zynaddsubfx-code.git] / src / Effects / Distorsion.cpp
blob0178a969d2840de22a220e78ee450f479a334e4d
1 /*
2 ZynAddSubFX - a software synthesizer
4 Distorsion.cpp - Distorsion effect
5 Copyright (C) 2002-2005 Nasca Octavian Paul
6 Author: Nasca Octavian Paul
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.
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>
22 namespace zyn {
24 #define rObject Distorsion
25 #define rBegin [](const char *msg, rtosc::RtData &d) {
26 #define rEnd }
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),
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)
71 Distorsion &dd = *(Distorsion*)d.obj;
72 float buffer[128], orig[128];
73 rtosc_arg_t args[128];
74 char arg_str[128+1] = {};
76 for(int i=0; i<128; ++i)
77 buffer[i] = 2*(i/128.0)-1;
78 memcpy(orig, buffer, sizeof(float_t)*128);
80 waveShapeSmps(sizeof(buffer)/sizeof(buffer[0]), buffer,
81 dd.Ptype + 1, dd.Pdrive, dd.Poffset, dd.Pfuncpar);
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;
88 d.replyArray(d.loc, arg_str, args);
89 }},
91 #undef rBegin
92 #undef rEnd
93 #undef rObject
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)
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();
117 Distorsion::~Distorsion()
119 memory.dealloc(lpfl);
120 memory.dealloc(lpfr);
121 memory.dealloc(hpfl);
122 memory.dealloc(hpfr);
125 //Cleanup the effect
126 void Distorsion::cleanup(void)
128 lpfl->cleanup();
129 hpfl->cleanup();
130 lpfr->cleanup();
131 hpfr->cleanup();
135 //Apply the filters
136 void Distorsion::applyfilters(float *efxoutl, float *efxoutr)
138 lpfl->filterout(efxoutl);
139 hpfl->filterout(efxoutl);
140 if(Pstereo != 0) { //stereo
141 lpfr->filterout(efxoutr);
142 hpfr->filterout(efxoutr);
147 //Effect output
148 void Distorsion::out(const Stereo<float *> &smp)
150 float inputvol = powf(5.0f, (Pdrive - 32.0f) / 127.0f);
151 if(Pnegate)
152 inputvol *= -1.0f;
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;
159 else //Mono
160 for(int i = 0; i < buffersize; ++i)
161 efxoutl[i] = (smp.l[i] * pangainL + smp.r[i] * pangainR) * inputvol;
163 if(Pprefiltering)
164 applyfilters(efxoutl, efxoutr);
166 waveShapeSmps(buffersize, efxoutl, Ptype + 1, Pdrive, Poffset, Pfuncpar);
167 if(Pstereo)
168 waveShapeSmps(buffersize, efxoutr, Ptype + 1, Pdrive, Poffset, Pfuncpar);
170 if(!Pprefiltering)
171 applyfilters(efxoutl, efxoutr);
173 if(!Pstereo)
174 memcpy(efxoutr, efxoutl, bufferbytes);
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;
185 efxoutl[i] = lout * 2.0f * level;
186 efxoutr[i] = rout * 2.0f * level;
191 //Parameter control
192 void Distorsion::setvolume(unsigned char _Pvolume)
194 Pvolume = _Pvolume;
196 if(insertion == 0) {
197 outvolume = powf(0.01f, (1.0f - Pvolume / 127.0f)) * 4.0f;
198 volume = 1.0f;
200 else
201 volume = outvolume = Pvolume / 127.0f;
202 if(Pvolume == 0)
203 cleanup();
206 void Distorsion::setlpf(unsigned char _Plpf)
208 Plpf = _Plpf;
209 float fr = expf(sqrtf(Plpf / 127.0f) * logf(25000.0f)) + 40.0f;
210 lpfl->setfreq(fr);
211 lpfr->setfreq(fr);
214 void Distorsion::sethpf(unsigned char _Phpf)
216 Phpf = _Phpf;
217 float fr = expf(sqrtf(Phpf / 127.0f) * logf(25000.0f)) + 20.0f;
218 hpfl->setfreq(fr);
219 hpfr->setfreq(fr);
222 unsigned char Distorsion::getpresetpar(unsigned char npreset, unsigned int npar)
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}
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;
245 return presets[npreset][npar];
247 return 0;
250 void Distorsion::setpreset(unsigned char npreset)
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();
260 void Distorsion::changepar(int npar, unsigned char value)
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;
311 unsigned char Distorsion::getpar(int npar) const
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