From a3b1018a65a19e78d66e01a3eaaef0c4313f92ed Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 29 Jul 2021 09:03:54 -0400 Subject: [PATCH] More waveshaper shapes and infrastructure (#4788) 1. Fix a register bug in dcBlocker which only came into effect if you use R1/R2 != 0,1 2. Add a 'soft rectified' which is SOFT(2|x|-1) using ADAA, TANH and dcBlock in combination Addresses #1964 --- src/common/FilterConfiguration.h | 44 +++++++----------------- src/common/dsp/QuadFilterWaveshapers.cpp | 36 ++++++++++++++++--- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/src/common/FilterConfiguration.h b/src/common/FilterConfiguration.h index da8f3bbede7..5e49f13dd6f 100644 --- a/src/common/FilterConfiguration.h +++ b/src/common/FilterConfiguration.h @@ -465,6 +465,7 @@ enum ws_type wst_fwrectify, wst_poswav, wst_negwav, + wst_softrect, wst_singlefold, wst_dualfold, @@ -487,41 +488,21 @@ enum ws_type n_ws_types, }; -const char wst_names[n_ws_types][16] = {"Off", - "Soft", - "Hard", - "Asymmetric", - "Sine", - "Digital", - "Soft Harm 2", - "Soft Harm 3", - "Soft Harm 4", - "Soft Harm 5", - "Abs Full Wave", - "Positive Wave", - "Negative Wave", - "Single Fold", - "Double Fold", - "WestCoast Fold", - "Additive 1+2", - "Additive 1+3", - "Additive 1+4", - "Additive 1+5", - "Additive 1234", - "Additive Saw 3", - "Additive Sqr 3", - - "Fuzz", - "Fuzz SoftClip", - "Heavy Fuzz", - "Fuzz Center" +const char wst_names[n_ws_types][16] = { + "Off", "Soft", "Hard", "Asymmetric", "Sine", + "Digital", "Soft Harm 2", "Soft Harm 3", "Soft Harm 4", "Soft Harm 5", + "Abs Full Wave", "Positive Wave", "Negative Wave", "Soft Rectified", "Single Fold", + "Double Fold", "WestCoast Fold", "Additive 1+2", "Additive 1+3", "Additive 1+4", + "Additive 1+5", "Additive 1234", "Additive Saw 3", "Additive Sqr 3", + + "Fuzz", "Fuzz SoftClip", "Heavy Fuzz", "Fuzz Center" }; const char wst_ui_names[n_ws_types][16] = { - "Off", "Soft", "Hard", "Asym", "Sine", "Digi", "Harm 2", "Harm 3", "Harm 4", - "Harm 5", "Abs", "Pos", "Neg", "1Fold", "2Fold", "WstFold", "+12", "+13", - "+14", "+15", "+12345", "+Saw3", "+Sqr3", "Fuzz", "FzSft", "FzHvy", "FzCtr"}; + "Off", "Soft", "Hard", "Asym", "Sine", "Digi", "Harm 2", "Harm 3", "Harm 4", "Harm 5", + "Abs", "Pos", "Neg", "SRect", "1Fold", "2Fold", "WstFold", "+12", "+13", "+14", + "+15", "+12345", "+Saw3", "+Sqr3", "Fuzz", "FzSft", "FzHvy", "FzCtr"}; struct WaveShaperSelectorMapper : public ParameterDiscreteIndexRemapper { @@ -556,6 +537,7 @@ struct WaveShaperSelectorMapper : public ParameterDiscreteIndexRemapper p(wst_fwrectify, "Rectify"); p(wst_poswav, "Rectify"); p(wst_negwav, "Rectify"); + p(wst_softrect, "Rectify"); p(wst_singlefold, "Folders"); p(wst_dualfold, "Folders"); diff --git a/src/common/dsp/QuadFilterWaveshapers.cpp b/src/common/dsp/QuadFilterWaveshapers.cpp index 1aae11147a5..d9315ebf454 100644 --- a/src/common/dsp/QuadFilterWaveshapers.cpp +++ b/src/common/dsp/QuadFilterWaveshapers.cpp @@ -198,8 +198,8 @@ template inline __m128 dcBlock(QuadFilterWaveshaperState *__res // https://www.dsprelated.com/freebooks/filters/DC_Blocker.html // y_n = x_n - x_n-1 + R y_n-1 const auto fac = _mm_set1_ps(0.9999); - auto dx = _mm_sub_ps(x, s->R[0]); - auto filtval = _mm_add_ps(dx, _mm_mul_ps(fac, s->R[1])); + auto dx = _mm_sub_ps(x, s->R[R1]); + auto filtval = _mm_add_ps(dx, _mm_mul_ps(fac, s->R[R2])); s->R[R1] = x; s->R[R2] = filtval; s->init = _mm_setzero_ps(); @@ -436,8 +436,10 @@ __m128 PlusSqr3(QuadFilterWaveshaperState *__restrict s, __m128 in, __m128 drive /* * Given a function which is from x -> (F, adF) and two registers, do the ADAA + * Set updateInit to false if you are going to wrap this in a dcBlocker (which + * resets init itself) or other init adjusting function. */ -template +template __m128 ADAA(QuadFilterWaveshaperState *__restrict s, __m128 x) { auto xPrior = s->R[xR]; @@ -460,7 +462,10 @@ __m128 ADAA(QuadFilterWaveshaperState *__restrict s, __m128 x) s->R[xR] = x; s->R[aR] = ad; - s->init = _mm_setzero_ps(); + if (updateInit) + { + s->init = _mm_setzero_ps(); + } return r; } @@ -528,6 +533,27 @@ __m128 ADAA_FULL_WAVE(QuadFilterWaveshaperState *__restrict s, __m128 x, __m128 return ADAA(s, x); } +void softrect_kernel(__m128 x, __m128 &F, __m128 &adF) +{ + /* + * F : x > 0 ? 2x-1 : -2x - 1 = 2 * ( sgn(x) * x ) - 1 + * adF : x > 0 ? x^2-x : -x^2 - x = sgn(x) * x^2 - x + */ + static const auto p2 = _mm_set1_ps(2.f); + static const auto p1 = _mm_set1_ps(1.f); + static const auto p05 = _mm_set1_ps(0.5f); + auto gz = _mm_cmpge_ps(x, _mm_setzero_ps()); + auto sgn = _mm_sub_ps(_mm_and_ps(gz, p1), _mm_andnot_ps(gz, p1)); + + F = _mm_sub_ps(_mm_mul_ps(p2, _mm_mul_ps(sgn, x)), p1); + adF = _mm_sub_ps(_mm_mul_ps(sgn, _mm_mul_ps(x, x)), x); +} + +__m128 ADAA_SOFTRECT_WAVE(QuadFilterWaveshaperState *__restrict s, __m128 x, __m128 drive) +{ + return TANH(s, dcBlock<2, 3>(s, ADAA(s, x)), drive); +} + template struct FolderADAA { FolderADAA(std::initializer_list xi, std::initializer_list yi) @@ -661,6 +687,8 @@ WaveshaperQFPtr GetQFPtrWaveshaper(int type) return CHEBY_CORE; case wst_fwrectify: return ADAA_FULL_WAVE; + case wst_softrect: + return ADAA_SOFTRECT_WAVE; case wst_poswav: return ADAA_POS_WAVE<0, 1>; case wst_negwav: