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"
19 #include <rtosc/ports.h>
20 #include <rtosc/port-sugar.h>
24 #define rObject Distorsion
25 #define rBegin [](const char *msg, rtosc::RtData &d) {
28 rtosc::Ports
Distorsion::ports
= {
29 {"preset::i", rProp(parameter
)
30 rOptions(Overdrive
1, Overdrive
2, A
. Exciter
1, A
. Exciter
2, Guitar Amp
,
32 rDoc("Instrument Presets"), 0,
34 rObject
*o
= (rObject
*)d
.obj
;
35 if(rtosc_narguments(msg
))
36 o
->setpreset(rtosc_argument(msg
, 0).i
);
38 d
.reply(d
.loc
, "i", o
->Ppreset
);
40 rEffParVol(rDefault(127), rPresetsAt(2, 64, 64)),
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
,
53 rPresets(Arctangent
, Asymmetric
, Zigzag
,
54 Asymmetric
, Pow
, Quantisize
),
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
) {
85 args
[i
].f
= (dd
.Pvolume
* buffer
[i
] + (127 - dd
.Pvolume
) * orig
[i
]) / 127.0f
;
88 d
.replyArray(d
.loc
, arg_str
, args
);
95 Distorsion::Distorsion(EffectParams pars
)
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
);
117 Distorsion::~Distorsion()
119 memory
.dealloc(lpfl
);
120 memory
.dealloc(lpfr
);
121 memory
.dealloc(hpfl
);
122 memory
.dealloc(hpfr
);
126 void Distorsion::cleanup(void)
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
);
148 void Distorsion::out(const Stereo
<float *> &smp
)
150 float inputvol
= powf(5.0f
, (Pdrive
- 32.0f
) / 127.0f
);
155 for(int i
= 0; i
< buffersize
; ++i
) {
156 efxoutl
[i
] = smp
.l
[i
] * inputvol
* pangainL
;
157 efxoutr
[i
] = smp
.r
[i
] * inputvol
* pangainR
;
160 for(int i
= 0; i
< buffersize
; ++i
)
161 efxoutl
[i
] = (smp
.l
[i
] * pangainL
+ smp
.r
[i
] * pangainR
) * inputvol
;
164 applyfilters(efxoutl
, efxoutr
);
166 waveShapeSmps(buffersize
, efxoutl
, Ptype
+ 1, Pdrive
, Poffset
, Pfuncpar
);
168 waveShapeSmps(buffersize
, efxoutr
, Ptype
+ 1, Pdrive
, Poffset
, Pfuncpar
);
171 applyfilters(efxoutl
, efxoutr
);
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
;
185 efxoutl
[i
] = lout
* 2.0f
* level
;
186 efxoutr
[i
] = rout
* 2.0f
* level
;
192 void Distorsion::setvolume(unsigned char _Pvolume
)
197 outvolume
= powf(0.01f
, (1.0f
- Pvolume
/ 127.0f
)) * 4.0f
;
201 volume
= outvolume
= Pvolume
/ 127.0f
;
206 void Distorsion::setlpf(unsigned char _Plpf
)
209 float fr
= expf(sqrtf(Plpf
/ 127.0f
) * logf(25000.0f
)) + 40.0f
;
214 void Distorsion::sethpf(unsigned char _Phpf
)
217 float fr
= expf(sqrtf(Phpf
/ 127.0f
) * logf(25000.0f
)) + 20.0f
;
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
] = {
228 {127, 64, 35, 56, 70, 0, 0, 96, 0, 0, 0, 32, 64},
230 {127, 64, 35, 29, 75, 1, 0, 127, 0, 0, 0, 32, 64},
232 {64, 64, 35, 75, 80, 5, 0, 127, 105, 1, 0, 32, 64},
234 {64, 64, 35, 85, 62, 1, 0, 127, 118, 1, 0, 32, 64},
236 {127, 64, 35, 63, 75, 2, 0, 55, 0, 0, 0, 32, 64},
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
];
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
));
260 void Distorsion::changepar(int npar
, unsigned char value
)
280 Ptype
= 16; //this must be increased if more distorsion types are added
297 Pstereo
= (value
> 1) ? 1 : value
;
300 Pprefiltering
= value
;
311 unsigned char Distorsion::getpar(int npar
) const
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
;
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