From 2318df9856b11798cdc37567c6a2d0f5ed344947 Mon Sep 17 00:00:00 2001 From: Paul Walker Date: Sat, 25 Jan 2020 13:05:06 -0500 Subject: [PATCH] Fix a Sus=0 special case with quadratic ditigal decay In a special case of the digital envelope decay type 1 and sustain exactly 0, you would oscillate away from zero rather than getting there. There's a math reason for this but it is undesirable so fix this special case with a limit if. Closes #1509 --- src/common/dsp/AdsrEnvelope.h | 6 ++++++ src/headless/UnitTestsMOD.cpp | 39 ++++++++++++++++++++++++++--------- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/common/dsp/AdsrEnvelope.h b/src/common/dsp/AdsrEnvelope.h index 64b8cdfbbab..fbaa5108a08 100644 --- a/src/common/dsp/AdsrEnvelope.h +++ b/src/common/dsp/AdsrEnvelope.h @@ -267,6 +267,7 @@ class AdsrEnvelope : public ModulationSource envelope_rate_linear(lc[d].f) * (adsr->d.temposync ? storage->temposyncratio : 1.f); float l_lo, l_hi; + switch (lc[d_s].i) { case 1: @@ -274,6 +275,11 @@ class AdsrEnvelope : public ModulationSource float sx = sqrt(phase); l_lo = phase - 2 * sx * rate + rate * rate; l_hi = phase + 2 * sx * rate + rate * rate; + // That + rate * rate in both means at low sustain ( < 1e-3 or so) you end up with + // lo and hi both pushing us up off sustain. Unfortunatley we ned to handle that case + // specially by pushing lo down + if( lc[s].f < 1e-3 && phase < 1e-3 ) + l_lo = 0; } break; case 2: diff --git a/src/headless/UnitTestsMOD.cpp b/src/headless/UnitTestsMOD.cpp index 7c6303b9fd8..55cf8432890 100644 --- a/src/headless/UnitTestsMOD.cpp +++ b/src/headless/UnitTestsMOD.cpp @@ -46,7 +46,12 @@ TEST_CASE( "ADSR Envelope Behaviour", "[mod]" ) { p->set_value_f01( p->value_to_normalized( limit_range( vn, p->val_min.f, p->val_max.f ) ) ); }; - + + auto svni = [](Parameter *p, int vn) + { + p->val.i = vn; + }; + auto inverseEnvtime = [](float desiredTime) { // 2^x = desired time @@ -59,9 +64,9 @@ TEST_CASE( "ADSR Envelope Behaviour", "[mod]" ) svn(&(adsrstorage->s), s); svn(&(adsrstorage->r), inverseEnvtime(r)); - svn(&(adsrstorage->a_s), a_s); - svn(&(adsrstorage->d_s), d_s); - svn(&(adsrstorage->r_s), r_s); + svni(&(adsrstorage->a_s), a_s); + svni(&(adsrstorage->d_s), d_s); + svni(&(adsrstorage->r_s), r_s); adsrstorage->mode.val.b = isAnalog; @@ -116,8 +121,8 @@ TEST_CASE( "ADSR Envelope Behaviour", "[mod]" ) { int ldir = 0; if( v > 0.999999f ) ldir = dir; // sometimes we get a double '1' - if( fabs( v - pv ) < 5e-6 && fabs( v ) < 1e-5) ldir = 0; // bouncing off of 0 is annoying - else if( fabs( v - pv ) < 5e-7 ) ldir = 0; + if( turns.size() > 1 && fabs( v - pv ) < 5e-6 && fabs( v ) < 1e-5) ldir = 0; // bouncing off of 0 is annoying + else if( fabs( v - pv ) < 1e-7 ) ldir = 0; else if( v > pv ) ldir = 1; else ldir = -1; @@ -144,8 +149,7 @@ TEST_CASE( "ADSR Envelope Behaviour", "[mod]" ) auto simple = runAdsr( a, d, s, r, a_s, d_s, r_s, isAnalog, a + d + sustime, totaltime ); auto sturns = detectTurnarounds(simple); - if( false ) - std::cout << "ADSR: " << a << " " << d << " " << s << " " << r << " switches: " << a_s << " " << d_s << " " << r_s << std::endl; + INFO( "ADSR: " << a << " " << d << " " << s << " " << r << " switches: " << a_s << " " << d_s << " " << r_s ); if( s == 0 ) { if( sturns.size() != 3 ) @@ -169,6 +173,7 @@ TEST_CASE( "ADSR Envelope Behaviour", "[mod]" ) { for( auto s : simple ) std::cout << s.first << " " << s.second << std::endl; + std::cout << "TURNS" << std::endl; for( auto s : sturns ) std::cout << s.first << " " << s.second << std::endl; } @@ -216,7 +221,22 @@ TEST_CASE( "ADSR Envelope Behaviour", "[mod]" ) } } } - + + SECTION( "Quadrtic Digital hits Zero" ) + { + auto res = runAdsr( 0.1, 0.1, 0.0, 0.1, + 0, 1, 0, + false, + 0.4, 0.5 ); + for( auto p : res ) + { + if( p.first > 0.22 ) + { + REQUIRE( p.second == 0.f ); + } + } + } + SECTION( "Test the Analog Envelope" ) { // OK so we can't check the same thing here since the turns aren't as tight in analog mode @@ -488,7 +508,6 @@ TEST_CASE( "ADSR Envelope Behaviour", "[mod]" ) testSusPush( s1, s2 ); } } - } TEST_CASE( "Non-MPE pitch bend", "[mod]" )