11class DualCosineOscillator {
13 enum class Mode { APPROX, EXACT };
15 template <Mode mode = Mode::APPROX>
16 constexpr DualCosineOscillator(std::array<float, 2> frequencies)
17 : frequencies_(ArgonHalf<float>::Load(frequencies.data())) {
20 ~DualCosineOscillator() =
default;
22 template <Mode mode = Mode::APPROX>
23 inline void SetFrequency(
int index,
float frequency) {
24 frequencies_[index] = frequency;
28 inline void InitApproximate() {
29 ArgonHalf<float> sign = 16.0f;
30 ArgonHalf<float> frequencies = frequencies_;
31 frequencies = frequencies.each_lane_with_index([&](
float& frequency,
int i) {
33 if (frequency < 0.0f) {
34 frequency = -frequency;
36 else if (frequency > 0.5f) {
43 iir_coefficient_ = sign * frequencies * (1.0f - (2.0f * frequencies));
44 initial_amplitude_ = iir_coefficient_ * 0.25f;
47 constexpr void Start() {
48 y_0 = initial_amplitude_;
52 [[nodiscard]]
inline ArgonHalf<float> values()
const {
return y_0 + 0.5f; }
54 inline ArgonHalf<float> Next() {
55 ArgonHalf<float> temp = y_1;
56 y_1 = iir_coefficient_ * y_1 - y_0;
62 template <Mode mode = Mode::APPROX>
64 if constexpr (mode == Mode::APPROX) {
68 for (
size_t i = 0; i < frequencies_.size(); ++i) {
69 iir_coefficient_[i] = 2.0f * std::cos(2.0f * std::numbers::pi_v<float> * frequencies_[i]);
70 initial_amplitude_[i] = iir_coefficient_[i] * 0.25f;
76 ArgonHalf<float> frequencies_;
79 ArgonHalf<float> iir_coefficient_;
80 ArgonHalf<float> initial_amplitude_;