From ce4127fb161f6ad9a360e3669a34d331214e192b Mon Sep 17 00:00:00 2001 From: Mikko Honkala Date: Sun, 4 Feb 2024 11:08:34 +0200 Subject: [PATCH 1/8] Added a lowpass filter before downsampling. Does not seem to reduce alias, though... --- dsp/RecursiveLinearFilter.cpp | 17 +++++++++++++++++ dsp/RecursiveLinearFilter.h | 7 +++++++ dsp/ResamplingContainer/ResamplingContainer.h | 15 +++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/dsp/RecursiveLinearFilter.cpp b/dsp/RecursiveLinearFilter.cpp index 7eb69b8..b056500 100644 --- a/dsp/RecursiveLinearFilter.cpp +++ b/dsp/RecursiveLinearFilter.cpp @@ -162,3 +162,20 @@ void recursive_linear_filter::HighShelf::SetParams(const recursive_linear_filter this->_AssignCoefficients(a0, a1, a2, b0, b1, b2); } + +void recursive_linear_filter::LowPassBiquad::SetParams(const recursive_linear_filter::BiquadParams& params) +{ + const double omega0 = params.GetOmega0(); + const double cosw0 = std::cos(omega0); + const double alpha = params.GetAlpha(omega0); + + const double b0 = (1.0 - cosw0) / 2.0; + const double b1 = 1.0 - cosw0; + const double b2 = (1.0 - cosw0) / 2.0; + const double a0 = 1.0 + alpha; + const double a1 = -2.0 * cosw0; + const double a2 = 1.0 - alpha; + + // Normalize the coefficients by a0 and assign them + this->_AssignCoefficients(a0, a1, a2, b0, b1, b2); +} diff --git a/dsp/RecursiveLinearFilter.h b/dsp/RecursiveLinearFilter.h index 737d297..a85acc7 100644 --- a/dsp/RecursiveLinearFilter.h +++ b/dsp/RecursiveLinearFilter.h @@ -202,4 +202,11 @@ class LowPass : public Base } }; +class LowPassBiquad : public Biquad +{ +public: + LowPassBiquad() : Biquad() {} + void SetParams(const BiquadParams& params) override; +}; + }; // namespace recursive_linear_filter diff --git a/dsp/ResamplingContainer/ResamplingContainer.h b/dsp/ResamplingContainer/ResamplingContainer.h index 4b8eb6c..f6477f1 100644 --- a/dsp/ResamplingContainer/ResamplingContainer.h +++ b/dsp/ResamplingContainer/ResamplingContainer.h @@ -54,6 +54,8 @@ iPlug 2 includes the following 3rd party libraries (see each license info): #include "Dependencies/WDL/ptrlist.h" #include "Dependencies/LanczosResampler.h" +#include "AudioDSPTools/dsp/RecursiveLinearFilter.h" + namespace dsp { @@ -133,6 +135,14 @@ class ResamplingContainer mResampler1 = std::make_unique(mInputSampleRate, mRenderingSampleRate); mResampler2 = std::make_unique(mRenderingSampleRate, mInputSampleRate); + + // Initialize the LowPassBiquad filter with appropriate parameters + double cutoffFrequency = std::min(mInputSampleRate, mRenderingSampleRate) / 2.0 * 0.9; // For example + double qualityFactor = 0.707; // A common choice for a Butterworth filter + double gainDB = 0; // Typically, no gain change for a low-pass filter + recursive_linear_filter::BiquadParams params(mRenderingSampleRate, cutoffFrequency, qualityFactor, gainDB); + mLowPassFilter.SetParams(params); + // Zeroes the scratch pointers so that we warm up with silence. ClearBuffers(); @@ -182,6 +192,9 @@ class ResamplingContainer { throw std::runtime_error("Got more encapsulated samples than the encapsulated DSP is prepared to handle!"); } + mLowPassFilter.Process(mEncapsulatedOutputPointers.GetList(), 1, populated1); + + func(mEncapsulatedInputPointers.GetList(), mEncapsulatedOutputPointers.GetList(), (int)populated1); // And push the results into the second resampler so that it has what the external context requires. mResampler2->PushBlock(mEncapsulatedOutputPointers.GetList(), populated1); @@ -201,6 +214,8 @@ class ResamplingContainer int GetLatency() const { return mLatency; } private: + recursive_linear_filter::LowPassBiquad mLowPassFilter; // Declaration of the LowPassBiquad filter + static inline int LinearInterpolate(T** inputs, T** outputs, int inputLen, double ratio, int maxOutputLen) { // FIXME check through this! From 4c1202f70d02d0df30408bc25fa0127549eac588 Mon Sep 17 00:00:00 2001 From: Mikko Honkala Date: Sun, 4 Feb 2024 12:36:54 +0200 Subject: [PATCH 2/8] Actually handle the return value of the lowpass filter before downsampling. Now it seems to work --- dsp/ResamplingContainer/ResamplingContainer.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dsp/ResamplingContainer/ResamplingContainer.h b/dsp/ResamplingContainer/ResamplingContainer.h index f6477f1..b14883f 100644 --- a/dsp/ResamplingContainer/ResamplingContainer.h +++ b/dsp/ResamplingContainer/ResamplingContainer.h @@ -192,12 +192,13 @@ class ResamplingContainer { throw std::runtime_error("Got more encapsulated samples than the encapsulated DSP is prepared to handle!"); } - mLowPassFilter.Process(mEncapsulatedOutputPointers.GetList(), 1, populated1); - + + func(mEncapsulatedInputPointers.GetList(), mEncapsulatedOutputPointers.GetList(), (int)populated1); + DSP_SAMPLE** filteredOutputs = mLowPassFilter.Process(mEncapsulatedOutputPointers.GetList(), 1, populated1); // And push the results into the second resampler so that it has what the external context requires. - mResampler2->PushBlock(mEncapsulatedOutputPointers.GetList(), populated1); + mResampler2->PushBlock(filteredOutputs, populated1); } // Pop the required output from the second resampler for the external context. From bc5e4c00b666a10ffdbfafcb4a296db82ac76cd3 Mon Sep 17 00:00:00 2001 From: Mikko Honkala Date: Sun, 4 Feb 2024 13:32:09 +0200 Subject: [PATCH 3/8] Also include the lowpass filter in the warmup in the Reset function. --- dsp/ResamplingContainer/ResamplingContainer.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dsp/ResamplingContainer/ResamplingContainer.h b/dsp/ResamplingContainer/ResamplingContainer.h index b14883f..bdfc52f 100644 --- a/dsp/ResamplingContainer/ResamplingContainer.h +++ b/dsp/ResamplingContainer/ResamplingContainer.h @@ -164,7 +164,8 @@ class ResamplingContainer // Therefore, we don't *acutally* need to use `func()`--we can assume that it would output silence! // func(mEncapsulatedInputPointers.GetList(), mEncapsulatedOutputPointers.GetList(), (int)populated); FallbackFunc(mEncapsulatedInputPointers.GetList(), mEncapsulatedOutputPointers.GetList(), (int)populated); - mResampler2->PushBlock(mEncapsulatedOutputPointers.GetList(), populated); + DSP_SAMPLE** silentProcessed = mLowPassFilter.Process(mEncapsulatedOutputPointers.GetList(), 1, populated); + mResampler2->PushBlock(silentProcessed, populated); // Now we're ready for the first "real" buffer. } } From 58e495e6e6ea30f61010868ed888e10bd3cb36e1 Mon Sep 17 00:00:00 2001 From: Mikko Honkala Date: Sun, 4 Feb 2024 16:47:27 +0200 Subject: [PATCH 4/8] Cleanup: moved to better place in the file, no functional change. --- dsp/ResamplingContainer/ResamplingContainer.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dsp/ResamplingContainer/ResamplingContainer.h b/dsp/ResamplingContainer/ResamplingContainer.h index bdfc52f..a4a32e7 100644 --- a/dsp/ResamplingContainer/ResamplingContainer.h +++ b/dsp/ResamplingContainer/ResamplingContainer.h @@ -216,7 +216,6 @@ class ResamplingContainer int GetLatency() const { return mLatency; } private: - recursive_linear_filter::LowPassBiquad mLowPassFilter; // Declaration of the LowPassBiquad filter static inline int LinearInterpolate(T** inputs, T** outputs, int inputLen, double ratio, int maxOutputLen) { @@ -338,6 +337,9 @@ class ResamplingContainer const double mRenderingSampleRate; // Pair of resamplers for (1) external -> encapsulated, (2) encapsulated -> external std::unique_ptr mResampler1, mResampler2; + // lowpass filter to reduce alias + recursive_linear_filter::LowPassBiquad mLowPassFilter; // Declaration of the LowPassBiquad filter + }; }; // namespace dsp From 749a845bdbaef2df8b8909b09eb51416d360e135 Mon Sep 17 00:00:00 2001 From: Mikko Honkala Date: Mon, 5 Feb 2024 23:27:02 +0200 Subject: [PATCH 5/8] Move LPF to resampler. --- .../Dependencies/LanczosResampler.h | 2 +- dsp/ResamplingContainer/ResamplingContainer.h | 83 ++++++++++++++----- 2 files changed, 64 insertions(+), 21 deletions(-) diff --git a/dsp/ResamplingContainer/Dependencies/LanczosResampler.h b/dsp/ResamplingContainer/Dependencies/LanczosResampler.h index 9849506..0b424df 100644 --- a/dsp/ResamplingContainer/Dependencies/LanczosResampler.h +++ b/dsp/ResamplingContainer/Dependencies/LanczosResampler.h @@ -205,7 +205,7 @@ class LanczosResampler return static_cast(std::max(res + 1.0, 0.0)); } - inline void PushBlock(T** inputs, size_t nFrames) + virtual inline void PushBlock(T** inputs, size_t nFrames) { for (auto s = 0; s < nFrames; s++) { diff --git a/dsp/ResamplingContainer/ResamplingContainer.h b/dsp/ResamplingContainer/ResamplingContainer.h index a4a32e7..740d829 100644 --- a/dsp/ResamplingContainer/ResamplingContainer.h +++ b/dsp/ResamplingContainer/ResamplingContainer.h @@ -56,10 +56,65 @@ iPlug 2 includes the following 3rd party libraries (see each license info): #include "Dependencies/LanczosResampler.h" #include "AudioDSPTools/dsp/RecursiveLinearFilter.h" +// #include "Dependencies/LanczosResamplerWithLPF.h" namespace dsp { +/** + * Extends the LanczosResampler class by integrating a LowPassBiquad filter to reduce aliasing. + * This subclass applies a low-pass filter to the input audio signal before performing + * the Lanczos resampling process. The low-pass filtering stage is crucial for removing + * high-frequency content that could cause aliasing when the signal is downsampled, + * ensuring a cleaner output signal with minimal distortion. + * + * The LowPassBiquad filter's parameters, such as the cutoff frequency, are set during + * the object's construction, allowing for flexible adaptation to various audio processing + * scenarios. This makes the LanczosResamplerWithLPF class particularly useful in applications + * where audio quality and fidelity are paramount, providing high-quality resampling + * with integrated anti-aliasing filtering. + * + * Template parameters: + * - T: The data type of the audio samples (e.g., float or double). + * - NCHANS: The number of audio channels to process (e.g., 1 for mono, 2 for stereo). + * - A: The filter size parameter of the Lanczos resampler, affecting quality and latency. + */ +template +class LanczosResamplerWithLPF : public LanczosResampler { +public: + recursive_linear_filter::LowPassBiquad lowPassFilter; + bool applyLPF = false; // Conditionally apply LPF + + // Constructor + LanczosResamplerWithLPF(float inputRate, float outputRate) + : LanczosResampler(inputRate, outputRate) { + // Compute cutoff frequency based on the output rate, set to just below Nyquist + float cutoffFrequency = outputRate / 2.0 * 0.9; // 90% of Nyquist frequency + + // Only initialize and apply LPF if downsampling + if (outputRate < inputRate) { + double qualityFactor = 0.707; // Common choice for a Butterworth filter + double gainDB = 0.0; // No gain change for a low-pass filter + recursive_linear_filter::BiquadParams params(inputRate, cutoffFrequency, qualityFactor, gainDB); + lowPassFilter.SetParams(params); + applyLPF = true; + } + } + + // Override the PushBlock method to conditionally apply LPF + void PushBlock(T** inputs, size_t nFrames) override { + if (applyLPF) { + // Apply the low-pass filter to the inputs before resampling + DSP_SAMPLE** dspInputs = reinterpret_cast(inputs); + DSP_SAMPLE** filteredOutputs = lowPassFilter.Process(dspInputs, NCHANS, nFrames); + LanczosResampler::PushBlock(reinterpret_cast(filteredOutputs), nFrames); + } else { + // Directly call base class PushBlock without LPF + LanczosResampler::PushBlock(inputs, nFrames); + } + } +}; + /** A multi-channel real-time resampling container that can be used to resample * audio processing to a specified sample rate for the situation where you have * some arbitary DSP code that requires a specific sample rate, then back to @@ -88,7 +143,7 @@ class ResamplingContainer { public: using BlockProcessFunc = std::function; - using LanczosResampler = LanczosResampler; + using LanczosResamplerWithLPF = LanczosResamplerWithLPF; // :param renderingSampleRate: The sample rate required by the code to be encapsulated. ResamplingContainer(double renderingSampleRate) @@ -132,16 +187,8 @@ class ResamplingContainer } { - mResampler1 = std::make_unique(mInputSampleRate, mRenderingSampleRate); - mResampler2 = std::make_unique(mRenderingSampleRate, mInputSampleRate); - - - // Initialize the LowPassBiquad filter with appropriate parameters - double cutoffFrequency = std::min(mInputSampleRate, mRenderingSampleRate) / 2.0 * 0.9; // For example - double qualityFactor = 0.707; // A common choice for a Butterworth filter - double gainDB = 0; // Typically, no gain change for a low-pass filter - recursive_linear_filter::BiquadParams params(mRenderingSampleRate, cutoffFrequency, qualityFactor, gainDB); - mLowPassFilter.SetParams(params); + mResampler1 = std::make_unique(mInputSampleRate, mRenderingSampleRate); + mResampler2 = std::make_unique(mRenderingSampleRate, mInputSampleRate); // Zeroes the scratch pointers so that we warm up with silence. ClearBuffers(); @@ -164,8 +211,7 @@ class ResamplingContainer // Therefore, we don't *acutally* need to use `func()`--we can assume that it would output silence! // func(mEncapsulatedInputPointers.GetList(), mEncapsulatedOutputPointers.GetList(), (int)populated); FallbackFunc(mEncapsulatedInputPointers.GetList(), mEncapsulatedOutputPointers.GetList(), (int)populated); - DSP_SAMPLE** silentProcessed = mLowPassFilter.Process(mEncapsulatedOutputPointers.GetList(), 1, populated); - mResampler2->PushBlock(silentProcessed, populated); + mResampler2->PushBlock(mEncapsulatedOutputPointers.GetList(), populated); // Now we're ready for the first "real" buffer. } } @@ -194,12 +240,9 @@ class ResamplingContainer throw std::runtime_error("Got more encapsulated samples than the encapsulated DSP is prepared to handle!"); } - - func(mEncapsulatedInputPointers.GetList(), mEncapsulatedOutputPointers.GetList(), (int)populated1); - DSP_SAMPLE** filteredOutputs = mLowPassFilter.Process(mEncapsulatedOutputPointers.GetList(), 1, populated1); // And push the results into the second resampler so that it has what the external context requires. - mResampler2->PushBlock(filteredOutputs, populated1); + mResampler2->PushBlock(mEncapsulatedOutputPointers.GetList(), populated1); } // Pop the required output from the second resampler for the external context. @@ -336,10 +379,10 @@ class ResamplingContainer // The sample rate required by the DSP that this object encapsulates const double mRenderingSampleRate; // Pair of resamplers for (1) external -> encapsulated, (2) encapsulated -> external - std::unique_ptr mResampler1, mResampler2; - // lowpass filter to reduce alias - recursive_linear_filter::LowPassBiquad mLowPassFilter; // Declaration of the LowPassBiquad filter + std::unique_ptr mResampler1, mResampler2; }; + + }; // namespace dsp From e69a93ae38bac3e77c6770e790635bf721249b6e Mon Sep 17 00:00:00 2001 From: Mikko Honkala Date: Mon, 5 Feb 2024 23:39:58 +0200 Subject: [PATCH 6/8] Move the modified resampler to its own file. --- .../Dependencies/LanczosResamplerWithLPF.h | 73 +++++++++++++++++++ dsp/ResamplingContainer/ResamplingContainer.h | 57 +-------------- 2 files changed, 74 insertions(+), 56 deletions(-) create mode 100644 dsp/ResamplingContainer/Dependencies/LanczosResamplerWithLPF.h diff --git a/dsp/ResamplingContainer/Dependencies/LanczosResamplerWithLPF.h b/dsp/ResamplingContainer/Dependencies/LanczosResamplerWithLPF.h new file mode 100644 index 0000000..d4d4fed --- /dev/null +++ b/dsp/ResamplingContainer/Dependencies/LanczosResamplerWithLPF.h @@ -0,0 +1,73 @@ +// File: ResamplingContainer.h +// Created Date: Monday February 5th 2024 +// Author: Mikko Honkala (mikko.honkala@gmail.com) + +// A container for real-time resampling using a Low pass filtered Lanczos anti-aliasing filter + +#pragma once + +#include +#include +#include + +#include "LanczosResampler.h" +#include "AudioDSPTools/dsp/RecursiveLinearFilter.h" + + +namespace dsp +{ +/** + * Extends the LanczosResampler class by integrating a LowPassBiquad filter to reduce aliasing. + * This subclass applies a low-pass filter to the input audio signal before performing + * the Lanczos resampling process. The low-pass filtering stage is crucial for removing + * high-frequency content that could cause aliasing when the signal is downsampled, + * ensuring a cleaner output signal with minimal distortion. + * + * The LowPassBiquad filter's parameters, such as the cutoff frequency, are set during + * the object's construction, allowing for flexible adaptation to various audio processing + * scenarios. This makes the LanczosResamplerWithLPF class particularly useful in applications + * where audio quality and fidelity are paramount, providing high-quality resampling + * with integrated anti-aliasing filtering. + * + * Template parameters: + * - T: The data type of the audio samples (e.g., float or double). + * - NCHANS: The number of audio channels to process (e.g., 1 for mono, 2 for stereo). + * - A: The filter size parameter of the Lanczos resampler, affecting quality and latency. + */ +template +class LanczosResamplerWithLPF : public LanczosResampler { +public: + recursive_linear_filter::LowPassBiquad lowPassFilter; + bool applyLPF = false; // Conditionally apply LPF + + // Constructor + LanczosResamplerWithLPF(float inputRate, float outputRate) + : LanczosResampler(inputRate, outputRate) { + // Compute cutoff frequency based on the output rate, set to just below Nyquist + float cutoffFrequency = outputRate / 2.0 * 0.9; // 90% of Nyquist frequency + + // Only initialize and apply LPF if downsampling + if (outputRate < inputRate) { + double qualityFactor = 0.707; // Common choice for a Butterworth filter + double gainDB = 0.0; // No gain change for a low-pass filter + recursive_linear_filter::BiquadParams params(inputRate, cutoffFrequency, qualityFactor, gainDB); + lowPassFilter.SetParams(params); + applyLPF = true; + } + } + + // Override the PushBlock method to conditionally apply LPF + void PushBlock(T** inputs, size_t nFrames) override { + if (applyLPF) { + // Apply the low-pass filter to the inputs before resampling + DSP_SAMPLE** dspInputs = reinterpret_cast(inputs); + DSP_SAMPLE** filteredOutputs = lowPassFilter.Process(dspInputs, NCHANS, nFrames); + LanczosResampler::PushBlock(reinterpret_cast(filteredOutputs), nFrames); + } else { + // Directly call base class PushBlock without LPF + LanczosResampler::PushBlock(inputs, nFrames); + } + } +}; + +}; // namespace dsp diff --git a/dsp/ResamplingContainer/ResamplingContainer.h b/dsp/ResamplingContainer/ResamplingContainer.h index 740d829..637f510 100644 --- a/dsp/ResamplingContainer/ResamplingContainer.h +++ b/dsp/ResamplingContainer/ResamplingContainer.h @@ -56,65 +56,10 @@ iPlug 2 includes the following 3rd party libraries (see each license info): #include "Dependencies/LanczosResampler.h" #include "AudioDSPTools/dsp/RecursiveLinearFilter.h" -// #include "Dependencies/LanczosResamplerWithLPF.h" +#include "Dependencies/LanczosResamplerWithLPF.h" namespace dsp { - -/** - * Extends the LanczosResampler class by integrating a LowPassBiquad filter to reduce aliasing. - * This subclass applies a low-pass filter to the input audio signal before performing - * the Lanczos resampling process. The low-pass filtering stage is crucial for removing - * high-frequency content that could cause aliasing when the signal is downsampled, - * ensuring a cleaner output signal with minimal distortion. - * - * The LowPassBiquad filter's parameters, such as the cutoff frequency, are set during - * the object's construction, allowing for flexible adaptation to various audio processing - * scenarios. This makes the LanczosResamplerWithLPF class particularly useful in applications - * where audio quality and fidelity are paramount, providing high-quality resampling - * with integrated anti-aliasing filtering. - * - * Template parameters: - * - T: The data type of the audio samples (e.g., float or double). - * - NCHANS: The number of audio channels to process (e.g., 1 for mono, 2 for stereo). - * - A: The filter size parameter of the Lanczos resampler, affecting quality and latency. - */ -template -class LanczosResamplerWithLPF : public LanczosResampler { -public: - recursive_linear_filter::LowPassBiquad lowPassFilter; - bool applyLPF = false; // Conditionally apply LPF - - // Constructor - LanczosResamplerWithLPF(float inputRate, float outputRate) - : LanczosResampler(inputRate, outputRate) { - // Compute cutoff frequency based on the output rate, set to just below Nyquist - float cutoffFrequency = outputRate / 2.0 * 0.9; // 90% of Nyquist frequency - - // Only initialize and apply LPF if downsampling - if (outputRate < inputRate) { - double qualityFactor = 0.707; // Common choice for a Butterworth filter - double gainDB = 0.0; // No gain change for a low-pass filter - recursive_linear_filter::BiquadParams params(inputRate, cutoffFrequency, qualityFactor, gainDB); - lowPassFilter.SetParams(params); - applyLPF = true; - } - } - - // Override the PushBlock method to conditionally apply LPF - void PushBlock(T** inputs, size_t nFrames) override { - if (applyLPF) { - // Apply the low-pass filter to the inputs before resampling - DSP_SAMPLE** dspInputs = reinterpret_cast(inputs); - DSP_SAMPLE** filteredOutputs = lowPassFilter.Process(dspInputs, NCHANS, nFrames); - LanczosResampler::PushBlock(reinterpret_cast(filteredOutputs), nFrames); - } else { - // Directly call base class PushBlock without LPF - LanczosResampler::PushBlock(inputs, nFrames); - } - } -}; - /** A multi-channel real-time resampling container that can be used to resample * audio processing to a specified sample rate for the situation where you have * some arbitary DSP code that requires a specific sample rate, then back to From 2bda267a222a22a33745c5fc76b3be1f9fe495af Mon Sep 17 00:00:00 2001 From: Mikko Honkala Date: Sat, 10 Feb 2024 10:14:27 +0200 Subject: [PATCH 7/8] Shortened comments. --- .../Dependencies/LanczosResamplerWithLPF.h | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/dsp/ResamplingContainer/Dependencies/LanczosResamplerWithLPF.h b/dsp/ResamplingContainer/Dependencies/LanczosResamplerWithLPF.h index d4d4fed..80af087 100644 --- a/dsp/ResamplingContainer/Dependencies/LanczosResamplerWithLPF.h +++ b/dsp/ResamplingContainer/Dependencies/LanczosResamplerWithLPF.h @@ -17,17 +17,10 @@ namespace dsp { /** - * Extends the LanczosResampler class by integrating a LowPassBiquad filter to reduce aliasing. + * Extends the LanczosResampler class by integrating a LowPassBiquad filter to reduce aliasing in + * the case of downsampilng. * This subclass applies a low-pass filter to the input audio signal before performing - * the Lanczos resampling process. The low-pass filtering stage is crucial for removing - * high-frequency content that could cause aliasing when the signal is downsampled, - * ensuring a cleaner output signal with minimal distortion. - * - * The LowPassBiquad filter's parameters, such as the cutoff frequency, are set during - * the object's construction, allowing for flexible adaptation to various audio processing - * scenarios. This makes the LanczosResamplerWithLPF class particularly useful in applications - * where audio quality and fidelity are paramount, providing high-quality resampling - * with integrated anti-aliasing filtering. + * the Lanczos downsampling process. In case of upsamping, the filter is not used. * * Template parameters: * - T: The data type of the audio samples (e.g., float or double). From 135d9ec52a8fb01e0c4900c3354015ca6a271c7f Mon Sep 17 00:00:00 2001 From: Mikko Honkala Date: Sat, 10 Feb 2024 11:00:36 +0200 Subject: [PATCH 8/8] Parametrize the cutoff ratio from Nyquist freq. --- .../Dependencies/LanczosResamplerWithLPF.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dsp/ResamplingContainer/Dependencies/LanczosResamplerWithLPF.h b/dsp/ResamplingContainer/Dependencies/LanczosResamplerWithLPF.h index 80af087..1922902 100644 --- a/dsp/ResamplingContainer/Dependencies/LanczosResamplerWithLPF.h +++ b/dsp/ResamplingContainer/Dependencies/LanczosResamplerWithLPF.h @@ -34,10 +34,10 @@ class LanczosResamplerWithLPF : public LanczosResampler { bool applyLPF = false; // Conditionally apply LPF // Constructor - LanczosResamplerWithLPF(float inputRate, float outputRate) + LanczosResamplerWithLPF(float inputRate, float outputRate, float cutoffRatioOfNyquist = 0.9) : LanczosResampler(inputRate, outputRate) { // Compute cutoff frequency based on the output rate, set to just below Nyquist - float cutoffFrequency = outputRate / 2.0 * 0.9; // 90% of Nyquist frequency + float cutoffFrequency = outputRate / 2.0 * cutoffRatioOfNyquist; // e.g., 90% of Nyquist frequency // Only initialize and apply LPF if downsampling if (outputRate < inputRate) {