AnalogTapeModel

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

commit 6d2a46aa1be134f957422d5283ea7839081ae063
parent 4477d4be55a53af00a4093beaa15b146082335c2
Author: jatinchowdhury18 <jatinchowdhury18@users.noreply.github.com>
Date:   Sun, 24 Feb 2019 00:51:33 -0800

reduce CPU load and fix oversampling

Diffstat:
MPlugin/Source/PluginProcessor.cpp | 2+-
MPlugin/Source/Processors/Hysteresis/HysteresisProcessor.cpp | 92+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
MPlugin/Source/Processors/Hysteresis/HysteresisProcessor.h | 9++++++---
3 files changed, 62 insertions(+), 41 deletions(-)

diff --git a/Plugin/Source/PluginProcessor.cpp b/Plugin/Source/PluginProcessor.cpp @@ -22,7 +22,7 @@ ChowtapeModelAudioProcessor::ChowtapeModelAudioProcessor() outGain->addListener (this); addParameter (overSampling = new AudioParameterChoice (String ("overSampling"), String ("Upsample"), - StringArray ({ "4x", "8x", "16x" }), 0)); + StringArray ({ "2x", "4x", "8x" }), 0)); overSampling->addListener (this); addParameter (tapeSpeed = new AudioParameterChoice (String ("tapeSpeed"), String ("Speed"), diff --git a/Plugin/Source/Processors/Hysteresis/HysteresisProcessor.cpp b/Plugin/Source/Processors/Hysteresis/HysteresisProcessor.cpp @@ -1,14 +1,10 @@ #include "HysteresisProcessor.h" -namespace -{ - constexpr float biasFilterFreq = 24000.0f; -} - HysteresisProcessor::HysteresisProcessor() : ProcessorBase ("HysteresisProcessor") { - overSample.reset (new dsp::Oversampling<float> (2, 1, dsp::Oversampling<float>::filterHalfBandFIREquiripple)); - biasFilter.setFreq (biasFilterFreq); + overSample2.reset (new dsp::Oversampling<float> (2, 1, dsp::Oversampling<float>::filterHalfBandFIREquiripple)); + overSample4.reset (new dsp::Oversampling<float> (2, 2, dsp::Oversampling<float>::filterHalfBandFIREquiripple)); + overSample8.reset (new dsp::Oversampling<float> (2, 3, dsp::Oversampling<float>::filterHalfBandFIREquiripple)); } void HysteresisProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) @@ -18,25 +14,43 @@ void HysteresisProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) hProcs[0].setSampleRate ((float) (sampleRate * overSamplingFactor)); hProcs[1].setSampleRate ((float) (sampleRate * overSamplingFactor)); - overSample->initProcessing (samplesPerBlock); - - biasFilter.prepareToPlay (sampleRate * overSamplingFactor, samplesPerBlock * overSamplingFactor); + if (overSamplingFactor == 8) + overSample8->initProcessing (samplesPerBlock); + else if (overSamplingFactor == 4) + overSample4->initProcessing (samplesPerBlock); + else + overSample2->initProcessing (samplesPerBlock); n[0] = 0; n[1] = 0; + + fadeIn = true; } void HysteresisProcessor::releaseResources() { - overSample->reset(); - - biasFilter.releaseResources(); + overSample2->reset(); + overSample4->reset(); + overSample8->reset(); } -void HysteresisProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& midi) +void HysteresisProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& /*midi*/) { + if (fadeIn) + { + buffer.applyGainRamp (0, buffer.getNumSamples(), 0.0f, 1.0f); + fadeIn = false; + } + dsp::AudioBlock<float> block (buffer); - dsp::AudioBlock<float> osBlock = overSample->processSamplesUp(block); + dsp::AudioBlock<float> osBlock; + + if (overSamplingFactor == 8) + osBlock = overSample8->processSamplesUp (block); + else if (overSamplingFactor == 4) + osBlock = overSample4->processSamplesUp (block); + else + osBlock = overSample2->processSamplesUp (block); float* ptrArray[] = { osBlock.getChannelPointer(0), osBlock.getChannelPointer(1) }; AudioBuffer<float> osBuffer (ptrArray, 2, static_cast<int> (osBlock.getNumSamples())); @@ -48,44 +62,38 @@ void HysteresisProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& auto* x = osBuffer.getWritePointer (channel); for (int samp = 0; samp < osBuffer.getNumSamples(); samp++) { - x[samp] = hProcs[channel].process ((float) 1e5 * (x[samp]));// + biasGain * sinf (sineTerm * (float) n[channel]))); + x[samp] = hProcs[channel].process ((float) 5e4 * (x[samp]));// + biasGain * sinf (sineTerm * (float) n[channel]))); n[channel]++; if ((float) (n[channel] / (getSampleRate() * overSamplingFactor)) >= 1.0f / biasFreq) n[channel] = 0; } } - biasFilter.processBlock (osBuffer, midi); - overSample->processSamplesDown(block); + if (overSamplingFactor == 8) + overSample8->processSamplesDown (block); + else if (overSamplingFactor == 4) + overSample4->processSamplesDown (block); + else + overSample2->processSamplesDown (block); } void HysteresisProcessor::setOverSamplingFactor (String osFactor) { - osFactor = "4x"; - //@TODO: figure out how to change oversampling factor without breaking everything - - int factor = overSamplingFactor; - - if (osFactor == "4x") - { + auto factor = overSamplingFactor; + if (osFactor == "2x") + factor = 2; // set overSample factor 2 = 2^1 + else if (osFactor == "4x") factor = 4; // set overSample factor 4 = 2^2 - overSample.reset (new dsp::Oversampling<float> (2, 2, dsp::Oversampling<float>::filterHalfBandFIREquiripple)); - } else if (osFactor == "8x") - { factor = 8; // set overSample factor 8 = 2^3 - overSample.reset (new dsp::Oversampling<float> (2, 3, dsp::Oversampling<float>::filterHalfBandFIREquiripple)); - } - else if (osFactor == "16x") + + if (factor != overSamplingFactor) { - factor = 16; // set overSample factor 16 = 2^4 - overSample.reset (new dsp::Oversampling<float> (2, 4, dsp::Oversampling<float>::filterHalfBandFIREquiripple)); + overSamplingFactor = factor; + releaseResources(); + prepareToPlay (getSampleRate(), getBlockSize()); } - - overSamplingFactor = factor; - overSample->reset(); - overSample->initProcessing (getBlockSize()); } void HysteresisProcessor::setBiasFreq (float newFreqKHz) @@ -97,3 +105,13 @@ void HysteresisProcessor::setBiasGain (float newGainDB) { biasGain = Decibels::decibelsToGain (newGainDB); } + +double HysteresisProcessor::getTailLengthSeconds() const +{ + if (overSamplingFactor == 8) + return overSample8->getLatencyInSamples() * getSampleRate(); + else if (overSamplingFactor == 4) + return overSample4->getLatencyInSamples() * getSampleRate(); + else + return overSample2->getLatencyInSamples() * getSampleRate(); +} diff --git a/Plugin/Source/Processors/Hysteresis/HysteresisProcessor.h b/Plugin/Source/Processors/Hysteresis/HysteresisProcessor.h @@ -14,7 +14,7 @@ public: void releaseResources() override; void processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiBuffer) override; - double getTailLengthSeconds() const override { return overSample->getLatencyInSamples() * getSampleRate(); } + double getTailLengthSeconds() const override; void setOverSamplingFactor (String osFactor); void setBiasFreq (float newFreqKHz); @@ -22,8 +22,9 @@ public: private: HysteresisProcessing hProcs[2]; - std::unique_ptr<dsp::Oversampling<float>> overSample; - BiasFilter biasFilter; + std::unique_ptr<dsp::Oversampling<float>> overSample2; + std::unique_ptr<dsp::Oversampling<float>> overSample4; + std::unique_ptr<dsp::Oversampling<float>> overSample8; int overSamplingFactor = 8; @@ -31,6 +32,8 @@ private: float biasGain = 5.0f; int n[2] = { 0, 0 }; + bool fadeIn = false; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HysteresisProcessor) };