Deluge Firmware 1.3.0
Build date: 2025.04.16
Loading...
Searching...
No Matches
cosine_oscillator.hpp
1// Copyright 2014 Emilie Gillet. MIT License.
2// Cosine oscillator. Generates a cosine between 0.0 and 1.0 with minimal
3// CPU use. Fixed frequency.
4
5#pragma once
6#include "argon.hpp"
7#include <cmath>
8#include <initializer_list>
9
10class DualCosineOscillator {
11public:
12 enum class Mode { APPROX, EXACT };
13
14 template <Mode mode = Mode::APPROX>
15 constexpr DualCosineOscillator(std::array<float, 2> frequencies) : frequencies_(frequencies) {
16 Init<mode>();
17 }
18 ~DualCosineOscillator() = default;
19
20 template <Mode mode = Mode::APPROX>
21 inline void SetFrequency(int index, float frequency) {
22 frequencies_[index] = frequency;
23 Init<mode>();
24 }
25
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) {
30 frequency -= 0.25f;
31 if (frequency < 0.0f) {
32 frequency = -frequency;
33 }
34 else if (frequency > 0.5f) {
35 frequency -= 0.5f;
36 }
37 else {
38 sign[i] = -16.0f;
39 }
40 });
41 iir_coefficient_ = sign * frequencies * (1.0f - (2.0f * frequencies));
42 initial_amplitude_ = iir_coefficient_ * 0.25f;
43 }
44
45 constexpr void Start() {
46 y_0 = initial_amplitude_;
47 y_1 = 0.5f;
48 }
49
50 [[nodiscard]] inline ArgonHalf<float> values() const { return y_0 + 0.5f; }
51
52 inline ArgonHalf<float> Next() {
53 ArgonHalf<float> temp = y_1;
54 y_1 = iir_coefficient_ * y_1 - y_0;
55 y_0 = temp;
56 return temp + 0.5f;
57 }
58
59private:
60 template <Mode mode = Mode::APPROX>
61 inline void Init() {
62 if constexpr (mode == Mode::APPROX) {
63 InitApproximate();
64 }
65 else {
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;
69 }
70 }
71 Start();
72 }
73
74 ArgonHalf<float> frequencies_;
75 ArgonHalf<float> y_0;
76 ArgonHalf<float> y_1;
77 ArgonHalf<float> iir_coefficient_;
78 ArgonHalf<float> initial_amplitude_;
79};