@@ -48,6 +48,10 @@ struct WaveshaperWidget : widgets::XTModuleWidget
48
48
49
49
menu->addChild (rack::createMenuItem (" Apply DC Blocker" , CHECKMARK (m->doDCBlock ),
50
50
[m]() { m->doDCBlock = !m->doDCBlock ; }));
51
+
52
+ menu->addChild (rack::createMenuItem (
53
+ " Show Transform and Response" , CHECKMARK (m->showTransformCurve ),
54
+ [m]() { m->showTransformCurve = !m->showTransformCurve ; }));
51
55
}
52
56
}
53
57
};
@@ -57,9 +61,11 @@ struct WaveshaperPlotWidget : public rack::widget::TransparentWidget, style::Sty
57
61
typename WaveshaperWidget::M *module {nullptr };
58
62
widgets::BufferedDrawFunctionWidget *bdw{nullptr };
59
63
widgets::BufferedDrawFunctionWidget *bdwPlot{nullptr };
64
+ widgets::BufferedDrawFunctionWidget *bdwResponse{nullptr };
60
65
61
66
std::vector<std::pair<float , float >> inputSignal;
62
67
std::vector<std::pair<float , float >> outputSignal;
68
+ std::vector<std::pair<float , float >> responseSignal;
63
69
void setup (typename WaveshaperWidget::M *m)
64
70
{
65
71
module = m;
@@ -75,13 +81,24 @@ struct WaveshaperPlotWidget : public rack::widget::TransparentWidget, style::Sty
75
81
rack::Vec (0 , 0 ), box.size , [this ](auto *vg) { drawPlot (vg); });
76
82
addChild (bdwPlot);
77
83
84
+ bdwResponse = new widgets::BufferedDrawFunctionWidgetOnLayer (
85
+ rack::Vec (box.size .x * 0.666 - rack::mm2px (0 ), rack::mm2px (0 )),
86
+ rack::Vec (box.size .x * 0.333 , box.size .y - rack::mm2px (0 )),
87
+ [this ](auto *vg) { drawResponse (vg); });
88
+ addChild (bdwResponse);
89
+ calculateInputSignal ();
90
+ }
91
+ void calculateInputSignal ()
92
+ {
93
+ inputSignal.clear ();
78
94
auto fac = 2.0 ;
79
95
auto inputRes = (int )box.size .x * fac;
80
96
auto dx = 1.0 / inputRes;
97
+ auto cmul = module ? (module ->showTransformCurve ? 6.0 : 4.0 ) : 4.0 ;
81
98
for (int i = 0 ; i < inputRes; ++i)
82
99
{
83
100
auto x = dx * i;
84
- auto y = std::sin (x * 4.0 * M_PI);
101
+ auto y = std::sin (x * cmul * M_PI);
85
102
inputSignal.emplace_back (x * box.size .x , y);
86
103
}
87
104
}
@@ -99,6 +116,7 @@ struct WaveshaperPlotWidget : public rack::widget::TransparentWidget, style::Sty
99
116
{
100
117
recalcPath ();
101
118
bdwPlot->dirty = true ;
119
+ bdwResponse->dirty = true ;
102
120
}
103
121
104
122
rack::widget::Widget::step ();
@@ -108,6 +126,7 @@ struct WaveshaperPlotWidget : public rack::widget::TransparentWidget, style::Sty
108
126
{
109
127
bdw->dirty = true ;
110
128
bdwPlot->dirty = true ;
129
+ bdwResponse->dirty = true ;
111
130
}
112
131
113
132
static WaveshaperPlotWidget *create (rack::Vec pos, rack::Vec size,
@@ -127,6 +146,7 @@ struct WaveshaperPlotWidget : public rack::widget::TransparentWidget, style::Sty
127
146
int dirtyCount{0 };
128
147
int sumDeact{-1 };
129
148
int sumAbs{-1 };
149
+ bool stc{false };
130
150
uint32_t wtloadCompare{842932918 };
131
151
132
152
bool isDirty ()
@@ -156,6 +176,14 @@ struct WaveshaperPlotWidget : public rack::widget::TransparentWidget, style::Sty
156
176
}
157
177
158
178
dval = wstype != lastType || ddb != lastDrive || bias != lastBias;
179
+
180
+ if (module ->showTransformCurve != stc)
181
+ {
182
+ dval = true ;
183
+ calculateInputSignal ();
184
+ stc = module ->showTransformCurve ;
185
+ bdw->dirty = true ; // special - gotta redo the background
186
+ }
159
187
}
160
188
return dval;
161
189
}
@@ -168,55 +196,88 @@ struct WaveshaperPlotWidget : public rack::widget::TransparentWidget, style::Sty
168
196
if (!module )
169
197
return ;
170
198
199
+ responseSignal.clear ();
171
200
outputSignal.clear ();
172
201
auto wstype = (sst::waveshapers::WaveshaperType)std::round (
173
202
module ->paramQuantities [Waveshaper::WSHP_TYPE]->getValue ());
174
203
sst::waveshapers::QuadWaveshaperState wss;
175
204
float R[4 ];
176
205
177
- initializeWaveshaperRegister (wstype, R);
178
-
179
- for (int i = 0 ; i < sst::waveshapers::n_waveshaper_registers; ++i)
180
206
{
181
- wss.R [i] = _mm_set1_ps (R[i]);
182
- }
207
+ initializeWaveshaperRegister (wstype, R);
183
208
184
- wss.init = _mm_cmpeq_ps (_mm_setzero_ps (), _mm_setzero_ps ()); // better way?
209
+ for (int i = 0 ; i < sst::waveshapers::n_waveshaper_registers; ++i)
210
+ {
211
+ wss.R [i] = _mm_set1_ps (R[i]);
212
+ }
185
213
186
- float ddb{0 .f }, bias{0 .f };
187
- if (style::XTStyle::getShowModulationAnimationOnDisplay ())
188
- {
189
- ddb = module ->modulationAssistant .values [Waveshaper::DRIVE][0 ];
190
- bias = module ->modulationAssistant .values [Waveshaper::BIAS][0 ];
191
- }
192
- else
193
- {
194
- ddb = module ->modulationAssistant .basevalues [Waveshaper::DRIVE];
195
- bias = module ->modulationAssistant .basevalues [Waveshaper::BIAS];
196
- }
214
+ wss.init = _mm_cmpeq_ps (_mm_setzero_ps (), _mm_setzero_ps ()); // better way?
197
215
198
- auto wsop = sst::waveshapers::GetQuadWaveshaper (wstype);
199
- auto damp = pow (10 , 0.05 * ddb);
200
- auto d1 = _mm_set1_ps (damp);
216
+ float ddb{0 .f }, bias{0 .f };
217
+ if (style::XTStyle::getShowModulationAnimationOnDisplay ())
218
+ {
219
+ ddb = module ->modulationAssistant .values [Waveshaper::DRIVE][0 ];
220
+ bias = module ->modulationAssistant .values [Waveshaper::BIAS][0 ];
221
+ }
222
+ else
223
+ {
224
+ ddb = module ->modulationAssistant .basevalues [Waveshaper::DRIVE];
225
+ bias = module ->modulationAssistant .basevalues [Waveshaper::BIAS];
226
+ }
227
+
228
+ auto wsop = sst::waveshapers::GetQuadWaveshaper (wstype);
229
+ auto damp = pow (10 , 0.05 * ddb);
230
+ auto d1 = _mm_set1_ps (damp);
231
+
232
+ lastType = wstype;
233
+ lastBias = bias;
234
+ lastDrive = ddb;
201
235
202
- lastType = wstype;
203
- lastBias = bias;
204
- lastDrive = ddb;
236
+ for (const auto &[x, y] : inputSignal)
237
+ {
238
+ auto ivs = _mm_set1_ps (y + bias);
239
+ auto ov1 = ivs;
240
+
241
+ if (wsop)
242
+ {
243
+ ov1 = wsop (&wss, ivs, d1);
244
+ }
245
+
246
+ float r alignas (16 )[8 ];
247
+ _mm_store_ps (r, ov1);
248
+
249
+ outputSignal.emplace_back (x, r[0 ]);
250
+ }
251
+ }
205
252
206
- for (const auto &[x, y] : inputSignal)
207
253
{
208
- auto ivs = _mm_set1_ps (y + bias);
209
- auto ov1 = ivs;
254
+ initializeWaveshaperRegister (wstype, R);
210
255
211
- if (wsop )
256
+ for ( int i = 0 ; i < sst::waveshapers::n_waveshaper_registers; ++i )
212
257
{
213
- ov1 = wsop (&wss, ivs, d1 );
258
+ wss. R [i] = _mm_set1_ps (R[i] );
214
259
}
215
260
216
- float r alignas (16 )[8 ];
217
- _mm_store_ps (r, ov1);
261
+ wss.init = _mm_cmpeq_ps (_mm_setzero_ps (), _mm_setzero_ps ()); // better way?
218
262
219
- outputSignal.emplace_back (x, r[0 ]);
263
+ auto wsop = sst::waveshapers::GetQuadWaveshaper (wstype);
264
+
265
+ for (float x = -2.0 ; x < 2.0 ; x += 2.0 * 0.01 )
266
+ {
267
+ auto ivs = _mm_set1_ps (x);
268
+ auto d1 = _mm_set1_ps (1 .f );
269
+ auto ov1 = ivs;
270
+
271
+ if (wsop)
272
+ {
273
+ ov1 = wsop (&wss, ivs, d1);
274
+ }
275
+
276
+ float r alignas (16 )[8 ];
277
+ _mm_store_ps (r, ov1);
278
+
279
+ responseSignal.emplace_back (x, r[0 ]);
280
+ }
220
281
}
221
282
}
222
283
@@ -230,6 +291,62 @@ struct WaveshaperPlotWidget : public rack::widget::TransparentWidget, style::Sty
230
291
return ypx;
231
292
}
232
293
294
+ void drawResponse (NVGcontext *vg)
295
+ {
296
+ if (!module )
297
+ return ;
298
+
299
+ if (!module ->showTransformCurve )
300
+ return ;
301
+
302
+ auto bx = bdwResponse->box ;
303
+ nvgBeginPath (vg);
304
+ auto markCol = style ()->getColor (style::XTStyle::PLOT_MARKS);
305
+ auto bCol = style ()->getColor (style::XTStyle::LED_PANEL);
306
+ // bCol.a = 0.95;
307
+ nvgStrokeColor (vg, markCol);
308
+ nvgFillColor (vg, bCol);
309
+ nvgRect (vg, 0 , 0 , bx.getWidth (), bx.getHeight ());
310
+ nvgStrokeWidth (vg, 1 );
311
+ nvgFill (vg);
312
+ nvgStroke (vg);
313
+
314
+ auto xs = 2 .0f , ys = 3 .8f ;
315
+
316
+ nvgBeginPath (vg);
317
+ bool start = true ;
318
+ for (float x = -xs; x <= xs; x += xs * 0.01 )
319
+ {
320
+ auto px = (x + xs) / (2 * xs) * bx.getWidth ();
321
+
322
+ auto ly = -x;
323
+ auto py = (ly + ys) / (2 * ys) * bx.getHeight ();
324
+ if (start)
325
+ nvgMoveTo (vg, px, py);
326
+ else
327
+ nvgLineTo (vg, px, py);
328
+ start = false ;
329
+ }
330
+ nvgStroke (vg);
331
+
332
+ auto crvCol = style ()->getColor (style::XTStyle::PLOT_CURVE);
333
+ nvgBeginPath (vg);
334
+ nvgStrokeColor (vg, crvCol);
335
+ start = true ;
336
+ for (auto &[x, y] : responseSignal)
337
+ {
338
+ auto px = (x + xs) / (2 * xs) * bx.getWidth ();
339
+
340
+ auto ly = -y;
341
+ auto py = (ly + ys) / (2 * ys) * bx.getHeight ();
342
+ if (start)
343
+ nvgMoveTo (vg, px, py);
344
+ else
345
+ nvgLineTo (vg, px, py);
346
+ start = false ;
347
+ }
348
+ nvgStroke (vg);
349
+ }
233
350
void drawPlotBackground (NVGcontext *vg)
234
351
{
235
352
// This will go in layer 0
0 commit comments