From 765324f319b2ba5f2d25f53c0d0e80788e6e5683 Mon Sep 17 00:00:00 2001 From: jatin Date: Sun, 21 Jan 2024 23:02:39 -0800 Subject: [PATCH] Re-organizing --- src/CMakeLists.txt | 2 +- src/processors/ProcessorStore.cpp | 2 +- .../other/{ => poly_octave}/PolyOctave.cpp | 156 +---------------- .../other/{ => poly_octave}/PolyOctave.h | 0 .../poly_octave/PolyOctaveFilterBandHelpers.h | 163 ++++++++++++++++++ 5 files changed, 169 insertions(+), 154 deletions(-) rename src/processors/other/{ => poly_octave}/PolyOctave.cpp (51%) rename src/processors/other/{ => poly_octave}/PolyOctave.h (100%) create mode 100644 src/processors/other/poly_octave/PolyOctaveFilterBandHelpers.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 28256b31..f44c1192 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -136,11 +136,11 @@ target_sources(BYOD PRIVATE processors/other/LevelDetective.cpp processors/other/Gate.cpp processors/other/Octaver.cpp - processors/other/PolyOctave.cpp processors/other/ShimmerReverb.cpp processors/other/SmoothReverb.cpp processors/other/cry_baby/CryBaby.cpp processors/other/cry_baby/CryBabyNDK.cpp + processors/other/poly_octave/PolyOctave.cpp processors/other/spring_reverb/SpringReverb.cpp processors/other/spring_reverb/SpringReverbProcessor.cpp processors/other/krusher/Krusher.cpp diff --git a/src/processors/ProcessorStore.cpp b/src/processors/ProcessorStore.cpp index 4a645b38..f56df9b7 100644 --- a/src/processors/ProcessorStore.cpp +++ b/src/processors/ProcessorStore.cpp @@ -57,11 +57,11 @@ #include "other/Gate.h" #include "other/LevelDetective.h" #include "other/Octaver.h" -#include "other/PolyOctave.h" #include "other/ShimmerReverb.h" #include "other/SmoothReverb.h" #include "other/cry_baby/CryBaby.h" #include "other/krusher/Krusher.h" +#include "other/poly_octave/PolyOctave.h" #include "other/spring_reverb/SpringReverbProcessor.h" #include "utility/CleanGain.h" diff --git a/src/processors/other/PolyOctave.cpp b/src/processors/other/poly_octave/PolyOctave.cpp similarity index 51% rename from src/processors/other/PolyOctave.cpp rename to src/processors/other/poly_octave/PolyOctave.cpp index 0cd7e6f4..cc732bbf 100644 --- a/src/processors/other/PolyOctave.cpp +++ b/src/processors/other/poly_octave/PolyOctave.cpp @@ -1,4 +1,5 @@ #include "PolyOctave.h" +#include "PolyOctaveFilterBandHelpers.h" #include "processors/ParameterHelpers.h" namespace PolyOctaveTags @@ -8,155 +9,6 @@ const String upOctaveTag = "up_octave"; const String up2OctaveTag = "up2_octave"; } // namespace PolyOctaveTags -namespace FilterBankHelpers -{ -// Reference for filter-bank design and octave shifting: -// https://aaltodoc.aalto.fi/server/api/core/bitstreams/ff9e52cf-fd79-45eb-b695-93038244ec0e/content - -using float_2 = PolyOctave::ComplexERBFilterBank::float_2; -static_assert (float_2::size == 2); -static constexpr auto vec_size = float_2::size; - -template -inline float_2 processSample (const chowdsp::IIRFilter<4, float_2>& f, std::array& z, float_2 x) -{ - auto y = z[1]; - if constexpr (! isImag) - y += x * f.b[0]; // for the imaginary filter, we know that b[0] == 0 - - z[1] = z[2] + x * f.b[1] - y * f.a[1]; - z[2] = z[3] + x * f.b[2] - y * f.a[2]; - z[3] = z[4] + x * f.b[3] - y * f.a[3]; - z[4] = x * f.b[4] - y * f.a[4]; - - return y; -} - -static constexpr auto q_c = 4.0; -static void designERBFilter (size_t erb_index, - double gamma, - double erb_start, - double q_ERB, - double sample_rate, - double (&b_coeffs_cplx_real)[5], - double (&b_coeffs_cplx_imag)[5], - double (&a_coeffs_cplx)[5]) -{ - const auto q_PS = gamma; - - const auto z = erb_start + static_cast (erb_index) * (q_c / q_ERB); - const auto center_target_freq = 228.7 * (std::pow (10.0, z / 21.3) - 1.0); - const auto filter_q = (1.0 / (q_PS * q_ERB)) * (24.7 + 0.108 * center_target_freq); - - double b_coeffs_proto[3]; - double a_coeffs_proto[3]; - chowdsp::CoefficientCalculators::calcSecondOrderBPF (b_coeffs_proto, - a_coeffs_proto, - center_target_freq / gamma, - filter_q * 0.5, - sample_rate); - - auto pole = (std::sqrt (std::pow (std::complex { a_coeffs_proto[1] }, 2.0) - 4.0 * a_coeffs_proto[2]) - a_coeffs_proto[1]) / 2.0; - auto conj_pole = std::conj (pole); - if (std::imag (pole) < 0.0) - pole = conj_pole; - else if (std::imag (conj_pole) < 0.0) - conj_pole = pole; - auto at = -(pole + conj_pole); - auto att = pole * conj_pole; - - auto ar1 = std::real (at); - auto ai1 = std::imag (at); - auto ar2 = std::real (att); - auto ai2 = std::imag (att); - - // a[] = 1 + 2 ar1 z + (ai1^2 + ar1^2 + 2 ar2) z^2 + (2 ai1 ai2 + 2 ar1 ar2) z^3 + (ai2^2 + ar2^2) z^4 - a_coeffs_cplx[0] = 1.0; - a_coeffs_cplx[1] = 2.0 * ar1; - a_coeffs_cplx[2] = ai1 * ai1 + ar1 * ar1 + 2.0 * ar2; - a_coeffs_cplx[3] = 2.0 * ai1 * ai2 + 2.0 * ar1 * ar2; - a_coeffs_cplx[4] = ai2 * ai2 + ar2 * ar2; - - // b_real[] = b0 + (ar1 b0 + b1) z + (ar2 b0 + ar1 b1 + b2) z^2 + (ar2 b1 + ar1 b2) z^3 + ar2 b2 z^4 - b_coeffs_cplx_real[0] = b_coeffs_proto[0]; - b_coeffs_cplx_real[1] = ar1 * b_coeffs_proto[0] + b_coeffs_proto[1]; - b_coeffs_cplx_real[2] = ar2 * b_coeffs_proto[0] + ar1 * b_coeffs_proto[1] + b_coeffs_proto[2]; - b_coeffs_cplx_real[3] = ar2 * b_coeffs_proto[1] + ar1 * b_coeffs_proto[2]; - b_coeffs_cplx_real[4] = ar2 * b_coeffs_proto[2]; - - // b_imag[] = -ai1 b0 z - (ai2 b0 + ai1 b1) z^2 - (ai2 b1 + ai1 br) z^3 - ai2 br z^4 - b_coeffs_cplx_imag[0] = 0.0; - b_coeffs_cplx_imag[1] = -ai1 * b_coeffs_proto[0]; - b_coeffs_cplx_imag[2] = -ai2 * b_coeffs_proto[0] - ai1 * b_coeffs_proto[1]; - b_coeffs_cplx_imag[3] = -ai2 * b_coeffs_proto[1] - ai1 * b_coeffs_proto[2]; - b_coeffs_cplx_imag[4] = -ai2 * b_coeffs_proto[2]; -} - -static void designFilterBank (std::array& filterBank, - double gamma, - double erb_start, - double q_ERB, - double sampleRate) -{ - for (size_t kiter = 0; kiter < PolyOctave::ComplexERBFilterBank::numFilterBands; kiter += vec_size) - { - alignas (16) std::array b_coeffs_cplx_real_simd[5]; - alignas (16) std::array b_coeffs_cplx_imag_simd[5]; - alignas (16) std::array a_coeffs_cplx_simd[5]; - for (size_t i = 0; i < float_2::size; ++i) - { - const auto k = kiter + i; - - double b_coeffs_cplx_real[5]; - double b_coeffs_cplx_imag[5]; - double a_coeffs_cplx[5]; - designERBFilter (k, gamma, erb_start, q_ERB, sampleRate, b_coeffs_cplx_real, b_coeffs_cplx_imag, a_coeffs_cplx); - - for (size_t c = 0; c < 5; ++c) - { - b_coeffs_cplx_real_simd[c][i] = static_cast (b_coeffs_cplx_real[c]); - b_coeffs_cplx_imag_simd[c][i] = static_cast (b_coeffs_cplx_imag[c]); - a_coeffs_cplx_simd[c][i] = static_cast (a_coeffs_cplx[c]); - } - } - - for (size_t ch = 0; ch < 2; ++ch) - { - filterBank[ch].erbFilterReal[kiter / vec_size].reset(); - filterBank[ch].erbFilterReal[kiter / vec_size].setCoefs ({ - xsimd::load_aligned (b_coeffs_cplx_real_simd[0].data()), - xsimd::load_aligned (b_coeffs_cplx_real_simd[1].data()), - xsimd::load_aligned (b_coeffs_cplx_real_simd[2].data()), - xsimd::load_aligned (b_coeffs_cplx_real_simd[3].data()), - xsimd::load_aligned (b_coeffs_cplx_real_simd[4].data()), - }, - { - xsimd::load_aligned (a_coeffs_cplx_simd[0].data()), - xsimd::load_aligned (a_coeffs_cplx_simd[1].data()), - xsimd::load_aligned (a_coeffs_cplx_simd[2].data()), - xsimd::load_aligned (a_coeffs_cplx_simd[3].data()), - xsimd::load_aligned (a_coeffs_cplx_simd[4].data()), - }); - filterBank[ch].erbFilterImag[kiter / vec_size].reset(); - filterBank[ch].erbFilterImag[kiter / vec_size].setCoefs ({ - xsimd::load_aligned (b_coeffs_cplx_imag_simd[0].data()), - xsimd::load_aligned (b_coeffs_cplx_imag_simd[1].data()), - xsimd::load_aligned (b_coeffs_cplx_imag_simd[2].data()), - xsimd::load_aligned (b_coeffs_cplx_imag_simd[3].data()), - xsimd::load_aligned (b_coeffs_cplx_imag_simd[4].data()), - }, - { - xsimd::load_aligned (a_coeffs_cplx_simd[0].data()), - xsimd::load_aligned (a_coeffs_cplx_simd[1].data()), - xsimd::load_aligned (a_coeffs_cplx_simd[2].data()), - xsimd::load_aligned (a_coeffs_cplx_simd[3].data()), - xsimd::load_aligned (a_coeffs_cplx_simd[4].data()), - }); - } - } -} -} // namespace FilterBankHelpers - PolyOctave::PolyOctave (UndoManager* um) : BaseProcessor ( "Poly Octave", @@ -167,13 +19,13 @@ PolyOctave::PolyOctave (UndoManager* um) { using namespace ParameterHelpers; const auto setupGainParam = [this] (const juce::String& paramID, - chowdsp::SmoothedBufferValue& gain) + auto& gain) { gain.setParameterHandle (getParameterPointer (vts, paramID)); gain.setRampLength (0.05); - gain.mappingFunction = [] (double x) + gain.mappingFunction = [] (auto x) { - return 2.0 * x * x; + return 2 * x * x; }; }; setupGainParam (PolyOctaveTags::dryTag, dryGain); diff --git a/src/processors/other/PolyOctave.h b/src/processors/other/poly_octave/PolyOctave.h similarity index 100% rename from src/processors/other/PolyOctave.h rename to src/processors/other/poly_octave/PolyOctave.h diff --git a/src/processors/other/poly_octave/PolyOctaveFilterBandHelpers.h b/src/processors/other/poly_octave/PolyOctaveFilterBandHelpers.h new file mode 100644 index 00000000..02d02a36 --- /dev/null +++ b/src/processors/other/poly_octave/PolyOctaveFilterBandHelpers.h @@ -0,0 +1,163 @@ +#pragma once + +#include "PolyOctave.h" + +namespace FilterBankHelpers +{ +// Reference for filter-bank design and octave shifting: +// https://aaltodoc.aalto.fi/server/api/core/bitstreams/ff9e52cf-fd79-45eb-b695-93038244ec0e/content + +using float_2 = PolyOctave::ComplexERBFilterBank::float_2; +static_assert (float_2::size == 2); +static_assert (xsimd::batch::size == 2); +static constexpr auto vec_size = float_2::size; + +template +inline float_2 processSample (const chowdsp::IIRFilter<4, float_2>& f, std::array& z, float_2 x) +{ + auto y = z[1]; + if constexpr (! isImag) + y += x * f.b[0]; // for the imaginary filter, we know that b[0] == 0 + + z[1] = z[2] + x * f.b[1] - y * f.a[1]; + z[2] = z[3] + x * f.b[2] - y * f.a[2]; + z[3] = z[4] + x * f.b[3] - y * f.a[3]; + z[4] = x * f.b[4] - y * f.a[4]; + + return y; +} + +static constexpr auto q_c = 4.0; +static auto designERBFilter (size_t erb_index, + double gamma, + double erb_start, + double q_ERB, + double sample_rate, + double (&b_coeffs_cplx_real)[5], + double (&b_coeffs_cplx_imag)[5], + double (&a_coeffs_cplx)[5]) +{ + const auto q_PS = gamma; + + const auto z = erb_start + static_cast (erb_index) * (q_c / q_ERB); + const auto center_target_freq = 228.7 * (std::pow (10.0, z / 21.3) - 1.0); + const auto filter_q = (1.0 / (q_PS * q_ERB)) * (24.7 + 0.108 * center_target_freq); + + double b_coeffs_proto[3]; + double a_coeffs_proto[3]; + chowdsp::CoefficientCalculators::calcSecondOrderBPF (b_coeffs_proto, + a_coeffs_proto, + center_target_freq / gamma, + filter_q * 0.5, + sample_rate); + + auto pole = (std::sqrt (std::pow (std::complex { a_coeffs_proto[1] }, 2.0) - 4.0 * a_coeffs_proto[2]) - a_coeffs_proto[1]) / 2.0; + auto conj_pole = std::conj (pole); + if (std::imag (pole) < 0.0) + pole = conj_pole; + else if (std::imag (conj_pole) < 0.0) + conj_pole = pole; + auto at = -(pole + conj_pole); + auto att = pole * conj_pole; + + auto ar1 = std::real (at); + auto ai1 = std::imag (at); + auto ar2 = std::real (att); + auto ai2 = std::imag (att); + + // a[] = 1 + 2 ar1 z + (ai1^2 + ar1^2 + 2 ar2) z^2 + (2 ai1 ai2 + 2 ar1 ar2) z^3 + (ai2^2 + ar2^2) z^4 + a_coeffs_cplx[0] = 1.0; + a_coeffs_cplx[1] = 2.0 * ar1; + a_coeffs_cplx[2] = ai1 * ai1 + ar1 * ar1 + 2.0 * ar2; + a_coeffs_cplx[3] = 2.0 * ai1 * ai2 + 2.0 * ar1 * ar2; + a_coeffs_cplx[4] = ai2 * ai2 + ar2 * ar2; + + // b_real[] = b0 + (ar1 b0 + b1) z + (ar2 b0 + ar1 b1 + b2) z^2 + (ar2 b1 + ar1 b2) z^3 + ar2 b2 z^4 + b_coeffs_cplx_real[0] = b_coeffs_proto[0]; + b_coeffs_cplx_real[1] = ar1 * b_coeffs_proto[0] + b_coeffs_proto[1]; + b_coeffs_cplx_real[2] = ar2 * b_coeffs_proto[0] + ar1 * b_coeffs_proto[1] + b_coeffs_proto[2]; + b_coeffs_cplx_real[3] = ar2 * b_coeffs_proto[1] + ar1 * b_coeffs_proto[2]; + b_coeffs_cplx_real[4] = ar2 * b_coeffs_proto[2]; + + // b_imag[] = -ai1 b0 z - (ai2 b0 + ai1 b1) z^2 - (ai2 b1 + ai1 br) z^3 - ai2 br z^4 + b_coeffs_cplx_imag[0] = 0.0; + b_coeffs_cplx_imag[1] = -ai1 * b_coeffs_proto[0]; + b_coeffs_cplx_imag[2] = -ai2 * b_coeffs_proto[0] - ai1 * b_coeffs_proto[1]; + b_coeffs_cplx_imag[3] = -ai2 * b_coeffs_proto[1] - ai1 * b_coeffs_proto[2]; + b_coeffs_cplx_imag[4] = -ai2 * b_coeffs_proto[2]; + + return center_target_freq; +} + +static void designFilterBank (std::array& filterBank, + double gamma, + double erb_start, + double q_ERB, + double sampleRate) +{ + for (size_t kiter = 0; kiter < PolyOctave::ComplexERBFilterBank::numFilterBands; kiter += vec_size) + { + alignas (16) std::array b_coeffs_cplx_real_simd[5]; + alignas (16) std::array b_coeffs_cplx_imag_simd[5]; + alignas (16) std::array a_coeffs_cplx_simd[5]; + alignas (16) std::array center_freqs; + for (size_t i = 0; i < float_2::size; ++i) + { + const auto k = kiter + i; + + double b_coeffs_cplx_real[5]; + double b_coeffs_cplx_imag[5]; + double a_coeffs_cplx[5]; + center_freqs[i] = designERBFilter (k, + gamma, + erb_start, + q_ERB, + sampleRate, + b_coeffs_cplx_real, + b_coeffs_cplx_imag, + a_coeffs_cplx); + + for (size_t c = 0; c < 5; ++c) + { + b_coeffs_cplx_real_simd[c][i] = static_cast (b_coeffs_cplx_real[c]); + b_coeffs_cplx_imag_simd[c][i] = static_cast (b_coeffs_cplx_imag[c]); + a_coeffs_cplx_simd[c][i] = static_cast (a_coeffs_cplx[c]); + } + } + + for (size_t ch = 0; ch < 2; ++ch) + { + filterBank[ch].erbFilterReal[kiter / vec_size].reset(); + filterBank[ch].erbFilterReal[kiter / vec_size].setCoefs ({ + xsimd::load_aligned (b_coeffs_cplx_real_simd[0].data()), + xsimd::load_aligned (b_coeffs_cplx_real_simd[1].data()), + xsimd::load_aligned (b_coeffs_cplx_real_simd[2].data()), + xsimd::load_aligned (b_coeffs_cplx_real_simd[3].data()), + xsimd::load_aligned (b_coeffs_cplx_real_simd[4].data()), + }, + { + xsimd::load_aligned (a_coeffs_cplx_simd[0].data()), + xsimd::load_aligned (a_coeffs_cplx_simd[1].data()), + xsimd::load_aligned (a_coeffs_cplx_simd[2].data()), + xsimd::load_aligned (a_coeffs_cplx_simd[3].data()), + xsimd::load_aligned (a_coeffs_cplx_simd[4].data()), + }); + filterBank[ch].erbFilterImag[kiter / vec_size].reset(); + filterBank[ch].erbFilterImag[kiter / vec_size].setCoefs ({ + xsimd::load_aligned (b_coeffs_cplx_imag_simd[0].data()), + xsimd::load_aligned (b_coeffs_cplx_imag_simd[1].data()), + xsimd::load_aligned (b_coeffs_cplx_imag_simd[2].data()), + xsimd::load_aligned (b_coeffs_cplx_imag_simd[3].data()), + xsimd::load_aligned (b_coeffs_cplx_imag_simd[4].data()), + }, + { + xsimd::load_aligned (a_coeffs_cplx_simd[0].data()), + xsimd::load_aligned (a_coeffs_cplx_simd[1].data()), + xsimd::load_aligned (a_coeffs_cplx_simd[2].data()), + xsimd::load_aligned (a_coeffs_cplx_simd[3].data()), + xsimd::load_aligned (a_coeffs_cplx_simd[4].data()), + }); + } + } +} +} // namespace FilterBankHelpers