48 r.bend_octaves = 0.08f;
49 r.brightness_octaves = 1.2f;
52 r.noise_balance = 0.25f;
56 snap_.set_cutoff_hz(6000.0);
57 snap_.set_decay_ms(4.0);
63 void set_tune_hz(
double hz) { tune_hz_ = std::clamp(hz, 60.0, 800.0); }
75 pitch_sweep_oct_ = std::clamp(octaves, 0.0, 4.0);
80 void set_fm_amount(
double amount) { fm_amount_ = std::clamp(amount, 0.0, 8.0); }
85 void set_ring(
double amount) { ring_ = std::clamp(amount, 0.0, 1.0); }
100 noise_sweep_oct_ = std::clamp(octaves, -4.0, 4.0);
104 void set_rattle(
double amount) { rattle_ = std::clamp(amount, 0.0, 1.0); }
120 return output_.latency_samples();
123 return output_.oversampling();
126 output_.set_oversampling(factor);
146 noise_filter_.set_sample_rate(
static_cast<float>(
sample_rate));
159 noise_filter_.reset();
169 high_previous_ = 0.0;
177 velocity_gain_ = response.gain(
velocity);
178 bend_octaves_ = pitch_sweep_oct_ + response.bend(
velocity);
179 brightness_ = response.brightness_scale(
velocity);
183 noise_tilt_ = response.noise_shift(
velocity);
189 high_previous_ = 0.0;
193 noise_filter_.reset();
195 pitch_env_.set_attack_ms(0.0);
196 pitch_env_.set_decay_time_constant_ms(pitch_sweep_ms_);
197 pitch_env_.trigger();
203 if (tone_level_ > 0.0) {
204 tone_env_.set_attack_ms(0.3);
205 tone_env_.set_decay_t60_ms(tone_decay_ms_);
208 if (noise_level_ > 0.0) {
209 noise_env_.set_attack_ms(0.2);
210 noise_env_.set_decay_t60_ms(noise_decay_ms_);
211 noise_env_.trigger();
214 snap_.trigger(brightness_);
215 shell_.set_frequency_hz(tune_hz_);
219 return (tone_level_ > 0.0 && tone_env_.is_active()) ||
220 (noise_level_ > 0.0 && noise_env_.is_active()) || snap_.is_active() ||
221 shell_.is_ringing() || tone_lofi_.has_tail() ||
222 noise_lofi_.has_tail() || output_.has_tail();
226 const double tone_gain = tone_level_ * (1.0 - noise_tilt_);
227 const double wire_gain = noise_level_ * (1.0 + noise_tilt_);
229 for (
int i = 0;
i < num_samples; ++
i) {
230 const auto tone = tone_lofi_.process(
231 static_cast<float>(render_tone(tone_gain)));
232 out[
i] +=
static_cast<float>(
233 output_.process(
static_cast<float>(
234 static_cast<double>(tone) + render_wires(wire_gain))) *
240 double render_tone(
double gain) {
241 if (!tone_env_.
is_active() || gain <= 0.0)
return 0.0;
243 const double pitch_env = pitch_env_.
process();
244 const double sweep = std::exp2(bend_octaves_ * pitch_env);
245 const double f_low = tune_hz_ * sweep;
246 const double f_high = f_low * tone_ratio_;
249 if (phase_high_ >= 1.0) phase_high_ -= std::floor(phase_high_);
250 const double high = std::sin(2.0 * 3.14159265358979323846 * phase_high_);
253 if (phase_low_ >= 1.0) phase_low_ -= std::floor(phase_low_);
256 const double low = std::sin(2.0 * 3.14159265358979323846 * phase_low_ +
257 fm_amount_ * high_previous_);
258 high_previous_ = high;
260 const double summed = 0.5 * (low + high);
261 const double ringed = low * high;
262 return (summed + ring_ * (ringed - summed)) * tone_env_.
process() * gain;
265 double render_wires(
double gain) {
267 static_cast<float>(snap_.
process(
static_cast<double>(noise_.
white()))));
270 if (noise_env_.
is_active() && gain > 0.0) {
271 const double envelope = noise_env_.
process();
275 const double corner = noise_cutoff_hz_ * brightness_ *
276 std::exp2(noise_sweep_oct_ * envelope);
278 static_cast<float>(std::clamp(corner, 20.0, 0.49 *
sample_rate())));
281 wires = noise_filter_.
process(noise_.
process()) * envelope * gain;
285 if (rattle_phase_ >= 1.0) rattle_phase_ -= std::floor(rattle_phase_);
286 wires *= 1.0 + rattle_ * std::sin(2.0 * 3.14159265358979323846 * rattle_phase_);
290 const double path = shell_.
process(wires + snap);
291 return noise_lofi_.
process(
static_cast<float>(path));
294 double tune_hz_ = 180.0;
295 double tone_ratio_ = 1.6;
296 double tone_level_ = 0.5;
297 double tone_decay_ms_ = 120.0;
298 double pitch_sweep_oct_ = 0.5;
299 double pitch_sweep_ms_ = 25.0;
300 double fm_amount_ = 0.0;
303 double noise_level_ = 0.6;
304 double noise_decay_ms_ = 180.0;
305 double noise_cutoff_hz_ = 3000.0;
306 double noise_q_ = 1.0;
307 double noise_sweep_oct_ = 0.0;
308 double rattle_ = 0.0;
309 double rattle_hz_ = 45.0;
323 double velocity_gain_ = 1.0;
324 double bend_octaves_ = 0.5;
325 double brightness_ = 1.0;
326 double noise_tilt_ = 0.0;
328 double phase_low_ = 0.0;
329 double phase_high_ = 0.0;
330 double rattle_phase_ = 0.0;
331 double high_previous_ = 0.0;
bool is_active() const
Definition decay_envelope.hpp:122
SampleType process()
Next envelope sample in [0, peak].
Definition decay_envelope.hpp:125
SampleType process(SampleType input)
Definition lofi_chain.hpp:300
SampleType process()
Next sample, normalised so every colour has approximately the same RMS.
Definition noise_source.hpp:111
SampleType white()
Raw uniform white sample in [-1, 1), bypassing the colour filter and the normalisation.
Definition noise_source.hpp:123
void set_frequency(SampleType hz)
Definition svf.hpp:21
void set_resonance(SampleType q)
Definition svf.hpp:22
SampleType process(SampleType input)
Definition svf.hpp:54
SampleType process_highpass(SampleType input)
Process and return the highpass output.
Definition tpt_filter.hpp:78
double process(double noise)
Next sample. noise is a raw white sample from the voice's generator.
Definition layers.hpp:85
double process(double excitation)
Definition layers.hpp:200
void set_pitch_sweep_ms(double ms)
Definition snare.hpp:77
LofiChain & tone_lofi()
Degradation applied to the pitched shell before it meets the wires.
Definition snare.hpp:132
void set_noise_cutoff_hz(double hz)
Corner and resonance of the filter the wires are heard through.
Definition snare.hpp:94
bool on_is_active() const override
Definition snare.hpp:218
OutputStage & output()
Definition snare.hpp:116
void set_pitch_sweep_octaves(double octaves)
Depth and time constant of the shared downward pitch sweep, in octaves.
Definition snare.hpp:74
void set_tune_hz(double hz)
Fundamental of the lower tone oscillator, in Hz.
Definition snare.hpp:63
void set_fm_amount(double amount)
Phase-modulation depth of the upper oscillator into the lower.
Definition snare.hpp:80
const OutputStage & output() const
Definition snare.hpp:117
void set_output_oversampling(OutputOversampling factor) override
Definition snare.hpp:125
SnareVoice()
Definition snare.hpp:43
void set_snap_decay_ms(double ms)
Definition snare.hpp:110
void set_rattle_hz(double hz)
Definition snare.hpp:105
void set_tone_ratio(double ratio)
Frequency ratio of the upper tone oscillator to the lower.
Definition snare.hpp:68
void on_prepare(double sample_rate) override
Sizes buffers and fixes coefficients.
Definition snare.hpp:140
void set_ring(double amount)
Crossfade from the two oscillators summed (0) to ring-modulated (1).
Definition snare.hpp:85
void on_note_on(float velocity) override
Starts a hit at the given velocity, already clamped to [0, 1].
Definition snare.hpp:172
void set_noise_sweep_octaves(double octaves)
How far that corner sweeps over the note, in octaves.
Definition snare.hpp:99
void set_tone_decay_ms(double ms)
Definition snare.hpp:71
void set_snap_cutoff_hz(double hz)
Definition snare.hpp:109
void set_noise_color(NoiseColor color)
Definition snare.hpp:91
OutputOversampling output_oversampling() const noexcept override
Output quality at the generic voice boundary.
Definition snare.hpp:122
void set_rattle(double amount)
Depth and rate of the wires' buzz against the head.
Definition snare.hpp:104
void set_noise_resonance(double q)
Definition snare.hpp:95
void set_tone_level(double level)
Definition snare.hpp:70
void set_noise_level(double level)
Definition snare.hpp:89
LofiChain & noise_lofi()
A second degradation chain on the noise path alone.
Definition snare.hpp:137
void set_snap_level(double level)
The strike itself: a short highpassed crack, distinct from the wires.
Definition snare.hpp:108
void set_noise_decay_ms(double ms)
Definition snare.hpp:90
OutputStage * output_stage() noexcept override
The terminal saturation and degradation stage, at the generic voice boundary.
Definition snare.hpp:118
void render_add(float *out, int num_samples) override
Adds the voice's output into out. Must add, never assign.
Definition snare.hpp:225
int latency_samples() const noexcept override
Fixed host-rate delay introduced by this voice's selected output quality.
Definition snare.hpp:119
void set_shell_level(double level)
Level of the shell resonance applied to the noise path, and its Q.
Definition snare.hpp:113
void set_shell_resonance(double q)
Definition snare.hpp:114
void on_reset() override
Clears every piece of state the voice carries, so is_active() becomes false and the next render start...
Definition snare.hpp:154
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
OutputStageT< float > OutputStage
Definition output_stage.hpp:384
LofiChainT< float > LofiChain
Definition lofi_chain.hpp:328
SvfT< float > Svf
Definition svf.hpp:148
TptFilterT< float > TptFilter
Definition tpt_filter.hpp:172
@ 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
How hard a hit changes the sound, beyond changing how loud it is.
Definition velocity.hpp:33
First-order topology-preserving transform (TPT) filter.