|
4 | 4 |
|
5 | 5 | static constexpr unsigned interp_size = 128; |
6 | 6 |
|
7 | | -void BBD_Line::setup(double fs, unsigned ns, const BBD_Filter_Spec &fsin, const BBD_Filter_Spec &fsout) |
| 7 | +template <unsigned Channels> |
| 8 | +void BBD_Line<Channels>::setup(double fs, unsigned ns, const BBD_Filter_Spec &fsin, const BBD_Filter_Spec &fsout) |
8 | 9 | { |
9 | | - mem_.reserve(8192); |
| 10 | + mem_.reserve(8192 * Channels); |
10 | 11 |
|
11 | 12 | const BBD_Filter_Coef &fin = BBD::compute_filter_cached(fs, interp_size, fsin); |
12 | 13 | const BBD_Filter_Coef &fout = BBD::compute_filter_cached(fs, interp_size, fsout); |
13 | 14 | fin_ = &fin; |
14 | 15 | fout_ = &fout; |
15 | 16 |
|
16 | | - unsigned Min = fin.M; |
17 | | - unsigned Mout = fout.M; |
18 | | - Xin_.reset(new cdouble[Min]); |
19 | | - Xout_.reset(new cdouble[Mout]); |
20 | | - Xout_mem_.reset(new cdouble[Mout]); |
21 | | - Gin_.reset(new cdouble[Min]); |
22 | | - Gout_.reset(new cdouble[Mout]); |
| 17 | + assert(fin.M <= Mmax); |
| 18 | + assert(fout.M <= Mmax); |
23 | 19 |
|
24 | 20 | set_delay_size(ns); |
25 | 21 | clear(); |
26 | 22 | } |
27 | 23 |
|
28 | | -void BBD_Line::set_delay_size(unsigned ns) |
| 24 | +template <unsigned Channels> |
| 25 | +void BBD_Line<Channels>::set_delay_size(unsigned ns) |
29 | 26 | { |
30 | 27 | mem_.clear(); |
31 | | - mem_.resize(ns); |
| 28 | + mem_.resize(ns * Channels); |
32 | 29 | imem_ = 0; |
33 | 30 | ns_ = ns; |
34 | 31 | } |
35 | 32 |
|
36 | | -void BBD_Line::clear() |
| 33 | +template <unsigned Channels> |
| 34 | +void BBD_Line<Channels>::clear() |
37 | 35 | { |
38 | 36 | std::fill(mem_.begin(), mem_.end(), 0); |
39 | 37 | imem_ = 0; |
40 | 38 | pclk_ = 0; |
41 | 39 | ptick_ = 0; |
42 | | - ybbd_old_ = 0; |
43 | | - unsigned Min = fin_->M; |
44 | | - unsigned Mout = fout_->M; |
45 | | - std::fill(&Xin_[0], &Xin_[Min], 0); |
46 | | - std::fill(&Xout_[0], &Xout_[Mout], 0); |
47 | | - std::fill(&Xout_mem_[0], &Xout_mem_[Mout], 0); |
| 40 | + ybbd1_.fill(0); |
| 41 | + for (unsigned c = 0; c < Channels; ++c) { |
| 42 | + Xin_[c].fill(0); |
| 43 | + Xout1_[c].fill(0); |
| 44 | + } |
48 | 45 | } |
49 | 46 |
|
50 | | -void BBD_Line::process(unsigned n, const float *input, float *output, const float *clock) |
| 47 | +template <unsigned Channels> |
| 48 | +void BBD_Line<Channels>::process(unsigned n, const float *const inputs[Channels], float *const outputs[Channels], const float *clock) |
51 | 49 | { |
52 | 50 | unsigned ns = ns_; |
53 | 51 | float *mem = mem_.data(); |
54 | 52 | unsigned imem = imem_; |
55 | 53 | double pclk = pclk_; |
56 | 54 | unsigned ptick = ptick_; |
57 | | - double ybbd_old = ybbd_old_; |
| 55 | + std::array<double, Channels> ybbd1 = ybbd1_; |
58 | 56 |
|
59 | | - const BBD_Filter_Coef &fin = *fin_, &fout = *fout_; |
60 | | - unsigned Min = fin.M, Mout = fout.M; |
61 | | - cdouble *Xin = Xin_.get(), *Xout = Xout_.get(); |
62 | | - cdouble *Xout_mem = Xout_mem_.get(); |
63 | | - cdouble *Gin = Gin_.get(), *Gout = Gout_.get(); |
64 | | - const cdouble *Pin = fin.P.get(), *Pout = fout.P.get(); |
| 57 | + const BBD_Filter_Coef &fin = *fin_; |
| 58 | + const BBD_Filter_Coef &fout = *fout_; |
| 59 | + unsigned Min = fin.M; |
| 60 | + unsigned Mout = fout.M; |
| 61 | + const cdouble *const Pin = fin.P.get(); |
| 62 | + const cdouble *const Pout = fout.P.get(); |
65 | 63 |
|
66 | 64 | for (unsigned i = 0; i < n; ++i) { |
67 | | - double fclk = clock[i]; |
68 | | - |
69 | | - for (unsigned m = 0; m < Mout; ++m) |
70 | | - Xout[m] = 0; |
| 65 | + std::array<cdouble, Mmax> Xout_[Channels] = {}; |
71 | 66 |
|
| 67 | + double fclk = clock[i]; |
72 | 68 | if (fclk > 0) { |
73 | 69 | double pclk_old = pclk; |
74 | 70 | pclk += fclk; |
| 71 | + |
75 | 72 | unsigned tick_count = (unsigned)pclk; |
76 | 73 | pclk -= tick_count; |
| 74 | + |
77 | 75 | for (unsigned tick = 0; tick < tick_count; ++tick) { |
78 | 76 | double d = (1 - pclk_old + tick) * (1 / fclk); |
79 | 77 | d -= (unsigned)d; |
| 78 | + |
80 | 79 | if ((ptick & 1) == 0) { |
| 80 | + cdouble Gin[Mmax]; |
81 | 81 | fin.interpolate_G(d, Gin); |
82 | | - cdouble s = 0; |
83 | | - for (unsigned m = 0; m < Min; ++m) |
84 | | - s += Gin[m] * Xin[m]; |
85 | | - mem[imem] = s.real(); |
| 82 | + |
| 83 | + for (unsigned c = 0; c < Channels; ++c) { |
| 84 | + const std::array<cdouble, Mmax> &Xin = Xin_[c]; |
| 85 | + cdouble s = 0; |
| 86 | + for (unsigned m = 0; m < Min; ++m) |
| 87 | + s += Gin[m] * Xin[m]; |
| 88 | + mem[imem * Channels + c] = s.real(); |
| 89 | + } |
| 90 | + |
86 | 91 | imem = ((imem + 1) < ns) ? (imem + 1) : 0; |
87 | 92 | } |
88 | 93 | else { |
| 94 | + cdouble Gout[Mmax]; |
89 | 95 | fout.interpolate_G(d, Gout); |
90 | | - double ybbd = mem[imem]; |
91 | | - double delta = ybbd - ybbd_old; |
92 | | - ybbd_old = ybbd; |
93 | | - for (unsigned m = 0; m < Mout; ++m) |
94 | | - Xout[m] += Gout[m] * delta; |
| 96 | + |
| 97 | + for (unsigned c = 0; c < Channels; ++c) { |
| 98 | + std::array<cdouble, Mmax> &Xout = Xout_[c]; |
| 99 | + double ybbd = mem[imem * Channels + c]; |
| 100 | + double delta = ybbd - ybbd1[c]; |
| 101 | + ybbd1[c] = ybbd; |
| 102 | + for (unsigned m = 0; m < Mout; ++m) |
| 103 | + Xout[m] += Gout[m] * delta; |
| 104 | + } |
95 | 105 | } |
| 106 | + |
96 | 107 | ++ptick; |
97 | 108 | } |
98 | 109 | } |
99 | 110 |
|
100 | | - for (unsigned m = 0; m < Min; ++m) |
101 | | - Xin[m] = Pin[m] * Xin[m] + cdouble(input[i]); |
| 111 | + for (unsigned c = 0; c < Channels; ++c) { |
| 112 | + const float *input = inputs[c]; |
| 113 | + float *output = outputs[c]; |
102 | 114 |
|
103 | | - cdouble y = fout.H * ybbd_old; |
104 | | - for (unsigned m = 0; m < Mout; ++m) { |
105 | | - cdouble xout = Pout[m] * Xout_mem[m] + Xout[m]; |
106 | | - Xout_mem[m] = xout; |
107 | | - y += xout; |
108 | | - } |
| 115 | + std::array<cdouble, Mmax> &Xin = Xin_[c]; |
| 116 | + std::array<cdouble, Mmax> &Xout1 = Xout1_[c]; |
| 117 | + const std::array<cdouble, Mmax> &Xout = Xout_[c]; |
109 | 118 |
|
110 | | - output[i] = y.real(); |
| 119 | + for (unsigned m = 0; m < Min; ++m) |
| 120 | + Xin[m] = Pin[m] * Xin[m] + cdouble(input[i]); |
| 121 | + |
| 122 | + cdouble y = fout.H * ybbd1[c]; |
| 123 | + for (unsigned m = 0; m < Mout; ++m) { |
| 124 | + cdouble xout = Pout[m] * Xout1[m] + Xout[m]; |
| 125 | + Xout1[m] = xout; |
| 126 | + y += xout; |
| 127 | + } |
| 128 | + |
| 129 | + output[i] = y.real(); |
| 130 | + } |
111 | 131 | } |
112 | 132 |
|
113 | 133 | imem_ = imem; |
114 | 134 | pclk_ = pclk; |
115 | 135 | ptick_ = ptick; |
116 | | - ybbd_old_ = ybbd_old; |
| 136 | + ybbd1_ = ybbd1; |
117 | 137 | } |
118 | 138 |
|
119 | | -void BBD_Line::process(unsigned n, float *inout, const float *clock) |
| 139 | +template <unsigned Channels> |
| 140 | +void BBD_Line<Channels>::process(unsigned n, float *const inouts[Channels], const float *clock) |
120 | 141 | { |
121 | | - process(n, inout, inout, clock); |
| 142 | + process(n, inouts, inouts, clock); |
122 | 143 | } |
| 144 | + |
| 145 | +template class BBD_Line<1>; |
| 146 | +template class BBD_Line<2>; |
0 commit comments