Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
blit_oscillator.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <cmath>
5#include <limits>
6#include <numbers>
7#include <type_traits>
8
9namespace pulp::signal {
10
22template <typename SampleType = float> class BlitOscillatorT {
23 public:
24 static_assert(std::is_same_v<SampleType, float> || std::is_same_v<SampleType, double>);
25
28 [[nodiscard]] bool prepare(SampleType sample_rate) noexcept {
29 return prepare(sample_rate, frequency_hz_);
30 }
31
34 [[nodiscard]] bool prepare(SampleType sample_rate, SampleType frequency_hz) noexcept {
35 if (!valid_configuration(sample_rate, frequency_hz))
36 return false;
37 sample_rate_ = sample_rate;
38 frequency_hz_ = frequency_hz;
39 update_harmonics();
40 return true;
41 }
42
45 [[nodiscard]] bool set_frequency(SampleType frequency_hz) noexcept {
46 if (!valid_configuration(sample_rate_, frequency_hz))
47 return false;
48 frequency_hz_ = frequency_hz;
49 update_harmonics();
50 return true;
51 }
52
53 SampleType sample_rate() const noexcept {
54 return sample_rate_;
55 }
56 SampleType frequency() const noexcept {
57 return frequency_hz_;
58 }
59 int harmonic_count() const noexcept {
60 return harmonics_;
61 }
62
64 [[nodiscard]] bool reset_phase(SampleType phase = SampleType{0}) noexcept {
65 if (!std::isfinite(phase) || phase < SampleType{0} || phase >= SampleType{1})
66 return false;
67 phase_ = static_cast<double>(phase);
68 return true;
69 }
70
71 double phase() const noexcept {
72 return phase_;
73 }
74
76 SampleType next() noexcept {
77 const double distance = std::min(phase_, 1.0 - phase_);
78 const double x = std::numbers::pi * distance;
79 const double terms = static_cast<double>(2 * harmonics_ + 1);
80 const double out = normalized_sinc(terms * x) / normalized_sinc(x);
81
82 phase_ += static_cast<double>(frequency_hz_) / static_cast<double>(sample_rate_);
83 phase_ -= std::floor(phase_);
84 if (!std::isfinite(phase_))
85 phase_ = SampleType{0};
86 return std::isfinite(out) ? static_cast<SampleType>(out) : SampleType{0};
87 }
88
89 private:
90 static constexpr int max_harmonics = (std::numeric_limits<int>::max() - 1) / 2;
91
92 static bool valid_configuration(SampleType sample_rate, SampleType frequency) noexcept {
93 if (!std::isfinite(sample_rate) || !(sample_rate > SampleType{0}) ||
94 !std::isfinite(frequency) || !(frequency > SampleType{0}) ||
95 frequency >= sample_rate * SampleType{0.5})
96 return false;
97 const long double requested = std::floor((static_cast<long double>(sample_rate) * 0.5L) /
98 static_cast<long double>(frequency));
99 return std::isfinite(requested) && requested >= 1.0L &&
100 requested <= static_cast<long double>(max_harmonics);
101 }
102
103 static double normalized_sinc(double x) noexcept {
104 const double magnitude = std::fabs(x);
105 if (magnitude < 1.0e-4) {
106 const double squared = x * x;
107 return 1.0 - squared / 6.0 + squared * squared / 120.0;
108 }
109 return std::sin(x) / x;
110 }
111
112 void update_harmonics() noexcept {
113 const long double nyquist = static_cast<long double>(sample_rate_) * 0.5L;
114 const long double frequency = static_cast<long double>(frequency_hz_);
115 harmonics_ = static_cast<int>(std::floor(nyquist / frequency));
116 if (static_cast<long double>(harmonics_) * frequency > nyquist)
117 --harmonics_;
118 }
119
120 SampleType sample_rate_ = SampleType{48000};
121 SampleType frequency_hz_ = SampleType{440};
122 double phase_ = 0.0;
123 int harmonics_ = 54;
124};
125
128
129} // namespace pulp::signal
Band-limited impulse train evaluated by discrete summation.
Definition blit_oscillator.hpp:22
bool set_frequency(SampleType frequency_hz) noexcept
Set the fundamental in Hz.
Definition blit_oscillator.hpp:45
double phase() const noexcept
Definition blit_oscillator.hpp:71
SampleType next() noexcept
Render the current phase and advance one sample.
Definition blit_oscillator.hpp:76
float sample_rate() const noexcept
Definition blit_oscillator.hpp:53
bool prepare(SampleType sample_rate) noexcept
Set the sample rate in Hz.
Definition blit_oscillator.hpp:28
bool prepare(SampleType sample_rate, SampleType frequency_hz) noexcept
Atomically set sample rate and fundamental.
Definition blit_oscillator.hpp:34
SampleType frequency() const noexcept
Definition blit_oscillator.hpp:56
bool reset_phase(SampleType phase=SampleType{0}) noexcept
Set normalized phase in [0, 1). Failure leaves state unchanged.
Definition blit_oscillator.hpp:64
int harmonic_count() const noexcept
Definition blit_oscillator.hpp:59
Definition additive_bank.hpp:218
BlitOscillatorT< float > BlitOscillator
Definition blit_oscillator.hpp:126
BlitOscillatorT< double > BlitOscillator64
Definition blit_oscillator.hpp:127
@ x
Definition input_events.hpp:41