DaisySP
Loading...
Searching...
No Matches
fir.h
1/*
2Copyright (c) 2020 Electrosmith, Corp, Alexander Petrov-Savchenko
3
4Use of this source code is governed by an MIT-style
5license that can be found in the LICENSE file or at
6https://opensource.org/licenses/MIT.
7*/
8
9#pragma once
10#ifndef DSY_FIRFILTER_H
11#define DSY_FIRFILTER_H
12
13#include <cstdint>
14#include <cstring> // for memset
15#include <cassert>
16#include <utility>
17
18#ifdef USE_ARM_DSP
19#include <arm_math.h> // required for platform-optimized version
20#endif
21
27namespace daisysp
28{
29/* use this as a template parameter to indicate user-provided memory storage */
30#define FIRFILTER_USER_MEMORY 0, 0
31
40template <size_t max_size, size_t max_block>
42{
43 /* Public part of the API to be passed through to the FIR users */
44 public:
45 /* Reset the internal filter state (but not the coefficients) */
46 void Reset() { memset(state_, 0, state_size_ * sizeof(state_[0])); }
47
48
49 protected:
50 FIRMemory() : state_{0}, coefs_{0}, size_(0) {}
51
52 /* Expression for the maximum block size */
53 static constexpr size_t MaxBlock() { return max_block; }
54
61 bool SetCoefs(const float coefs[], size_t size, bool reverse)
62 {
63 /* truncate silently */
64 size_ = DSY_MIN(size, max_size);
65
66 if(reverse)
67 {
68 /* reverse the IR */
69 for(size_t i = 0; i < size_; i++)
70 {
71 /* start from size, not size_! */
72 coefs_[i] = coefs[size - 1u - i];
73 }
74 }
75 else
76 {
77 /* just copy as is */
78 memcpy(coefs_, coefs, size_ * sizeof(coefs[0]));
79 }
80
81 return true;
82 }
83
84 static constexpr size_t state_size_ = max_size + max_block - 1u;
85 float state_[state_size_]; /*< Internal state buffer */
86 float coefs_[max_size]; /*< Filter coefficients */
87 size_t size_; /*< Active filter length (<= max_size) */
88};
89
90/* Specialization for user-provided memory */
91template <>
92struct FIRMemory<FIRFILTER_USER_MEMORY>
93{
94 /* Public part of the API to be passed through to the FIRFilter user */
95 public:
102 void SetStateBuffer(float state[], size_t length)
103 {
104 state_ = state;
105 state_size_ = length;
106 }
107 /* Reset the internal filter state (but not the coefficients) */
108 void Reset()
109 {
110 assert(nullptr != state_);
111 assert(0 != state_size_);
112 if(nullptr != state_)
113 {
114 memset(state_, 0, state_size_ * sizeof(state_[0]));
115 }
116 }
117
118 protected:
119 FIRMemory() : state_(nullptr), coefs_(nullptr), size_(0), state_size_(0) {}
120
121 /* Expression for the maximum processing block size currently supported */
122 size_t MaxBlock() const
123 {
124 return state_size_ + 1u > size_ ? state_size_ + 1u - size_ : 0;
125 }
126
133 bool SetCoefs(const float coefs[], size_t size, bool reverse)
134 {
135 /* reversing of external IR is not supported*/
136 assert(false == reverse);
137 assert(nullptr != coefs || 0 == size);
138
139 if(false == reverse && (nullptr != coefs || 0 == size))
140 {
141 coefs_ = coefs;
142 size_ = size;
143 return true;
144 }
145
146 return false;
147 }
148
149 /* Internal member variables */
150
151 float* state_; /*< Internal state buffer */
152 const float* coefs_; /*< Filter coefficients */
153 size_t size_; /*< number of filter coefficients */
154 size_t state_size_; /*< length of the state buffer */
155};
156
157
166template <size_t max_size, size_t max_block>
167class FIRFilterImplGeneric : public FIRMemory<max_size, max_block>
168{
169 private:
170 using FIRMem = FIRMemory<max_size, max_block>; // just a shorthand
171
172 public:
173 /* Default constructor */
175
176 /* Reset filter state (but not the coefficients) */
177 using FIRMem::Reset;
178
179 /* FIR Latency is always 0, but API is unified with FFT and fast convolution */
180 static constexpr size_t GetLatency() { return 0; }
181
182 /* Process one sample at a time */
183 float Process(float in)
184 {
185 assert(size_ > 0u);
186 /* Feed data into the buffer */
187 state_[size_ - 1u] = in;
188
189 /* Convolution loop */
190 float acc(0);
191 for(size_t i = 0; i < size_ - 1; i++)
192 {
193 acc += state_[i] * coefs_[i];
197 state_[i] = state_[1 + i];
198 }
199 acc += in * coefs_[size_ - 1u];
200
201 return acc;
202 }
203
204 /* Process a block of data */
205 void ProcessBlock(const float* pSrc, float* pDst, size_t block)
206 {
207 /* be sure to run debug version from time to time */
208 assert(block <= FIRMem::MaxBlock());
209 assert(size_ > 0u);
210 assert(nullptr != pSrc);
211 assert(nullptr != pDst);
212
213 /* Process the block of data */
214 for(size_t j = 0; j < block; j++)
215 {
216 /* Feed data into the buffer */
217 state_[size_ - 1u + j] = pSrc[j];
218
219 /* Convolution loop */
220 float acc = 0.0f;
221 for(size_t i = 0; i < size_; i++)
222 {
223 acc += state_[j + i] * coefs_[i];
224 }
225
226 /* Write output */
227 pDst[j] = acc;
228 }
229
230 /* Copy data tail for the next block */
231 for(size_t i = 0; i < size_ - 1u; i++)
232 {
233 state_[i] = state_[block + i];
234 }
235 }
236
242 bool SetIR(const float* ir, size_t len, bool reverse)
243 {
244 /* Function order is important */
245 const bool result = FIRMem::SetCoefs(ir, len, reverse);
246 Reset();
247 return result;
248 }
249
250 /* Create an alias to comply with DaisySP API conventions */
251 template <typename... Args>
252 inline auto Init(Args&&... args)
253 -> decltype(SetIR(std::forward<Args>(args)...))
254 {
255 return SetIR(std::forward<Args>(args)...);
256 }
257
258
259 protected:
260 using FIRMem::coefs_; /*< FIR coefficients buffer or pointer */
261 using FIRMem::size_; /*< FIR length */
262 using FIRMem::state_; /*< FIR state buffer or pointer */
263};
264
265
266#if(defined(USE_ARM_DSP) && defined(__arm__))
267
275template <size_t max_size, size_t max_block>
276class FIRFilterImplARM : public FIRMemory<max_size, max_block>
277{
278 private:
279 using FIRMem = FIRMemory<max_size, max_block>; // just a shorthand
280
281 public:
282 /* Default constructor */
283 FIRFilterImplARM() : fir_{0} {}
284
285 /* Reset filter state (but not the coefficients) */
286 using FIRMem::Reset;
287
288 /* FIR Latency is always 0, but API is unified with FFT and FastConv */
289 static constexpr size_t GetLatency() { return 0; }
290
291 /* Process one sample at a time */
292 float Process(float in)
293 {
294 float out(0);
295 arm_fir_f32(&fir_, &in, &out, 1);
296 return out;
297 }
298
299 /* Process a block of data */
300 void ProcessBlock(float* pSrc, float* pDst, size_t block)
301 {
302 assert(block <= FIRMem::MaxBlock());
303 arm_fir_f32(&fir_, pSrc, pDst, block);
304 }
305
311 bool SetIR(const float* ir, size_t len, bool reverse)
312 {
313 /* Function order is important */
314 const bool result = FIRMem::SetCoefs(ir, len, reverse);
315 arm_fir_init_f32(&fir_, len, (float*)coefs_, state_, max_block);
316 return result;
317 }
318
319 /* Create an alias to comply with DaisySP API conventions */
320 template <typename... Args>
321 inline auto Init(Args&&... args)
322 -> decltype(SetIR(std::forward<Args>(args)...))
323 {
324 return SetIR(std::forward<Args>(args)...);
325 }
326
327 protected:
328 arm_fir_instance_f32 fir_; /*< ARM CMSIS DSP library FIR filter instance */
329 using FIRMem::coefs_; /*< FIR coefficients buffer or pointer */
330 using FIRMem::size_; /*< FIR length*/
331 using FIRMem::state_; /*< FIR state buffer or pointer */
332};
333
334
335/* default to ARM implementation */
336template <size_t max_size, size_t max_block>
337using FIR = FIRFilterImplARM<max_size, max_block>;
338
339
340#else // USE_ARM_DSP
341
342/* default to generic implementation */
343template <size_t max_size, size_t max_block>
344using FIR = FIRFilterImplGeneric<max_size, max_block>;
345
346#endif // USE_ARM_DSP
347
348
349} // namespace daisysp
350
351#endif // DSY_FIRFILTER_H
Definition delayline.h:29
void Init()
Definition delayline.h:35
Definition fir.h:168
bool SetIR(const float *ir, size_t len, bool reverse)
Definition fir.h:242
float Process(float in)
Definition fir.h:183
FIR Filter implementation, generic and ARM CMSIS DSP based.
Definition adenv.h:16
bool SetCoefs(const float coefs[], size_t size, bool reverse)
Definition fir.h:133
void SetStateBuffer(float state[], size_t length)
Definition fir.h:102
Definition fir.h:42
bool SetCoefs(const float coefs[], size_t size, bool reverse)
Definition fir.h:61