commit 24f83b8d3bf40a2e560c7b259342f2f04e8289d5
parent 19f1a8b093c4a11bcd326b1a46bab13cb24d2f21
Author: jatinchowdhury18 <jatinchowdhury18@gmail.com>
Date: Sun, 28 Feb 2021 22:55:48 -0800
Use std::vector instead of raw pointer arrays for FIR Filter, and fix vDSP include (#147)
* Use std::vector instead of raw pointer arrays for FIR Filter, and fix vDSP include
* {Apply clang-format}
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Diffstat:
5 files changed, 119 insertions(+), 22 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
@@ -2,13 +2,15 @@
All notable changes to this project will be documented in
this file.
-
## [Unreleased]
+- Added Variance and Drift parameters for Wow control.
- Fixed stability issue in tone filters.
- Improved parameter names for automation menus.
- Fixed GUI freezing bug in Cakewalk.
- Fixed gain staging bug in Renoise.
- Migrated build pipeline to CMake.
+- Updated "STN" hysteresis mode to use XSIMD backend.
+- Created installer packages for Windows/Mac.
## [2.7.0] - 2020-11-25
- Added new hysteresis mode: State Transition Network (STN)
diff --git a/Plugin/Source/Headless/Benchmarks.cpp b/Plugin/Source/Headless/Benchmarks.cpp
@@ -12,7 +12,7 @@ Benchmarks::Benchmarks()
{
this->commandOption = "--bench";
this->argumentDescription = "--bench --file=FILE --mode=MODE";
- this->shortDescription = "Runs benchmarks for ChowTapeModel documentation";
+ this->shortDescription = "Runs benchmarks for ChowTapeModel";
this->longDescription = "";
this->command = std::bind (&Benchmarks::runBenchmarks, this, std::placeholders::_1);
}
diff --git a/Plugin/Source/Headless/FirBench.h b/Plugin/Source/Headless/FirBench.h
@@ -0,0 +1,89 @@
+#include "../Processors/Loss_Effects/FIRFilter.h"
+
+namespace
+{
+constexpr double pluginSampleRate = 48000.0;
+constexpr int samplesPerBlock = 256;
+} // namespace
+
+class FirBench : public ConsoleApplication::Command
+{
+public:
+ FirBench()
+ {
+ this->commandOption = "--fir-bench";
+ this->argumentDescription = "--fir-bench --size=FILTER_SIZE --length=AUDIO_LENGTH";
+ this->shortDescription = "Runs benchmarks for ChowTapeModel FIR Filters";
+ this->longDescription = "";
+ this->command = std::bind (&FirBench::runBench, this, std::placeholders::_1);
+ }
+
+ void runBench (const ArgumentList& args)
+ {
+ int firSize = 128;
+ if (args.containsOption ("--size"))
+ firSize = args.getValueForOption ("--size").getIntValue();
+
+ std::cout << "Creating FIR filter with size " << firSize << std::endl;
+ FIRFilter filter { firSize };
+ setFilterCoefs (filter, (size_t) firSize);
+
+ float audioLength = 30.0f;
+ if (args.containsOption ("--length"))
+ audioLength = args.getValueForOption ("--length").getFloatValue();
+
+ std::cout << "Creating audio buffer of length " << audioLength << " seconds" << std::endl;
+ const int numSamples = int (audioLength * pluginSampleRate);
+ auto buffer = createAudio (numSamples);
+
+ std::cout << "Processing audio..." << std::endl;
+ filter.reset();
+ auto time = timeAudioProcess (filter, buffer, samplesPerBlock);
+
+ std::cout << "Results:" << std::endl;
+ std::cout << audioLength / time << "x real-time" << std::endl;
+ std::cout << time << " seconds" << std::endl;
+ }
+
+private:
+ void setFilterCoefs (FIRFilter& filter, const size_t size)
+ {
+ std::vector<float> coefs (size);
+ Random r;
+ for (size_t i = 0; i < size; ++i)
+ coefs[i] = r.nextFloat() * 2.0f + 1.0f;
+
+ filter.setCoefs (coefs.data());
+ }
+
+ AudioBuffer<float> createAudio (const int numSamples)
+ {
+ AudioBuffer<float> buffer (1, numSamples);
+ Random r;
+ for (int i = 0; i < numSamples; ++i)
+ buffer.setSample (0, i, r.nextFloat() * 2.0f + 1.0f);
+
+ return buffer;
+ }
+
+ double timeAudioProcess (FIRFilter& filter, AudioBuffer<float>& audio, const int blockSize)
+ {
+ auto totalNumSamples = audio.getNumSamples();
+ int samplePtr = 0;
+
+ Time time;
+ auto start = time.getMillisecondCounterHiRes();
+ while (totalNumSamples > 0)
+ {
+ auto curBlockSize = jmin (totalNumSamples, blockSize);
+ totalNumSamples -= curBlockSize;
+
+ filter.process (audio.getWritePointer (0) + samplePtr, curBlockSize);
+ samplePtr += curBlockSize;
+ }
+
+ return (time.getMillisecondCounterHiRes() - start) / 1000.0;
+ }
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FirBench)
+};
diff --git a/Plugin/Source/Headless/Main.cpp b/Plugin/Source/Headless/Main.cpp
@@ -1,6 +1,6 @@
#include "Benchmarks.h"
+#include "FirBench.h"
#include "ScreenshotHelper.h"
-#include <JuceHeader.h>
String getVersion()
{
@@ -31,5 +31,8 @@ int main (int argc, char* argv[])
Benchmarks benchmarks;
app.addCommand (benchmarks);
+ FirBench firBench;
+ app.addCommand (firBench);
+
return app.findAndRunCommand (argc, argv);
}
diff --git a/Plugin/Source/Processors/Loss_Effects/FIRFilter.h b/Plugin/Source/Processors/Loss_Effects/FIRFilter.h
@@ -1,34 +1,37 @@
#ifndef FIRFILTER_H_INCLUDED
#define FIRFILTER_H_INCLUDED
-#include "JuceHeader.h"
+// include <Accelerate> on Apple devices so we can use vDSP_dotpr
+#if JUCE_MAC || JUCE_IOS
+#define Point CarbonDummyPointName
+#define Component CarbonDummyCompName
+#include <Accelerate/Accelerate.h>
+#undef Point
+#undef Component
+#endif
+
+#include <JuceHeader.h>
#include <numeric>
/** FIR filter using a double-buffer and std::inner_product */
class FIRFilter
{
public:
- FIRFilter (int order) : order (order)
- {
- h = new float[order];
- z = new float[2 * order];
- }
-
- ~FIRFilter()
+ FIRFilter (int filter_order) : order ((size_t) filter_order)
{
- delete[] h;
- delete[] z;
+ h.resize (order);
+ z.resize (2 * order);
}
void reset()
{
zPtr = 0;
- FloatVectorOperations::fill (z, 0.0f, 2 * order);
+ FloatVectorOperations::fill (z.data(), 0.0f, 2 * (int) order);
}
void setCoefs (float* coefs)
{
- FloatVectorOperations::copy (h, coefs, order);
+ FloatVectorOperations::copy (h.data(), coefs, (int) order);
}
inline void process (float* buffer, int numSamples)
@@ -40,11 +43,11 @@ public:
z[zPtr] = buffer[n];
z[zPtr + order] = buffer[n];
-#ifdef JUCE_USE_VDSP_FRAMEWORK
+#if JUCE_MAC || JUCE_IOS
y = 0.0f;
- vDSP_dotpr (z + zPtr, 1, h, 1, &y, order); // use Acclerate inner product (if available)
+ vDSP_dotpr (z.data() + zPtr, 1, h.data(), 1, &y, order); // use Acclerate inner product (if available)
#else
- y = std::inner_product (z + zPtr, z + zPtr + order, h, 0.0f); // comput inner product
+ y = std::inner_product (z.data() + zPtr, z.data() + zPtr + order, h.data(), 0.0f); // comput inner product
#endif
zPtr = (zPtr == 0 ? order - 1 : zPtr - 1); // iterate state pointer in reverse
@@ -63,12 +66,12 @@ public:
}
protected:
- float* h;
- const int order;
+ std::vector<float> h;
+ const size_t order;
private:
- float* z;
- int zPtr = 0;
+ std::vector<float> z;
+ size_t zPtr = 0;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FIRFilter)
};