50 r.bend_octaves = 0.1f;
53 r.brightness_octaves = 1.0f;
56 click_.set_level(0.2);
57 click_.set_cutoff_hz(6000.0);
58 click_.set_decay_ms(1.5);
62 void set_tune_hz(
double hz) { tune_hz_ = std::clamp(hz, 20.0, 4000.0); }
70 void set_index(
double index) { index_ = std::clamp(index, 0.0, 24.0); }
71 void set_index_ms(
double ms) { index_ms_ = std::clamp(ms, 0.5, 2000.0); }
74 void set_decay_ms(
double ms) { decay_ms_ = std::clamp(ms, 10.0, 4000.0); }
78 pitch_sweep_oct_ = std::clamp(octaves, 0.0, 6.0);
84 void set_feedback(
double amount) { feedback_ = std::clamp(amount, 0.0, 1.0); }
95 carrier_warp_ = std::clamp(amount, 0.0, 1.0);
98 modulator_warp_ = std::clamp(amount, 0.0, 1.0);
101 carrier_warp_ms_ = std::clamp(ms, 0.5, 2000.0);
104 modulator_warp_ms_ = std::clamp(ms, 0.5, 2000.0);
111 lfo_depth_octaves_ = std::clamp(octaves, 0.0, 2.0);
122 transient_ = std::clamp(index, -1,
124 if (transient_ >= 0) apply_transient();
128 noise_level_ = std::max(level, 0.0);
132 noise_decay_ms_ = std::clamp(ms, 0.5, 500.0);
136 noise_color_ = color;
137 if (noise_.color() != color) noise_.set_color(color);
141 void set_cutoff_hz(
double hz) { cutoff_hz_ = std::clamp(hz, 40.0, 18000.0); }
147 click_.set_level(level);
151 click_.set_cutoff_hz(hz);
158 return output_.latency_samples();
161 return output_.oversampling();
164 output_.set_oversampling(factor);
177 filter_.set_sample_rate(
static_cast<float>(
sample_rate));
185 carrier_warp_env_.reset();
186 modulator_warp_env_.reset();
192 carrier_phase_ = 0.0;
193 modulator_phase_ = 0.0;
196 samples_since_note_ = 0;
200 output_.reset_nonlinear_state();
203 velocity_gain_ = response.gain(
velocity);
204 applied_bend_ = pitch_sweep_oct_ + response.bend(
velocity);
206 index_ *
static_cast<double>(response.brightness_scale(
velocity));
209 carrier_phase_ = 0.0;
210 modulator_phase_ = 0.0;
213 samples_since_note_ = 0;
215 static_cast<int>(0.001 * lfo_delay_ms_ *
sample_rate());
217 std::max(1,
static_cast<int>(0.001 * lfo_fade_ms_ *
sample_rate()));
219 filter_.set_mode(bandpass_ ? Svf::Mode::bandpass : Svf::Mode::lowpass);
220 filter_.set_frequency(
221 static_cast<float>(std::min(cutoff_hz_, 0.49 *
sample_rate())));
222 filter_.set_resonance(
static_cast<float>(resonance_));
224 pitch_env_.set_attack_ms(0.0);
225 pitch_env_.set_decay_time_constant_ms(pitch_sweep_ms_);
226 pitch_env_.trigger();
228 index_env_.set_attack_ms(0.0);
229 index_env_.set_decay_time_constant_ms(index_ms_);
230 index_env_.trigger();
232 carrier_warp_env_.set_attack_ms(0.0);
233 carrier_warp_env_.set_decay_time_constant_ms(carrier_warp_ms_);
234 carrier_warp_env_.trigger();
235 modulator_warp_env_.set_attack_ms(0.0);
236 modulator_warp_env_.set_decay_time_constant_ms(modulator_warp_ms_);
237 modulator_warp_env_.trigger();
239 amp_env_.set_attack_ms(0.3);
240 amp_env_.set_decay_t60_ms(decay_ms_);
243 noise_env_.set_attack_ms(0.0);
244 noise_env_.set_decay_time_constant_ms(noise_decay_ms_);
245 if (noise_level_ > 0.0) noise_env_.trigger();
250 return amp_env_.is_active() || noise_env_.is_active() ||
251 click_.is_active() || output_.has_tail();
255 for (
int i = 0;
i < num_samples; ++
i) {
256 const double pitch = pitch_env_.process();
257 const double index = applied_index_ * index_env_.process();
258 const double amplitude = amp_env_.process();
259 const double carrier_warp =
260 carrier_warp_ * carrier_warp_env_.process();
261 const double modulator_warp =
262 modulator_warp_ * modulator_warp_env_.process();
265 if (lfo_depth_octaves_ > 0.0 &&
266 samples_since_note_ >= lfo_delay_samples_) {
267 const double fade = std::min(
268 static_cast<double>(samples_since_note_ - lfo_delay_samples_) /
269 static_cast<double>(lfo_fade_samples_),
271 lfo = lfo_depth_octaves_ * fade *
272 std::sin(2.0 * 3.14159265358979323846 * lfo_phase_);
275 if (lfo_phase_ >= 1.0) lfo_phase_ -= std::floor(lfo_phase_);
276 ++samples_since_note_;
278 const double carrier_hz =
279 std::min(tune_hz_ * std::exp2(applied_bend_ * pitch + lfo),
281 const double modulator_hz = std::min(carrier_hz * ratio_, 0.49 *
sample_rate());
284 const bool carrier_wrapped = carrier_phase_ >= 1.0;
285 if (carrier_wrapped) carrier_phase_ -= std::floor(carrier_phase_);
287 if (hard_sync_ && carrier_wrapped) {
288 modulator_phase_ = 0.0;
292 if (modulator_phase_ >= 1.0) modulator_phase_ -= std::floor(modulator_phase_);
296 const double modulator_phase =
299 feedback_ * kFeedbackDepth * modulator_z_ /
300 (2.0 * 3.14159265358979323846),
302 const double modulator =
305 modulator_z_ = modulator;
307 const double carrier_phase =
309 carrier_phase_ + index * modulator /
310 (2.0 * 3.14159265358979323846),
312 const double carrier =
316 const double body = filter_.process(
static_cast<float>(carrier)) * amplitude;
317 const double strike = click_.process(
static_cast<double>(noise_.white()));
318 const double noise_envelope =
319 noise_env_.is_active() ? noise_env_.process() : 0.0;
322 ?
static_cast<double>(noise_.process()) *
323 noise_envelope * noise_level_
326 out[
i] +=
static_cast<float>(
327 output_.process(
static_cast<float>(body + strike + noise)) *
333 void apply_transient() {
336 noise_color_ = recipe.color;
337 noise_level_ = recipe.noise_level;
338 noise_decay_ms_ = recipe.noise_decay_ms;
342 if (noise_.
color() != noise_color_)
349 static constexpr double kFeedbackDepth = 6.0;
351 double tune_hz_ = 110.0;
352 double ratio_ = 1.41;
354 double index_ms_ = 40.0;
355 double decay_ms_ = 400.0;
356 double pitch_sweep_oct_ = 0.0;
357 double pitch_sweep_ms_ = 30.0;
358 double feedback_ = 0.0;
359 double cutoff_hz_ = 12000.0;
360 double resonance_ = 0.8;
361 bool bandpass_ =
false;
362 int carrier_wave_ = 0;
363 int modulator_wave_ = 0;
364 double carrier_warp_ = 0.0;
365 double modulator_warp_ = 0.0;
366 double carrier_warp_ms_ = 40.0;
367 double modulator_warp_ms_ = 40.0;
368 double lfo_rate_hz_ = 5.0;
369 double lfo_depth_octaves_ = 0.0;
370 double lfo_delay_ms_ = 0.0;
371 double lfo_fade_ms_ = 0.0;
372 bool hard_sync_ =
false;
375 double noise_level_ = 0.0;
376 double noise_decay_ms_ = 10.0;
389 double velocity_gain_ = 1.0;
390 double applied_bend_ = 0.0;
391 double applied_index_ = 6.0;
392 double carrier_phase_ = 0.0;
393 double modulator_phase_ = 0.0;
394 double modulator_z_ = 0.0;
395 double lfo_phase_ = 0.0;
396 int samples_since_note_ = 0;
397 int lfo_delay_samples_ = 0;
398 int lfo_fade_samples_ = 1;
446 {{0, 0, 0, 0, 0, 0, 0, 0}, 0xFF},
447 {{0x02, 0, 0, 0, 0, 0, 0, 0}, 0xFD},
448 {{0x02, 0, 0x08, 0, 0, 0, 0, 0}, 0xF5},
449 {{0x02, 0, 0x08, 0, 0x20, 0, 0, 0}, 0xD5},
450 {{0x02, 0, 0x08, 0, 0x20, 0, 0x80, 0}, 0x55},
451 {{0x06, 0, 0, 0, 0, 0, 0, 0}, 0xF9},
452 {{0x0E, 0, 0, 0, 0, 0, 0, 0}, 0xF1},
453 {{0x1E, 0, 0, 0, 0, 0, 0, 0}, 0xE1},
454 {{0x02, 0x04, 0, 0, 0, 0, 0, 0}, 0xF9},
455 {{0x02, 0x04, 0x08, 0, 0, 0, 0, 0}, 0xF1},
456 {{0x02, 0x04, 0, 0x20, 0, 0, 0, 0}, 0xD9},
457 {{0x06, 0x18, 0, 0, 0, 0, 0, 0}, 0xE1},
458 {{0x02, 0x0C, 0x10, 0, 0, 0, 0, 0}, 0xE1},
459 {{0x02, 0x04, 0x08, 0x10, 0, 0, 0, 0}, 0xE1},
460 {{0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0, 0}, 0x81},
461 {{0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0}, 0x01},
467 r.brightness_octaves = 1.0f;
476 void set_tune_hz(
double hz) { tune_hz_ = std::clamp(hz, 20.0, 4000.0); }
481 ratios_[
static_cast<std::size_t
>(op)] = std::clamp(
ratio, 0.1, 32.0);
487 levels_[
static_cast<std::size_t
>(op)] = std::clamp(level, 0.0, 1.0);
495 decays_[
static_cast<std::size_t
>(op)] = std::clamp(ms, 1.0, 4000.0);
501 feedbacks_[
static_cast<std::size_t
>(op)] = std::clamp(amount, 0.0, 1.0);
506 waves_[
static_cast<std::size_t
>(op)] =
511 void set_depth(
double depth) { depth_ = std::clamp(depth, 0.0, 12.0); }
518 transient_ = std::clamp(index, -1,
520 if (transient_ >= 0) apply_transient();
524 noise_level_ = std::max(level, 0.0);
528 noise_decay_ms_ = std::clamp(ms, 0.5, 500.0);
532 noise_color_ = color;
533 if (noise_.color() != color) noise_.set_color(color);
537 click_.set_level(level);
544 return output_.latency_samples();
547 return output_.oversampling();
550 output_.set_oversampling(factor);
556 for (
auto& env : envelopes_) env.set_sample_rate(
sample_rate);
559 formant_.set_sample_rate(
static_cast<float>(
sample_rate));
560 formant_.set_mode(Svf::Mode::bandpass);
565 for (
auto& env : envelopes_) env.reset();
577 output_.reset_nonlinear_state();
580 velocity_gain_ = response.gain(
velocity);
582 depth_ *
static_cast<double>(response.brightness_scale(
velocity));
587 formant_.set_frequency(
588 static_cast<float>(std::min(formant_hz_, 0.49 *
sample_rate())));
589 formant_.set_resonance(
static_cast<float>(formant_q_));
592 envelopes_[op].set_attack_ms(0.2);
593 envelopes_[op].set_decay_t60_ms(decays_[op]);
594 envelopes_[op].trigger();
597 noise_env_.set_attack_ms(0.0);
598 noise_env_.set_decay_time_constant_ms(noise_decay_ms_);
599 if (noise_level_ > 0.0) noise_env_.trigger();
604 for (
const auto& env : envelopes_) {
605 if (env.is_active())
return true;
607 return noise_env_.is_active() || click_.is_active() ||
614 for (
int i = 0;
i < num_samples; ++
i) {
615 std::array<double, operator_count> amplitudes{};
616 std::array<double, operator_count>
feedback{};
618 amplitudes[op] = envelopes_[op].process() * levels_[op];
619 feedback[op] = feedbacks_[op] * kFeedbackDepth;
622 const auto frequency = [&](std::size_t op) {
623 return tune_hz_ * ratios_[op];
625 const auto phase_route = [&](std::size_t destination,
626 std::size_t source) {
631 const auto no_frequency_route = [](std::size_t, std::size_t) {
634 const auto carrier = [&](std::size_t op) {
635 return (alg.
carriers & (1u << op)) ? 1.0 : 0.0;
637 const auto wave = [&](std::size_t op,
double phase_cycles,
638 double phase_offset_radians,
639 double phase_increment) {
643 phase_offset_radians /
644 (2.0 * 3.14159265358979323846),
650 feedback, frequency, phase_route, no_frequency_route, carrier,
653 const double shaped = formant_.process(
static_cast<float>(summed));
654 const double noise_envelope =
655 noise_env_.is_active() ? noise_env_.process() : 0.0;
658 ?
static_cast<double>(noise_.process()) *
659 noise_envelope * noise_level_
662 click_.process(
static_cast<double>(noise_.white()));
663 out[
i] +=
static_cast<float>(
664 output_.process(
static_cast<float>(shaped + noise + click)) *
670 void apply_transient() {
673 noise_color_ = recipe.color;
674 noise_level_ = recipe.noise_level;
675 noise_decay_ms_ = recipe.noise_decay_ms;
679 if (noise_.
color() != noise_color_)
683 static constexpr double kFeedbackDepth = 6.0;
686 double tune_hz_ = 110.0;
688 double formant_hz_ = 2000.0;
689 double formant_q_ = 1.0;
692 double noise_level_ = 0.0;
693 double noise_decay_ms_ = 10.0;
695 std::array<double, operator_count> ratios_ = {1.0, 1.41, 2.0, 3.17,
696 4.0, 5.63, 7.0, 9.41};
697 std::array<double, operator_count> levels_ = {1.0, 0.8, 0.7, 0.6,
698 0.5, 0.4, 0.35, 0.3};
699 std::array<double, operator_count> decays_ = {400.0, 220.0, 160.0, 110.0,
700 80.0, 60.0, 45.0, 30.0};
701 std::array<double, operator_count> feedbacks_{};
702 std::array<int, operator_count> waves_{};
705 std::array<DecayEnvelope64, operator_count> envelopes_;
708 std::array<double, operator_count> phases_{};
709 std::array<double, operator_count> previous_{};
713 double velocity_gain_ = 1.0;
714 double applied_depth_ = 3.0;
void set_color(NoiseColor c)
Selects the spectral tilt.
Definition noise_source.hpp:83
NoiseColor color() const
Definition noise_source.hpp:90
void set_cutoff_hz(double hz)
Definition layers.hpp:50
void set_level(double level)
Definition layers.hpp:46
void set_decay_ms(double ms)
Definition layers.hpp:54
void set_operator_wave(int op, int wave)
Definition fm.hpp:504
const OutputStage & output() const
Definition fm.hpp:541
void render_add(float *out, int num_samples) override
Adds the voice's output into out. Must add, never assign.
Definition fm.hpp:611
void on_prepare(double sample_rate) override
Sizes buffers and fixes coefficients.
Definition fm.hpp:554
bool on_is_active() const override
Definition fm.hpp:603
void set_noise_level(double level)
Definition fm.hpp:522
static constexpr int algorithm_count
Definition fm.hpp:433
void set_transient(int index)
Definition fm.hpp:517
void set_noise_color(NoiseColor color)
Definition fm.hpp:530
OutputStage * output_stage() noexcept override
The terminal saturation and degradation stage, at the generic voice boundary.
Definition fm.hpp:542
void set_operator_ratio(int op, double ratio)
Frequency ratio of one operator to the voice's tuning.
Definition fm.hpp:479
OutputOversampling output_oversampling() const noexcept override
Output quality at the generic voice boundary.
Definition fm.hpp:546
void set_click_level(double level)
Definition fm.hpp:535
void on_note_on(float velocity) override
Starts a hit at the given velocity, already clamped to [0, 1].
Definition fm.hpp:576
void set_operator_level(int op, double level)
Output level of one operator, before the algorithm's routing.
Definition fm.hpp:485
int latency_samples() const noexcept override
Fixed host-rate delay introduced by this voice's selected output quality.
Definition fm.hpp:543
void set_noise_decay_ms(double ms)
Definition fm.hpp:526
int algorithm() const
Definition fm.hpp:474
OutputStage & output()
Definition fm.hpp:540
void set_operator_decay_ms(int op, double ms)
Decay of one operator's own envelope, as a T60.
Definition fm.hpp:493
static constexpr int operator_count
Definition fm.hpp:432
Fm8DrumVoice()
Definition fm.hpp:464
void set_tune_hz(double hz)
Definition fm.hpp:476
void set_formant_q(double q)
Definition fm.hpp:515
static constexpr Algorithm algorithms[algorithm_count]
The sixteen routings, ordered roughly from most parallel to most serial: 0 is eight independent carri...
Definition fm.hpp:445
void set_depth(double depth)
Overall modulation depth, scaling every routed connection at once.
Definition fm.hpp:511
void set_algorithm(int index)
Definition fm.hpp:471
void set_output_oversampling(OutputOversampling factor) override
Definition fm.hpp:549
void set_operator_feedback(int op, double amount)
Self-feedback on one operator.
Definition fm.hpp:499
void set_formant_hz(double hz)
A formant bandpass on the summed carriers.
Definition fm.hpp:514
void on_reset() override
Clears every piece of state the voice carries, so is_active() becomes false and the next render start...
Definition fm.hpp:564
void set_decay_ms(double ms)
How long the note lasts, as a T60.
Definition fm.hpp:74
void set_lfo_depth_octaves(double octaves)
Definition fm.hpp:110
void set_bandpass(bool bandpass)
Definition fm.hpp:143
void set_transient(int index)
Select one of the shared 24 procedural strike recipes.
Definition fm.hpp:121
void set_index_ms(double ms)
Definition fm.hpp:71
void set_lfo_rate_hz(double hz)
Delayed, faded pitch LFO.
Definition fm.hpp:109
void set_pitch_sweep_octaves(double octaves)
Pitch envelope depth in octaves and its time constant.
Definition fm.hpp:77
void set_modulator_warp_ms(double ms)
Definition fm.hpp:103
void render_add(float *out, int num_samples) override
Adds the voice's output into out. Must add, never assign.
Definition fm.hpp:254
int latency_samples() const noexcept override
Fixed host-rate delay introduced by this voice's selected output quality.
Definition fm.hpp:157
void set_pitch_sweep_ms(double ms)
Definition fm.hpp:80
void set_lfo_delay_ms(double ms)
Definition fm.hpp:113
OutputStage * output_stage() noexcept override
The terminal saturation and degradation stage, at the generic voice boundary.
Definition fm.hpp:156
void set_noise_color(NoiseColor color)
Definition fm.hpp:134
void set_feedback(double amount)
Modulator self-feedback, 0 to 1.
Definition fm.hpp:84
void set_resonance(double q)
Definition fm.hpp:142
FmDrumVoice()
Definition fm.hpp:47
void set_noise_level(double level)
Definition fm.hpp:126
void set_click_cutoff_hz(double hz)
Definition fm.hpp:149
bool on_is_active() const override
Definition fm.hpp:249
void set_ratio(double ratio)
Modulator frequency as a ratio of the carrier.
Definition fm.hpp:66
void set_carrier_warp(double amount)
Definition fm.hpp:94
const OutputStage & output() const
Definition fm.hpp:155
void set_lfo_fade_ms(double ms)
Definition fm.hpp:114
void set_cutoff_hz(double hz)
A bandpass on the output, for picking one formant out of the sidebands.
Definition fm.hpp:141
void set_tune_hz(double hz)
Carrier frequency, in Hz.
Definition fm.hpp:62
void set_click_level(double level)
Definition fm.hpp:145
void set_noise_decay_ms(double ms)
Definition fm.hpp:130
void set_output_oversampling(OutputOversampling factor) override
Definition fm.hpp:163
void on_prepare(double sample_rate) override
Sizes buffers and fixes coefficients.
Definition fm.hpp:168
void on_note_on(float velocity) override
Starts a hit at the given velocity, already clamped to [0, 1].
Definition fm.hpp:199
void set_modulator_warp(double amount)
Definition fm.hpp:97
OutputOversampling output_oversampling() const noexcept override
Output quality at the generic voice boundary.
Definition fm.hpp:160
void set_index(double index)
Modulation index at the strike, and how fast it collapses.
Definition fm.hpp:70
void set_carrier_wave(int wave)
The 26 shared phase-readable waves and each operator's decaying Casio-family phase warp.
Definition fm.hpp:88
void set_hard_sync(bool sync)
Reset the modulator phase whenever the carrier wraps.
Definition fm.hpp:117
void set_carrier_warp_ms(double ms)
Definition fm.hpp:100
void on_reset() override
Clears every piece of state the voice carries, so is_active() becomes false and the next render start...
Definition fm.hpp:181
OutputStage & output()
Definition fm.hpp:154
void set_modulator_wave(int wave)
Definition fm.hpp:91
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
SampleType render_fm_operator_sample(std::size_t operator_count, SampleType sample_rate, FmOperatorAliasPolicy alias_policy, std::array< SampleType, MaxOperators > &phases, std::array< SampleType, MaxOperators > &previous, const std::array< SampleType, MaxOperators > &litudes, const std::array< SampleType, MaxOperators > &feedback_radians, FrequencyFn &&base_frequency, PhaseRouteFn &&phase_route, FrequencyRouteFn &&frequency_route, CarrierGainFn &&carrier_gain, OscillatorFn &&oscillator) noexcept
Canonical one-sample-delayed operator evaluator shared by melodic and drum engines.
Definition fm_operator_engine.hpp:145
@ sync
Definition string.hpp:19
OutputOversampling
Realtime quality choices for the shared drum output nonlinearity.
Definition output_stage.hpp:20
constexpr std::array< FmTransient, 24 > kFmTransients
Twenty-four original procedural strike recipes.
Definition fm_tables.hpp:104
OutputStageT< float > OutputStage
Definition output_stage.hpp:384
@ feedback
Definition comb_filter.hpp:18
SvfT< float > Svf
Definition svf.hpp:148
@ bounded
Definition fm_operator_engine.hpp:35
@ ratio
base_frequency_hz * ratio.
Definition fm_operator_engine.hpp:20
@ i
Definition formant_filter_bank.hpp:20
@ bandpass
Definition filter_morph.hpp:19
NoiseColor
Spectral tilt of a NoiseSourceT, named by the usual colour convention.
Definition noise_source.hpp:17
@ white
0 dB/octave — the raw generator output.
Definition noise_source.hpp:18
DecayEnvelopeT< double > DecayEnvelope64
Definition decay_envelope.hpp:201
NoiseSourceT< float > NoiseSource
Definition noise_source.hpp:279
One routing: for each operator, a bitmask of the operators that modulate it, and whether it is heard ...
Definition fm.hpp:437
std::uint8_t modulated_by[operator_count]
Definition fm.hpp:438
std::uint8_t carriers
bit per operator
Definition fm.hpp:439
static double warp(double phase, double amount)
Casio-family phase warp: amount zero is identity; one moves the bend point close to the start of the ...
Definition fm_tables.hpp:85
static constexpr int wave_count
Definition fm_tables.hpp:17
static double read(int wave, double phase, double phase_increment=0.0)
Definition fm_tables.hpp:50
How hard a hit changes the sound, beyond changing how loud it is.
Definition velocity.hpp:33