JPL Spatial
Sound spatialization and propagation library
Loading...
Searching...
No Matches
CrossoverFilter.h
Go to the documentation of this file.
1//
2// ██╗██████╗ ██╗ ██╗██████╗ ███████╗
3// ██║██╔══██╗ ██║ ██║██╔══██╗██╔════╝ ** JPLSpatial **
4// ██║██████╔╝ ██║ ██║██████╔╝███████╗
5// ██ ██║██╔═══╝ ██║ ██║██╔══██╗╚════██║ https://github.com/Jaytheway/JPLSpatial
6// ╚█████╔╝██║ ███████╗██║██████╔╝███████║
7// ╚════╝ ╚═╝ ╚══════╝╚═╝╚═════╝ ╚══════╝
8//
9// Copyright Jaroslav Pevno, JPLSpatial is offered under the terms of the ISC license:
10//
11// Permission to use, copy, modify, and/or distribute this software for any purpose with or
12// without fee is hereby granted, provided that the above copyright notice and this permission
13// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
14// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
15// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
16// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
17// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20#pragma once
21
22#include "JPLSpatial/Core.h"
27
28#include <algorithm>
29#include <cmath>
30#include <complex>
31#include <numbers>
32#include <span>
33
34namespace JPL
35{
37 {
38 std::complex<double> Low;
39 std::complex<double> Band;
40 std::complex<double> High;
41 };
42
44 {
45 std::complex<double> Low;
46 std::complex<double> High;
47 };
48
49 //==========================================================================
52 {
53 struct Params
54 {
55 float g = 0.0f;
56 float d = 0.0f;
57 float MinusRg = 0.0f;
58 };
59
60 // State
61 float s1 = 0.0f, s2 = 0.0f;
62
64 [[nodiscard]] static JPL_INLINE Params Prepare(float sampleRate, float frequency) noexcept
65 {
66 static constexpr float R = std::numbers::sqrt2_v<float>;
67 const float g = std::tan(JPL_PI * (frequency / sampleRate));
68 // d = 1.0f / (1.0f + R * g + g * g);
69 return Params{
70 .g = g,
71 .d = 1.0f / Math::FMA(g, R + g, 1.0f),
72 .MinusRg = -(R + g)
73 };
74 }
75
76 [[nodiscard]] static SVFResponse CalculateResponse(const Params& params, double normalizedFrequency)
77 {
78 using Complex = std::complex<double>;
79
80 const double omega = 2.0 * std::numbers::pi_v<double> * normalizedFrequency;
81
82 const Complex q = std::polar(1.0, -omega);
83 const Complex u = Complex(1.0, 0.0) - q;
84 const Complex v = Complex(1.0, 0.0) + q;
85
86 const double g = params.g;
87 static constexpr double R = std::numbers::sqrt2_v<double>;
88
89 const Complex denominator = u * u + R * g * u * v + g * g * v * v;
90
91 return SVFResponse{
92 .Low = g * g * v * v / denominator,
93 .Band = g * u * v / denominator,
94 .High = u * u / denominator
95 };
96 }
97
98 JPL_INLINE void Reset() noexcept { s1 = 0.0f; s2 = 0.0f; }
99
100 JPL_INLINE void Process(const Params& params, float x, float& yL, float& yB, float& yH) noexcept
101 {
102 // HP := (x-g1*s1-s2)*d; // g1=2R+g, d=1/(1+2Rg+g^2)
103 // v1 := g*HP; BP := v1+s1; s1 := BP+v1; // first integrator
104 // v2 := g*BP; LP := v2+s2; s2 := LP+v2; // second integrator
105
106 // yH = (x - (R + g) * s1 - s2) * d;
107 yH = Math::FMA(params.MinusRg, s1, x - s2) * params.d;
108 yB = Math::FMA(params.g, yH, s1);
109 s1 = Math::FMA(params.g, yH, yB);
110 yL = Math::FMA(params.g, yB, s2);
111 s2 = Math::FMA(params.g, yB, yL);
112 }
113
114 JPL_INLINE void ProcessBPLP(const Params& params, float x, float& yL, float& yB)
115 {
116 // BP: = (g * (x - s2) + s1) * d; // d=1/(1+2Rg+g^2)
117 // v1 := BP-s1; s1 := BP+v1; // first integrator
118 // v2 := g*BP; LP := v2+s2; s2 := LP+v2; // second integrator
119
120 yB = Math::FMA(params.g, (x - s2), s1) * params.d;
121 s1 = yB + yB - s1;
122 yL = Math::FMA(params.g, yB, s2);
123 s2 = Math::FMA(params.g, yB, yL);
124 }
125
126 JPL_INLINE void ProcessBPHP(const Params& params, float x, float& yB, float& yH)
127 {
128 // HP := (x-g1*s1-s2)*d; // g1=2R+g, d=1/(1+2Rg+g^2)
129 // v1 := g*HP; BP := v1+s1; s1 := BP+v1; // first integrator
130 // v22 := g*BP2; s2 := s2+v22; // second integrator
131
132 // yH = (x - (R + g) * s1 - s2) * d;
133 yH = Math::FMA(params.MinusRg, s1, x - s2) * params.d;
134 yB = Math::FMA(params.g, yH, s1);
135 s1 = Math::FMA(params.g, yH, yB);
136 s2 = Math::FMA(params.g, yB + yB, s2);
137 }
138
139 JPL_INLINE void ProcessBP(const Params& params, float x, float& yB)
140 {
141 // BP: = (g * (x - s2) + s1) * d; // d=1/(1+2Rg+g^2)
142 // BP2 := BP+BP; s1 := BP2-s1; // first integrator
143 // v22 := g*BP2; s2 := s2+v22; // second integrator
144
145 yB = Math::FMA(params.g, (x - s2), s1) * params.d;
146 yB = yB + yB;
147 s1 = yB - s1;
148 s2 = Math::FMA(params.g, yB, s2);
149 }
150
151 JPL_INLINE void ProcessAP(const Params& params, float x, float& yAP)
152 {
153 static constexpr float minusR = -std::numbers::sqrt2_v<float>;
154 float yL, yB, yH;
155 Process(params, x, yL, yB, yH);
156 yAP = Math::FMA(minusR, yB, yH + yL); // yL - R * yB + yH;
157 }
158 };
159
160 //==========================================================================
164 {
165 struct Params
166 {
167 simd g = 0.0f;
168 simd d = 0.0f;
169 simd MinusRg = 0.0f;
170 };
171
172 // State
173 simd s1 = 0.0f, s2 = 0.0f;
174
175 [[nodiscard]] static JPL_INLINE Params Prepare(const simd& sampleRate, const simd& frequency) noexcept
176 {
177 static const simd R = std::numbers::sqrt2_v<float>;
178 const simd g = tan(JPL_PI * (frequency / sampleRate));
179 // d = 1.0f / (1.0f + R * g + g * g);
180 return Params{
181 .g = g,
182 .d = simd::c_1() / Math::FMA(g, R + g, 1.0f),
183 .MinusRg = -(R + g)
184 };
185 }
186
187 JPL_INLINE void Reset() noexcept { s1 = 0.0f; s2 = 0.0f; }
188
189 JPL_INLINE void Process(const Params& params, const simd& x, simd& yL, simd& yB, simd& yH) noexcept
190 {
191 // yH = (x - (R + g) * s1 - s2) * d;
192 yH = Math::FMA(params.MinusRg, s1, x - s2) * params.d;
193 yB = Math::FMA(params.g, yH, s1);
194 s1 = Math::FMA(params.g, yH, yB);
195 yL = Math::FMA(params.g, yB, s2);
196 s2 = Math::FMA(params.g, yB, yL);
197 }
198
199 JPL_INLINE void ProcessBPLP(const Params& params, simd x, simd& yL, simd& yB)
200 {
201 yB = Math::FMA(params.g, (x - s2), s1) * params.d;
202 s1 = yB + yB - s1;
203 yL = Math::FMA(params.g, yB, s2);
204 s2 = Math::FMA(params.g, yB, yL);
205 }
206
207 JPL_INLINE void ProcessBPHP(const Params& params, simd x, simd& yB, simd& yH)
208 {
209 yH = Math::FMA(params.MinusRg, s1, x - s2) * params.d;
210 yB = Math::FMA(params.g, yH, s1);
211 s1 = Math::FMA(params.g, yH, yB);
212 s2 = Math::FMA(params.g, yB + yB, s2);
213 }
214
215 JPL_INLINE void ProcessBP(const Params& params, simd x, simd& yB)
216 {
217 yB = Math::FMA(params.g, (x - s2), s1) * params.d;
218 yB = yB + yB;
219 s1 = yB - s1;
220 s2 = Math::FMA(params.g, yB, s2);
221 }
222
223 JPL_INLINE void ProcessAP(const Params& params, simd x, simd& yAP)
224 {
225 static const simd minusR = -std::numbers::sqrt2_v<float>;
226 simd yL, yB, yH;
227 Process(params, x, yL, yB, yH);
228 yAP = Math::FMA(minusR, yB, yH + yL); // yL - R * yB + yH;
229 }
230 };
231
232 //==========================================================================
234 {
236
237 JPL_INLINE void Prepare(float sampleRate, float frequency) noexcept
238 {
239 Params = StateVariableFilterTPT::Prepare(sampleRate, frequency);
240 }
241
242 JPL_INLINE void Reset() noexcept
243 {
245 }
246
247 [[nodiscard]] JPL_INLINE float Process(float x) noexcept
248 {
249 static constexpr float minusR = -std::numbers::sqrt2_v<float>;
250 float yL, yB, yH;
252 return Math::FMA(minusR, yB, yH + yL); // yL - R * yB + yH;
253 }
254
255 [[nodiscard]] static auto CalculateResponse(const typename StateVariableFilterTPT::Params& params, double normalizedFrequency)
256 {
257 const SVFResponse response = StateVariableFilterTPT::CalculateResponse(params, normalizedFrequency);
258 return response.Low - std::numbers::sqrt2_v<double> * response.Band + response.High;
259 }
260 };
261
262 //==========================================================================
264 {
266
267 JPL_INLINE void Prepare(const simd& sampleRate, const simd& frequency) noexcept
268 {
269 Params = TPTSVFStageSIMD::Prepare(sampleRate, frequency);
270 }
271
272 JPL_INLINE void Reset() noexcept
273 {
275 }
276
277 [[nodiscard]] JPL_INLINE simd Process(const simd& x) noexcept
278 {
279 simd yAP;
281 return yAP;
282 }
283 };
284
285 //==========================================================================
287 struct LR4Split
288 {
291
293
294 JPL_INLINE void Prepare(float sampleRate, float frequency) noexcept
295 {
296 frequency = std::clamp(frequency, 1.0f, 0.49f * sampleRate);
297 Params = StateVariableFilterTPT::Prepare(sampleRate, frequency);
298 Reset();
299 }
300
301 JPL_INLINE void Reset() noexcept
302 {
303 Stage1.Reset();
304 Stage2.Reset();
305 }
306
307 [[nodiscard]] JPL_INLINE float ProcessLP(float x) noexcept
308 {
309 // 1. TPT-SVF stage
310 float yL, yB;
311 Stage1.ProcessBPLP(Params, x, yL, yB);
312
313 // 2. Cascade the second stage (to make LR4 LP)
314 float yL2, yB2;
315 Stage2.ProcessBPLP(Params, yL, yL2, yB2);
316
317 return yL2;
318 }
319
320 [[nodiscard]] JPL_INLINE float ProcessHP(float x) noexcept
321 {
322 // 1. TPT-SVF stage
323 float yB, yH;
324 Stage1.ProcessBPHP(Params, x, yB, yH);
325
326 // 2. Cascade the second stage (to make LR4 LP)
327 float yB2, yH2;
328 Stage2.ProcessBPHP(Params, yH, yB2, yH2);
329 // (for high pass the input to the second stage
330 // is high-pass from the first, the rest is the same)
331 return yH2;
332 }
333
334 // Process one sample through a proper LR4 crossover:
335 // returns {low, high} such that low+high == x (allpass-filtered) and magnitudes are LR4
336 JPL_INLINE void Process(float x, float& low, float& high) noexcept
337 {
338 static constexpr float minusR = -std::numbers::sqrt2_v<float>;
339
340 // 1. TPT-SVF stage
341 float yL, yB, yH;
342 Stage1.Process(Params, x, yL, yB, yH);
343
344 // 2. Cascade the second stage (to make LR4 LP)
345 float yL2, yB2, yH2;
346 Stage2.Process(Params, yL, yL2, yB2, yH2);
347
348 // Outputs
349 low = yL2;
350 // high = yL - R * yB + yH - yL2;
351 high = Math::FMA(minusR, yB, yL + yH - yL2);
352 }
353
354
355 [[nodiscard]] static LR4Response CalculateResponse(const typename StateVariableFilterTPT::Params& params, double normalizedFrequency)
356 {
357 const SVFResponse svf = StateVariableFilterTPT::CalculateResponse(params, normalizedFrequency);
358 const std::complex<double> allpass = svf.Low - std::numbers::sqrt2_v<double> * svf.Band + svf.High;
359 const auto low = svf.Low * svf.Low;
360 const auto high = allpass - low;
361 return LR4Response{ .Low = low, .High = high };
362 }
363 };
364
365 //==========================================================================
377 {
380
381 // 4 allpasses for phase equalization
382 // f3 AP on bands 1 & 2
383 // f1 AP on bands 3 & 4
385
386 // Reusing filter parameters for the two stages
388
389 // Input split frequencies must be as follows: f1 < f2 < f3,
390 // where `f2` is the frequency of the previous splitter,
391 // output of which will be fed into this splitter.
392 JPL_INLINE void Prepare(float sampleRate, float f1, float f3) noexcept
393 {
394 // Interleave f1 and f3 to be able to vectorize as much
395 // as possible with as little shuffling as possible
396 const simd frequency = clamp(simd(f1, f3, f1, f3),
397 simd(1.0f),
398 simd(0.49f) * sampleRate);
399
400 Params = TPTSVFStageSIMD::Prepare(sampleRate, frequency);
401
402 // Interleave frequencies according to 2-lane
403 // vectorized LR4 splitter output { b1, b3, b2, b4 }:
404 // { f3, f1, f3, f1 }
405 AllpassEqualizer.Prepare(sampleRate, reverse(frequency));
406 // ..reversing `frequency` to reuse the clamp above,
407 // however the relationship is not necessarily reversal)
408
409 Reset();
410 }
411
412 JPL_INLINE void Reset() noexcept
413 {
414 Stage1.Reset();
415 Stage2.Reset();
417 }
418
419 // Process `low` and `high` from the first split through proper LR4 crossover.
420 // @param low : low part of the output from the first middle split
421 // @param high : high part of the output from the first middle split
422 // @param out_b1324 : output frequency bands, interleaved { b1, b3, b2, b4 }
423 JPL_INLINE void ProcessInterleaved(float low, float high, simd& out_b1324) noexcept
424 {
425 // We SIMDI-fy this as follows:
426 // - Stage 1 works on the two input lanes interleaved (half saturated)
427 // - Stage1(low, high, low, high) -> L and H for f1 and f3
428 // - Stage 2 takes different inputs for each lane: (fully saturated)
429 // - Stage2(L_f1, L_f3, H_f1, H_f3) -> L2 and H2 for f1 and f3
430 //
431 // Therefore the biggest SIMD benefit is in the Stage 2,
432 // while Stage 1 gives only half benefit compared to scalar version.
433
434 const simd x(low, high, low, high);
435
436 // yL = { yL_f1, yL_f3, yL_f1, yL_f3 }
437 // yH = { yH_f1, yH_f3, yH_f1, yH_f3 }
438 simd yL, yB, yH;
439 Stage1.Process(Params, x, yL, yB, yH);
440
441 // x2 = { yL_f1, yL_f3, yH_f1, yH_f3 }
442 const simd x2 = combine_lo(yL, yH);
443 simd yL2, yB2, yH2;
444 Stage2.Process(Params, x2, yL2, yB2, yH2);
445
446 // out = { yL2_f1, yL2_f3, yH2_f1, yH2_f3 }
447 out_b1324 = combine_lohi(yL2, yH2);
448 // (we leave it up to the caller to deinterleave the output if/when necessary)
449
450 // Equalize the messed up phase
451 //out_b1324 = AllpassEqualizer.Process(out_b1324);
452 out_b1324 = AllpassEqualizer.Process(out_b1324);
453 }
454
455 // Same as ProcessInterleaved, but followed by deinterleaving
456 // the bands for the output, since the caller most likely
457 // expects bands in ascending frequency order.
458 // @param out_b1234 : output frequency bands in order { b1, b2, b3, b4 }
459 JPL_INLINE void Process(float low, float high, simd& out_b1234) noexcept
460 {
461 ProcessInterleaved(low, high, out_b1234);
462 out_b1234 = interleave_lohi(out_b1234);
463 }
464 };
465
466 //==========================================================================
469 {
470 // First splitter at the mid frequency
472
473 // Combined splitter for the lower and higher
474 // parts of the first splitter output
476
477 JPL_INLINE void Prepare(float sampleRate, SplitFrequencies splits = cDefaultFrequencySplits) noexcept
478 {
479 X2.Prepare(sampleRate, splits.F2);
480 X13.Prepare(sampleRate, splits.F1, splits.F3);
481
482 Reset();
483 }
484
485 JPL_INLINE void Reset() noexcept
486 {
487 X2.Reset();
488 X13.Reset();
489 }
490
491 inline void SplitSample(float sample, simd& outBands) noexcept
492 {
493 // Process the first split into `low` and `high` parts
494 float low, high;
495 X2.Process(sample, low, high);
496
497 // Process the secod layer splits from `low` and `high`
498 // to produce the bands { b1, b2, b3, b4 }
499 X13.Process(low, high, outBands);
500 }
501
502 JPL_INLINE simd SplitSample(float sample) noexcept
503 {
504 simd bands; SplitSample(sample, bands);
505 return bands;
506 }
507
508 JPL_INLINE float ProcessSample(float sample, simd gains) noexcept
509 {
510 return (SplitSample(sample) * gains).reduce();
511 }
512
513 // Process block of float samples and return 4 bands per sample packed into simd lanes
514 inline void ProcessBlock(std::span<const float> in, std::span<simd> outBands) noexcept
515 {
516 JPL_ASSERT(in.size() <= outBands.size());
517
518 for (size_t i = 0; i < in.size(); ++i)
519 {
520 SplitSample(in[i], outBands[i]);
521 }
522 }
523
524 // Process block of float samples, apply per band gains and return processed float samples
525 inline void ProcessBlock(std::span<const float> in, simd gains, std::span<float> out) noexcept
526 {
527 // Interleave gains to match the 2-lane
528 // vectorized LR4 splitter output { b1, b3, b2, b4 }
529 // We do this here once, to avoid interleaving
530 // the output of the splitter for each sample iteration.
531 // Since we immediately recombine the bands here,
532 // their order doesn't matter.
533 gains = interleave_lohi(gains);
534
535 for (size_t i = 0; i < in.size(); ++i)
536 {
537 // Process the first split into `low` and `high` parts
538 float low, high;
539 X2.Process(in[i], low, high);
540
541#if 0 //? debugging with just single split
542 out[i] = low * gains[0] + high * gains[3];
543#else
544 // Process the secod layer splits from `low` and `high`
545 // to produce interleaved bands { b1, b3, b2, b4 }
546 simd bands;
547 X13.ProcessInterleaved(low, high, bands);
548
549 // Sum up the 4 bands togther into the final output sample
550 out[i] = (bands * gains).reduce();
551#endif
552 }
553 }
554
555 // Process block of float samples, apply per band gains with ramp from @startGains to @endGains
556 // and return processed float samples
557 inline void ProcessBlock(std::span<const float> in,
558 simd startGains,
559 simd endGains,
560 std::span<float> out) noexcept
561 {
562 // Interleave gains to match the 2-lane
563 // vectorized LR4 splitter output { b1, b3, b2, b4 }
564 // We do this here once, to avoid interleaving
565 // the output of the splitter for each sample iteration.
566 // Since we immediately recombine the bands here,
567 // their order doesn't matter.
568 startGains = interleave_lohi(startGains);
569 endGains = interleave_lohi(endGains);
570 const simd increment = (endGains - startGains) / static_cast<float>(in.size());
571
572 for (size_t i = 0; i < in.size(); ++i)
573 {
574 // Process the first split into `low` and `high` parts
575 float low, high;
576 X2.Process(in[i], low, high);
577 // Process the secod layer splits from `low` and `high`
578 // to produce interleaved bands { b1, b3, b2, b4 }
579 simd bands;
580 X13.ProcessInterleaved(low, high, bands);
581
582 // Sum up the 4 bands togther into the final output sample
583 out[i] = (bands * startGains).reduce();
584
585 startGains += increment;
586 }
587 }
588
589 [[nodiscard]] static std::complex<double> CalculateResponse(double sampleRate, double normalizedFrequency, std::span<const float, 4> gains, SplitFrequencies splits = cDefaultFrequencySplits)
590 {
591 using Complex = std::complex<double>;
592
593 const auto [L1, H1] = LR4Split::CalculateResponse(StateVariableFilterTPT::Prepare(sampleRate, splits.F1), normalizedFrequency);
594 const auto [L2, H2] = LR4Split::CalculateResponse(StateVariableFilterTPT::Prepare(sampleRate, splits.F2), normalizedFrequency);
595 const auto [L3, H3] = LR4Split::CalculateResponse(StateVariableFilterTPT::Prepare(sampleRate, splits.F3), normalizedFrequency);
596
597 const Complex A1 = L1 + H1;
598 const Complex A3 = L3 + H3;
599
600 const Complex total =
601 double(gains[0]) * L2 * L1 * A3 +
602 double(gains[1]) * L2 * H1 * A3 +
603 double(gains[2]) * H2 * L3 * A1 +
604 double(gains[3]) * H2 * H3 * A1;
605
606 return total;
607 }
608 };
609} // namespace JPL
#define JPL_ASSERT(inExpression,...)
Main assert macro, usage: JPL_ASSERT(condition, message) or JPL_ASSERT(condition)
Definition ErrorReporting.h:80
JPL_INLINE constexpr T FMA(T a, T b, T c) noexcept
Inlined fuse multiply-add. Compiler in some circumstances is more eager to optimize this than std::fm...
Definition Math.h:186
Definition AcousticMaterial.h:36
JPL_INLINE simd clamp(const simd &value, const simd &minV, const simd &maxV) noexcept
Element-wise clamp.
Definition SIMD.h:1838
constexpr SplitFrequencies cDefaultFrequencySplits
At the moment JPL Spatial uses these frequency sptits for sound propagation.
Definition FrequencyBands.h:53
JPL_INLINE simd reverse(const simd &vec) noexcept
Reverse the order of the lanes.
Definition SIMD.h:2005
JPL_INLINE simd combine_lohi(const simd &a, const simd &b) noexcept
Combine two low lanes of a and two high lanes from b as { a0, a1, b2, b3 }.
Definition SIMD.h:1994
JPL_INLINE simd interleave_lohi(const simd &vec) noexcept
Interleave two low lanes with the two high lanes (e.g. { 0, 1, 2, 3 } -> { 0, 2, 1,...
Definition SIMD.h:1950
JPL_INLINE simd combine_lo(const simd &a, const simd &b) noexcept
Combine two low lanes of input a and b as { a0, a1, b0, b1 }.
Definition SIMD.h:1962
simd tan(simd x) noexcept
Definition SIMDMath.h:643
4th order Linkwitz-Riley 4-band crossover
Definition CrossoverFilter.h:469
JPL_INLINE simd SplitSample(float sample) noexcept
Definition CrossoverFilter.h:502
void ProcessBlock(std::span< const float > in, simd startGains, simd endGains, std::span< float > out) noexcept
Definition CrossoverFilter.h:557
void ProcessBlock(std::span< const float > in, simd gains, std::span< float > out) noexcept
Definition CrossoverFilter.h:525
void SplitSample(float sample, simd &outBands) noexcept
Definition CrossoverFilter.h:491
void ProcessBlock(std::span< const float > in, std::span< simd > outBands) noexcept
Definition CrossoverFilter.h:514
JPL_INLINE float ProcessSample(float sample, simd gains) noexcept
Definition CrossoverFilter.h:508
static std::complex< double > CalculateResponse(double sampleRate, double normalizedFrequency, std::span< const float, 4 > gains, SplitFrequencies splits=cDefaultFrequencySplits)
Definition CrossoverFilter.h:589
JPL_INLINE void Prepare(float sampleRate, SplitFrequencies splits=cDefaultFrequencySplits) noexcept
Definition CrossoverFilter.h:477
LR4Split X2
Definition CrossoverFilter.h:471
JPL_INLINE void Reset() noexcept
Definition CrossoverFilter.h:485
LR4Split2Lanes X13
Definition CrossoverFilter.h:475
Definition CrossoverFilter.h:44
std::complex< double > Low
Definition CrossoverFilter.h:45
std::complex< double > High
Definition CrossoverFilter.h:46
Definition CrossoverFilter.h:377
JPL_INLINE void Reset() noexcept
Definition CrossoverFilter.h:412
TPTSVFStageSIMD Stage1
Definition CrossoverFilter.h:378
TPTSVFStageSIMD Stage2
Definition CrossoverFilter.h:379
JPL_INLINE void Process(float low, float high, simd &out_b1234) noexcept
Definition CrossoverFilter.h:459
JPL_INLINE void Prepare(float sampleRate, float f1, float f3) noexcept
Definition CrossoverFilter.h:392
TPTSVFAllpassSIMD AllpassEqualizer
Definition CrossoverFilter.h:384
JPL_INLINE void ProcessInterleaved(float low, float high, simd &out_b1324) noexcept
Definition CrossoverFilter.h:423
TPTSVFStageSIMD::Params Params
Definition CrossoverFilter.h:387
4th order Linkwitz-Riley crossover
Definition CrossoverFilter.h:288
JPL_INLINE float ProcessLP(float x) noexcept
Definition CrossoverFilter.h:307
JPL_INLINE void Reset() noexcept
Definition CrossoverFilter.h:301
JPL_INLINE void Prepare(float sampleRate, float frequency) noexcept
Definition CrossoverFilter.h:294
JPL_INLINE void Process(float x, float &low, float &high) noexcept
Definition CrossoverFilter.h:336
JPL_INLINE float ProcessHP(float x) noexcept
Definition CrossoverFilter.h:320
StateVariableFilterTPT::Params Params
Definition CrossoverFilter.h:292
StateVariableFilterTPT Stage2
Definition CrossoverFilter.h:290
StateVariableFilterTPT Stage1
Definition CrossoverFilter.h:289
static LR4Response CalculateResponse(const typename StateVariableFilterTPT::Params &params, double normalizedFrequency)
Definition CrossoverFilter.h:355
Definition CrossoverFilter.h:37
std::complex< double > Band
Definition CrossoverFilter.h:39
std::complex< double > High
Definition CrossoverFilter.h:40
std::complex< double > Low
Definition CrossoverFilter.h:38
Split frequencies points for crossover.
Definition FrequencyBands.h:46
Definition CrossoverFilter.h:54
float g
Definition CrossoverFilter.h:55
float d
Definition CrossoverFilter.h:56
float MinusRg
Definition CrossoverFilter.h:57
State Variable Filter with Topology-Preserving Transform structure.
Definition CrossoverFilter.h:52
JPL_INLINE void Reset() noexcept
Definition CrossoverFilter.h:98
static SVFResponse CalculateResponse(const Params &params, double normalizedFrequency)
Definition CrossoverFilter.h:76
float s1
Definition CrossoverFilter.h:61
JPL_INLINE void Process(const Params &params, float x, float &yL, float &yB, float &yH) noexcept
Definition CrossoverFilter.h:100
JPL_INLINE void ProcessBP(const Params &params, float x, float &yB)
Definition CrossoverFilter.h:139
JPL_INLINE void ProcessBPLP(const Params &params, float x, float &yL, float &yB)
Definition CrossoverFilter.h:114
JPL_INLINE void ProcessBPHP(const Params &params, float x, float &yB, float &yH)
Definition CrossoverFilter.h:126
static JPL_INLINE Params Prepare(float sampleRate, float frequency) noexcept
Prepare parameters for a TPT SVGF Stage.
Definition CrossoverFilter.h:64
JPL_INLINE void ProcessAP(const Params &params, float x, float &yAP)
Definition CrossoverFilter.h:151
float s2
Definition CrossoverFilter.h:61
Definition CrossoverFilter.h:264
JPL_INLINE void Prepare(const simd &sampleRate, const simd &frequency) noexcept
Definition CrossoverFilter.h:267
TPTSVFStageSIMD::Params Params
Definition CrossoverFilter.h:265
JPL_INLINE simd Process(const simd &x) noexcept
Definition CrossoverFilter.h:277
JPL_INLINE void Reset() noexcept
Definition CrossoverFilter.h:272
Definition CrossoverFilter.h:234
StateVariableFilterTPT::Params Params
Definition CrossoverFilter.h:235
JPL_INLINE void Reset() noexcept
Definition CrossoverFilter.h:242
JPL_INLINE void Prepare(float sampleRate, float frequency) noexcept
Definition CrossoverFilter.h:237
static auto CalculateResponse(const typename StateVariableFilterTPT::Params &params, double normalizedFrequency)
Definition CrossoverFilter.h:255
JPL_INLINE float Process(float x) noexcept
Definition CrossoverFilter.h:247
Definition CrossoverFilter.h:166
simd d
Definition CrossoverFilter.h:168
simd MinusRg
Definition CrossoverFilter.h:169
simd g
Definition CrossoverFilter.h:167
Definition CrossoverFilter.h:164
JPL_INLINE void Reset() noexcept
Definition CrossoverFilter.h:187
JPL_INLINE void ProcessBP(const Params &params, simd x, simd &yB)
Definition CrossoverFilter.h:215
static JPL_INLINE Params Prepare(const simd &sampleRate, const simd &frequency) noexcept
Definition CrossoverFilter.h:175
JPL_INLINE void ProcessBPLP(const Params &params, simd x, simd &yL, simd &yB)
Definition CrossoverFilter.h:199
JPL_INLINE void ProcessAP(const Params &params, simd x, simd &yAP)
Definition CrossoverFilter.h:223
simd s1
Definition CrossoverFilter.h:173
JPL_INLINE void ProcessBPHP(const Params &params, simd x, simd &yB, simd &yH)
Definition CrossoverFilter.h:207
simd s2
Definition CrossoverFilter.h:173
JPL_INLINE void Process(const Params &params, const simd &x, simd &yL, simd &yB, simd &yH) noexcept
Definition CrossoverFilter.h:189
Minimal 4-wide 32-bit float vector implementation for SIMD.
Definition SIMD.h:60
static JPL_INLINE simd c_1() noexcept
Definition SIMD.h:461