10class DualCosineOscillator {
12 enum class Mode { APPROX, EXACT };
14 template <Mode mode = Mode::APPROX>
15 constexpr DualCosineOscillator(std::array<float, 2> frequencies)
16 : frequencies_(ArgonHalf<float>::Load(frequencies.data())) {
19 ~DualCosineOscillator() =
default;
21 template <Mode mode = Mode::APPROX>
22 inline void SetFrequency(
int index,
float frequency) {
23 frequencies_[index] = frequency;
27 inline void InitApproximate() {
28 ArgonHalf<float> sign = 16.0f;
29 ArgonHalf<float> frequencies = frequencies_;
30 frequencies = frequencies.each_lane_with_index([&](
float& frequency,
int i) {
32 if (frequency < 0.0f) {
33 frequency = -frequency;
35 else if (frequency > 0.5f) {
42 iir_coefficient_ = sign * frequencies * (1.0f - (2.0f * frequencies));
43 initial_amplitude_ = iir_coefficient_ * 0.25f;
46 constexpr void Start() {
47 y_0 = initial_amplitude_;
51 [[nodiscard]]
inline ArgonHalf<float> values()
const {
return y_0 + 0.5f; }
53 inline ArgonHalf<float> Next() {
54 ArgonHalf<float> temp = y_1;
55 y_1 = iir_coefficient_ * y_1 - y_0;
61 template <Mode mode = Mode::APPROX>
63 if constexpr (mode == Mode::APPROX) {
67 for (
size_t i = 0; i < frequencies_.size(); ++i) {
68 iir_coefficient_[i] = 2.0f * std::cos(2.0f * std::numbers::pi_v<float> * frequencies_[i]);
69 initial_amplitude_[i] = iir_coefficient_[i] * 0.25f;
75 ArgonHalf<float> frequencies_;
78 ArgonHalf<float> iir_coefficient_;
79 ArgonHalf<float> initial_amplitude_;