1 #include "DistortionEffect.h"
2 #include <vt_dsp/halfratefilter.h>
3 #include "QuadFilterUnit.h"
4 
5 // feedback can get tricky with packed SSE
6 
7 const int dist_OS_bits = 2;
8 const int distortion_OS = 1 << dist_OS_bits;
9 
DistortionEffect(SurgeStorage * storage,FxStorage * fxdata,pdata * pd)10 DistortionEffect::DistortionEffect(SurgeStorage *storage, FxStorage *fxdata, pdata *pd)
11     : Effect(storage, fxdata, pd), band1(storage), band2(storage), lp1(storage), lp2(storage),
12       hr_a(3, false), hr_b(3, true)
13 {
14     lp1.setBlockSize(BLOCK_SIZE * distortion_OS);
15     lp2.setBlockSize(BLOCK_SIZE * distortion_OS);
16     drive.set_blocksize(BLOCK_SIZE);
17     outgain.set_blocksize(BLOCK_SIZE);
18 }
19 
~DistortionEffect()20 DistortionEffect::~DistortionEffect() {}
21 
init()22 void DistortionEffect::init()
23 {
24     setvars(true);
25     band1.suspend();
26     band2.suspend();
27     lp1.suspend();
28     lp2.suspend();
29     bi = 0.f;
30     L = 0.f;
31     R = 0.f;
32 }
33 
setvars(bool init)34 void DistortionEffect::setvars(bool init)
35 {
36 
37     if (init)
38     {
39         float pregain = fxdata->p[dist_preeq_gain].get_extended(fxdata->p[dist_preeq_gain].val.f);
40         float postgain =
41             fxdata->p[dist_posteq_gain].get_extended(fxdata->p[dist_posteq_gain].val.f);
42         band1.coeff_peakEQ(band1.calc_omega(fxdata->p[dist_preeq_freq].val.f / 12.f),
43                            fxdata->p[dist_preeq_bw].val.f, pregain);
44         band2.coeff_peakEQ(band2.calc_omega(fxdata->p[dist_posteq_freq].val.f / 12.f),
45                            fxdata->p[dist_posteq_bw].val.f, postgain);
46         drive.set_target(0.f);
47         outgain.set_target(0.f);
48     }
49     else
50     {
51         float pregain = fxdata->p[dist_preeq_gain].get_extended(*f[dist_preeq_gain]);
52         float postgain = fxdata->p[dist_posteq_gain].get_extended(*f[dist_posteq_gain]);
53         band1.coeff_peakEQ(band1.calc_omega(*f[dist_preeq_freq] / 12.f), *f[dist_preeq_bw],
54                            pregain);
55         band2.coeff_peakEQ(band2.calc_omega(*f[dist_posteq_freq] / 12.f), *f[dist_posteq_bw],
56                            postgain);
57         lp1.coeff_LP2B(lp1.calc_omega((*f[dist_preeq_highcut] / 12.0) - 2.f), 0.707);
58         lp2.coeff_LP2B(lp2.calc_omega((*f[dist_posteq_highcut] / 12.0) - 2.f), 0.707);
59         lp1.coeff_instantize();
60         lp2.coeff_instantize();
61     }
62 }
63 
process(float * dataL,float * dataR)64 void DistortionEffect::process(float *dataL, float *dataR)
65 {
66     // TODO fix denormals!
67     if (bi == 0)
68         setvars(false);
69     bi = (bi + 1) & slowrate_m1;
70 
71     band1.process_block(dataL, dataR);
72     auto dS = drive.get_target();
73     auto dE = db_to_linear(fxdata->p[dist_drive].get_extended(*f[dist_drive]));
74     drive.set_target_smoothed(dE);
75     outgain.set_target_smoothed(db_to_linear(*f[dist_gain]));
76     float fb = *f[dist_feedback];
77     int ws = *pdata_ival[dist_model];
78     if (ws < 0 || ws >= n_ws_types)
79         ws = 0;
80 
81     float bL alignas(16)[BLOCK_SIZE << dist_OS_bits];
82     float bR alignas(16)[BLOCK_SIZE << dist_OS_bits];
83     assert(dist_OS_bits == 2);
84 
85     drive.multiply_2_blocks(dataL, dataR, BLOCK_SIZE_QUAD);
86 
87     bool useSSEShaper = (ws + wst_soft == wst_digital || ws + wst_soft == wst_sine);
88 
89     auto wsop = GetQFPtrWaveshaper(wst_soft + ws);
90 
91     float dD = 0.f;
92     float dNow = dS;
93     if (useSSEShaper)
94     {
95         dD = (dE - dS) / (BLOCK_SIZE * dist_OS_bits);
96     }
97 
98     for (int k = 0; k < BLOCK_SIZE; k++)
99     {
100         float a = (k & 16) ? 0.00000001 : -0.00000001; // denormal thingy
101         float Lin = dataL[k];
102         float Rin = dataR[k];
103         for (int s = 0; s < distortion_OS; s++)
104         {
105             L = Lin + fb * L;
106             R = Rin + fb * R;
107 
108             if (!fxdata->p[dist_preeq_highcut].deactivated)
109             {
110                 lp1.process_sample_nolag(L, R);
111             }
112 
113             if (useSSEShaper)
114             {
115                 float sb[4];
116                 auto dInv = 1.f / dNow;
117 
118                 sb[0] = L * dInv;
119                 sb[1] = R * dInv;
120                 auto lr128 = _mm_load_ps(sb);
121                 auto wsres = wsop(lr128, _mm_set1_ps(dNow));
122                 _mm_store_ps(sb, wsres);
123                 L = sb[0];
124                 R = sb[1];
125 
126                 dNow += dD;
127             }
128             else
129             {
130                 L = lookup_waveshape(wst_soft + ws, L);
131                 R = lookup_waveshape(wst_soft + ws, R);
132             }
133 
134             L += a;
135             R += a; // denormal
136 
137             if (!fxdata->p[dist_posteq_highcut].deactivated)
138             {
139                 lp2.process_sample_nolag(L, R);
140             }
141 
142             bL[s + (k << dist_OS_bits)] = L;
143             bR[s + (k << dist_OS_bits)] = R;
144         }
145     }
146 
147     hr_a.process_block_D2(bL, bR, 128);
148     hr_b.process_block_D2(bL, bR, 64);
149 
150     outgain.multiply_2_blocks_to(bL, bR, dataL, dataR, BLOCK_SIZE_QUAD);
151 
152     band2.process_block(dataL, dataR);
153 }
154 
suspend()155 void DistortionEffect::suspend() { init(); }
156 
group_label(int id)157 const char *DistortionEffect::group_label(int id)
158 {
159     switch (id)
160     {
161     case 0:
162         return "Pre-EQ";
163     case 1:
164         return "Distortion";
165     case 2:
166         return "Post-EQ";
167     case 3:
168         return "Output";
169     }
170     return 0;
171 }
group_label_ypos(int id)172 int DistortionEffect::group_label_ypos(int id)
173 {
174     switch (id)
175     {
176     case 0:
177         return 1;
178     case 1:
179         return 11;
180     case 2:
181         return 19;
182     case 3:
183         return 29;
184     }
185     return 0;
186 }
187 
init_ctrltypes()188 void DistortionEffect::init_ctrltypes()
189 {
190     Effect::init_ctrltypes();
191 
192     fxdata->p[dist_preeq_gain].set_name("Gain");
193     fxdata->p[dist_preeq_gain].set_type(ct_decibel_extendable);
194     fxdata->p[dist_preeq_freq].set_name("Frequency");
195     fxdata->p[dist_preeq_freq].set_type(ct_freq_audible);
196     fxdata->p[dist_preeq_bw].set_name("Bandwidth");
197     fxdata->p[dist_preeq_bw].set_type(ct_bandwidth);
198     fxdata->p[dist_preeq_highcut].set_name("High Cut");
199     fxdata->p[dist_preeq_highcut].set_type(ct_freq_audible_deactivatable);
200 
201     fxdata->p[dist_drive].set_name("Drive");
202     fxdata->p[dist_drive].set_type(ct_decibel_narrow_extendable);
203     fxdata->p[dist_feedback].set_name("Feedback");
204     fxdata->p[dist_feedback].set_type(ct_percent_bipolar);
205     fxdata->p[dist_model].set_name("Model");
206     fxdata->p[dist_model].set_type(ct_distortion_waveshape);
207 
208     fxdata->p[dist_posteq_gain].set_name("Gain");
209     fxdata->p[dist_posteq_gain].set_type(ct_decibel_extendable);
210     fxdata->p[dist_posteq_freq].set_name("Frequency");
211     fxdata->p[dist_posteq_freq].set_type(ct_freq_audible);
212     fxdata->p[dist_posteq_bw].set_name("Bandwidth");
213     fxdata->p[dist_posteq_bw].set_type(ct_bandwidth);
214     fxdata->p[dist_posteq_highcut].set_name("High Cut");
215     fxdata->p[dist_posteq_highcut].set_type(ct_freq_audible_deactivatable);
216 
217     fxdata->p[dist_gain].set_name("Gain");
218     fxdata->p[dist_gain].set_type(ct_decibel_narrow);
219 
220     fxdata->p[dist_preeq_gain].posy_offset = 1;
221     fxdata->p[dist_preeq_freq].posy_offset = 1;
222     fxdata->p[dist_preeq_bw].posy_offset = 1;
223     fxdata->p[dist_preeq_highcut].posy_offset = 1;
224 
225     fxdata->p[dist_drive].posy_offset = 5;
226     fxdata->p[dist_feedback].posy_offset = 5;
227     fxdata->p[dist_model].posy_offset = -11;
228 
229     fxdata->p[dist_posteq_gain].posy_offset = 7;
230     fxdata->p[dist_posteq_freq].posy_offset = 7;
231     fxdata->p[dist_posteq_bw].posy_offset = 7;
232     fxdata->p[dist_posteq_highcut].posy_offset = 7;
233 
234     fxdata->p[dist_gain].posy_offset = 9;
235 }
init_default_values()236 void DistortionEffect::init_default_values()
237 {
238     fxdata->p[dist_preeq_gain].val.f = 0.f;
239     fxdata->p[dist_preeq_freq].val.f = 0.f;
240     fxdata->p[dist_preeq_bw].val.f = 2.f;
241     fxdata->p[dist_preeq_highcut].deactivated = false;
242 
243     fxdata->p[dist_model].val.f = 0.f;
244 
245     fxdata->p[dist_posteq_gain].val.f = 0.f;
246     fxdata->p[dist_posteq_freq].val.f = 0.f;
247     fxdata->p[dist_posteq_bw].val.f = 2.f;
248     fxdata->p[dist_posteq_highcut].deactivated = false;
249 
250     fxdata->p[dist_gain].val.f = 0.f;
251 }
252 
handleStreamingMismatches(int streamingRevision,int currentSynthStreamingRevision)253 void DistortionEffect::handleStreamingMismatches(int streamingRevision,
254                                                  int currentSynthStreamingRevision)
255 {
256     if (streamingRevision <= 11)
257     {
258         fxdata->p[dist_model].val.i = 0;
259         fxdata->p[dist_preeq_gain].extend_range = false;
260         fxdata->p[dist_posteq_gain].extend_range = false;
261     }
262 
263     if (streamingRevision <= 15)
264     {
265         fxdata->p[dist_preeq_highcut].deactivated = false;
266         fxdata->p[dist_posteq_highcut].deactivated = false;
267     }
268 }
269