Skip to content

Commit

Permalink
Multi-output configuration for Poly Octave
Browse files Browse the repository at this point in the history
  • Loading branch information
jatinchowdhury18 committed Jan 20, 2024
1 parent 24ec591 commit 5b6d917
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 19 deletions.
89 changes: 74 additions & 15 deletions src/processors/other/PolyOctave.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<PolyOctave::ERBFilterBank, 2>& filterBank,
static void designFilterBank (std::array<PolyOctave::ComplexERBFilterBank, 2>& 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<float_2::value_type, float_2::size> b_coeffs_cplx_real_simd[5];
alignas (16) std::array<float_2::value_type, float_2::size> b_coeffs_cplx_imag_simd[5];
Expand Down Expand Up @@ -158,7 +158,12 @@ static void designFilterBank (std::array<PolyOctave::ERBFilterBank, 2>& 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,
Expand Down Expand Up @@ -200,14 +205,21 @@ void PolyOctave::prepare (double sampleRate, int samplesPerBlock)
upOctaveGain.prepare (sampleRate, samplesPerBlock);

doubleBuffer.setMaxSize (2, samplesPerBlock);
up2OctaveBuffer.setMaxSize (2, static_cast<int> (ERBFilterBank::float_2::size) * samplesPerBlock); // allocate extra space for SIMD
upOctaveBuffer.setMaxSize (2, static_cast<int> (ERBFilterBank::float_2::size) * samplesPerBlock); // allocate extra space for SIMD
up2OctaveBuffer.setMaxSize (2, static_cast<int> (ComplexERBFilterBank::float_2::size) * samplesPerBlock); // allocate extra space for SIMD
upOctaveBuffer.setMaxSize (2, static_cast<int> (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<float>& buffer)
Expand All @@ -221,7 +233,7 @@ void PolyOctave::processAudio (AudioBuffer<float>& 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);
Expand All @@ -240,7 +252,7 @@ void PolyOctave::processAudio (AudioBuffer<float>& buffer)
auto& up2FilterBank = octaveUp2FilterBank[static_cast<size_t> (ch)];
static constexpr auto eps = std::numeric_limits<double>::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];
Expand Down Expand Up @@ -268,7 +280,7 @@ void PolyOctave::processAudio (AudioBuffer<float>& 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];
Expand All @@ -293,11 +305,11 @@ void PolyOctave::processAudio (AudioBuffer<float>& buffer)
up2Data[n] = xsimd::reduce_add (up2DataSIMD[n]);
}

chowdsp::BufferMath::applyGain (upOctaveBuffer, 2.0 / static_cast<double> (ERBFilterBank::numFilterBands));
chowdsp::BufferMath::applyGain (upOctaveBuffer, 2.0 / static_cast<double> (ComplexERBFilterBank::numFilterBands));
upOctaveGain.process (numSamples);
chowdsp::BufferMath::applyGainSmoothedBuffer (upOctaveBuffer, upOctaveGain);

chowdsp::BufferMath::applyGain (up2OctaveBuffer, 2.0 / static_cast<double> (ERBFilterBank::numFilterBands));
chowdsp::BufferMath::applyGain (up2OctaveBuffer, 2.0 / static_cast<double> (ComplexERBFilterBank::numFilterBands));
up2OctaveGain.process (numSamples);
chowdsp::BufferMath::applyGainSmoothedBuffer (up2OctaveBuffer, up2OctaveGain);

Expand All @@ -306,7 +318,54 @@ void PolyOctave::processAudio (AudioBuffer<float>& 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<float>& 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);
}
24 changes: 20 additions & 4 deletions src/processors/other/PolyOctave.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,26 @@ class PolyOctave : public BaseProcessor

void prepare (double sampleRate, int samplesPerBlock) override;
void processAudio (AudioBuffer<float>& buffer) override;
void processAudioBypassed (AudioBuffer<float>& buffer) override;

struct ERBFilterBank
String getTooltipForPort (int portIndex, bool isInput) override;

struct ComplexERBFilterBank
{
static constexpr size_t numFilterBands = 44;
using float_2 = xsimd::batch<double>;
std::array<chowdsp::IIRFilter<4, float_2>, numFilterBands / float_2::size> erbFilterReal, erbFilterImag;
};

enum OutputPort
{
MixOutput,
Up1Output,
Up2Output,
};

static constexpr auto numOutputs = (int) magic_enum::enum_count<OutputPort>();

private:
chowdsp::SmoothedBufferValue<double> dryGain {};
chowdsp::SmoothedBufferValue<double> upOctaveGain {};
Expand All @@ -29,10 +41,14 @@ class PolyOctave : public BaseProcessor
chowdsp::Buffer<double> upOctaveBuffer;
chowdsp::Buffer<double> up2OctaveBuffer;

std::array<ERBFilterBank, 2> octaveUpFilterBank;
std::array<ERBFilterBank, 2> octaveUp2FilterBank;
std::array<ComplexERBFilterBank, 2> octaveUpFilterBank;
std::array<ComplexERBFilterBank, 2> octaveUp2FilterBank;

std::array<chowdsp::FirstOrderHPF<float>, (size_t) numOutputs> dcBlocker;

chowdsp::FirstOrderHPF<float> dcBlocker;
juce::AudioBuffer<float> mixOutBuffer;
juce::AudioBuffer<float> up1OutBuffer;
juce::AudioBuffer<float> up2OutBuffer;

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PolyOctave)
};

0 comments on commit 5b6d917

Please sign in to comment.