OpenShot Audio Library | OpenShotAudio 0.3.2
Loading...
Searching...
No Matches
juce_FIRFilter_test.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 5 End-User License
11 Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
12 27th April 2017).
13
14 End User License Agreement: www.juce.com/juce-5-licence
15 Privacy Policy: www.juce.com/juce-5-privacy-policy
16
17 Or: You may also use this code under the terms of the GPL v3 (see
18 www.gnu.org/licenses).
19
20 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22 DISCLAIMED.
23
24 ==============================================================================
25*/
26
27namespace juce
28{
29namespace dsp
30{
31
32class FIRFilterTest : public UnitTest
33{
34 template <typename Type>
35 struct Helpers
36 {
37 static void fillRandom (Random& random, Type* buffer, size_t n)
38 {
39 for (size_t i = 0; i < n; ++i)
40 buffer[i] = (2.0f * random.nextFloat()) - 1.0f;
41 }
42
43 static bool checkArrayIsSimilar (Type* a, Type* b, size_t n) noexcept
44 {
45 for (size_t i = 0; i < n; ++i)
46 if (std::abs (a[i] - b[i]) > 1e-6f)
47 return false;
48
49 return true;
50 }
51 };
52
53 #if JUCE_USE_SIMD
54 template <typename Type>
55 struct Helpers<SIMDRegister<Type>>
56 {
57 static void fillRandom (Random& random, SIMDRegister<Type>* buffer, size_t n)
58 {
59 Helpers<Type>::fillRandom (random, reinterpret_cast<Type*> (buffer), n * SIMDRegister<Type>::size());
60 }
61
62 static bool checkArrayIsSimilar (SIMDRegister<Type>* a, SIMDRegister<Type>* b, size_t n) noexcept
63 {
64 return Helpers<Type>::checkArrayIsSimilar (reinterpret_cast<Type*> (a),
65 reinterpret_cast<Type*> (b),
67 }
68 };
69 #endif
70
71 template <typename Type>
72 static void fillRandom (Random& random, Type* buffer, size_t n) { Helpers<Type>::fillRandom (random, buffer, n); }
73
74 template <typename Type>
75 static bool checkArrayIsSimilar (Type* a, Type* b, size_t n) noexcept { return Helpers<Type>::checkArrayIsSimilar (a, b, n); }
76
77 //==============================================================================
78 // reference implementation of an FIR
79 template <typename SampleType, typename NumericType>
80 static void reference (const NumericType* firCoefficients, size_t numCoefficients,
81 const SampleType* input, SampleType* output, size_t n) noexcept
82 {
83 if (numCoefficients == 0)
84 {
85 zeromem (output, sizeof (SampleType) * n);
86 return;
87 }
88
89 HeapBlock<SampleType> scratchBuffer (numCoefficients
90 #if JUCE_USE_SIMD
91 + (SIMDRegister<NumericType>::SIMDRegisterSize / sizeof (SampleType))
92 #endif
93 );
94 #if JUCE_USE_SIMD
95 SampleType* buffer = reinterpret_cast<SampleType*> (SIMDRegister<NumericType>::getNextSIMDAlignedPtr (reinterpret_cast<NumericType*> (scratchBuffer.getData())));
96 #else
97 SampleType* buffer = scratchBuffer.getData();
98 #endif
99
100 zeromem (buffer, sizeof (SampleType) * numCoefficients);
101
102 for (size_t i = 0; i < n; ++i)
103 {
104 for (size_t j = (numCoefficients - 1); j >= 1; --j)
105 buffer[j] = buffer[j-1];
106
107 buffer[0] = input[i];
108
109 SampleType sum (0);
110
111 for (size_t j = 0; j < numCoefficients; ++j)
112 sum += buffer[j] * firCoefficients[j];
113
114 output[i] = sum;
115 }
116 }
117
118 //==============================================================================
119 struct LargeBlockTest
120 {
121 template <typename FloatType>
122 static void run (FIR::Filter<FloatType>& filter, FloatType* src, FloatType* dst, size_t n)
123 {
124 AudioBlock<const FloatType> input (&src, 1, n);
125 AudioBlock<FloatType> output (&dst, 1, n);
126 ProcessContextNonReplacing<FloatType> context (input, output);
127
128 filter.process (context);
129 }
130 };
131
132 struct SampleBySampleTest
133 {
134 template <typename FloatType>
135 static void run (FIR::Filter<FloatType>& filter, FloatType* src, FloatType* dst, size_t n)
136 {
137 for (size_t i = 0; i < n; ++i)
138 dst[i] = filter.processSample (src[i]);
139 }
140 };
141
142 struct SplitBlockTest
143 {
144 template <typename FloatType>
145 static void run (FIR::Filter<FloatType>& filter, FloatType* input, FloatType* output, size_t n)
146 {
147 size_t len = 0;
148 for (size_t i = 0; i < n; i += len)
149 {
150 len = jmin (n - i, n / 3);
151 auto* src = input + i;
152 auto* dst = output + i;
153
154 AudioBlock<const FloatType> inBlock (&src, 1, len);
155 AudioBlock<FloatType> outBlock (&dst, 1, len);
156 ProcessContextNonReplacing<FloatType> context (inBlock, outBlock);
157
158 filter.process (context);
159 }
160 }
161 };
162
163 //==============================================================================
164 template <typename TheTest, typename SampleType, typename NumericType>
165 void runTestForType()
166 {
167 Random random (8392829);
168
169 for (auto size : {1, 2, 4, 8, 12, 13, 25})
170 {
171 constexpr size_t n = 813;
172
173 HeapBlock<char> inputBuffer, outputBuffer, refBuffer;
174 AudioBlock<SampleType> input (inputBuffer, 1, n), output (outputBuffer, 1, n), ref (refBuffer, 1, n);
175 fillRandom (random, input.getChannelPointer (0), n);
176
177 HeapBlock<char> firBlock;
178 AudioBlock<NumericType> fir (firBlock, 1, static_cast<size_t> (size));
179 fillRandom (random, fir.getChannelPointer (0), static_cast<size_t> (size));
180
181 FIR::Filter<SampleType> filter (*new FIR::Coefficients<NumericType> (fir.getChannelPointer (0), static_cast<size_t> (size)));
182 ProcessSpec spec {0.0, n, 1};
183 filter.prepare (spec);
184
185 reference<SampleType, NumericType> (fir.getChannelPointer (0), static_cast<size_t> (size),
186 input.getChannelPointer (0), ref.getChannelPointer (0), n);
187
188 TheTest::template run<SampleType> (filter, input.getChannelPointer (0), output.getChannelPointer (0), n);
189 expect (checkArrayIsSimilar (output.getChannelPointer (0), ref.getChannelPointer (0), n));
190 }
191 }
192
193 template <typename TheTest>
194 void runTestForAllTypes (const char* unitTestName)
195 {
196 beginTest (unitTestName);
197
198 runTestForType<TheTest, float, float>();
199 runTestForType<TheTest, double, double>();
200 #if JUCE_USE_SIMD
201 runTestForType<TheTest, SIMDRegister<float>, float>();
202 runTestForType<TheTest, SIMDRegister<double>, double>();
203 #endif
204 }
205
206
207public:
208 FIRFilterTest()
209 : UnitTest ("FIR Filter", UnitTestCategories::dsp)
210 {}
211
212 void runTest() override
213 {
214 runTestForAllTypes<LargeBlockTest> ("Large Blocks");
215 runTestForAllTypes<SampleBySampleTest> ("Sample by Sample");
216 runTestForAllTypes<SplitBlockTest> ("Split Block");
217 }
218};
219
220static FIRFilterTest firFilterUnitTest;
221
222} // namespace dsp
223} // namespace juce
UnitTest(const String &name, const String &category=String())
void beginTest(const String &testName)
void expect(bool testResult, const String &failureMessage=String())
static ElementType * getNextSIMDAlignedPtr(ElementType *ptr) noexcept
static constexpr size_t SIMDRegisterSize
static constexpr size_t size() noexcept