58 r.brightness_octaves = 0.7f;
80 void set_gap_jitter(
double amount) { gap_jitter_ = std::clamp(amount, 0.0, 1.0); }
90 stereo_width_ = std::clamp(width, 0.0, 1.0);
100 void set_cutoff_hz(
double hz) { cutoff_hz_ = std::clamp(hz, 200.0, 16000.0); }
109 void set_body_hz(
double hz) { body_hz_ = std::clamp(hz, 40.0, 2000.0); }
115 return output_.latency_samples();
118 return output_.oversampling();
121 output_.set_oversampling(factor);
129 filter_.set_sample_rate(
static_cast<float>(
sample_rate));
130 filter_.set_mode(Svf::Mode::bandpass);
140 burst_output_.reset();
141 stereo_path_active_ =
false;
145 samples_until_burst_ = 0;
150 jitter_state_ = kJitterSeed;
154 output_.reset_nonlinear_state();
156 if (stereo_path_active_) {
157 burst_output_.sync_configuration_from(output_);
158 burst_output_.reset_nonlinear_state();
159 burst_output_.trigger();
162 velocity_gain_ = response.gain(
velocity);
163 brightness_ = response.brightness_scale(
velocity);
174 filter_.set_frequency(
static_cast<float>(
175 std::min(cutoff_hz_ * brightness_, 0.49 *
sample_rate())));
176 filter_.set_resonance(
static_cast<float>(resonance_));
178 spacing_samples_ = std::max(1,
static_cast<int>(0.001 * spacing_ms_ *
sample_rate()));
180 burst_env_.set_attack_ms(0.0);
181 burst_env_.set_decay_time_constant_ms(burst_decay_ms_);
182 tail_env_.set_attack_ms(0.5);
183 tail_env_.set_decay_t60_ms(tail_decay_ms_);
190 jitter_state_ = kJitterSeed;
191 burst_env_.trigger();
194 samples_until_burst_ = next_gap();
198 return burst_env_.is_active() || tail_env_.is_active() ||
199 next_burst_ < burst_count_ || output_.has_tail();
205 stereo_path_active_ =
false;
206 for (
int i = 0;
i < num_samples; ++
i) {
207 out[
i] += render_frame(
false).mono;
212 int num_samples)
override {
213 const bool quality_changed =
214 burst_output_.oversampling() != output_.oversampling();
215 burst_output_.sync_configuration_from(output_);
216 if (!stereo_path_active_ || quality_changed) {
217 burst_output_.reset();
218 burst_output_.trigger();
220 stereo_path_active_ =
true;
222 for (
int i = 0;
i < num_samples; ++
i) {
223 const RenderFrame frame = render_frame(
true);
224 const double pan = frame.burst_pan * stereo_width_;
225 left[
i] +=
static_cast<float>(
226 0.5 * frame.mono - 0.5 * pan * frame.burst);
227 right[
i] +=
static_cast<float>(
228 0.5 * frame.mono + 0.5 * pan * frame.burst);
236 double burst_pan = 0.0;
239 RenderFrame render_frame(
bool render_burst_side) {
240 if (next_burst_ < burst_count_ && --samples_until_burst_ <= 0) {
241 burst_gain_ *= falloff_;
242 if (alternate_polarity_) burst_sign_ = -burst_sign_;
243 burst_pan_ = (next_burst_ & 1) != 0 ? 1.0 : -1.0;
246 samples_until_burst_ = next_gap();
251 filtered * burst_env_.
process() * burst_gain_ * burst_sign_;
252 const double tail_env = tail_env_.
process();
253 const double room = filtered * tail_env * tail_level_;
256 if (body_level_ > 0.0) {
258 if (body_phase_ >= 1.0) body_phase_ -= std::floor(body_phase_);
259 body = std::sin(2.0 * 3.14159265358979323846 * body_phase_) *
260 tail_env * body_level_;
263 const double centre = room + body;
266 frame.mono =
static_cast<float>(
267 output_.
process(
static_cast<float>(train + centre)) * velocity_gain_);
272 if (render_burst_side) {
274 burst_output_.
process(
static_cast<float>(train)) * velocity_gain_;
276 frame.burst_pan = delayed_burst_pan();
280 void reset_pan_delay() {
281 burst_pan_delay_.fill(burst_pan_);
282 burst_pan_write_ = 0;
285 double delayed_burst_pan() {
286 burst_pan_delay_[
static_cast<std::size_t
>(burst_pan_write_)] =
288 const int size =
static_cast<int>(burst_pan_delay_.size());
289 const int delay = burst_output_.latency_samples();
291 const double delayed =
292 burst_pan_delay_[
static_cast<std::size_t
>(
read)];
293 burst_pan_write_ = (burst_pan_write_ + 1) % size;
300 static constexpr std::uint32_t kJitterSeed = 0x2545F491u;
304 if (gap_jitter_ <= 0.0)
return spacing_samples_;
305 jitter_state_ ^= jitter_state_ << 13;
306 jitter_state_ ^= jitter_state_ >> 17;
307 jitter_state_ ^= jitter_state_ << 5;
309 static_cast<double>(jitter_state_) * (1.0 / 2147483648.0) - 1.0;
310 const double scaled =
311 static_cast<double>(spacing_samples_) * (1.0 + 0.5 * gap_jitter_ *
bipolar);
312 return std::max(1,
static_cast<int>(scaled));
315 int burst_count_ = 4;
316 double spacing_ms_ = 11.0;
317 double burst_decay_ms_ = 6.0;
318 double falloff_ = 0.82;
321 double gap_jitter_ = 0.35;
322 bool alternate_polarity_ =
false;
323 double stereo_width_ = 1.0;
324 double tail_level_ = 0.35;
325 double tail_decay_ms_ = 180.0;
326 double cutoff_hz_ = 1400.0;
327 double resonance_ = 1.4;
328 double body_level_ = 0.0;
329 double body_hz_ = 300.0;
337 bool stereo_path_active_ =
false;
338 static constexpr int kMaxOutputLatency =
340 std::array<double, kMaxOutputLatency + 1> burst_pan_delay_{};
341 int burst_pan_write_ = 0;
343 double velocity_gain_ = 1.0;
344 double brightness_ = 1.0;
345 double body_phase_ = 0.0;
347 int spacing_samples_ = 1;
349 int samples_until_burst_ = 0;
350 double burst_gain_ = 1.0;
351 double burst_sign_ = 1.0;
352 double burst_pan_ = -1.0;
353 std::uint32_t jitter_state_ = kJitterSeed;
SampleType process()
Next envelope sample in [0, peak].
Definition decay_envelope.hpp:125
void trigger(SampleType peak=SampleType{1})
Starts the envelope from silence.
Definition decay_envelope.hpp:101
SampleType process()
Next sample, normalised so every colour has approximately the same RMS.
Definition noise_source.hpp:111
SampleType process(SampleType input)
Definition svf.hpp:54
void set_noise_color(NoiseColor color)
Definition clap.hpp:103
void set_cutoff_hz(double hz)
Centre and resonance of the bandpass the noise is heard through.
Definition clap.hpp:100
void on_note_on(float velocity) override
Starts a hit at the given velocity, already clamped to [0, 1].
Definition clap.hpp:153
static constexpr int max_bursts
Upper bound on the burst train.
Definition clap.hpp:53
void set_gap_jitter(double amount)
How much each gap varies from the nominal spacing, 0 to 1.
Definition clap.hpp:80
const OutputStage & output() const
Definition clap.hpp:112
void set_burst_decay_ms(double ms)
How quickly each burst decays.
Definition clap.hpp:69
void on_reset() override
Clears every piece of state the voice carries, so is_active() becomes false and the next render start...
Definition clap.hpp:135
OutputStage * output_stage() noexcept override
The terminal saturation and degradation stage, at the generic voice boundary.
Definition clap.hpp:113
void set_output_oversampling(OutputOversampling factor) override
Definition clap.hpp:120
void set_burst_count(int count)
How many bursts the train contains.
Definition clap.hpp:63
void set_burst_spacing_ms(double ms)
Milliseconds between bursts.
Definition clap.hpp:66
void set_burst_falloff(double ratio)
How much quieter each burst is than the one before it, as a ratio.
Definition clap.hpp:74
void set_body_hz(double hz)
Definition clap.hpp:109
void set_alternate_polarity(bool alternate)
Invert every other burst.
Definition clap.hpp:85
void set_tail_decay_ms(double ms)
Definition clap.hpp:95
void set_tail_level(double level)
Level and decay of the tail that fuses the train.
Definition clap.hpp:94
void set_resonance(double q)
Definition clap.hpp:101
OutputStage & output()
Definition clap.hpp:111
void on_prepare(double sample_rate) override
Sizes buffers and fixes coefficients.
Definition clap.hpp:125
void set_body_level(double level)
Level of an optional sine under the train, at set_body_hz.
Definition clap.hpp:108
void render_add(float *out, int num_samples) override
Adds the voice's output into out. Must add, never assign.
Definition clap.hpp:202
ClapVoice()
Definition clap.hpp:55
void set_stereo_width(double width)
Alternating burst width, 0 for mono through 1 for hard left/right.
Definition clap.hpp:89
void render_add_stereo(float *left, float *right, int num_samples) override
Optional stereo realization.
Definition clap.hpp:211
int latency_samples() const noexcept override
Fixed host-rate delay introduced by this voice's selected output quality.
Definition clap.hpp:114
OutputOversampling output_oversampling() const noexcept override
Output quality at the generic voice boundary.
Definition clap.hpp:117
bool on_is_active() const override
Definition clap.hpp:197
static constexpr int latency_samples_for(OutputOversampling factor) noexcept
Definition output_stage.hpp:97
SampleType process(SampleType input)
Definition output_stage.hpp:204
double sample_rate() const
Definition voice.hpp:105
void set_velocity_response(const VelocityResponse &r)
Definition voice.hpp:129
float velocity() const
Definition voice.hpp:104
const VelocityResponse & velocity_response() const
Definition voice.hpp:130
OutputOversampling
Realtime quality choices for the shared drum output nonlinearity.
Definition output_stage.hpp:20
@ x4
Definition output_stage.hpp:23
OutputStageT< float > OutputStage
Definition output_stage.hpp:384
@ size
Definition config.hpp:216
std::uint64_t read(std::span< const std::uint8_t > b, std::size_t p, unsigned n) noexcept
Definition spectral_frame_codec.hpp:111
@ right
Definition multi_channel_meter.hpp:67
@ left
Definition multi_channel_meter.hpp:66
SvfT< float > Svf
Definition svf.hpp:148
@ delay
Definition envelope.hpp:57
@ ratio
base_frequency_hz * ratio.
Definition fm_operator_engine.hpp:20
@ i
Definition formant_filter_bank.hpp:20
NoiseColor
Spectral tilt of a NoiseSourceT, named by the usual colour convention.
Definition noise_source.hpp:17
DecayEnvelopeT< double > DecayEnvelope64
Definition decay_envelope.hpp:201
NoiseSourceT< float > NoiseSource
Definition noise_source.hpp:279
@ bipolar
Definition nonlinear_shaping.hpp:436
How hard a hit changes the sound, beyond changing how loud it is.
Definition velocity.hpp:33