Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EQ Updates #523

Merged
merged 6 commits into from
Apr 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/build-teensy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ jobs:
- name: Build
run: |
cc=~/.platformio/packages/toolchain-gccarmnoneeabi/bin/arm-none-eabi-g++
$cc -DCORE_TEENSY=1 --std=c++17 -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 --specs=nosys.specs -Imodules/common -Imodules/dsp -DJUCE_MODULE_AVAILABLE_chowdsp_buffers=1 -c modules/common/chowdsp_core/chowdsp_core.cpp
$cc -DCORE_TEENSY=1 --std=c++17 -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 --specs=nosys.specs -Imodules/common -Imodules/dsp -DJUCE_MODULE_AVAILABLE_chowdsp_buffers=1 -c modules/dsp/chowdsp_buffers/chowdsp_buffers.cpp
$cc -DCORE_TEENSY=1 --std=c++17 -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 --specs=nosys.specs -Imodules/common -Imodules/dsp -DJUCE_MODULE_AVAILABLE_chowdsp_buffers=1 -c modules/dsp/chowdsp_dsp_data_structures/chowdsp_dsp_data_structures.cpp
$cc -DCORE_TEENSY=1 --std=c++17 -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 --specs=nosys.specs -Imodules/common -Imodules/dsp -DJUCE_MODULE_AVAILABLE_chowdsp_buffers=1 -c modules/dsp/chowdsp_dsp_utils/chowdsp_dsp_utils.cpp
$cc -DCORE_TEENSY=1 --std=c++17 -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 --specs=nosys.specs -Imodules/common -Imodules/dsp -DJUCE_MODULE_AVAILABLE_chowdsp_buffers=1 -c modules/dsp/chowdsp_math/chowdsp_math.cpp
$cc -DCORE_TEENSY=1 --std=c++17 -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 --specs=nosys.specs -Imodules/common -Imodules/dsp -DJUCE_MODULE_AVAILABLE_chowdsp_buffers=1 -DJUCE_MODULE_AVAILABLE_chowdsp_data_structures=1 -c modules/common/chowdsp_core/chowdsp_core.cpp
$cc -DCORE_TEENSY=1 --std=c++17 -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 --specs=nosys.specs -Imodules/common -Imodules/dsp -DJUCE_MODULE_AVAILABLE_chowdsp_buffers=1 -DJUCE_MODULE_AVAILABLE_chowdsp_data_structures=1 -c modules/dsp/chowdsp_buffers/chowdsp_buffers.cpp
$cc -DCORE_TEENSY=1 --std=c++17 -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 --specs=nosys.specs -Imodules/common -Imodules/dsp -DJUCE_MODULE_AVAILABLE_chowdsp_buffers=1 -DJUCE_MODULE_AVAILABLE_chowdsp_data_structures=1 -c modules/dsp/chowdsp_dsp_data_structures/chowdsp_dsp_data_structures.cpp
$cc -DCORE_TEENSY=1 --std=c++17 -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 --specs=nosys.specs -Imodules/common -Imodules/dsp -DJUCE_MODULE_AVAILABLE_chowdsp_buffers=1 -DJUCE_MODULE_AVAILABLE_chowdsp_data_structures=1 -c modules/dsp/chowdsp_dsp_utils/chowdsp_dsp_utils.cpp
$cc -DCORE_TEENSY=1 --std=c++17 -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 --specs=nosys.specs -Imodules/common -Imodules/dsp -DJUCE_MODULE_AVAILABLE_chowdsp_buffers=1 -DJUCE_MODULE_AVAILABLE_chowdsp_data_structures=1 -c modules/dsp/chowdsp_math/chowdsp_math.cpp
4 changes: 4 additions & 0 deletions examples/SimpleEQ/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ target_sources(SimpleEQ
PluginEditor.cpp
FilterPlots.cpp
)
target_compile_definitions(SimpleEQ
PRIVATE
CHOWDSP_BUFFER_MAX_NUM_CHANNELS=2
)
2 changes: 1 addition & 1 deletion examples/SimpleEQ/SimpleEQPlugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ void SimpleEQPlugin::processAudioBlock (juce::AudioBuffer<float>& buffer)
// any thread, but we'll do it on the audio thread here.
setEQParams();

if (state.params.linPhaseMode.get())
if (state.params.linPhaseMode->get())
{
// Linear phase mode is on: processing the linear phase EQ here!
linPhaseEQ.processBlock (buffer);
Expand Down
18 changes: 18 additions & 0 deletions modules/dsp/chowdsp_buffers/Buffers/chowdsp_BufferView.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#pragma once

#if JUCE_MODULE_AVAILABLE_chowdsp_data_structures
#include <chowdsp_data_structures/chowdsp_data_structures.h>
#endif

namespace chowdsp
{
/**
Expand Down Expand Up @@ -372,4 +376,18 @@ template <typename BufferType,
std::is_same_v<BufferType, const Buffer<xsimd::batch<double>>> || (std::is_const_v<BufferType> && detail::is_static_buffer_v<std::remove_const_t<BufferType>, xsimd::batch<double>>)>>
BufferView (BufferType&, Ts...) -> BufferView<const xsimd::batch<double>>;
#endif // ! CHOWDSP_NO_XSIMD

#if JUCE_MODULE_AVAILABLE_chowdsp_data_structures
template <typename T>
BufferView<T> make_temp_buffer (ArenaAllocatorView arena, int num_channels, int num_samples)
{
std::array<T*, CHOWDSP_BUFFER_MAX_NUM_CHANNELS> channel_pointers {};
for (size_t ch = 0; ch < static_cast<size_t> (num_channels); ++ch)
{
channel_pointers[ch] = arena.allocate<T> (num_samples, SIMDUtils::defaultSIMDAlignment);
jassert (channel_pointers[ch] != nullptr);
}
return { channel_pointers.data(), num_channels, num_samples };
}
#endif
} // namespace chowdsp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@ void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (int numSample
}
}

template <typename FloatType, typename ValueSmoothingTypes>
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (int numSamples, ArenaAllocatorView alloc)
{
bufferData = alloc.allocate<FloatType> (numSamples, bufferAlignment);
jassert (bufferData != nullptr); // arena allocator is out of memory!
process (numSamples);
}

template <typename FloatType, typename ValueSmoothingTypes>
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (FloatType value, int numSamples)
{
Expand All @@ -117,6 +125,14 @@ void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (FloatType val
bufferData[n] = smoother.getNextValue();
}

template <typename FloatType, typename ValueSmoothingTypes>
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (FloatType value, int numSamples, ArenaAllocatorView alloc)
{
bufferData = alloc.allocate<FloatType> (numSamples, bufferAlignment);
jassert (bufferData != nullptr); // arena allocator is out of memory!
process (value, numSamples);
}

template class SmoothedBufferValue<float, juce::ValueSmoothingTypes::Linear>;
template class SmoothedBufferValue<double, juce::ValueSmoothingTypes::Linear>;
template class SmoothedBufferValue<float, juce::ValueSmoothingTypes::Multiplicative>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,25 +79,15 @@ class SmoothedBufferValue
*/
void process (int numSamples);

void process (int numSamples, ArenaAllocatorView alloc)
{
bufferData = alloc.allocate<FloatType> (numSamples, bufferAlignment);
jassert (bufferData != nullptr); // arena allocator is out of memory!
process (numSamples);
}
void process (int numSamples, ArenaAllocatorView alloc);

/**
* Process smoothing for the input value.
* If smoothing an audio parameter, it is recommended to use a parameter handle instead!
*/
void process (FloatType value, int numSamples);

void process (FloatType value, int numSamples, ArenaAllocatorView alloc)
{
bufferData = alloc.allocate<FloatType> (numSamples, bufferAlignment);
jassert (bufferData != nullptr); // arena allocator is out of memory!
process (value, numSamples);
}
void process (FloatType value, int numSamples, ArenaAllocatorView alloc);

/** Returns a pointer to the current smoothed buffer. */
[[nodiscard]] const FloatType* getSmoothedBuffer() const { return bufferData; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
namespace chowdsp
{
template <typename SampleType, typename DelayInterpType>
void BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<std::is_same_v<DelayInterpType, std::nullptr_t>>>::prepare (const juce::dsp::ProcessSpec& spec, bool onOffParam)
void BypassProcessor<SampleType,
DelayInterpType,
std::enable_if_t<std::is_same_v<DelayInterpType, NullType>>>::prepare (const juce::dsp::ProcessSpec& spec, bool onOffParam, bool useInternalBuffer)
{
prevOnOffParam = onOffParam;
fadeBuffer.setMaxSize ((int) spec.numChannels, (int) spec.maximumBlockSize);
if (useInternalBuffer)
fadeBuffer.setMaxSize ((int) spec.numChannels, (int) spec.maximumBlockSize);
}

template <typename SampleType, typename DelayInterpType>
bool BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<std::is_same_v<DelayInterpType, std::nullptr_t>>>::processBlockIn (const BufferView<const SampleType>& block, bool onOffParam)
bool BypassProcessor<SampleType,
DelayInterpType,
std::enable_if_t<std::is_same_v<DelayInterpType, NullType>>>::processBlockIn (const BufferView<const SampleType>& block,
bool onOffParam,
std::optional<ArenaAllocatorView> arena)
{
if (! onOffParam && ! prevOnOffParam)
{
Expand All @@ -17,15 +24,21 @@ bool BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<std::is_same_

if (onOffParam != prevOnOffParam)
{
fadeBuffer.setCurrentSize (block.getNumChannels(), block.getNumSamples());
BufferMath::copyBufferData (block, fadeBuffer);
if (arena.has_value())
fadeBufferView = make_temp_buffer<SampleType> (*arena, block.getNumChannels(), block.getNumSamples());
else
fadeBufferView = BufferView { fadeBuffer, 0, block.getNumSamples(), 0, block.getNumChannels() };

BufferMath::copyBufferData (block, fadeBufferView);
}

return true;
}

template <typename SampleType, typename DelayInterpType>
void BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<std::is_same_v<DelayInterpType, std::nullptr_t>>>::processBlockOut (const BufferView<SampleType>& block, bool onOffParam)
void BypassProcessor<SampleType,
DelayInterpType,
std::enable_if_t<std::is_same_v<DelayInterpType, NullType>>>::processBlockOut (const BufferView<SampleType>& block, bool onOffParam)
{
auto fadeOutputBuffer = [onOffParam] (auto* blockPtr, const auto* fadePtr, const int startSample, const int numSamples)
{
Expand Down Expand Up @@ -68,7 +81,7 @@ void BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<std::is_same_
for (int ch = 0; ch < numChannels; ++ch)
{
auto* blockPtr = block.getWritePointer (ch);
const auto* fadePtr = fadeBuffer.getReadPointer (ch);
const auto* fadePtr = fadeBufferView.getReadPointer (ch);

fadeOutputBuffer (blockPtr, fadePtr, 0, numSamples);
}
Expand All @@ -79,29 +92,40 @@ void BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<std::is_same_

//===========================================================
template <typename SampleType, typename DelayInterpType>
void BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<! std::is_same_v<DelayInterpType, std::nullptr_t>>>::prepare (const juce::dsp::ProcessSpec& spec, bool onOffParam)
void BypassProcessor<SampleType,
DelayInterpType,
std::enable_if_t<! std::is_same_v<DelayInterpType, NullType>>>::prepare (const juce::dsp::ProcessSpec& spec,
bool onOffParam,
bool useInternalBuffer)
{
prevOnOffParam = onOffParam;
fadeBuffer.setMaxSize ((int) spec.numChannels, (int) spec.maximumBlockSize);
if (useInternalBuffer)
fadeBuffer.setMaxSize ((int) spec.numChannels, (int) spec.maximumBlockSize);

compDelay.prepare (spec); // sample rate does not matter
}

template <typename SampleType, typename DelayInterpType>
void BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<! std::is_same_v<DelayInterpType, std::nullptr_t>>>::setLatencySamples (int delaySamples)
void BypassProcessor<SampleType,
DelayInterpType,
std::enable_if_t<! std::is_same_v<DelayInterpType, NullType>>>::setLatencySamples (int delaySamples)
{
setLatencySamplesInternal ((NumericType) delaySamples);
}

template <typename SampleType, typename DelayInterpType>
void BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<! std::is_same_v<DelayInterpType, std::nullptr_t>>>::setLatencySamples (NumericType delaySamples)
void BypassProcessor<SampleType,
DelayInterpType,
std::enable_if_t<! std::is_same_v<DelayInterpType, NullType>>>::setLatencySamples (NumericType delaySamples)
{
static_assert (! std::is_same_v<DelayInterpType, DelayLineInterpolationTypes::None>, "Attempting to set non-integer latency value without using delay interpolation!");
setLatencySamplesInternal (delaySamples);
}

template <typename SampleType, typename DelayInterpType>
void BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<! std::is_same_v<DelayInterpType, std::nullptr_t>>>::setLatencySamplesInternal (NumericType delaySamples)
void BypassProcessor<SampleType,
DelayInterpType,
std::enable_if_t<! std::is_same_v<DelayInterpType, NullType>>>::setLatencySamplesInternal (NumericType delaySamples)
{
if (juce::approximatelyEqual (delaySamples, prevDelay))
return;
Expand All @@ -115,7 +139,11 @@ void BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<! std::is_sam
}

template <typename SampleType, typename DelayInterpType>
bool BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<! std::is_same_v<DelayInterpType, std::nullptr_t>>>::processBlockIn (const BufferView<SampleType>& block, bool onOffParam)
bool BypassProcessor<SampleType,
DelayInterpType,
std::enable_if_t<! std::is_same_v<DelayInterpType, NullType>>>::processBlockIn (const BufferView<SampleType>& block,
bool onOffParam,
std::optional<ArenaAllocatorView> arena)
{
enum class DelayOp
{
Expand Down Expand Up @@ -161,9 +189,13 @@ bool BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<! std::is_sam

if (onOffParam != prevOnOffParam)
{
fadeBuffer.setCurrentSize (block.getNumChannels(), block.getNumSamples());
BufferMath::copyBufferData (block, fadeBuffer);
doDelayOp (fadeBuffer, compDelay, DelayOp::Pop);
if (arena.has_value())
fadeBufferView = make_temp_buffer<SampleType> (*arena, block.getNumChannels(), block.getNumSamples());
else
fadeBufferView = BufferView { fadeBuffer, 0, block.getNumSamples(), 0, block.getNumChannels() };

BufferMath::copyBufferData (block, fadeBufferView);
doDelayOp (fadeBufferView, compDelay, DelayOp::Pop);

if (onOffParam && latencySampleCount < 0)
latencySampleCount = (int) compDelay.getDelay();
Expand All @@ -177,7 +209,9 @@ bool BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<! std::is_sam
}

template <typename SampleType, typename DelayInterpType>
void BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<! std::is_same_v<DelayInterpType, std::nullptr_t>>>::processBlockOut (const BufferView<SampleType>& block, bool onOffParam)
void BypassProcessor<SampleType,
DelayInterpType,
std::enable_if_t<! std::is_same_v<DelayInterpType, NullType>>>::processBlockOut (const BufferView<SampleType>& block, bool onOffParam)
{
auto fadeOutputBuffer = [onOffParam] (auto* blockPtr, const auto* fadePtr, const int startSample, const int numSamples)
{
Expand Down Expand Up @@ -222,7 +256,7 @@ void BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<! std::is_sam
for (int ch = 0; ch < numChannels; ++ch)
{
auto* blockPtr = block.getWritePointer (ch);
const auto* fadePtr = fadeBuffer.getReadPointer (ch);
const auto* fadePtr = fadeBufferView.getReadPointer (ch);

fadeOutputBuffer (blockPtr, fadePtr, startSample, numSamples);
}
Expand All @@ -232,7 +266,9 @@ void BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<! std::is_sam
}

template <typename SampleType, typename DelayInterpType>
int BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<! std::is_same_v<DelayInterpType, std::nullptr_t>>>::getFadeStartSample (const int numSamples)
int BypassProcessor<SampleType,
DelayInterpType,
std::enable_if_t<! std::is_same_v<DelayInterpType, NullType>>>::getFadeStartSample (const int numSamples)
{
if (latencySampleCount <= 0)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ namespace chowdsp
* }
* ```
*/
template <typename SampleType, typename DelayInterpType = std::nullptr_t, typename = void>
template <typename SampleType, typename DelayInterpType = NullType, typename = void>
class BypassProcessor;

template <typename SampleType, typename DelayInterpType>
class BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<std::is_same_v<DelayInterpType, std::nullptr_t>>>
class BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<std::is_same_v<DelayInterpType, NullType>>>
{
public:
using NumericType = SampleTypeHelpers::NumericType<SampleType>;
Expand All @@ -40,14 +40,14 @@ class BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<std::is_same
}

/** Allocated required memory, and resets the property */
void prepare (const juce::dsp::ProcessSpec& spec, bool onOffParam);
void prepare (const juce::dsp::ProcessSpec& spec, bool onOffParam, bool useInternalBuffer = true);

/**
* Call this at the start of your processBlock().
* If it returns false, you can safely skip all other
* processing.
*/
bool processBlockIn (const BufferView<const SampleType>& buffer, bool onOffParam);
bool processBlockIn (const BufferView<const SampleType>& buffer, bool onOffParam, std::optional<ArenaAllocatorView> arena = std::nullopt);

/**
* Call this at the end of your processBlock().
Expand All @@ -59,12 +59,13 @@ class BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<std::is_same
private:
bool prevOnOffParam = false;
Buffer<SampleType> fadeBuffer;
BufferView<SampleType> fadeBufferView;

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BypassProcessor)
};

template <typename SampleType, typename DelayInterpType>
class BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<! std::is_same_v<DelayInterpType, std::nullptr_t>>>
class BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<! std::is_same_v<DelayInterpType, NullType>>>
{
public:
using NumericType = SampleTypeHelpers::NumericType<SampleType>;
Expand All @@ -78,7 +79,7 @@ class BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<! std::is_sa
}

/** Allocated required memory, and resets the property */
void prepare (const juce::dsp::ProcessSpec& spec, bool onOffParam);
void prepare (const juce::dsp::ProcessSpec& spec, bool onOffParam, bool useInternalBuffer = true);

/**
* If the non-bypassed processing has some associated
Expand All @@ -101,7 +102,7 @@ class BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<! std::is_sa
* If it returns false, you can safely skip all other
* processing.
*/
bool processBlockIn (const BufferView<SampleType>& buffer, bool onOffParam);
bool processBlockIn (const BufferView<SampleType>& buffer, bool onOffParam, std::optional<ArenaAllocatorView> arena = std::nullopt);

/**
* Call this at the end of your processBlock().
Expand All @@ -116,6 +117,7 @@ class BypassProcessor<SampleType, DelayInterpType, std::enable_if_t<! std::is_sa

bool prevOnOffParam = false;
Buffer<SampleType> fadeBuffer;
BufferView<SampleType> fadeBufferView;

DelayLine<SampleType, DelayInterpType> compDelay { 1 << 18 }; // max latency = 2^18 = 262144 samples
NumericType prevDelay {};
Expand Down
Loading
Loading