AnalogTapeModel

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

commit 6143c902d78edbe343dcb8692eac6a78339dc981
parent e72f08bdeebc629c9ea97587d104abfc83b3ee20
Author: jatinchowdhury18 <jatinchowdhury18@users.noreply.github.com>
Date:   Wed, 13 May 2020 11:11:52 -0700

Use alpha transform instead of bilinear to allow 1x oversampling

Diffstat:
MPlugin/Source/Processors/Hysteresis/HysteresisProcessing.cpp | 3++-
MPlugin/Source/Processors/Hysteresis/HysteresisProcessing.h | 9++++-----
MPlugin/Source/Processors/Hysteresis/HysteresisProcessor.cpp | 25++++++++++---------------
MPlugin/Source/Processors/Hysteresis/HysteresisProcessor.h | 2+-
4 files changed, 17 insertions(+), 22 deletions(-)

diff --git a/Plugin/Source/Processors/Hysteresis/HysteresisProcessing.cpp b/Plugin/Source/Processors/Hysteresis/HysteresisProcessing.cpp @@ -63,7 +63,8 @@ inline float HysteresisProcessing::langevinD (float x) inline float HysteresisProcessing::deriv (float x_n, float x_n1, float x_d_n1) { - return (twoFs * (x_n - x_n1)) - x_d_n1; + constexpr float dAlpha = 0.9f; + return (((1.0f + dAlpha) / T) * (x_n - x_n1)) - dAlpha * x_d_n1; } inline float HysteresisProcessing::hysteresisFunc (float M, float H, float H_d) diff --git a/Plugin/Source/Processors/Hysteresis/HysteresisProcessing.h b/Plugin/Source/Processors/Hysteresis/HysteresisProcessing.h @@ -17,20 +17,20 @@ public: float process (float H); void reset(); - void setSampleRate (float newSR) { fs = newSR; T = 1.0f / fs; twoFs = 2.0f * fs; } + void setSampleRate (float newSR) { fs = newSR; T = 1.0f / fs; } void cook (float drive, float width, float sat); private: - /* Continued fraction approximation for hyperbolic cotangent */ + /* DEPRECATED (Continued fraction approximation for hyperbolic cotangent) */ inline float cothApprox (float x); inline float langevin (float x); // Langevin function inline float langevinD (float x); // Derivative of Langevin function - inline float deriv (float x_n, float x_n1, float x_d_n1); // Derivative by trapezoidal rule + inline float deriv (float x_n, float x_n1, float x_d_n1); // Derivative by alpha transform inline float hysteresisFunc (float M, float H, float H_d); - float M_n (float M_n1, float k1, float k2, float k3, float k4); + float M_n (float M_n1, float k1, float k2, float k3, float k4); // DEPRECATED (from RK4 version) float fs = 48000.0f; float T = 1.0f / fs; @@ -41,7 +41,6 @@ private: float c = (float) 1.7e-1; // Save calculations - float twoFs = 2.0f * fs; float nc = 1-c; float M_s_oa = M_s / a; float M_s_oa_tc = c * M_s / a; diff --git a/Plugin/Source/Processors/Hysteresis/HysteresisProcessor.cpp b/Plugin/Source/Processors/Hysteresis/HysteresisProcessor.cpp @@ -13,10 +13,9 @@ HysteresisProcessor::HysteresisProcessor (AudioProcessorValueTreeState& vts) widthParam = vts.getRawParameterValue ("width"); osParam = vts.getRawParameterValue ("os"); - overSample[0].reset (new dsp::Oversampling<float> (2, 1, dsp::Oversampling<float>::filterHalfBandPolyphaseIIR)); - overSample[1].reset (new dsp::Oversampling<float> (2, 2, dsp::Oversampling<float>::filterHalfBandPolyphaseIIR)); - overSample[2].reset (new dsp::Oversampling<float> (2, 3, dsp::Oversampling<float>::filterHalfBandPolyphaseIIR)); - overSample[3].reset (new dsp::Oversampling<float> (2, 4, dsp::Oversampling<float>::filterHalfBandPolyphaseIIR)); + for (int i = 0; i < 5; ++i) + overSample[i] = std::make_unique<dsp::Oversampling<float>> + (2, i, dsp::Oversampling<float>::filterHalfBandPolyphaseIIR); for (int ch = 0; ch < 2; ++ch) { @@ -33,7 +32,7 @@ void HysteresisProcessor::createParameterLayout (std::vector<std::unique_ptr<Ran params.push_back (std::make_unique<AudioParameterFloat> ("sat", "Saturation", 0.0f, 1.0f, 0.5f)); params.push_back (std::make_unique<AudioParameterFloat> ("width", "Bias", 0.0f, 1.0f, 0.5f)); - params.push_back (std::make_unique<AudioParameterChoice> ("os", "Oversampling", StringArray ({"2x", "4x", "8x", "16x"}), 0)); + params.push_back (std::make_unique<AudioParameterChoice> ("os", "Oversampling", StringArray ({"1x", "2x", "4x", "8x", "16x"}), 1)); } float HysteresisProcessor::calcMakeup() @@ -78,7 +77,7 @@ void HysteresisProcessor::toggleOnOff (bool shouldBeOn) void HysteresisProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) { fs = (float) sampleRate; - overSamplingFactor = (int) powf(2.0f, *osParam + 1); + overSamplingFactor = (int) powf(2.0f, *osParam); for (int ch = 0; ch < 2; ++ch) { @@ -92,10 +91,8 @@ void HysteresisProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) hProcs[ch].reset(); } - overSample[0]->initProcessing (samplesPerBlock); - overSample[1]->initProcessing (samplesPerBlock); - overSample[2]->initProcessing (samplesPerBlock); - overSample[3]->initProcessing (samplesPerBlock); + for (int i = 0; i < 5; ++i) + overSample[i]->initProcessing (samplesPerBlock); prevOS = (int) *osParam; dcBlocker[0].reset (sampleRate); @@ -116,10 +113,8 @@ void HysteresisProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) void HysteresisProcessor::releaseResources() { - overSample[0]->reset(); - overSample[1]->reset(); - overSample[2]->reset(); - overSample[3]->reset(); + for (int i = 0; i < 5; ++i) + overSample[i]->reset(); } void HysteresisProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& /*midi*/) @@ -130,7 +125,7 @@ void HysteresisProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& if ((int) *osParam != prevOS) { - overSamplingFactor = (int) powf(2.0f, *osParam + 1); + overSamplingFactor = (int) powf(2.0f, *osParam); prevOS = (int) *osParam; for (int ch = 0; ch < 2; ++ch) diff --git a/Plugin/Source/Processors/Hysteresis/HysteresisProcessor.h b/Plugin/Source/Processors/Hysteresis/HysteresisProcessor.h @@ -148,7 +148,7 @@ private: float fs = 44100.0f; int prevOS = 0; HysteresisProcessing hProcs[2]; - std::unique_ptr<dsp::Oversampling<float>> overSample[4]; // needs oversampling to avoid aliasing + std::unique_ptr<dsp::Oversampling<float>> overSample[5]; // needs oversampling to avoid aliasing TransformerHPF dcBlocker[2]; // TransformerShelf dcLower[2];