Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
supersaw.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4#include <cmath>
5#include <cstddef>
6#include <cstdint>
7#include <type_traits>
8
11
12namespace pulp::signal {
13
14template <typename SampleType> struct StereoSampleT {
15 SampleType left{};
16 SampleType right{};
17};
18
19template <typename SampleType = float, std::size_t MaximumVoices = 16>
20class SupersawT {
21public:
22 static_assert(std::is_floating_point_v<SampleType>);
23
26 bool prepare(SampleType sample_rate, const UnisonSpec& spec) noexcept {
27 if (!std::isfinite(sample_rate) || sample_rate <= SampleType{0}) return false;
29 if (!check.configure(spec)) return false;
30 sample_rate_ = sample_rate;
31 spec_ = spec;
32 prepared_ = true;
33 active_ = false;
34 return true;
35 }
36
40 bool trigger(SampleType frequency, std::uint64_t seed,
41 std::uint64_t note_instance_id) noexcept {
42 if (!prepared_ || !std::isfinite(frequency) || frequency <= SampleType{0})
43 return false;
45 if (!next_layout.configure(spec_, seed, note_instance_id)) return false;
46 const double worst_cents = spec_.detune_cents + spec_.drift_cents;
47 const double maximum_frequency = static_cast<double>(frequency) *
48 std::exp2(worst_cents / 1200.0);
49 if (!std::isfinite(maximum_frequency) || maximum_frequency >= sample_rate_ * 0.5)
50 return false;
51 auto next_oscillators = oscillators_;
52 for (std::size_t i = 0; i < next_layout.size(); ++i) {
53 next_oscillators[i].set_sample_rate(sample_rate_);
54 next_oscillators[i].set_waveform(OscillatorT<SampleType>::Waveform::saw);
55 if (!next_oscillators[i].reset_phase(
56 static_cast<SampleType>(next_layout[i].phase))) return false;
57 }
58 layout_ = next_layout;
59 oscillators_ = next_oscillators;
60 base_frequency_ = frequency;
61 active_ = true;
62 return true;
63 }
64
68 StereoSampleT<SampleType> next(std::uint64_t absolute_frame) noexcept {
70 if (!active_) return output;
71 constexpr double half_pi = 1.57079632679489661923;
72 for (std::size_t i = 0; i < layout_.size(); ++i) {
73 const auto& voice = layout_[i];
74 const double cents = voice.detune_cents + layout_.drift_cents(i, absolute_frame);
75 oscillators_[i].set_frequency(static_cast<SampleType>(
76 static_cast<double>(base_frequency_) * std::exp2(cents / 1200.0)));
77 const double sample = oscillators_[i].next() * voice.gain;
78 const double angle = (voice.pan + 1.0) * 0.5 * half_pi;
79 output.left += static_cast<SampleType>(sample * std::cos(angle));
80 output.right += static_cast<SampleType>(sample * std::sin(angle));
81 }
82 return output;
83 }
84
87 void reset() noexcept {
88 for (auto& oscillator : oscillators_) oscillator.reset();
89 active_ = false;
90 }
91
92 bool prepared() const noexcept { return prepared_; }
93 bool active() const noexcept { return active_; }
94 const UnisonLayout<MaximumVoices>& layout() const noexcept { return layout_; }
95
96private:
97 std::array<OscillatorT<SampleType>, MaximumVoices> oscillators_{};
98 UnisonLayout<MaximumVoices> layout_{};
99 UnisonSpec spec_{};
100 SampleType sample_rate_ = SampleType{0};
101 SampleType base_frequency_ = SampleType{0};
102 bool prepared_ = false;
103 bool active_ = false;
104};
105
108
109} // namespace pulp::signal
@ saw
Definition oscillator.hpp:21
Definition supersaw.hpp:20
bool trigger(SampleType frequency, std::uint64_t seed, std::uint64_t note_instance_id) noexcept
Audio-thread-safe note start.
Definition supersaw.hpp:40
StereoSampleT< SampleType > next(std::uint64_t absolute_frame) noexcept
Render one stereo sample for the supplied absolute audio-frame index.
Definition supersaw.hpp:68
void reset() noexcept
Audio-thread-safe hard reset.
Definition supersaw.hpp:87
const UnisonLayout< MaximumVoices > & layout() const noexcept
Definition supersaw.hpp:94
bool active() const noexcept
Definition supersaw.hpp:93
bool prepare(SampleType sample_rate, const UnisonSpec &spec) noexcept
Control-side preparation.
Definition supersaw.hpp:26
bool prepared() const noexcept
Definition supersaw.hpp:92
Definition unison.hpp:38
std::size_t size() const noexcept
Definition unison.hpp:76
double drift_cents(std::size_t voice, std::uint64_t absolute_frame) const noexcept
Definition unison.hpp:84
bool configure(const UnisonSpec &spec, std::uint64_t seed=0, std::uint64_t note_instance_id=0) noexcept
Definition unison.hpp:42
Definition additive_bank.hpp:218
SupersawT< float > Supersaw
Definition supersaw.hpp:106
@ i
Definition formant_filter_bank.hpp:20
SupersawT< double > Supersaw64
Definition supersaw.hpp:107
Definition supersaw.hpp:14
SampleType left
Definition supersaw.hpp:15
SampleType right
Definition supersaw.hpp:16
Control-side configuration for a fixed unison layout.
Definition unison.hpp:20