Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
sub_oscillator.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cmath>
4#include <cstdint>
5#include <numbers>
6#include <type_traits>
7
8namespace pulp::signal {
9
15
27template <typename SampleType = float> class SubOscillatorT {
28 public:
29 static_assert(std::is_same_v<SampleType, float> || std::is_same_v<SampleType, double>);
30
33 [[nodiscard]] bool set_octave(int octave) noexcept {
34 if (octave != 1 && octave != 2)
35 return false;
36 octave_ = octave;
37 return true;
38 }
39
40 int octave() const noexcept {
41 return octave_;
42 }
43
45 waveform_ = waveform;
46 }
48 return waveform_;
49 }
50
52 void reset(std::uint32_t completed_parent_cycles = 0) noexcept {
53 cycle_index_ = completed_parent_cycles % max_divisor;
54 phase_ = SampleType{0};
55 }
56
58 void on_parent_cycle() noexcept {
59 cycle_index_ = (cycle_index_ + 1u) % max_divisor;
60 }
61
65 SampleType next(SampleType parent_phase) noexcept {
66 if (!std::isfinite(parent_phase) || parent_phase < SampleType{0} ||
67 parent_phase >= SampleType{1}) {
68 reset();
69 return SampleType{0};
70 }
71
72 phase_ = (static_cast<SampleType>(cycle_index_ % divisor()) + parent_phase) /
73 static_cast<SampleType>(divisor());
74 if (waveform_ == SubOscillatorWaveform::square)
75 return phase_ < SampleType{0.5} ? SampleType{1} : SampleType{-1};
76 return std::sin(SampleType{2} * std::numbers::pi_v<SampleType> * phase_);
77 }
78
81 SampleType next(SampleType parent_phase, bool parent_cycle_edge) noexcept {
82 if (parent_cycle_edge)
84 return next(parent_phase);
85 }
86
88 SampleType phase() const noexcept {
89 return phase_;
90 }
91
92 private:
93 static constexpr std::uint32_t max_divisor = 4;
94
95 std::uint32_t divisor() const noexcept {
96 return std::uint32_t{1} << octave_;
97 }
98
99 std::uint32_t cycle_index_ = 0;
100 int octave_ = 1;
101 SampleType phase_ = SampleType{0};
103};
104
107
108} // namespace pulp::signal
A one- or two-octave divider derived from an explicit parent phase.
Definition sub_oscillator.hpp:27
bool set_octave(int octave) noexcept
Select one or two octaves below the parent.
Definition sub_oscillator.hpp:33
void reset(std::uint32_t completed_parent_cycles=0) noexcept
Re-anchor the divider to a known completed parent-cycle count.
Definition sub_oscillator.hpp:52
SampleType next(SampleType parent_phase) noexcept
Render from the parent's current normalized phase in [0, 1).
Definition sub_oscillator.hpp:65
int octave() const noexcept
Definition sub_oscillator.hpp:40
SubOscillatorWaveform waveform() const noexcept
Definition sub_oscillator.hpp:47
SampleType phase() const noexcept
The phase used for the most recently rendered valid sample.
Definition sub_oscillator.hpp:88
SampleType next(SampleType parent_phase, bool parent_cycle_edge) noexcept
Convenience form for a wrap and render in one call.
Definition sub_oscillator.hpp:81
void on_parent_cycle() noexcept
Report one completed parent cycle. Call before next(0) on a wrap.
Definition sub_oscillator.hpp:58
void set_waveform(SubOscillatorWaveform waveform) noexcept
Definition sub_oscillator.hpp:44
Definition additive_bank.hpp:218
SubOscillatorT< double > SubOscillator64
Definition sub_oscillator.hpp:106
SubOscillatorWaveform
Output shape for a parent-phase-locked sub-oscillator.
Definition sub_oscillator.hpp:11
@ square
Definition sub_oscillator.hpp:12
@ square
Definition lfo_sampling.hpp:58
@ sine
Definition lfo_sampling.hpp:54
SubOscillatorT< float > SubOscillator
Definition sub_oscillator.hpp:105