AnalogTapeModel

Physical modelling signal processing for analog tape recording
Log | Files | Refs | Submodules | README | LICENSE

commit 9af3571d2cec79cde6a1473c9e5576518365ede7
parent b07eba0758bc76cfaee77f94cf4213f83a70d46d
Author: jatinchowdhury18 <jatinchowdhury18@gmail.com>
Date:   Sun, 15 May 2022 23:41:16 +0100

Rough (but working) accessibility support (#263)

* Rough (but working) accessibility support

* Update chowdsp submodule

* Apply clang-format

* Try to fix unit test with compiler error

* Fix ARM compilation error

* Try again to fix ARM compilation error

* Update submodule

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Diffstat:
MPlugin/Source/Headless/UnitTests/HysteresisOpsTest.cpp | 2+-
MPlugin/Source/Processors/Chew/Dropout.h | 2+-
MPlugin/Source/Processors/Compression/CompressionProcessor.cpp | 26+++++++++-----------------
MPlugin/Source/Processors/Hysteresis/HysteresisOps.h | 59++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
MPlugin/Source/Processors/Hysteresis/HysteresisProcessing.h | 7++++---
MPlugin/modules/CMakeLists.txt | 8+++++---
6 files changed, 78 insertions(+), 26 deletions(-)

diff --git a/Plugin/Source/Headless/UnitTests/HysteresisOpsTest.cpp b/Plugin/Source/Headless/UnitTests/HysteresisOpsTest.cpp @@ -40,7 +40,7 @@ public: #if HYSTERESIS_USE_SIMD auto testFunc = [=] (Vec2 H_d, Vec2 M_diff, Vec2 nc, double kap1_exp, double f1_exp) { const auto delta = ((Vec2) 1.0 & Vec2::greaterThanOrEqual (H_d, (Vec2) 0.0)) - ((Vec2) 1.0 & Vec2::lessThan (H_d, (Vec2) 0.0)); - const auto delta_M = Vec2::equal (chowdsp::signumSIMD (delta), chowdsp::signumSIMD (M_diff)); + const auto delta_M = Vec2::equal (HysteresisOps::signumSIMD (delta), HysteresisOps::signumSIMD (M_diff)); auto kap1 = (Vec2) nc & delta_M; auto f1 = (Vec2) nc * delta; diff --git a/Plugin/Source/Processors/Chew/Dropout.h b/Plugin/Source/Processors/Chew/Dropout.h @@ -49,7 +49,7 @@ public: inline float dropout (float x, size_t ch) { - auto sign = (float) chowdsp::signum (x); + auto sign = (float) chowdsp::sign (x); return pow (abs (x), powerSmooth[ch].getNextValue()) * sign; } diff --git a/Plugin/Source/Processors/Compression/CompressionProcessor.cpp b/Plugin/Source/Processors/Compression/CompressionProcessor.cpp @@ -49,26 +49,18 @@ void CompressionProcessor::prepare (double sr, int samplesPerBlock, int numChann compGainVec.resize (osFactor * (size_t) samplesPerBlock, 0.0f); } -inline float compressionDB (float xDB, float dbPlus) -{ - auto window = 2.0f * dbPlus; - - if (dbPlus <= 0.0f || xDB < -window) - return dbPlus; - - return std::log (xDB + window + 1.0f) - dbPlus - xDB; -} - -inline dsp::SIMDRegister<float> compressionDB (dsp::SIMDRegister<float> xDB, float dbPlus) +template <typename T> +inline T compressionDB (const T& xDB, float dbPlus) { using namespace chowdsp::SIMDUtils; + CHOWDSP_USING_XSIMD_STD (log) if (dbPlus <= 0.0f) - return (vec4) dbPlus; + return (T) dbPlus; auto window = 2.0f * dbPlus; - auto belowWin = vec4::lessThan (xDB, -window); - return ((logSIMD (xDB + window + 1.0f) - dbPlus - xDB) & ~belowWin) + ((vec4) dbPlus & belowWin); + auto belowWin = xDB < -window; + return select (belowWin, (T) dbPlus, log (xDB + window + 1.0f) - dbPlus - xDB); } void CompressionProcessor::processBlock (AudioBuffer<float>& buffer) @@ -92,14 +84,14 @@ void CompressionProcessor::processBlock (AudioBuffer<float>& buffer) size_t n = 0; for (; n < (size_t) numSamples; n += inc) { - auto xDB = dsp::SIMDRegister<float>::fromRawArray (&xDBVec[n]); + auto xDB = xsimd::load_aligned (&xDBVec[n]); xDB = chowdsp::SIMDUtils::gainToDecibels (xDB); auto compDB = compressionDB (xDB, dbPlusSmooth[ch].skip ((int) inc)); auto compGain = chowdsp::SIMDUtils::decibelsToGain (compDB); - xDB.copyToRawArray (&xDBVec[n]); - compGain.copyToRawArray (&compGainVec[n]); + xsimd::store_aligned (&xDBVec[n], xDB); + xsimd::store_aligned (&compGainVec[n], compGain); } // remaining samples that can't be vectorized diff --git a/Plugin/Source/Processors/Hysteresis/HysteresisOps.h b/Plugin/Source/Processors/Hysteresis/HysteresisOps.h @@ -9,6 +9,63 @@ namespace HysteresisOps { using namespace chowdsp::SIMDUtils; +/** SIMD implementation of std::tanh */ +template <typename T> +inline juce::dsp::SIMDRegister<T> tanhSIMD (juce::dsp::SIMDRegister<T> x) +{ + using x_type = xsimd::batch<T>; + return (juce::dsp::SIMDRegister<T>) xsimd::tanh ((x_type) x.value); +} + +/** Signum function to determine the sign of the input. */ +template <typename T> +inline juce::dsp::SIMDRegister<T> signumSIMD (juce::dsp::SIMDRegister<T> val) +{ + auto positive = juce::dsp::SIMDRegister<T> ((T) 1) & juce::dsp::SIMDRegister<T>::lessThan (juce::dsp::SIMDRegister<T> ((T) 0), val); + auto negative = juce::dsp::SIMDRegister<T> ((T) 1) & juce::dsp::SIMDRegister<T>::lessThan (val, juce::dsp::SIMDRegister<T> ((T) 0)); + return positive - negative; +} + +/** SIMD implementation of std::isnan */ +template <typename T> +inline typename juce::dsp::SIMDRegister<T>::vMaskType isnanSIMD (juce::dsp::SIMDRegister<T> x) +{ + using x_type = xsimd::batch<T>; + + // For some reason, xsimd::isnan returns a batch of doubles when using SSE + // but returns a batch of unsigned ints when using ARM NEON. +#if JUCE_ARM + return (typename juce::dsp::SIMDRegister<T>::vMaskType) xsimd::isnan ((x_type) x.value); +#else + using Vec = juce::dsp::SIMDRegister<T>; + return Vec::notEqual ((Vec) xsimd::isnan ((x_type) x.value), (Vec) 0); +#endif +} + +/** +JUCE doesn't implement the divide operator for +SIMDRegister, so here's a simple implementation. +Based on: https://forum.juce.com/t/divide-by-simdregister/28968/18 +*/ + +#if defined(__i386__) || defined(__amd64__) || defined(_M_X64) || defined(_X86_) || defined(_M_IX86) +/** Divides another SIMDRegister to the receiver. */ +inline juce::dsp::SIMDRegister<double> operator/ (const juce::dsp::SIMDRegister<double>& l, const juce::dsp::SIMDRegister<double>& r) +{ + return _mm_div_pd (l.value, r.value); +} + +#elif defined(_M_ARM64) || defined(__arm64__) || defined(__aarch64__) +/** Divides another SIMDRegister to the receiver. */ +inline juce::dsp::SIMDRegister<double> operator/ (const juce::dsp::SIMDRegister<double>& l, const juce::dsp::SIMDRegister<double>& r) +{ + return vdivq_f64 (l.value, r.value); +} + +#else +JUCE_COMPILER_WARNING ("SIMD divide not implemented for this platform... using non-vectorized implementation") +#endif + struct HysteresisState { // parameter values @@ -112,7 +169,7 @@ static inline Float hysteresisFunc (Float M, Float H, Float H_d, HysteresisState #if HYSTERESIS_USE_SIMD const auto delta = ((Float) 1.0 & Float::greaterThanOrEqual (H_d, (Float) 0.0)) - ((Float) 1.0 & Float::lessThan (H_d, (Float) 0.0)); - const auto delta_M = Float::equal (chowdsp::signumSIMD (delta), chowdsp::signumSIMD (hp.M_diff)); + const auto delta_M = Float::equal (signumSIMD (delta), signumSIMD (hp.M_diff)); hp.kap1 = (Float) hp.nc & delta_M; #else const auto delta = (Float) ((H_d >= 0.0) - (H_d < 0.0)); diff --git a/Plugin/Source/Processors/Hysteresis/HysteresisProcessing.h b/Plugin/Source/Processors/Hysteresis/HysteresisProcessing.h @@ -61,7 +61,7 @@ public: // check for instability #if HYSTERESIS_USE_SIMD - auto notIllCondition = ~(chowdsp::SIMDUtils::isnanSIMD (M) | Float::greaterThan (M, (Float) upperLim)); + auto notIllCondition = ~(HysteresisOps::isnanSIMD (M) | Float::greaterThan (M, (Float) upperLim)); M = M & notIllCondition; H_d = H_d & notIllCondition; #else @@ -118,8 +118,9 @@ private: Float deltaNR; for (int n = 0; n < nIterations; ++n) { - dMdt = HysteresisOps::hysteresisFunc (M, H, H_d, hpState); - dMdtPrime = HysteresisOps::hysteresisFuncPrime (H_d, dMdt, hpState); + using namespace HysteresisOps; + dMdt = hysteresisFunc (M, H, H_d, hpState); + dMdtPrime = hysteresisFuncPrime (H_d, dMdt, hpState); deltaNR = (M - M_n1 - (Float) Talpha * (dMdt + last_dMdt)) / (Float (1.0) - (Float) Talpha * dMdtPrime); M -= deltaNR; } diff --git a/Plugin/modules/CMakeLists.txt b/Plugin/modules/CMakeLists.txt @@ -26,9 +26,11 @@ target_link_libraries(juce_plugin_modules juce::juce_audio_utils juce::juce_audio_plugin_client chowdsp_juce_dsp - chowdsp_dsp - chowdsp_gui - chowdsp_plugin_utils + chowdsp::chowdsp_dsp_utils + chowdsp::chowdsp_plugin_base + chowdsp::chowdsp_plugin_utils + chowdsp::chowdsp_presets + chowdsp::chowdsp_foleys foleys_gui_magic RTNeural PUBLIC