From 5b6d9176196cd59db45e6ef4271bb7f458fd9d1a Mon Sep 17 00:00:00 2001 From: jatin Date: Fri, 19 Jan 2024 21:27:56 -0800 Subject: [PATCH] Multi-output configuration for Poly Octave --- src/processors/other/PolyOctave.cpp | 89 ++++++++++++++++++++++++----- src/processors/other/PolyOctave.h | 24 ++++++-- 2 files changed, 94 insertions(+), 19 deletions(-) diff --git a/src/processors/other/PolyOctave.cpp b/src/processors/other/PolyOctave.cpp index 9174cf36..0cd7e6f4 100644 --- a/src/processors/other/PolyOctave.cpp +++ b/src/processors/other/PolyOctave.cpp @@ -13,7 +13,7 @@ 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::ERBFilterBank::float_2; +using float_2 = PolyOctave::ComplexERBFilterBank::float_2; static_assert (float_2::size == 2); static constexpr auto vec_size = float_2::size; @@ -92,13 +92,13 @@ static void designERBFilter (size_t erb_index, b_coeffs_cplx_imag[4] = -ai2 * b_coeffs_proto[2]; } -static void designFilterBank (std::array& filterBank, +static void designFilterBank (std::array& filterBank, double gamma, double erb_start, double q_ERB, double sampleRate) { - for (size_t kiter = 0; kiter < PolyOctave::ERBFilterBank::numFilterBands; kiter += vec_size) + 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]; @@ -158,7 +158,12 @@ static void designFilterBank (std::array& filterBa } // namespace FilterBankHelpers PolyOctave::PolyOctave (UndoManager* um) - : BaseProcessor ("Poly Octave", createParameterLayout(), um) + : BaseProcessor ( + "Poly Octave", + createParameterLayout(), + BasicInputPort {}, + OutputPort {}, + um) { using namespace ParameterHelpers; const auto setupGainParam = [this] (const juce::String& paramID, @@ -200,14 +205,21 @@ void PolyOctave::prepare (double sampleRate, int samplesPerBlock) upOctaveGain.prepare (sampleRate, samplesPerBlock); doubleBuffer.setMaxSize (2, samplesPerBlock); - up2OctaveBuffer.setMaxSize (2, static_cast (ERBFilterBank::float_2::size) * samplesPerBlock); // allocate extra space for SIMD - upOctaveBuffer.setMaxSize (2, static_cast (ERBFilterBank::float_2::size) * samplesPerBlock); // allocate extra space for SIMD + up2OctaveBuffer.setMaxSize (2, static_cast (ComplexERBFilterBank::float_2::size) * samplesPerBlock); // allocate extra space for SIMD + upOctaveBuffer.setMaxSize (2, static_cast (ComplexERBFilterBank::float_2::size) * samplesPerBlock); // allocate extra space for SIMD FilterBankHelpers::designFilterBank (octaveUpFilterBank, 2.0, 5.0, 6.0, sampleRate); FilterBankHelpers::designFilterBank (octaveUp2FilterBank, 3.0, 7.0, 4.0, sampleRate); - dcBlocker.prepare (2); - dcBlocker.calcCoefs (20.0f, (float) sampleRate); + for (auto& busDCBlocker : dcBlocker) + { + busDCBlocker.prepare (2); + busDCBlocker.calcCoefs (20.0f, (float) sampleRate); + } + + mixOutBuffer.setSize (2, samplesPerBlock); + up1OutBuffer.setSize (2, samplesPerBlock); + up2OutBuffer.setSize (2, samplesPerBlock); } void PolyOctave::processAudio (AudioBuffer& buffer) @@ -221,7 +233,7 @@ void PolyOctave::processAudio (AudioBuffer& buffer) chowdsp::BufferMath::copyBufferData (buffer, doubleBuffer); - using float_2 = ERBFilterBank::float_2; + using float_2 = ComplexERBFilterBank::float_2; for (int ch = 0; ch < numChannels; ++ch) { auto* dryData = doubleBuffer.getReadPointer (ch); @@ -240,7 +252,7 @@ void PolyOctave::processAudio (AudioBuffer& buffer) auto& up2FilterBank = octaveUp2FilterBank[static_cast (ch)]; static constexpr auto eps = std::numeric_limits::epsilon(); - for (size_t k = 0; k < ERBFilterBank::numFilterBands; k += float_2::size) + for (size_t k = 0; k < ComplexERBFilterBank::numFilterBands; k += float_2::size) { const auto filter_idx = k / float_2::size; auto& realFilter = upFilterBank.erbFilterReal[filter_idx]; @@ -268,7 +280,7 @@ void PolyOctave::processAudio (AudioBuffer& buffer) for (int n = 0; n < numSamples; ++n) upData[n] = xsimd::reduce_add (upDataSIMD[n]); - for (size_t k = 0; k < ERBFilterBank::numFilterBands; k += float_2::size) + for (size_t k = 0; k < ComplexERBFilterBank::numFilterBands; k += float_2::size) { const auto filter_idx = k / float_2::size; auto& realFilter = up2FilterBank.erbFilterReal[filter_idx]; @@ -293,11 +305,11 @@ void PolyOctave::processAudio (AudioBuffer& buffer) up2Data[n] = xsimd::reduce_add (up2DataSIMD[n]); } - chowdsp::BufferMath::applyGain (upOctaveBuffer, 2.0 / static_cast (ERBFilterBank::numFilterBands)); + chowdsp::BufferMath::applyGain (upOctaveBuffer, 2.0 / static_cast (ComplexERBFilterBank::numFilterBands)); upOctaveGain.process (numSamples); chowdsp::BufferMath::applyGainSmoothedBuffer (upOctaveBuffer, upOctaveGain); - chowdsp::BufferMath::applyGain (up2OctaveBuffer, 2.0 / static_cast (ERBFilterBank::numFilterBands)); + chowdsp::BufferMath::applyGain (up2OctaveBuffer, 2.0 / static_cast (ComplexERBFilterBank::numFilterBands)); up2OctaveGain.process (numSamples); chowdsp::BufferMath::applyGainSmoothedBuffer (up2OctaveBuffer, up2OctaveGain); @@ -306,7 +318,54 @@ void PolyOctave::processAudio (AudioBuffer& buffer) chowdsp::BufferMath::addBufferData (up2OctaveBuffer, doubleBuffer); chowdsp::BufferMath::addBufferData (upOctaveBuffer, doubleBuffer); - chowdsp::BufferMath::copyBufferData (doubleBuffer, buffer); + mixOutBuffer.setSize (numChannels, numSamples, false, false, true); + up1OutBuffer.setSize (numChannels, numSamples, false, false, true); + up2OutBuffer.setSize (numChannels, numSamples, false, false, true); + + chowdsp::BufferMath::copyBufferData (doubleBuffer, mixOutBuffer); + chowdsp::BufferMath::copyBufferData (upOctaveBuffer, up1OutBuffer); + chowdsp::BufferMath::copyBufferData (up2OctaveBuffer, up2OutBuffer); + + dcBlocker[MixOutput].processBlock (mixOutBuffer); + dcBlocker[Up1Output].processBlock (up1OutBuffer); + dcBlocker[Up2Output].processBlock (up2OutBuffer); + + outputBuffers.getReference (MixOutput) = &mixOutBuffer; + outputBuffers.getReference (Up1Output) = &up1OutBuffer; + outputBuffers.getReference (Up2Output) = &up2OutBuffer; +} + +void PolyOctave::processAudioBypassed (AudioBuffer& buffer) +{ + const auto numSamples = buffer.getNumSamples(); + + mixOutBuffer.setSize (buffer.getNumChannels(), numSamples, false, false, true); + up1OutBuffer.setSize (1, numSamples, false, false, true); + up2OutBuffer.setSize (1, numSamples, false, false, true); + + chowdsp::BufferMath::copyBufferData (buffer, mixOutBuffer); + up1OutBuffer.clear(); + up2OutBuffer.clear(); + + outputBuffers.getReference (MixOutput) = &mixOutBuffer; + outputBuffers.getReference (Up1Output) = &up1OutBuffer; + outputBuffers.getReference (Up2Output) = &up2OutBuffer; +} + +String PolyOctave::getTooltipForPort (int portIndex, bool isInput) +{ + if (! isInput) + { + switch ((OutputPort) portIndex) + { + case OutputPort::MixOutput: + return "Mix Output"; + case OutputPort::Up1Output: + return "+1 Octave Output"; + case OutputPort::Up2Output: + return "+2 Octave Output"; + } + } - dcBlocker.processBlock (buffer); + return BaseProcessor::getTooltipForPort (portIndex, isInput); } diff --git a/src/processors/other/PolyOctave.h b/src/processors/other/PolyOctave.h index c365623f..9f2230b9 100644 --- a/src/processors/other/PolyOctave.h +++ b/src/processors/other/PolyOctave.h @@ -12,14 +12,26 @@ class PolyOctave : public BaseProcessor void prepare (double sampleRate, int samplesPerBlock) override; void processAudio (AudioBuffer& buffer) override; + void processAudioBypassed (AudioBuffer& buffer) override; - struct ERBFilterBank + String getTooltipForPort (int portIndex, bool isInput) override; + + struct ComplexERBFilterBank { static constexpr size_t numFilterBands = 44; using float_2 = xsimd::batch; std::array, numFilterBands / float_2::size> erbFilterReal, erbFilterImag; }; + enum OutputPort + { + MixOutput, + Up1Output, + Up2Output, + }; + + static constexpr auto numOutputs = (int) magic_enum::enum_count(); + private: chowdsp::SmoothedBufferValue dryGain {}; chowdsp::SmoothedBufferValue upOctaveGain {}; @@ -29,10 +41,14 @@ class PolyOctave : public BaseProcessor chowdsp::Buffer upOctaveBuffer; chowdsp::Buffer up2OctaveBuffer; - std::array octaveUpFilterBank; - std::array octaveUp2FilterBank; + std::array octaveUpFilterBank; + std::array octaveUp2FilterBank; + + std::array, (size_t) numOutputs> dcBlocker; - chowdsp::FirstOrderHPF dcBlocker; + juce::AudioBuffer mixOutBuffer; + juce::AudioBuffer up1OutBuffer; + juce::AudioBuffer up2OutBuffer; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PolyOctave) };