Audacity 3.2.0
DistortionBase.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 DistortionBase.cpp
6
7 Steve Daulton
8
9 // TODO: Add a graph display of the waveshaper equation.
10 // TODO: Allow the user to draw the graph.
11
12******************************************************************//*******************************************************************/
18#include "DistortionBase.h"
19#include "ShuttleAutomation.h"
20#include <utility>
21
22#define STEPS 1024 // number of +ve or -ve steps in lookup tabe
23
25 { XO("Hard Clipping") }, { XO("Soft Clipping") },
26 { XO("Soft Overdrive") }, { XO("Medium Overdrive") },
27 { XO("Hard Overdrive") }, { XO("Cubic Curve (odd harmonics)") },
28 { XO("Even Harmonics") }, { XO("Expand and Compress") },
29 { XO("Leveller") }, { XO("Rectifier Distortion") },
30 { XO("Hard Limiter 1413") }
31};
32
34{
35 static CapturedParameters<
38 parameters;
39 return parameters;
40}
41
42// How many samples are processed before recomputing the lookup table again
43#define skipsamples 1000
44
45static const struct
46{
50 // clang-format off
51{
52 // Table DCBlock threshold floor Param1 Param2 Repeats
53 // Defaults: 0 false -6.0 -70.0(off) 50.0 50.0 1
54 //
55 // xgettext:no-c-format
56 { XO("Hard clip -12dB, 80% make-up gain"), { 0, 0, -12.0, -70.0, 0.0, 80.0, 0 } },
57 // xgettext:no-c-format
58 { XO("Soft clip -12dB, 80% make-up gain"), { 1, 0, -12.0, -70.0, 50.0, 80.0, 0 } },
59 { XO("Fuzz Box"), { 1, 0, -30.0, -70.0, 80.0, 80.0, 0 } },
60 { XO("Walkie-talkie"), { 1, 0, -50.0, -70.0, 60.0, 80.0, 0 } },
61 { XO("Blues drive sustain"), { 2, 0, -6.0, -70.0, 30.0, 80.0, 0 } },
62 { XO("Light Crunch Overdrive"), { 3, 0, -6.0, -70.0, 20.0, 80.0, 0 } },
63 { XO("Heavy Overdrive"), { 4, 0, -6.0, -70.0, 90.0, 80.0, 0 } },
64 { XO("3rd Harmonic (Perfect Fifth)"), { 5, 0, -6.0, -70.0, 100.0, 60.0, 0 } },
65 { XO("Valve Overdrive"), { 6, 1, -6.0, -70.0, 30.0, 40.0, 0 } },
66 { XO("2nd Harmonic (Octave)"), { 6, 1, -6.0, -70.0, 50.0, 0.0, 0 } },
67 { XO("Gated Expansion Distortion"), { 7, 0, -6.0, -70.0, 30.0, 80.0, 0 } },
68 { XO("Leveller, Light, -70dB noise floor"), { 8, 0, -6.0, -70.0, 0.0, 50.0, 1 } },
69 { XO("Leveller, Moderate, -70dB noise floor"), { 8, 0, -6.0, -70.0, 0.0, 50.0, 2 } },
70 { XO("Leveller, Heavy, -70dB noise floor"), { 8, 0, -6.0, -70.0, 0.0, 50.0, 3 } },
71 { XO("Leveller, Heavier, -70dB noise floor"), { 8, 0, -6.0, -70.0, 0.0, 50.0, 4 } },
72 { XO("Leveller, Heaviest, -70dB noise floor"), { 8, 0, -6.0, -70.0, 0.0, 50.0, 5 } },
73 { XO("Half-wave Rectifier"), { 9, 0, -6.0, -70.0, 50.0, 50.0, 0 } },
74 { XO("Full-wave Rectifier"), { 9, 0, -6.0, -70.0, 100.0, 50.0, 0 } },
75 { XO("Full-wave Rectifier (DC blocked)"), { 9, 1, -6.0, -70.0, 100.0, 50.0, 0 } },
76 { XO("Percussion Limiter"), {10, 0, -12.0, -70.0, 100.0, 30.0, 0 } },
77};
78// clang-format on
79
81
82std::shared_ptr<EffectInstance> DistortionBase::MakeInstance() const
83{
84 return std::make_shared<Instance>(*this);
85}
86
88{
89 wxASSERT(nTableTypes == WXSIZEOF(kTableTypeStrings));
90
92}
93
95{
96}
97
98// ComponentInterface implementation
99
101{
102 return Symbol;
103}
104
106{
107 return XO("Waveshaping distortion effect");
108}
109
111{
112 return L"Distortion";
113}
114
115// EffectDefinitionInterface implementation
116
118{
119 return EffectTypeProcess;
120}
121
123{
125}
126
128{
129 return 1;
130}
131
133{
134 return 1;
135}
136
139{
140 InstanceInit(mMaster, settings, sampleRate);
141 return true;
142}
143
145 EffectSettings& settings, const float* const* inBlock,
146 float* const* outBlock, size_t blockLen)
147{
148 return InstanceProcess(settings, mMaster, inBlock, outBlock, blockLen);
149}
150
152{
153 SetBlockSize(512);
154 mSlaves.clear();
155 return true;
156}
157
160{
162
163 InstanceInit(slave, settings, sampleRate);
164
165 mSlaves.push_back(slave);
166
167 return true;
168}
169
171{
172 mSlaves.clear();
173
174 return true;
175}
176
178 size_t group, EffectSettings& settings, const float* const* inbuf,
179 float* const* outbuf, size_t numSamples)
180{
181 if (group >= mSlaves.size())
182 return 0;
183 return InstanceProcess(settings, mSlaves[group], inbuf, outbuf, numSamples);
184}
185
187{
189
190 for (size_t i = 0; i < WXSIZEOF(FactoryPresets); i++)
191 {
192 names.push_back(FactoryPresets[i].name.Translation());
193 }
194
195 return names;
196}
197
200{
201 // To do: externalize state so const_cast isn't needed
202 return const_cast<DistortionBase*>(this)->DoLoadFactoryPreset(id, settings);
203}
204
207{
208 if (id < 0 || id >= (int)WXSIZEOF(FactoryPresets))
209 {
210 return {};
211 }
212
214
215 return { nullptr };
216}
217
220{
221 auto& ms = GetSettings(settings);
222
223 data.samplerate = sampleRate;
224 data.skipcount = 0;
225 data.tablechoiceindx = ms.mTableChoiceIndx;
226 data.dcblock = ms.mDCBlock;
227 data.threshold = ms.mThreshold_dB;
228 data.noisefloor = ms.mNoiseFloor;
229 data.param1 = ms.mParam1;
230 data.param2 = ms.mParam2;
231 data.repeats = ms.mRepeats;
232
233 // DC block filter variables
234 data.queuetotal = 0.0;
235
236 // std::queue<float>().swap(data.queuesamples);
237 while (!data.queuesamples.empty())
238 data.queuesamples.pop();
239
240 MakeTable(data, ms);
241
242 return;
243}
244
247 const float* const* inBlock, float* const* outBlock, size_t blockLen)
248{
249 auto& ms = GetSettings(settings);
250
251 const float* ibuf = inBlock[0];
252 float* obuf = outBlock[0];
253
254 bool update =
255 (ms.mTableChoiceIndx == data.tablechoiceindx &&
256 ms.mNoiseFloor == data.noisefloor &&
257 ms.mThreshold_dB == data.threshold && ms.mParam1 == data.param1 &&
258 ms.mParam2 == data.param2 && ms.mRepeats == data.repeats) ?
259 false :
260 true;
261
262 double p1 = ms.mParam1 / 100.0;
263 double p2 = ms.mParam2 / 100.0;
264
265 data.tablechoiceindx = ms.mTableChoiceIndx;
266 data.threshold = ms.mThreshold_dB;
267 data.noisefloor = ms.mNoiseFloor;
268 data.param1 = ms.mParam1;
269 data.repeats = ms.mRepeats;
270
271 for (decltype(blockLen) i = 0; i < blockLen; i++)
272 {
273 if (update && ((data.skipcount++) % skipsamples == 0))
274 {
275 MakeTable(data, ms);
276 }
277
278 switch (ms.mTableChoiceIndx)
279 {
280 case kHardClip:
281 // Param2 = make-up gain.
282 obuf[i] =
283 WaveShaper(ibuf[i], ms) * ((1 - p2) + (data.mMakeupGain * p2));
284 break;
285 case kSoftClip:
286 // Param2 = make-up gain.
287 obuf[i] =
288 WaveShaper(ibuf[i], ms) * ((1 - p2) + (data.mMakeupGain * p2));
289 break;
290 case kHalfSinCurve:
291 obuf[i] = WaveShaper(ibuf[i], ms) * p2;
292 break;
293 case kExpCurve:
294 obuf[i] = WaveShaper(ibuf[i], ms) * p2;
295 break;
296 case kLogCurve:
297 obuf[i] = WaveShaper(ibuf[i], ms) * p2;
298 break;
299 case kCubic:
300 obuf[i] = WaveShaper(ibuf[i], ms) * p2;
301 break;
302 case kEvenHarmonics:
303 obuf[i] = WaveShaper(ibuf[i], ms);
304 break;
305 case kSinCurve:
306 obuf[i] = WaveShaper(ibuf[i], ms) * p2;
307 break;
308 case kLeveller:
309 obuf[i] = WaveShaper(ibuf[i], ms);
310 break;
311 case kRectifier:
312 obuf[i] = WaveShaper(ibuf[i], ms);
313 break;
314 case kHardLimiter:
315 // Mix equivalent to LADSPA effect's "Wet / Residual" mix
316 obuf[i] = (WaveShaper(ibuf[i], ms) * (p1 - p2)) + (ibuf[i] * p2);
317 break;
318 default:
319 obuf[i] = WaveShaper(ibuf[i], ms);
320 }
321 if (ms.mDCBlock)
322 {
323 obuf[i] = DCFilter(data, obuf[i]);
324 }
325 }
326
327 return blockLen;
328}
329
332{
333 switch (ms.mTableChoiceIndx)
334 {
335 case kHardClip:
336 HardClip(state, ms);
337 break;
338 case kSoftClip:
339 SoftClip(state, ms);
340 break;
341 case kHalfSinCurve:
342 HalfSinTable(ms);
343 break;
344 case kExpCurve:
345 ExponentialTable(ms);
346 break;
347 case kLogCurve:
348 LogarithmicTable(ms);
349 break;
350 case kCubic:
351 CubicTable(ms);
352 break;
353 case kEvenHarmonics:
354 EvenHarmonicTable(ms);
355 break;
356 case kSinCurve:
357 SineTable(ms);
358 break;
359 case kLeveller:
360 Leveller(ms);
361 break;
362 case kRectifier:
363 Rectifier(ms);
364 break;
365 case kHardLimiter:
366 HardLimiter(state, ms);
367 break;
368 }
369}
370
371//
372// Preset tables for gain lookup
373//
374
377{
378 const double threshold = DB_TO_LINEAR(ms.mThreshold_dB);
379
380 double lowThresh = 1 - threshold;
381 double highThresh = 1 + threshold;
382
383 for (int n = 0; n < TABLESIZE; n++)
384 {
385 if (n < (STEPS * lowThresh))
386 mTable[n] = -threshold;
387 else if (n > (STEPS * highThresh))
388 mTable[n] = threshold;
389 else
390 mTable[n] = n / (double)STEPS - 1;
391
392 state.mMakeupGain = 1.0 / threshold;
393 }
394}
395
398{
399 const double thresholdLinear = DB_TO_LINEAR(ms.mThreshold_dB);
400
401 double threshold = 1 + thresholdLinear;
402 double amount = std::pow(2.0, 7.0 * ms.mParam1 / 100.0); // range 1 to 128
403 double peak = LogCurve(thresholdLinear, 1.0, amount);
404 state.mMakeupGain = 1.0 / peak;
405 mTable[STEPS] = 0.0; // origin
406
407 // positive half of table
408 for (int n = STEPS; n < TABLESIZE; n++)
409 {
410 if (n < (STEPS * threshold)) // origin to threshold
411 mTable[n] = n / (float)STEPS - 1;
412 else
413 mTable[n] = LogCurve(thresholdLinear, n / (double)STEPS - 1, amount);
414 }
415 CopyHalfTable();
416}
417
419 double threshold, float value, double ratio)
420{
421 return threshold + ((std::exp(ratio * (threshold - value)) - 1) / -ratio);
422}
423
425 const EffectDistortionSettings& ms)
426{
427 double amount =
428 std::min(0.999, DB_TO_LINEAR(-1 * ms.mParam1)); // avoid divide by zero
429
430 for (int n = STEPS; n < TABLESIZE; n++)
431 {
432 double linVal = n / (float)STEPS;
433 double scale = -1.0 / (1.0 - amount); // unity gain at 0dB
434 double curve = std::exp((linVal - 1) * std::log(amount));
435 mTable[n] = scale * (curve - 1);
436 }
437 CopyHalfTable();
438}
439
441 const EffectDistortionSettings& ms)
442{
443 double amount = ms.mParam1;
444 double stepsize = 1.0 / STEPS;
445 double linVal = 0;
446
447 if (amount == 0)
448 {
449 for (int n = STEPS; n < TABLESIZE; n++)
450 {
451 mTable[n] = linVal;
452 linVal += stepsize;
453 }
454 }
455 else
456 {
457 for (int n = STEPS; n < TABLESIZE; n++)
458 {
459 mTable[n] = std::log(1 + (amount * linVal)) / std::log(1 + amount);
460 linVal += stepsize;
461 }
462 }
463 CopyHalfTable();
464}
465
467{
468 int iter = std::floor(ms.mParam1 / 20.0);
469 double fractionalpart = (ms.mParam1 / 20.0) - iter;
470 double stepsize = 1.0 / STEPS;
471 double linVal = 0;
472
473 for (int n = STEPS; n < TABLESIZE; n++)
474 {
475 mTable[n] = linVal;
476 for (int i = 0; i < iter; i++)
477 {
478 mTable[n] = std::sin(mTable[n] * M_PI_2);
479 }
480 mTable[n] +=
481 ((std::sin(mTable[n] * M_PI_2) - mTable[n]) * fractionalpart);
482 linVal += stepsize;
483 }
484 CopyHalfTable();
485}
486
488{
489 double amount = ms.mParam1 * std::sqrt(3.0) / 100.0;
490 double gain = 1.0;
491 if (amount != 0.0)
492 gain = 1.0 / Cubic(ms, std::min(amount, 1.0));
493
494 double stepsize = amount / STEPS;
495 double x = -amount;
496
497 if (amount == 0)
498 {
499 for (int i = 0; i < TABLESIZE; i++)
500 {
501 mTable[i] = (i / (double)STEPS) - 1.0;
502 }
503 }
504 else
505 {
506 for (int i = 0; i < TABLESIZE; i++)
507 {
508 mTable[i] = gain * Cubic(ms, x);
509 for (int j = 0; j < ms.mRepeats; j++)
510 {
511 mTable[i] = gain * Cubic(ms, mTable[i] * amount);
512 }
513 x += stepsize;
514 }
515 }
516}
517
518double
520{
521 if (ms.mParam1 == 0.0)
522 return x;
523
524 return x - (std::pow(x, 3.0) / 3.0);
525}
526
528 const EffectDistortionSettings& ms)
529{
530 double amount = ms.mParam1 / -100.0;
531 // double C = std::sin(std::max(0.001, mParams.mParam2) / 100.0) * 10.0;
532 double C = std::max(0.001, ms.mParam2) / 10.0;
533
534 double step = 1.0 / STEPS;
535 double xval = -1.0;
536
537 for (int i = 0; i < TABLESIZE; i++)
538 {
539 mTable[i] = ((1 + amount) * xval) -
540 (xval * (amount / std::tanh(C)) * std::tanh(C * xval));
541 xval += step;
542 }
543}
544
546{
547 int iter = std::floor(ms.mParam1 / 20.0);
548 double fractionalpart = (ms.mParam1 / 20.0) - iter;
549 double stepsize = 1.0 / STEPS;
550 double linVal = 0.0;
551
552 for (int n = STEPS; n < TABLESIZE; n++)
553 {
554 mTable[n] = linVal;
555 for (int i = 0; i < iter; i++)
556 {
557 mTable[n] = (1.0 + std::sin((mTable[n] * M_PI) - M_PI_2)) / 2.0;
558 }
559 mTable[n] +=
560 (((1.0 + std::sin((mTable[n] * M_PI) - M_PI_2)) / 2.0) - mTable[n]) *
561 fractionalpart;
562 linVal += stepsize;
563 }
564 CopyHalfTable();
565}
566
568{
569 double noiseFloor = DB_TO_LINEAR(ms.mNoiseFloor);
570 int numPasses = ms.mRepeats;
571 double fractionalPass = ms.mParam1 / 100.0;
572
573 const int numPoints = 6;
574 const double gainFactors[numPoints] = { 0.80, 1.00, 1.20, 1.20, 1.00, 0.80 };
575 double gainLimits[numPoints] = { 0.0001, 0.0, 0.1, 0.3, 0.5, 1.0 };
576 double addOnValues[numPoints];
577
578 gainLimits[1] = noiseFloor;
579 /* In the original Leveller effect, behaviour was undefined for threshold >
580 * 20 dB. If we want to support > 20 dB we need to scale the points to keep
581 * them non-decreasing.
582 *
583 * if (noiseFloor > gainLimits[2]) {
584 * for (int i = 3; i < numPoints; i++) {
585 * gainLimits[i] = noiseFloor + ((1 - noiseFloor)*((gainLimits[i] - 0.1) /
586 * 0.9));
587 * }
588 * gainLimits[2] = noiseFloor;
589 * }
590 */
591
592 // Calculate add-on values
593 addOnValues[0] = 0.0;
594 for (int i = 0; i < numPoints - 1; i++)
595 {
596 addOnValues[i + 1] =
597 addOnValues[i] +
598 (gainLimits[i] * (gainFactors[i] - gainFactors[1 + i]));
599 }
600
601 // Positive half of table.
602 // The original effect increased the 'strength' of the effect by
603 // repeated passes over the audio data.
604 // Here we model that more efficiently by repeated passes over a linear
605 // table.
606 for (int n = STEPS; n < TABLESIZE; n++)
607 {
608 mTable[n] = ((double)(n - STEPS) / (double)STEPS);
609 for (int j = 0; j < numPasses; j++)
610 {
611 // Find the highest index for gain adjustment
612 int index = numPoints - 1;
613 for (int i = index; i >= 0 && mTable[n] < gainLimits[i]; i--)
614 {
615 index = i;
616 }
617 // the whole number of 'repeats'
618 mTable[n] = (mTable[n] * gainFactors[index]) + addOnValues[index];
619 }
620 // Extrapolate for fine adjustment.
621 // tiny fractions are not worth the processing time
622 if (fractionalPass > 0.001)
623 {
624 int index = numPoints - 1;
625 for (int i = index; i >= 0 && mTable[n] < gainLimits[i]; i--)
626 {
627 index = i;
628 }
629 mTable[n] += fractionalPass * ((mTable[n] * (gainFactors[index] - 1)) +
630 addOnValues[index]);
631 }
632 }
633 CopyHalfTable();
634}
635
637{
638 double amount = (ms.mParam1 / 50.0) - 1;
639 double stepsize = 1.0 / STEPS;
640 int index = STEPS;
641
642 // positive half of waveform is passed unaltered.
643 for (int n = 0; n <= STEPS; n++)
644 {
645 mTable[index] = n * stepsize;
646 index += 1;
647 }
648
649 // negative half of table
650 index = STEPS - 1;
651 for (int n = 1; n <= STEPS; n++)
652 {
653 mTable[index] = n * stepsize * amount;
654 index--;
655 }
656}
657
660{
661 // The LADSPA "hardLimiter 1413" is basically hard clipping,
662 // but with a 'kind of' wet/dry mix:
663 // out = ((wet-residual)*clipped) + (residual*in)
664 HardClip(state, settings);
665}
666
667// Helper functions for lookup tables
668
670{
671 // Copy negative half of table from positive half
672 int count = TABLESIZE - 1;
673 for (int n = 0; n < STEPS; n++)
674 {
675 mTable[n] = -mTable[count];
676 count--;
677 }
678}
679
681 float sample, EffectDistortionSettings& ms)
682{
683 float out;
684 int index;
685 double xOffset;
686 double amount = 1;
687
688 switch (ms.mTableChoiceIndx)
689 {
690 // Do any pre-processing here
691 case kHardClip:
692 // Pre-gain
693 amount = ms.mParam1 / 100.0;
694 sample *= 1 + amount;
695 break;
696 default:
697 break;
698 }
699
700 index = std::floor(sample * STEPS) + STEPS;
701 index = std::max<int>(std::min<int>(index, 2 * STEPS - 1), 0);
702 xOffset = ((1 + sample) * STEPS) - index;
703 xOffset = std::min<double>(std::max<double>(xOffset, 0.0), 1.0); // Clip at 0dB
704
705 // linear interpolation: y = y0 + (y1-y0)*(x-x0)
706 out = mTable[index] + (mTable[index + 1] - mTable[index]) * xOffset;
707
708 return out;
709}
710
712 EffectDistortionState& data, float sample)
713{
714 // Rolling average gives less offset at the start than an IIR filter.
715 const unsigned int queueLength = std::floor(data.samplerate / 20.0);
716
717 data.queuetotal += sample;
718 data.queuesamples.push(sample);
719
720 if (data.queuesamples.size() > queueLength)
721 {
722 data.queuetotal -= data.queuesamples.front();
723 data.queuesamples.pop();
724 }
725
726 return sample - (data.queuetotal / data.queuesamples.size());
727}
int min(int a, int b)
#define M_PI_2
Definition: Distortion.cpp:25
#define M_PI
Definition: Distortion.cpp:22
#define STEPS
static const struct @103 FactoryPresets[]
EffectDistortionSettings params
#define skipsamples
const TranslatableString name
#define TABLESIZE
EffectType
@ EffectTypeProcess
ChannelName
std::optional< std::unique_ptr< EffectSettingsAccess::Message > > OptionalMessage
XO("Cut/Copy/Paste")
std::vector< RegistryPath > RegistryPaths
Definition: Identifier.h:219
#define DB_TO_LINEAR(x)
Definition: MemoryX.h:338
static TranslatableStrings names
Definition: TagsEditor.cpp:153
static Settings & settings()
Definition: TrackInfo.cpp:51
int id
Generates EffectParameterMethods overrides from variadic template arguments.
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
A WaveShaper distortion effect.
static constexpr EffectParameter DCBlock
static const EnumValueSymbol kTableTypeStrings[nTableTypes]
std::shared_ptr< EffectInstance > MakeInstance() const override
Make an object maintaining short-term state of an Effect.
OptionalMessage DoLoadFactoryPreset(int id, EffectSettings &settings)
static constexpr EffectParameter NoiseFloor
virtual ~DistortionBase()
RealtimeSince RealtimeSupport() const override
Since which version of Audacity has the effect supported realtime?
static constexpr EffectParameter Threshold_dB
static const ComponentInterfaceSymbol Symbol
TranslatableString GetDescription() const override
static constexpr EnumParameter TableTypeIndx
OptionalMessage LoadFactoryPreset(int id, EffectSettings &settings) const override
RegistryPaths GetFactoryPresets() const override
Report names of factory presets.
static constexpr EffectParameter Repeats
static constexpr EffectParameter Param1
EffectType GetType() const override
Type determines how it behaves.
ManualPageID ManualPage() const override
Name of a page in the Audacity alpha manual, default is empty.
static constexpr EffectParameter Param2
const EffectParameterMethods & Parameters() const override
ComponentInterfaceSymbol GetSymbol() const override
void SetLinearEffectFlag(bool linearEffectFlag)
Definition: EffectBase.cpp:210
RealtimeSince
In which versions of Audacity was an effect realtime capable?
std::queue< float > queuesamples
Hold values to send to effect output meters.
Interface for manipulations of an Effect's settings.
static EffectDistortionSettings & GetSettings(EffectSettings &settings)
Assume settings originated from MakeSettings() and copies thereof.
Definition: Effect.h:166
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
__finl float_x4 __vecc sqrt(const float_x4 &a)
void Rectifier(const EffectDistortionSettings &)
size_t InstanceProcess(EffectSettings &settings, EffectDistortionState &data, const float *const *inBlock, float *const *outBlock, size_t blockLen)
bool RealtimeAddProcessor(EffectSettings &settings, EffectOutputs *pOutputs, unsigned numChannels, float sampleRate) override
void SineTable(const EffectDistortionSettings &)
void EvenHarmonicTable(const EffectDistortionSettings &)
unsigned GetAudioOutCount() const override
How many output buffers to allocate at once.
void LogarithmicTable(const EffectDistortionSettings &)
size_t ProcessBlock(EffectSettings &settings, const float *const *inBlock, float *const *outBlock, size_t blockLen) override
Called for destructive effect computation.
void InstanceInit(EffectDistortionState &data, EffectSettings &settings, float sampleRate)
size_t RealtimeProcess(size_t group, EffectSettings &settings, const float *const *inbuf, float *const *outbuf, size_t numSamples) override
void MakeTable(EffectDistortionState &state, const EffectDistortionSettings &ms)
float LogCurve(double threshold, float value, double ratio)
bool RealtimeInitialize(EffectSettings &settings, double) override
float DCFilter(EffectDistortionState &data, float sample)
float WaveShaper(float sample, EffectDistortionSettings &ms)
unsigned GetAudioInCount() const override
How many input buffers to allocate at once.
void HardLimiter(EffectDistortionState &state, const EffectDistortionSettings &)
bool RealtimeFinalize(EffectSettings &settings) noexcept override
void HalfSinTable(const EffectDistortionSettings &)
void ExponentialTable(const EffectDistortionSettings &)
void Leveller(const EffectDistortionSettings &)
void CubicTable(const EffectDistortionSettings &)
void SoftClip(EffectDistortionState &, const EffectDistortionSettings &)
double Cubic(const EffectDistortionSettings &, double x)
bool ProcessInitialize(EffectSettings &settings, double sampleRate, ChannelNames chanMap) override
void HardClip(EffectDistortionState &, const EffectDistortionSettings &)
Externalized state of a plug-in.