diff --git a/src/fx_components.cpp b/src/fx_components.cpp index e2ec3b4..9dd0665 100644 --- a/src/fx_components.cpp +++ b/src/fx_components.cpp @@ -56,8 +56,8 @@ void FastLFO::setNormalizedFrequency(float32_t normalized_frequency) this->frequency_ = frequency; this->unitary_frequency_ = this->frequency_ / this->getSamplingRate(); - this->nb_sub_increment_ = (frequency >= 3.0f ? 1 : 300); - this->unitary_frequency_ *= this->nb_sub_increment_; + this->nb_sub_increment_ = (frequency >= 3.0f ? 10 : 100); + this->unitary_frequency_ *= static_cast(this->nb_sub_increment_); this->updateCoefficient(); } @@ -78,8 +78,8 @@ void FastLFO::setFrequency(float32_t frequency) this->frequency_ = frequency; this->unitary_frequency_ = this->frequency_ / this->getSamplingRate(); - this->nb_sub_increment_ = (frequency >= 3.0f ? 1 : 300); - this->unitary_frequency_ *= this->nb_sub_increment_; + this->nb_sub_increment_ = (frequency >= 3.0f ? 10 : (frequency < 0.1f ? 1000 : 100)); + this->unitary_frequency_ *= static_cast(this->nb_sub_increment_); this->updateCoefficient(); } @@ -92,27 +92,6 @@ float32_t FastLFO::getFrequency() const void FastLFO::updateCoefficient() { - // float32_t frequency = this->unitary_frequency_ * 1.00669889338314f; - - // float32_t sign = 16.0f; - // frequency -= 0.25f; - // if(frequency < 0.0f) - // { - // frequency = -frequency; - // } - // else - // { - // if(frequency > 0.5f) - // { - // frequency -= 0.5f; - // } - // else - // { - // sign = -16.0f; - // } - // } - - // this->iir_coefficient_ = sign * frequency * (1.0f - 2.0f * frequency); this->iir_coefficient_ = 2.0f * cos(Constants::M2PI * this->unitary_frequency_); this->initial_amplitude_ = this->iir_coefficient_ * 0.25f; @@ -121,6 +100,7 @@ void FastLFO::updateCoefficient() void FastLFO::reset() { + static const float32_t epsi = 2e-7; static const float32_t epsilon = 1e-3; this->sub_increment_ = 0.0f; @@ -134,8 +114,10 @@ void FastLFO::reset() return; } + float32_t p_i = Constants::M2PI * this->unitary_frequency_ / static_cast(this->nb_sub_increment_); float32_t p = Constants::MPI_2; + float32_t oldP = 1000.0f; float32_t t_p = this->InitialPhase; const float32_t target = sin(this->InitialPhase); if(t_p < p) @@ -145,8 +127,14 @@ void FastLFO::reset() float32_t tuning = -3.0f; while(p < t_p || abs(tuning - target) > epsilon) { + oldP = p; tuning = this->process(); p += p_i; + if(oldP == p) + { + return; + } + // std::cout << "p = " << p << "; p_i = " << p_i << "; t_p = " << t_p << "; tuning = " << tuning << "; target = " << target << std::endl; } } diff --git a/src/test/test_fx_components.cpp b/src/test/test_fx_components.cpp index e5be074..8bf7738 100644 --- a/src/test/test_fx_components.cpp +++ b/src/test/test_fx_components.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "test_fx_helper.h" @@ -126,24 +127,172 @@ TEST(CppOptimization, InterpolatedSineOscillatorPrecisionTest) EXPECT_GT(epsilon, max_delta); } -TEST(CppOptimization, FastLFOPrecisionTest) +void testFastLFOPrecision(float32_t freq, float32_t init_phase) { - const float32_t freq = 0.15f; const size_t NB = static_cast(2.0f * SAMPLING_FREQUENCY); + const float32_t init_phase_deg = init_phase * 180.0f / PI; - const float32_t epsilon = 1e-3; + const float32_t epsilon = 40e-3; - ComplexLFO lfo1(SAMPLING_FREQUENCY, 0.0f, 10.0f, 0.0f, true); - FastLFO lfo2(SAMPLING_FREQUENCY, 0.0f, 10.0f, 0.0f, true); + ComplexLFO lfo1(SAMPLING_FREQUENCY, 0.0f, 220.0f, init_phase, true); + FastLFO lfo2(SAMPLING_FREQUENCY, 0.0f, 220.0f, init_phase, true); lfo1.setFrequency(freq); lfo2.setFrequency(freq); + + std::string file1 = string("testFastLFOPrecision.ComplexLFO.") + std::to_string(freq) + "Hz-" + std::to_string(init_phase_deg) + ".data"; + std::string file2 = string("testFastLFOPrecision.FastLFO.") + std::to_string(freq) + "Hz-" + std::to_string(init_phase_deg) + ".data"; + std::string file3 = string("testFastLFOPrecision.") + std::to_string(freq) + "Hz-" + std::to_string(init_phase_deg) + ".data.m"; + + std::ofstream _lfo1(getResultFile(file1, true)); + std::ofstream _lfo2(getResultFile(file2, true)); + std::ofstream _m(getResultFile(file3, true)); + float32_t max_delta = 0.0f; for(size_t i = 0; i < NB; ++i) { float32_t v1 = lfo1.process(); float32_t v2 = lfo2.process(); + _lfo1 << std::setprecision(6) << std::fixed << v1 << ((i == (NB - 1)) ? "" : ", "); + _lfo2 << std::setprecision(6) << std::fixed << v2 << ((i == (NB - 1)) ? "" : ", "); + max_delta = std::max(max_delta, std::abs(v1 - v2)); } + + _lfo1.close(); + _lfo2.close(); + + _m << "# Tests of FastLFO precision:" << std::endl; + _m << std::setprecision(2) << std::fixed << "# + frequency: " << freq << " Hz" << std::endl; + _m << std::setprecision(2) << std::fixed << "# + initial phase: " << init_phase << std::endl; + _m << std::endl; + _m << "time = 0 : " << (NB - 1) << ";" << std::endl; + _m << "cplx_lfo = load(\"-ascii\", \"" << file1 << "\");" << std::endl; + _m << "fast_lfo = load(\"-ascii\", \"" << file2 << "\");" << std::endl; + _m << "plot(time, cplx_lfo, '-b', 'LineWidth', 6, time, fast_lfo, '-r', 'LineWidth', 4);" << std::endl; + _m << "title('LFO tuning @ " << freq << "Hz / " << init_phase_deg << "°');" << std::endl; + _m << "legend('ComplexLFO', 'FastLFO');" << std::endl; + _m.close(); + EXPECT_GT(epsilon, max_delta); } + +TEST(CppOptimization, FastLFOPrecisionTest0_01Hz) +{ + const float32_t freq = 0.01f; + testFastLFOPrecision(freq, 0.0f); + testFastLFOPrecision(freq, PI / 6.0f); + testFastLFOPrecision(freq, PI / 3.0f); + testFastLFOPrecision(freq, PI / 2.0f); + testFastLFOPrecision(freq, 2.0f * PI / 3.0f); + testFastLFOPrecision(freq, 3.0f * PI / 4.0f); + testFastLFOPrecision(freq, 3.0f * PI / 2.0f); +} + +TEST(CppOptimization, FastLFOPrecisionTest0_15Hz) +{ + const float32_t freq = 0.15f; + testFastLFOPrecision(freq, 0.0f); + testFastLFOPrecision(freq, PI / 6.0f); + testFastLFOPrecision(freq, PI / 3.0f); + testFastLFOPrecision(freq, PI / 2.0f); + testFastLFOPrecision(freq, 2.0f * PI / 3.0f); + testFastLFOPrecision(freq, 3.0f * PI / 4.0f); + testFastLFOPrecision(freq, 3.0f * PI / 2.0f); +} + +TEST(CppOptimization, FastLFOPrecisionTest0_2Hz) +{ + const float32_t freq = 0.2f; + testFastLFOPrecision(freq, 0.0f); + testFastLFOPrecision(freq, PI / 6.0f); + testFastLFOPrecision(freq, PI / 3.0f); + testFastLFOPrecision(freq, PI / 2.0f); + testFastLFOPrecision(freq, 2.0f * PI / 3.0f); + testFastLFOPrecision(freq, 3.0f * PI / 4.0f); + testFastLFOPrecision(freq, 3.0f * PI / 2.0f); +} + +TEST(CppOptimization, FastLFOPrecisionTest0_3Hz) +{ + const float32_t freq = 0.3f; + testFastLFOPrecision(freq, 0.0f); + testFastLFOPrecision(freq, PI / 6.0f); + testFastLFOPrecision(freq, PI / 3.0f); + testFastLFOPrecision(freq, PI / 2.0f); + testFastLFOPrecision(freq, 2.0f * PI / 3.0f); + testFastLFOPrecision(freq, 3.0f * PI / 4.0f); + testFastLFOPrecision(freq, 3.0f * PI / 2.0f); +} + +TEST(CppOptimization, FastLFOPrecisionTest0_5Hz) +{ + const float32_t freq = 0.5f; + testFastLFOPrecision(freq, 0.0f); + testFastLFOPrecision(freq, PI / 6.0f); + testFastLFOPrecision(freq, PI / 3.0f); + testFastLFOPrecision(freq, PI / 2.0f); + testFastLFOPrecision(freq, 2.0f * PI / 3.0f); + testFastLFOPrecision(freq, 3.0f * PI / 4.0f); + testFastLFOPrecision(freq, 3.0f * PI / 2.0f); +} + +TEST(CppOptimization, FastLFOPrecisionTest1Hz) +{ + const float32_t freq = 1.0f; + testFastLFOPrecision(freq, 0.0f); + testFastLFOPrecision(freq, PI / 6.0f); + testFastLFOPrecision(freq, PI / 3.0f); + testFastLFOPrecision(freq, PI / 2.0f); + testFastLFOPrecision(freq, 2.0f * PI / 3.0f); + testFastLFOPrecision(freq, 3.0f * PI / 4.0f); + testFastLFOPrecision(freq, 3.0f * PI / 2.0f); +} + +TEST(CppOptimization, FastLFOPrecisionTest2_15Hz) +{ + const float32_t freq = 2.15f; + testFastLFOPrecision(freq, 0.0f); + testFastLFOPrecision(freq, PI / 6.0f); + testFastLFOPrecision(freq, PI / 3.0f); + testFastLFOPrecision(freq, PI / 2.0f); + testFastLFOPrecision(freq, 2.0f * PI / 3.0f); + testFastLFOPrecision(freq, 3.0f * PI / 4.0f); + testFastLFOPrecision(freq, 3.0f * PI / 2.0f); +} + +TEST(CppOptimization, FastLFOPrecisionTest5Hz) +{ + const float32_t freq = 5.0f; + testFastLFOPrecision(freq, 0.0f); + testFastLFOPrecision(freq, PI / 6.0f); + testFastLFOPrecision(freq, PI / 3.0f); + testFastLFOPrecision(freq, PI / 2.0f); + testFastLFOPrecision(freq, 2.0f * PI / 3.0f); + testFastLFOPrecision(freq, 3.0f * PI / 4.0f); + testFastLFOPrecision(freq, 3.0f * PI / 2.0f); +} + +TEST(CppOptimization, FastLFOPrecisionTest10_5Hz) +{ + const float32_t freq = 10.5f; + testFastLFOPrecision(freq, 0.0f); + testFastLFOPrecision(freq, PI / 6.0f); + testFastLFOPrecision(freq, PI / 3.0f); + testFastLFOPrecision(freq, PI / 2.0f); + testFastLFOPrecision(freq, 2.0f * PI / 3.0f); + testFastLFOPrecision(freq, 3.0f * PI / 4.0f); + testFastLFOPrecision(freq, 3.0f * PI / 2.0f); +} + +TEST(CppOptimization, FastLFOPrecisionTest120_5Hz) +{ + const float32_t freq = 120.5f; + testFastLFOPrecision(freq, 0.0f); + testFastLFOPrecision(freq, PI / 6.0f); + testFastLFOPrecision(freq, PI / 3.0f); + testFastLFOPrecision(freq, PI / 2.0f); + testFastLFOPrecision(freq, 2.0f * PI / 3.0f); + testFastLFOPrecision(freq, 3.0f * PI / 4.0f); + testFastLFOPrecision(freq, 3.0f * PI / 2.0f); +}