AnalogTapeModel

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

commit d3194a13dab62fb4eaa86524556aa3a9386311b4
parent 8952e472fed6458f3c7d11d4decb33fbde4b8693
Author: jatinchowdhury18 <[email protected]>
Date:   Wed, 16 Mar 2022 02:50:21 +0000

Use chowdsp::VariableOversampling instead of custom OSManager (#251)

* Use chowdsp::VariableOversampling instead of custom OSManager

* Apply clang-format

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Diffstat:
MPlugin/Source/GUI/Assets/gui.xml | 10++++------
MPlugin/Source/GUI/Assets/gui_ios.xml | 6++----
MPlugin/Source/GUI/CMakeLists.txt | 1-
DPlugin/Source/GUI/OversamplingMenu.cpp | 162-------------------------------------------------------------------------------
DPlugin/Source/GUI/OversamplingMenu.h | 71-----------------------------------------------------------------------
MPlugin/Source/PluginProcessor.cpp | 5++---
MPlugin/Source/PluginProcessor.h | 2++
MPlugin/Source/Processors/CMakeLists.txt | 1-
MPlugin/Source/Processors/Hysteresis/HysteresisProcessor.cpp | 16+++++++++-------
MPlugin/Source/Processors/Hysteresis/HysteresisProcessor.h | 7+++----
DPlugin/Source/Processors/Hysteresis/OversamplingManager.cpp | 63---------------------------------------------------------------
DPlugin/Source/Processors/Hysteresis/OversamplingManager.h | 41-----------------------------------------
12 files changed, 22 insertions(+), 363 deletions(-)

diff --git a/Plugin/Source/GUI/Assets/gui.xml b/Plugin/Source/GUI/Assets/gui.xml @@ -255,12 +255,10 @@ <View max-height="35" margin="0" padding="0" background-color="FF31323A" flex-grow="0.1"> <View background-color="00000000" flex-grow="0.05"/> - <OversamplingMenu caption="Oversampling" os-param="os" os-mode="os_mode" os-off-param="os_render_factor" - os-off-mode="os_render_mode" os-off-same="os_render_like_realtime" - class="Slider" flex-grow="1.2" caption-size="0" padding="0" combo-text="FFEAA92C" - combo-background="00000000" max-height="100" margin="0" lookAndFeel="ComboBoxLNF" - name="Oversampling" tooltip="Sets the amount of oversampling used for the hysteresis processing. More oversampling will reduce aliasing artifacts, but requires more CPU resources." - border=""/> + <OversamplingMenu caption="Oversampling" class="Slider" flex-grow="1.2" caption-size="0" padding="0" + combo-text="FFEAA92C" menu-accent="FFEAA92C" combo-background="00000000" max-height="100" + margin="0" lookAndFeel="ComboBoxLNF" name="Oversampling" + tooltip="Sets the amount of oversampling used for the hysteresis processing. More oversampling will reduce aliasing artifacts, but requires more CPU resources."/> <ComboBox lookAndFeel="ComboBoxLNF" padding="0" border="0" background-color="00000000" name="Hysteresis Mode" caption="Hysteresis Mode" caption-size="0" combo-text="FFEAA92C" caption-color="FFFFFFFF" max-height="100" diff --git a/Plugin/Source/GUI/Assets/gui_ios.xml b/Plugin/Source/GUI/Assets/gui_ios.xml @@ -33,11 +33,9 @@ <View max-height="40" min-height="20" margin="0" padding="0" background-color="FF31323A" flex-grow="0.1"> <View background-color="00000000" flex-grow="0.1"/> - <OversamplingMenu caption="Oversampling" os-param="os" os-mode="os_mode" - os-off-param="os_render_factor" os-off-mode="os_render_mode" - os-off-same="os_render_like_realtime" class="Slider" + <OversamplingMenu caption="Oversampling" class="Slider" caption-size="0" padding="0" combo-text="FFEAA92C" combo-background="00000000" - max-height="100" margin="" lookAndFeel="ComboBoxLNF" name="Oversampling" + menu-accent="FFEAA92C" max-height="100" lookAndFeel="ComboBoxLNF" name="Oversampling" tooltip="Sets the amount of oversampling used for the hysteresis processing. More oversampling will reduce aliasing artifacts, but requires more CPU resources."/> <ComboBox lookAndFeel="ComboBoxLNF" padding="0" border="0" background-color="00000000" name="Hysteresis Mode" caption="Hysteresis Mode" caption-size="0" diff --git a/Plugin/Source/GUI/CMakeLists.txt b/Plugin/Source/GUI/CMakeLists.txt @@ -1,7 +1,6 @@ target_sources(CHOWTapeModel PRIVATE AutoUpdating.cpp MyLNF.cpp - OversamplingMenu.cpp SettingsButton.cpp TitleComp.cpp TooltipComp.cpp diff --git a/Plugin/Source/GUI/OversamplingMenu.cpp b/Plugin/Source/GUI/OversamplingMenu.cpp @@ -1,162 +0,0 @@ -#include "OversamplingMenu.h" -#include "../PluginProcessor.h" - -OversamplingMenu::OversamplingMenu (foleys::MagicGUIBuilder& builder, const ValueTree& node) : foleys::GuiItem (builder, node), - osManager (dynamic_cast<ChowtapeModelAudioProcessor*> (getMagicState() - .getProcessor()) - ->getHysteresisProcessor() - .getOSManager()) -{ - setColourTranslation ( - { { "combo-background", ComboBox::backgroundColourId }, - { "combo-text", ComboBox::textColourId }, - { "combo-outline", ComboBox::outlineColourId }, - { "combo-button", ComboBox::buttonColourId }, - { "combo-arrow", ComboBox::arrowColourId }, - { "combo-focused-outline", ComboBox::focusedOutlineColourId }, - { "combo-menu-background", PopupMenu::backgroundColourId }, - { "combo-menu-background-highlight", PopupMenu::highlightedBackgroundColourId }, - { "combo-menu-text", PopupMenu::textColourId }, - { "combo-menu-text-highlight", PopupMenu::highlightedTextColourId } }); - - addAndMakeVisible (comboBox); - comboBox.setLookAndFeel (&lnf); - - for (int i = 0; i < 5; ++i) - parameters[i] = nullptr; -} - -OversamplingMenu::~OversamplingMenu() -{ - comboBox.setLookAndFeel (nullptr); -} - -void OversamplingMenu::update() -{ - auto& vts = dynamic_cast<ChowtapeModelAudioProcessor*> (getMagicState().getProcessor())->getVTS(); - - int count = 0; - for (auto paramTag : { &osParam, &osMode, &osOfflineParam, &osOfflineMode, &osOfflineSame }) - { - attachments[count].reset(); - auto paramID = configNode.getProperty (*paramTag, String()).toString(); - if (paramID.isNotEmpty()) - { - parameters[count] = vts.getParameter (paramID); - attachments[count] = std::make_unique<ParameterAttachment> ( - *parameters[count], - [=] (float) { generateComboBoxMenu(); }, - vts.undoManager); - } - - count += 1; - } - - generateComboBoxMenu(); -} - -void OversamplingMenu::generateComboBoxMenu() -{ - comboBox.clear(); - auto* menu = comboBox.getRootMenu(); - - auto createParamItem = [=] (PopupMenu::Item& item, auto* parameter, auto& attachment, int& menuIdx, int menuOffset, const String& choice, bool forceOff = false, bool disableSame = false) { - item.itemID = menuIdx++; - int paramVal = item.itemID - menuOffset; - bool isSelected = ((int) parameter->convertFrom0to1 (parameter->getValue()) == paramVal) && ! forceOff; - item.text = choice; - item.colour = isSelected ? Colour (0xFFEAA92C) : Colours::white; - item.action = [this, paramVal, disableSame, &attachment] { - if (disableSame) - attachments[4]->setValueAsCompleteGesture (0.0f); - attachment->setValueAsCompleteGesture (float (paramVal)); - }; - return isSelected; - }; - - // set up main menu - StringArray headers { "OS Factor", "Mode", "OS Factor", "Mode" }; - int menuIdx = 1; - int menuOffset = menuIdx; - - // set up offline menu - PopupMenu offlineMenu; - int offlineMenuIdx = 1; - int offlineMenuOffset = menuIdx; - - bool sameAsRT = false; - { // same as real-time option - PopupMenu::Item item; - item.itemID = menuIdx++; - auto* parameter = parameters[4]; - sameAsRT = parameter != nullptr ? (int) parameter->convertFrom0to1 (parameter->getValue()) == 1 : false; - item.text = "Same as real-time"; - item.colour = sameAsRT ? Colour (0xFFEAA92C) : Colours::white; - item.action = [&] { attachments[4]->setValueAsCompleteGesture (1.0f); }; - offlineMenu.addItem (item); - } - - // add parameter to menus - std::pair<String, String> selectedText; - for (int paramIdx = 0; paramIdx < 4; ++paramIdx) - { - if (parameters[paramIdx] == nullptr) - continue; - - bool isOfflineParam = paramIdx >= 2; - auto* thisMenu = isOfflineParam ? &offlineMenu : menu; - auto& thisMenuIdx = isOfflineParam ? offlineMenuIdx : menuIdx; - auto& thisMenuOffset = isOfflineParam ? offlineMenuOffset : menuOffset; - thisMenuOffset = thisMenuIdx; - - thisMenu->addSectionHeader (headers[paramIdx]); - for (auto& choice : parameters[paramIdx]->getAllValueStrings()) - { - PopupMenu::Item item; - bool isSelected = createParamItem (item, - parameters[paramIdx], - attachments[paramIdx], - thisMenuIdx, - thisMenuOffset, - choice, - sameAsRT && isOfflineParam, - isOfflineParam); - thisMenu->addItem (item); - - if (isSelected && paramIdx == 0) - selectedText.first = item.text; - else if (isSelected && paramIdx == 2) - selectedText.second = item.text; - } - } - - String comboBoxText = selectedText.first; - if (! sameAsRT) - comboBoxText += " / " + selectedText.second; - comboBox.setText (comboBoxText); - - menu->addSeparator(); - menu->addSubMenu ("Offline:", offlineMenu); - - auto osParam = parameters[0] != nullptr ? parameters[0]->convertFrom0to1 (parameters[0]->getValue()) : 0; - auto osMode = parameters[1] != nullptr ? parameters[1]->convertFrom0to1 (parameters[1]->getValue()) : 0; - auto osIndex = osManager.getOSIndex (osParam, osMode); - auto curLatencyMs = osManager.getLatencyMilliseconds (osIndex); - menu->addSectionHeader ("Current Latency: " + String (curLatencyMs, 3) + " ms"); -} - -std::vector<foleys::SettableProperty> OversamplingMenu::getSettableProperties() const -{ - std::vector<foleys::SettableProperty> properties; - properties.push_back ({ configNode, osParam, foleys::SettableProperty::Choice, {}, magicBuilder.createParameterMenuLambda() }); - properties.push_back ({ configNode, osMode, foleys::SettableProperty::Choice, {}, magicBuilder.createParameterMenuLambda() }); - properties.push_back ({ configNode, osOfflineParam, foleys::SettableProperty::Choice, {}, magicBuilder.createParameterMenuLambda() }); - properties.push_back ({ configNode, osOfflineMode, foleys::SettableProperty::Choice, {}, magicBuilder.createParameterMenuLambda() }); - return properties; -} - -const Identifier OversamplingMenu::osParam = { "os-param" }; -const Identifier OversamplingMenu::osMode = { "os-mode" }; -const Identifier OversamplingMenu::osOfflineParam = { "os-off-param" }; -const Identifier OversamplingMenu::osOfflineMode = { "os-off-mode" }; -const Identifier OversamplingMenu::osOfflineSame = { "os-off-same" }; diff --git a/Plugin/Source/GUI/OversamplingMenu.h b/Plugin/Source/GUI/OversamplingMenu.h @@ -1,71 +0,0 @@ -#pragma once - -#include "../Processors/Hysteresis/OversamplingManager.h" -#include "MyLNF.h" - -class OversamplingMenu : public foleys::GuiItem -{ -public: - FOLEYS_DECLARE_GUI_FACTORY (OversamplingMenu) - - static const Identifier osParam; - static const Identifier osMode; - static const Identifier osOfflineParam; - static const Identifier osOfflineMode; - static const Identifier osOfflineSame; - - OversamplingMenu (foleys::MagicGUIBuilder& builder, const ValueTree& node); - ~OversamplingMenu(); - - void update() override; - std::vector<foleys::SettableProperty> getSettableProperties() const override; - - Component* getWrappedComponent() override { return &comboBox; } - -private: - class OversamplingLNF : public ComboBoxLNF - { - public: - OversamplingLNF() = default; - - void drawComboBox (Graphics& g, int width, int height, bool, int, int, int, int, ComboBox& box) override - { - auto cornerSize = 5.0f; - Rectangle<int> boxBounds (0, 0, width, height); - - g.setColour (box.findColour (ComboBox::backgroundColourId)); - g.fillRoundedRectangle (boxBounds.toFloat(), cornerSize); - - auto name = box.getName(); - auto font = getComboBoxFont (box).boldened(); - g.setColour (Colours::white); - g.setFont (font); - - auto nameBox = boxBounds.removeFromLeft (font.getStringWidth (name)); - g.drawFittedText (name + ": ", nameBox, Justification::left, 1); - } - - void positionComboBoxText (ComboBox& box, Label& label) override - { - auto name = box.getName(); - auto font = getComboBoxFont (box).boldened(); - auto b = box.getBounds(); - b.removeFromLeft (font.getStringWidth (name)); - - label.setBounds (b); - label.setFont (getComboBoxFont (box).boldened()); - label.setJustificationType (Justification::centred); - } - } lnf; - - void generateComboBoxMenu(); - - ComboBox comboBox; - - std::unique_ptr<ParameterAttachment> attachments[5]; - RangedAudioParameter* parameters[5]; - - const OversamplingManager& osManager; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OversamplingMenu) -}; diff --git a/Plugin/Source/PluginProcessor.cpp b/Plugin/Source/PluginProcessor.cpp @@ -10,7 +10,6 @@ #include "PluginProcessor.h" #include "GUI/OnOff/PowerButton.h" -#include "GUI/OversamplingMenu.h" #include "GUI/SettingsButton.h" #include "GUI/TitleComp.h" #include "GUI/TooltipComp.h" @@ -37,7 +36,7 @@ ChowtapeModelAudioProcessor::ChowtapeModelAudioProcessor() midSideController (vts), toneControl (vts), compressionProcessor (vts), - hysteresis (vts, *this), + hysteresis (vts), degrade (vts), chewer (vts), lossFilter (vts), @@ -321,7 +320,7 @@ AudioProcessorEditor* ChowtapeModelAudioProcessor::createEditor() builder->registerFactory ("TitleComp", &TitleItem::factory); builder->registerFactory ("MixGroupViz", &MixGroupVizItem::factory); builder->registerFactory ("PowerButton", &PowerButtonItem::factory); - builder->registerFactory ("OversamplingMenu", &OversamplingMenu::factory); + builder->registerFactory ("OversamplingMenu", &chowdsp::OversamplingMenuItem<ChowtapeModelAudioProcessor>::factory); builder->registerFactory ("SettingsButton", &SettingsButtonItem::factory); builder->registerFactory ("InfoComp", &chowdsp::InfoItem<ChowTapeInfoProvider, ChowtapeModelAudioProcessor>::factory); diff --git a/Plugin/Source/PluginProcessor.h b/Plugin/Source/PluginProcessor.h @@ -87,9 +87,11 @@ public: String getWrapperTypeString() const; PresetManager& getPresetManager() { return presetManager; } const AudioProcessorValueTreeState& getVTS() const { return vts; } + AudioProcessorValueTreeState& getVTS() { return vts; } const AudioPlayHead::CurrentPositionInfo& getPositionInfo() const { return positionInfo; } HysteresisProcessor& getHysteresisProcessor() { return hysteresis; } auto* getOpenGLHelper() { return openGLHelper.get(); } + auto& getOversampling() { return hysteresis.getOSManager(); } private: using DryDelayType = chowdsp::DelayLine<float, chowdsp::DelayLineInterpolationTypes::Lagrange5th>; diff --git a/Plugin/Source/Processors/CMakeLists.txt b/Plugin/Source/Processors/CMakeLists.txt @@ -6,7 +6,6 @@ target_sources(CHOWTapeModel PRIVATE Hysteresis/HysteresisProcessing.cpp Hysteresis/HysteresisProcessor.cpp Hysteresis/HysteresisSTN.cpp - Hysteresis/OversamplingManager.cpp Hysteresis/STNModel.cpp Hysteresis/ToneControl.cpp diff --git a/Plugin/Source/Processors/Hysteresis/HysteresisProcessor.cpp b/Plugin/Source/Processors/Hysteresis/HysteresisProcessor.cpp @@ -15,7 +15,7 @@ static void interleaveSamples (const T** source, T* dest, int numSamples, int nu for (int chan = 0; chan < numChannels; ++chan) { auto i = chan; - auto src = source[chan]; + const auto* src = source[chan]; for (int j = 0; j < numSamples; ++j) { @@ -31,7 +31,7 @@ static void deinterleaveSamples (const T* source, T** dest, int numSamples, int for (int chan = 0; chan < numChannels; ++chan) { auto i = chan; - auto dst = dest[chan]; + auto* dst = dest[chan]; for (int j = 0; j < numSamples; ++j) { @@ -42,7 +42,7 @@ static void deinterleaveSamples (const T* source, T** dest, int numSamples, int } } // namespace -HysteresisProcessor::HysteresisProcessor (AudioProcessorValueTreeState& vts, const AudioProcessor& p) : osManager (vts, p) +HysteresisProcessor::HysteresisProcessor (AudioProcessorValueTreeState& vts) : osManager (vts) { driveParam = vts.getRawParameterValue ("drive"); satParam = vts.getRawParameterValue ("sat"); @@ -68,7 +68,9 @@ void HysteresisProcessor::createParameterLayout (std::vector<std::unique_ptr<Ran params.push_back (std::make_unique<AudioParameterFloat> ("width", "Tape Bias", 0.0f, 1.0f, 0.5f)); params.push_back (std::make_unique<AudioParameterChoice> ("mode", "Tape Mode", StringArray ({ "RK2", "RK4", "NR4", "NR8", "STN", "V1" }), 0)); - OversamplingManager::createParameterLayout (params); + + using OSManager = decltype (osManager); + OSManager::createParameterLayout (params, OSManager::OSFactor::TwoX, OSManager::OSMode::MinPhase); } void HysteresisProcessor::setSolver (int newSolver) @@ -181,7 +183,7 @@ void HysteresisProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) void HysteresisProcessor::releaseResources() { - osManager.releaseResources(); + osManager.reset(); } float HysteresisProcessor::getLatencySamples() const noexcept @@ -227,7 +229,7 @@ void HysteresisProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& doubleBuffer.makeCopyOf (buffer, true); dsp::AudioBlock<double> block (doubleBuffer); - dsp::AudioBlock<double> osBlock = osManager.getOversampler()->processSamplesUp (block); + dsp::AudioBlock<double> osBlock = osManager.processSamplesUp (block); #if HYSTERESIS_USE_SIMD const auto n = osBlock.getNumSamples(); @@ -297,7 +299,7 @@ void HysteresisProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& static_cast<int> (Vec2::size())); #endif - osManager.getOversampler()->processSamplesDown (block); + osManager.processSamplesDown (block); buffer.makeCopyOf (doubleBuffer, true); applyDCBlockers (buffer); diff --git a/Plugin/Source/Processors/Hysteresis/HysteresisProcessor.h b/Plugin/Source/Processors/Hysteresis/HysteresisProcessor.h @@ -4,13 +4,12 @@ #include "../BypassProcessor.h" #include "DCBlocker.h" #include "HysteresisProcessing.h" -#include "OversamplingManager.h" /* Hysteresis Processor for tape. */ class HysteresisProcessor { public: - HysteresisProcessor (AudioProcessorValueTreeState& vts, const AudioProcessor& p); + HysteresisProcessor (AudioProcessorValueTreeState& vts); /* Reset fade buffers, filters, and processors. Prepare oversampling */ void prepareToPlay (double sampleRate, int samplesPerBlock); @@ -24,7 +23,7 @@ public: static void createParameterLayout (std::vector<std::unique_ptr<RangedAudioParameter>>& params); float getLatencySamples() const noexcept; - const OversamplingManager& getOSManager() const { return osManager; } + auto& getOSManager() { return osManager; } private: void setSolver (int newSolver); @@ -59,7 +58,7 @@ private: double fs = 44100.0f; HysteresisProcessing hProcs[2]; SolverType solver = SolverType::RK4; - OversamplingManager osManager; // needs oversampling to avoid aliasing + chowdsp::VariableOversampling<double> osManager; // needs oversampling to avoid aliasing DCBlocker dcBlocker[2]; static constexpr double dcFreq = 35.0; diff --git a/Plugin/Source/Processors/Hysteresis/OversamplingManager.cpp b/Plugin/Source/Processors/Hysteresis/OversamplingManager.cpp @@ -1,63 +0,0 @@ -#include "OversamplingManager.h" - -OversamplingManager::OversamplingManager (const AudioProcessorValueTreeState& vts, const AudioProcessor& p) : proc (p) -{ - osParam = vts.getRawParameterValue ("os"); - osModeParam = vts.getRawParameterValue ("os_mode"); - osOfflineParam = vts.getRawParameterValue ("os_render_factor"); - osOfflineModeParam = vts.getRawParameterValue ("os_render_mode"); - osOfflineSameParam = vts.getRawParameterValue ("os_render_like_realtime"); - - for (int i = 0; i < numOSChoices; ++i) - { - overSample[i] = std::make_unique<dsp::Oversampling<double>> (2, i, dsp::Oversampling<double>::filterHalfBandPolyphaseIIR); - overSample[i + numOSChoices] = std::make_unique<dsp::Oversampling<double>> (2, i, dsp::Oversampling<double>::filterHalfBandFIREquiripple); - } -} - -void OversamplingManager::createParameterLayout (std::vector<std::unique_ptr<RangedAudioParameter>>& params) -{ - params.push_back (std::make_unique<AudioParameterChoice> ("os", "Oversampling", StringArray ({ "1x", "2x", "4x", "8x", "16x" }), 1)); - params.push_back (std::make_unique<AudioParameterChoice> ("os_mode", "Oversampling Mode", StringArray ({ "Min. Phase", "Linear Phase" }), 0)); - - params.push_back (std::make_unique<AudioParameterChoice> ("os_render_factor", "Oversampling (render)", StringArray ({ "1x", "2x", "4x", "8x", "16x" }), 1)); - params.push_back (std::make_unique<AudioParameterChoice> ("os_render_mode", "Oversampling Mode (render)", StringArray ({ "Min. Phase", "Linear Phase" }), 0)); - params.push_back (std::make_unique<AudioParameterBool> ("os_render_like_realtime", "Oversampling (render like real-time)", true)); -} - -bool OversamplingManager::updateOSFactor() -{ - curOS = getOSIndex (*osParam, *osModeParam); - if (proc.isNonRealtime() && *osOfflineSameParam == 0.0f) - { - curOS = getOSIndex (*osOfflineParam, *osOfflineModeParam); - } - if (curOS != prevOS) - { - overSamplingFactor = 1 << (curOS % numOSChoices); - prevOS = curOS; - return true; - } - - return false; -} - -void OversamplingManager::prepareToPlay (double sr, int samplesPerBlock) -{ - sampleRate = (float) sr; - - overSamplingFactor = 1 << curOS; - - for (int i = 0; i < numOSChoices; ++i) - { - overSample[i]->initProcessing ((size_t) samplesPerBlock); - overSample[i + numOSChoices]->initProcessing ((size_t) samplesPerBlock); - } - prevOS = curOS; -} - -void OversamplingManager::releaseResources() -{ - for (int i = 0; i < numOSChoices; ++i) - overSample[i]->reset(); -} diff --git a/Plugin/Source/Processors/Hysteresis/OversamplingManager.h b/Plugin/Source/Processors/Hysteresis/OversamplingManager.h @@ -1,41 +0,0 @@ -#pragma once - -#include <JuceHeader.h> - -class OversamplingManager -{ -public: - OversamplingManager (const AudioProcessorValueTreeState& vts, const AudioProcessor& p); - - static void createParameterLayout (std::vector<std::unique_ptr<RangedAudioParameter>>& params); - - void prepareToPlay (double sampleRate, int samplesPerBlock); - void releaseResources(); - - int getOSFactor() const noexcept { return overSamplingFactor; } - bool updateOSFactor(); - - static int getOSIndex (float osFactor, float osMode) { return (int) osFactor + (numOSChoices * (int) osMode); } - float getLatencySamples() const noexcept { return (float) overSample[curOS]->getLatencyInSamples(); } - float getLatencyMilliseconds (int osIndex) const noexcept { return ((float) overSample[osIndex]->getLatencyInSamples() / sampleRate) * 1000.0f; } - - dsp::Oversampling<double>* getOversampler() { return overSample[curOS].get(); } - -private: - std::atomic<float>* osParam = nullptr; - std::atomic<float>* osModeParam = nullptr; - std::atomic<float>* osOfflineParam = nullptr; - std::atomic<float>* osOfflineModeParam = nullptr; - std::atomic<float>* osOfflineSameParam = nullptr; - - int curOS = 0, prevOS = 0; - int overSamplingFactor = 2; - float sampleRate = 48000.0f; - - static constexpr int numOSChoices = 5; - std::unique_ptr<dsp::Oversampling<double>> overSample[2 * numOSChoices]; - - const AudioProcessor& proc; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OversamplingManager) -};