Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
rungler.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <pulp/signal/detail/modular_sequencing_common.hpp>
5
6#include <algorithm>
7#include <cstdint>
8
9namespace pulp::signal {
10
11// ── Rungler ───────────────────────────────────────────────────────────────
12
67template <typename SampleType = float>
68class RunglerT {
69public:
72 static constexpr int kMinBits = 4;
73 static constexpr int kMaxBits = 16;
74 static constexpr int kDefaultBits = 8;
75
78 static constexpr int kMinDacBits = 1;
79 static constexpr int kMaxDacBits = 4;
80 static constexpr int kDefaultDacBits = 3;
81
84 static constexpr std::uint32_t kSeedPattern = 0b10110100u;
85
88 static constexpr int kFeedbackTap = 0;
89
92 static constexpr double kRangeV = 2.0;
93
98 static constexpr double kMaxRangeV = 1000.0;
99
100 RunglerT() { load_seed(); }
101
102 void prepare(double sample_rate) {
103 sample_rate_ = sample_rate > 0.0 ? sample_rate : sample_rate_;
104 }
105
111 void set_reg_bits(int n) {
112 bits_ = std::clamp(n, kMinBits, kMaxBits);
113 clamp_config();
114 load_seed();
115 }
116 int reg_bits() const { return bits_; }
117
118 void set_dac_bits(int d) {
119 dac_bits_ = std::clamp(d, kMinDacBits, kMaxDacBits);
120 clamp_config();
121 refresh_output();
122 }
123 int dac_bits() const { return dac_bits_; }
124
125 void set_feedback_tap(int tap) {
126 tap_ = tap;
127 clamp_config();
128 (void)register_.set_feedback_mask(feedback_mask());
129 }
130 int feedback_tap() const { return tap_; }
131
132 void set_range_v(double volts) {
133 range_v_ = seq_detail::clamp_finite(volts, 0.0, kMaxRangeV);
134 refresh_output();
135 }
136 double range_v() const { return range_v_; }
137
138 void set_external_data(bool on) { external_data_ = on; }
139 bool external_data() const { return external_data_; }
140
141 void set_seed_pattern(std::uint32_t pattern) {
142 seed_pattern_ = pattern;
143 load_seed();
144 }
145 std::uint32_t seed_pattern() const { return seed_pattern_; }
146
150 void apply_reset_edge() { load_seed(); }
151
152 void reset() { load_seed(); }
153
154 static constexpr int latency_samples() { return 0; }
155
157 std::uint32_t register_bits() const { return register_.state(); }
159 int dac_code() const { return static_cast<int>(register_.state() & dac_mask()); }
160 SampleType value() const { return out_; }
161
165 SampleType process(bool run_high, bool reset_edge, bool clock_edge, bool data_in = false) {
166 if (reset_edge) apply_reset_edge();
167 if (!run_high) return out_;
168 if (!clock_edge) return out_;
169
170 register_.clock(external_data_ && data_in);
171 refresh_output();
172 return out_;
173 }
174
175private:
176 std::uint32_t dac_mask() const { return (1u << dac_bits_) - 1u; }
177
178 std::uint32_t feedback_mask() const {
179 return (std::uint32_t{1} << (bits_ - 1)) | (std::uint32_t{1} << tap_);
180 }
181
182 void clamp_config() {
183 if (dac_bits_ > bits_) dac_bits_ = bits_;
184 tap_ = std::clamp(tap_, 0, std::max(bits_ - 2, 0));
185 }
186
187 void load_seed() {
188 clamp_config();
189 (void)register_.configure(bits_, feedback_mask(), seed_pattern_);
190 refresh_output();
191 }
192
193 void refresh_output() {
194 const double levels = static_cast<double>(dac_mask());
195 const double k = static_cast<double>(register_.state() & dac_mask());
196 const double unit = levels > 0.0 ? (2.0 * k / levels - 1.0) : 0.0;
197 out_ = static_cast<SampleType>(range_v_ * unit);
198 }
199
200 double sample_rate_ = 44100.0;
201 int bits_ = kDefaultBits;
202 int dac_bits_ = kDefaultDacBits;
203 int tap_ = kFeedbackTap;
204 double range_v_ = kRangeV;
205 bool external_data_ = false;
206 std::uint32_t seed_pattern_ = kSeedPattern;
207
208 LfsrT<SampleType> register_{};
209 SampleType out_ = SampleType{0};
210};
211
214
215} // namespace pulp::signal
The Hordijk shift-register / DAC chaos sequencer.
Definition rungler.hpp:68
static constexpr int latency_samples()
Definition rungler.hpp:154
RunglerT()
Definition rungler.hpp:100
bool external_data() const
Definition rungler.hpp:139
static constexpr int kMinBits
Definition rungler.hpp:72
static constexpr int kMaxDacBits
Definition rungler.hpp:79
static constexpr int kDefaultDacBits
Definition rungler.hpp:80
static constexpr int kDefaultBits
Definition rungler.hpp:74
void set_dac_bits(int d)
Definition rungler.hpp:118
std::uint32_t register_bits() const
Current register contents, bit i at bit position i.
Definition rungler.hpp:157
static constexpr std::uint32_t kSeedPattern
Definition rungler.hpp:84
int feedback_tap() const
Definition rungler.hpp:130
int dac_bits() const
Definition rungler.hpp:123
void reset()
Definition rungler.hpp:152
void set_feedback_tap(int tap)
Definition rungler.hpp:125
SampleType value() const
Definition rungler.hpp:160
static constexpr int kMinDacBits
Definition rungler.hpp:78
void apply_reset_edge()
Verb 2 — and the one documented exception to "continuous outputs hold": the register goes back to the...
Definition rungler.hpp:150
void set_seed_pattern(std::uint32_t pattern)
Definition rungler.hpp:141
void set_external_data(bool on)
Definition rungler.hpp:138
static constexpr int kFeedbackTap
Definition rungler.hpp:88
SampleType process(bool run_high, bool reset_edge, bool clock_edge, bool data_in=false)
Advances one sample.
Definition rungler.hpp:165
static constexpr double kMaxRangeV
Definition rungler.hpp:98
int dac_code() const
Current DAC code in 0 .. 2^D − 1.
Definition rungler.hpp:159
void set_range_v(double volts)
Definition rungler.hpp:132
void prepare(double sample_rate)
Definition rungler.hpp:102
static constexpr int kMaxBits
Definition rungler.hpp:73
double range_v() const
Definition rungler.hpp:136
static constexpr double kRangeV
Definition rungler.hpp:92
std::uint32_t seed_pattern() const
Definition rungler.hpp:145
int reg_bits() const
Definition rungler.hpp:116
void set_reg_bits(int n)
Changing the register length reloads the seed pattern.
Definition rungler.hpp:111
Definition additive_bank.hpp:218
RunglerT< float > Rungler
Definition rungler.hpp:212
RunglerT< double > Rungler64
Definition rungler.hpp:213
@ levels
Definition multi_channel_meter.hpp:48
@ u
Definition formant_filter_bank.hpp:20
@ k
Definition input_events.hpp:40