10class DualCosineOscillator {
12 enum class Mode { APPROX, EXACT };
14 template <Mode mode = Mode::APPROX>
15 constexpr DualCosineOscillator(std::array<float, 2> frequencies) : frequencies_(frequencies) {
18 ~DualCosineOscillator() =
default;
20 template <Mode mode = Mode::APPROX>
21 inline void SetFrequency(
int index,
float frequency) {
22 frequencies_[index] = frequency;
26 inline void InitApproximate() {
27 ArgonHalf<float> sign = 16.0f;
28 ArgonHalf<float> frequencies = frequencies_;
29 frequencies = frequencies.each_lane_with_index([&](
float& frequency,
int i) {
31 if (frequency < 0.0f) {
32 frequency = -frequency;
34 else if (frequency > 0.5f) {
41 iir_coefficient_ = sign * frequencies * (1.0f - (2.0f * frequencies));
42 initial_amplitude_ = iir_coefficient_ * 0.25f;
45 constexpr void Start() {
46 y_0 = initial_amplitude_;
50 [[nodiscard]]
inline ArgonHalf<float> values()
const {
return y_0 + 0.5f; }
52 inline ArgonHalf<float> Next() {
53 ArgonHalf<float> temp = y_1;
54 y_1 = iir_coefficient_ * y_1 - y_0;
60 template <Mode mode = Mode::APPROX>
62 if constexpr (mode == Mode::APPROX) {
66 for (
size_t i = 0; i < frequencies_.size(); ++i) {
67 iir_coefficient_[i] = 2.0f * std::cos(2.0f * std::numbers::pi_v<float> * frequencies_[i]);
68 initial_amplitude_[i] = iir_coefficient_[i] * 0.25f;
74 ArgonHalf<float> frequencies_;
77 ArgonHalf<float> iir_coefficient_;
78 ArgonHalf<float> initial_amplitude_;