Skip to content

Commit

Permalink
Setting up v1 mode
Browse files Browse the repository at this point in the history
  • Loading branch information
jatinchowdhury18 committed Apr 29, 2024
1 parent 3562e3c commit ef8df8b
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 62 deletions.
112 changes: 72 additions & 40 deletions src/processors/other/poly_octave/PolyOctave.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const String dryTag = "dry";
const String upOctaveTag = "up_octave";
const String up2OctaveTag = "up2_octave";
const String downOctaveTag = "down_octave";
const String v1Tag = "v1_mode";
} // namespace PolyOctaveTags

PolyOctave::PolyOctave (UndoManager* um)
Expand All @@ -34,6 +35,9 @@ PolyOctave::PolyOctave (UndoManager* um)
setupGainParam (PolyOctaveTags::upOctaveTag, upOctaveGain);
setupGainParam (PolyOctaveTags::up2OctaveTag, up2OctaveGain);

ParameterHelpers::loadParameterPointer (v1_mode, vts, PolyOctaveTags::v1Tag);
addPopupMenuParameter (PolyOctaveTags::v1Tag);

uiOptions.backgroundColour = Colour { 0xff9fa09d };
uiOptions.powerColour = Colour { 0xffe70510 };
uiOptions.info.description = "A \"polyphonic octave generator\" effect.";
Expand All @@ -49,6 +53,7 @@ ParamLayout PolyOctave::createParameterLayout()
createPercentParameter (params, PolyOctaveTags::dryTag, "+0 Oct", 0.5f);
createPercentParameter (params, PolyOctaveTags::upOctaveTag, "+1 Oct", 0.0f);
createPercentParameter (params, PolyOctaveTags::up2OctaveTag, "+2 Oct", 0.0f);
emplace_param<chowdsp::BoolParameter> (params, PolyOctaveTags::v1Tag, "V1 Mode", false); // @TODO: version streaming

return { params.begin(), params.end() };
}
Expand All @@ -61,12 +66,12 @@ void PolyOctave::prepare (double sampleRate, int samplesPerBlock)
downOctaveGain.prepare (sampleRate, samplesPerBlock);

doubleBuffer.setMaxSize (2, samplesPerBlock);
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
downOctaveBuffer.setMaxSize (2, samplesPerBlock);
up2OctaveBuffer_double.setMaxSize (2, 2 * samplesPerBlock); // allocate extra space for SIMD
upOctaveBuffer_double.setMaxSize (2, 2 * samplesPerBlock); // allocate extra space for SIMD
downOctaveBuffer_double.setMaxSize (2, samplesPerBlock);

FilterBankHelpers::designFilterBank (octaveUpFilterBank, 2.0, 5.0, 6.0, sampleRate);
FilterBankHelpers::designFilterBank (octaveUp2FilterBank, 3.0, 7.0, 4.0, sampleRate);
poly_octave_v1::designFilterBank (octaveUpFilterBank, 2.0, 5.0, 6.0, sampleRate);
poly_octave_v1::designFilterBank (octaveUp2FilterBank, 3.0, 7.0, 4.0, sampleRate);

for (auto& shifter : downOctavePitchShifters)
{
Expand All @@ -87,45 +92,56 @@ void PolyOctave::prepare (double sampleRate, int samplesPerBlock)
}

void PolyOctave::processAudio (AudioBuffer<float>& buffer)
{
if (v1_mode->get())
{
processAudioV1 (buffer);
return;
}


}

void PolyOctave::processAudioV1 (AudioBuffer<float>& buffer)
{
const auto numChannels = buffer.getNumChannels();
const auto numSamples = buffer.getNumSamples();

doubleBuffer.setCurrentSize (numChannels, numSamples);
upOctaveBuffer.setCurrentSize (numChannels, numSamples);
up2OctaveBuffer.setCurrentSize (numChannels, numSamples);
downOctaveBuffer.setCurrentSize (numChannels, numSamples);
upOctaveBuffer_double.setCurrentSize (numChannels, numSamples);
up2OctaveBuffer_double.setCurrentSize (numChannels, numSamples);
downOctaveBuffer_double.setCurrentSize (numChannels, numSamples);

chowdsp::BufferMath::copyBufferData (buffer, doubleBuffer);

// "down" processing
for (auto [ch, data_in, data_out] : chowdsp::buffer_iters::zip_channels (std::as_const (doubleBuffer), downOctaveBuffer))
for (auto [ch, data_in, data_out] : chowdsp::buffer_iters::zip_channels (std::as_const (doubleBuffer), downOctaveBuffer_double))
{
for (auto [x, y] : chowdsp::zip (data_in, data_out))
y = downOctavePitchShifters[(size_t) ch].process_sample (x);
}

// "up" processing
using float_2 = ComplexERBFilterBank::float_2;
for (int ch = 0; ch < numChannels; ++ch)
{
using poly_octave_v1::float_2;
auto* dryData = doubleBuffer.getReadPointer (ch);

auto* upData = upOctaveBuffer.getWritePointer (ch);
auto* upDataSIMD = reinterpret_cast<float_2*> (upOctaveBuffer.getWritePointer (ch));
auto* upData = upOctaveBuffer_double.getWritePointer (ch);
auto* upDataSIMD = reinterpret_cast<float_2*> (upOctaveBuffer_double.getWritePointer (ch));
jassert (juce::snapPointerToAlignment (upDataSIMD, xsimd::default_arch::alignment()) == upDataSIMD);
std::fill (upDataSIMD, upDataSIMD + numSamples, float_2 {});

auto* up2Data = up2OctaveBuffer.getWritePointer (ch);
auto* up2DataSIMD = reinterpret_cast<float_2*> (up2OctaveBuffer.getWritePointer (ch));
auto* up2Data = up2OctaveBuffer_double.getWritePointer (ch);
auto* up2DataSIMD = reinterpret_cast<float_2*> (up2OctaveBuffer_double.getWritePointer (ch));
jassert (juce::snapPointerToAlignment (up2DataSIMD, xsimd::default_arch::alignment()) == up2DataSIMD);
std::fill (up2DataSIMD, up2DataSIMD + numSamples, float_2 {});

auto& upFilterBank = octaveUpFilterBank[static_cast<size_t> (ch)];
auto& up2FilterBank = octaveUp2FilterBank[static_cast<size_t> (ch)];
static constexpr auto eps = std::numeric_limits<double>::epsilon();

for (size_t k = 0; k < ComplexERBFilterBank::numFilterBands; k += float_2::size)
for (size_t k = 0; k < poly_octave_v1::ComplexERBFilterBank::numFilterBands; k += float_2::size)
{
const auto filter_idx = k / float_2::size;
auto& realFilter = upFilterBank.erbFilterReal[filter_idx];
Expand All @@ -134,8 +150,8 @@ void PolyOctave::processAudio (AudioBuffer<float>& buffer)
chowdsp::ScopedValue z_im { imagFilter.z[0] };
for (int n = 0; n < numSamples; ++n)
{
auto x_re = FilterBankHelpers::processSample (realFilter, z_re.get(), dryData[n]);
auto x_im = FilterBankHelpers::processSample<true> (imagFilter, z_im.get(), dryData[n]);
auto x_re = poly_octave_v1::processSample (realFilter, z_re.get(), dryData[n]);
auto x_im = poly_octave_v1::processSample<true> (imagFilter, z_im.get(), dryData[n]);

auto x_re_sq = x_re * x_re;
auto x_im_sq = x_im * x_im;
Expand All @@ -153,7 +169,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 < ComplexERBFilterBank::numFilterBands; k += float_2::size)
for (size_t k = 0; k < poly_octave_v1::ComplexERBFilterBank::numFilterBands; k += float_2::size)
{
const auto filter_idx = k / float_2::size;
auto& realFilter = up2FilterBank.erbFilterReal[filter_idx];
Expand All @@ -163,8 +179,8 @@ void PolyOctave::processAudio (AudioBuffer<float>& buffer)

for (int n = 0; n < numSamples; ++n)
{
auto x_re = FilterBankHelpers::processSample (realFilter, z_re.get(), dryData[n]);
auto x_im = FilterBankHelpers::processSample<true> (imagFilter, z_im.get(), dryData[n]);
auto x_re = poly_octave_v1::processSample (realFilter, z_re.get(), dryData[n]);
auto x_im = poly_octave_v1::processSample<true> (imagFilter, z_im.get(), dryData[n]);

auto x_re_sq = x_re * x_re;
auto x_im_sq = x_im * x_im;
Expand All @@ -178,33 +194,32 @@ void PolyOctave::processAudio (AudioBuffer<float>& buffer)
up2Data[n] = xsimd::reduce_add (up2DataSIMD[n]);
}

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> (ComplexERBFilterBank::numFilterBands));
up2OctaveGain.process (numSamples);
chowdsp::BufferMath::applyGainSmoothedBuffer (up2OctaveBuffer, up2OctaveGain);

chowdsp::BufferMath::applyGain (downOctaveBuffer, juce::Decibels::decibelsToGain (3.0f));
downOctaveGain.process (numSamples);
chowdsp::BufferMath::applyGainSmoothedBuffer (downOctaveBuffer, downOctaveGain);

dryGain.process (numSamples);
chowdsp::BufferMath::applyGainSmoothedBuffer (doubleBuffer, dryGain);
chowdsp::BufferMath::addBufferData (up2OctaveBuffer, doubleBuffer);
chowdsp::BufferMath::addBufferData (upOctaveBuffer, doubleBuffer);
chowdsp::BufferMath::addBufferData (downOctaveBuffer, doubleBuffer);
chowdsp::BufferMath::applyGain (upOctaveBuffer_double, 2.0 / static_cast<double> (poly_octave_v1::ComplexERBFilterBank::numFilterBands));
chowdsp::BufferMath::applyGain (up2OctaveBuffer_double, 2.0 / static_cast<double> (poly_octave_v1::ComplexERBFilterBank::numFilterBands));
chowdsp::BufferMath::applyGain (downOctaveBuffer_double, juce::Decibels::decibelsToGain (3.0f));

mixOutBuffer.setSize (numChannels, numSamples, false, false, true);
up1OutBuffer.setSize (numChannels, numSamples, false, false, true);
up2OutBuffer.setSize (numChannels, numSamples, false, false, true);
down1OutBuffer.setSize (numChannels, numSamples, false, false, true);

chowdsp::BufferMath::copyBufferData (doubleBuffer, mixOutBuffer);
chowdsp::BufferMath::copyBufferData (upOctaveBuffer, up1OutBuffer);
chowdsp::BufferMath::copyBufferData (up2OctaveBuffer, up2OutBuffer);
chowdsp::BufferMath::copyBufferData (downOctaveBuffer, down1OutBuffer);
chowdsp::BufferMath::copyBufferData (upOctaveBuffer_double, up1OutBuffer);
chowdsp::BufferMath::copyBufferData (up2OctaveBuffer_double, up2OutBuffer);
chowdsp::BufferMath::copyBufferData (downOctaveBuffer_double, down1OutBuffer);

upOctaveGain.process (numSamples);
chowdsp::BufferMath::applyGainSmoothedBuffer (up1OutBuffer, upOctaveGain);
up2OctaveGain.process (numSamples);
chowdsp::BufferMath::applyGainSmoothedBuffer (up2OutBuffer, up2OctaveGain);
downOctaveGain.process (numSamples);
chowdsp::BufferMath::applyGainSmoothedBuffer (down1OutBuffer, downOctaveGain);

dryGain.process (numSamples);
chowdsp::BufferMath::applyGainSmoothedBuffer (mixOutBuffer, dryGain);
chowdsp::BufferMath::addBufferData (up1OutBuffer, mixOutBuffer);
chowdsp::BufferMath::addBufferData (up2OutBuffer, mixOutBuffer);
chowdsp::BufferMath::addBufferData (down1OutBuffer, mixOutBuffer);

dcBlocker[MixOutput].processBlock (mixOutBuffer);
dcBlocker[Up1Output].processBlock (up1OutBuffer);
Expand All @@ -217,6 +232,7 @@ void PolyOctave::processAudio (AudioBuffer<float>& buffer)
outputBuffers.getReference (Down1Output) = &down1OutBuffer;
}


void PolyOctave::processAudioBypassed (AudioBuffer<float>& buffer)
{
const auto numSamples = buffer.getNumSamples();
Expand Down Expand Up @@ -256,3 +272,19 @@ String PolyOctave::getTooltipForPort (int portIndex, bool isInput)

return BaseProcessor::getTooltipForPort (portIndex, isInput);
}

void PolyOctave::fromXML (XmlElement* xml, const chowdsp::Version& version, bool loadPosition)
{
BaseProcessor::fromXML (xml, version, loadPosition);

using namespace std::string_view_literals;
#if JUCE_IOS
if (version <= chowdsp::Version { "2.1.0"sv })
#else
if (version <= chowdsp::Version { "1.3.0"sv })
#endif
{
// For versions before 1.3.0, default to v1 mode
v1_mode->setValueNotifyingHost (1.0f);
}
}
34 changes: 17 additions & 17 deletions src/processors/other/poly_octave/PolyOctave.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "DelayPitchShifter.h"
#include "processors/BaseProcessor.h"
#include "PolyOctaveFilterBankTypes.h"

class PolyOctave : public BaseProcessor
{
Expand All @@ -15,14 +16,9 @@ class PolyOctave : public BaseProcessor
void processAudio (AudioBuffer<float>& buffer) override;
void processAudioBypassed (AudioBuffer<float>& buffer) override;

String getTooltipForPort (int portIndex, bool isInput) override;
void fromXML (XmlElement* xml, const chowdsp::Version& version, bool loadPosition) 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;
};
String getTooltipForPort (int portIndex, bool isInput) override;

enum OutputPort
{
Expand All @@ -35,18 +31,22 @@ class PolyOctave : public BaseProcessor
static constexpr auto numOutputs = (int) magic_enum::enum_count<OutputPort>();

private:
chowdsp::SmoothedBufferValue<double> dryGain {};
chowdsp::SmoothedBufferValue<double> upOctaveGain {};
chowdsp::SmoothedBufferValue<double> up2OctaveGain {};
chowdsp::SmoothedBufferValue<double> downOctaveGain {};
void processAudioV1 (AudioBuffer<float>& buffer);

chowdsp::Buffer<double> doubleBuffer;
chowdsp::Buffer<double> upOctaveBuffer;
chowdsp::Buffer<double> up2OctaveBuffer;
chowdsp::Buffer<double> downOctaveBuffer;
chowdsp::BoolParameter* v1_mode = nullptr;

chowdsp::SmoothedBufferValue<float> dryGain {};
chowdsp::SmoothedBufferValue<float> upOctaveGain {};
chowdsp::SmoothedBufferValue<float> up2OctaveGain {};
chowdsp::SmoothedBufferValue<float> downOctaveGain {};

std::array<ComplexERBFilterBank, 2> octaveUpFilterBank;
std::array<ComplexERBFilterBank, 2> octaveUp2FilterBank;
// V1 processing stuff...
chowdsp::Buffer<double> doubleBuffer;
chowdsp::Buffer<double> upOctaveBuffer_double;
chowdsp::Buffer<double> up2OctaveBuffer_double;
chowdsp::Buffer<double> downOctaveBuffer_double;
std::array<poly_octave_v1::ComplexERBFilterBank, 2> octaveUpFilterBank;
std::array<poly_octave_v1::ComplexERBFilterBank, 2> octaveUp2FilterBank;
std::array<pitch_shift::Processor<double>, 2> downOctavePitchShifters;

std::array<chowdsp::FirstOrderHPF<float>, (size_t) numOutputs> dcBlocker;
Expand Down
14 changes: 9 additions & 5 deletions src/processors/other/poly_octave/PolyOctaveFilterBandHelpers.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
#pragma once

#include "PolyOctave.h"
#include "PolyOctaveFilterBankTypes.h"

namespace FilterBankHelpers
namespace poly_octave_v1
{
// 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::ComplexERBFilterBank::float_2;
static_assert (float_2::size == 2);
static_assert (xsimd::batch<double>::size == 2);
static constexpr auto vec_size = float_2::size;
Expand Down Expand Up @@ -89,13 +88,13 @@ static auto designERBFilter (size_t erb_index,
return center_target_freq;
}

static void designFilterBank (std::array<PolyOctave::ComplexERBFilterBank, 2>& filterBank,
static void designFilterBank (std::array<ComplexERBFilterBank, 2>& filterBank,
double gamma,
double erb_start,
double q_ERB,
double sampleRate)
{
for (size_t kiter = 0; kiter < PolyOctave::ComplexERBFilterBank::numFilterBands; kiter += vec_size)
for (size_t kiter = 0; kiter < 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 @@ -160,4 +159,9 @@ static void designFilterBank (std::array<PolyOctave::ComplexERBFilterBank, 2>& f
}
}
}

void process_filter_bank()
{

}
} // namespace FilterBankHelpers
13 changes: 13 additions & 0 deletions src/processors/other/poly_octave/PolyOctaveFilterBankTypes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include <pch.h>

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

0 comments on commit ef8df8b

Please sign in to comment.