53 for (
auto& s : states_)
70 assert(channel >= 0 && channel < MaxChannels);
74 channel = std::clamp(channel, 0, MaxChannels - 1);
75 return processState(sample, states_[
static_cast<size_t>(channel)]);
86 assert(channel >= 0 && channel < MaxChannels);
87 channel = std::clamp(channel, 0, MaxChannels - 1);
88 auto state = states_[
static_cast<size_t>(channel)];
90 for (
int i = 0; i < kTaps - 1; ++i)
91 peak = std::max(peak, processState(T(0), state));
96 [[nodiscard]]
static constexpr int getLatency() noexcept {
return kTaps / 2; }
106 [[nodiscard]]
static constexpr int getTaps() noexcept {
return kTaps; }
109 static constexpr int kTaps = 12;
110 static constexpr int kPhases = 4;
111 static constexpr int kHistSize = 16;
112 static constexpr int kHistMask = kHistSize - 1;
118 T history[kHistSize * 2] = {};
122 [[nodiscard]]
static T processState(T sample, State& tp)
noexcept
125 tp.history[
static_cast<size_t>(tp.writePos)] = sample;
126 tp.history[
static_cast<size_t>(tp.writePos + kHistSize)] = sample;
127 const int newest = tp.writePos;
128 tp.writePos = (tp.writePos + 1) & kHistMask;
129 const T* window = &tp.history[
static_cast<size_t>(newest + kHistSize - (kTaps - 1))];
130 T peak = std::abs(sample);
131 for (
int phase = 0; phase < kPhases; ++phase)
134 kReversedCoeffs[
static_cast<size_t>(phase)].data(), window, kTaps);
135 const T a = std::abs(interp);
136 if (a > peak) peak = a;
151 [[nodiscard]]
static constexpr std::array<std::array<T, kTaps>, kPhases>
152 buildReversedPhaseTable() noexcept
154 constexpr double kAnnex2[kPhases][kTaps] = {
155 { 0.0017089843750, 0.0109863281250, -0.0196533203125,
156 0.0332031250000, -0.0594482421875, 0.1373291015625,
157 0.9721679687500, -0.1022949218750, 0.0476074218750,
158 -0.0266113281250, 0.0148925781250, -0.0083007812500 },
159 { -0.0291748046875, 0.0292968750000, -0.0517578125000,
160 0.0891113281250, -0.1665039062500, 0.4650878906250,
161 0.7797851562500, -0.2003173828125, 0.1015625000000,
162 -0.0582275390625, 0.0330810546875, -0.0189208984375 },
163 { -0.0189208984375, 0.0330810546875, -0.0582275390625,
164 0.1015625000000, -0.2003173828125, 0.7797851562500,
165 0.4650878906250, -0.1665039062500, 0.0891113281250,
166 -0.0517578125000, 0.0292968750000, -0.0291748046875 },
167 { -0.0083007812500, 0.0148925781250, -0.0266113281250,
168 0.0476074218750, -0.1022949218750, 0.9721679687500,
169 0.1373291015625, -0.0594482421875, 0.0332031250000,
170 -0.0196533203125, 0.0109863281250, 0.0017089843750 },
173 std::array<std::array<T, kTaps>, kPhases> result {};
174 for (
int phase = 0; phase < kPhases; ++phase)
175 for (
int k = 0; k < kTaps; ++k)
176 result[
static_cast<size_t>(phase)][
static_cast<size_t>(kTaps - 1 - k)]
177 =
static_cast<T
>(kAnnex2[phase][k]);
183 static constexpr std::array<std::array<T, kTaps>, kPhases> kReversedCoeffs =
184 buildReversedPhaseTable();
186 std::array<State, MaxChannels> states_ {};