81 velocity_ = std::clamp(
velocity, 0.0f, 1.0f);
88 void choke(
float fade_ms = 4.0f) {
90 const double samples = std::max(0.001 *
static_cast<double>(fade_ms) * sample_rate_, 1.0);
91 choke_step_ =
static_cast<float>(1.0 / samples);
134 if (out ==
nullptr || num_samples <= 0 || !
is_active())
return;
146 while (done < num_samples) {
147 const int n = std::min(kScratchSamples, num_samples - done);
148 std::fill(scratch_, scratch_ + n, 0.0f);
150 for (
int i = 0;
i < n; ++
i) {
151 out[done +
i] += scratch_[
i] * choke_gain_;
152 choke_gain_ = std::max(choke_gain_ - choke_step_, 0.0f);
155 if (choke_gain_ <= 0.0f)
break;
158 if (choke_gain_ <= 0.0f)
reset();
168 if (
left ==
nullptr ||
right ==
nullptr || num_samples <= 0 ||
178 while (done < num_samples) {
179 const int n = std::min(kScratchSamples, num_samples - done);
180 std::fill(stereo_left_scratch_, stereo_left_scratch_ + n, 0.0f);
181 std::fill(stereo_right_scratch_, stereo_right_scratch_ + n, 0.0f);
183 for (
int i = 0;
i < n; ++
i) {
184 left[done +
i] += stereo_left_scratch_[
i] * choke_gain_;
185 right[done +
i] += stereo_right_scratch_[
i] * choke_gain_;
186 choke_gain_ = std::max(choke_gain_ - choke_step_, 0.0f);
189 if (choke_gain_ <= 0.0f)
break;
192 if (choke_gain_ <= 0.0f)
reset();
217 while (done < num_samples) {
218 const int n = std::min(kScratchSamples, num_samples - done);
219 std::fill(mono_stereo_scratch_, mono_stereo_scratch_ + n, 0.0f);
221 for (
int i = 0;
i < n; ++
i) {
222 const float centred = 0.5f * mono_stereo_scratch_[
i];
223 left[done +
i] += centred;
224 right[done +
i] += centred;
234 static constexpr int kScratchSamples = 256;
236 double sample_rate_ = 44100.0;
237 float velocity_ = 1.0f;
240 bool choking_ =
false;
241 float choke_gain_ = 1.0f;
242 float choke_step_ = 1.0f;
243 float scratch_[kScratchSamples]{};
244 float mono_stereo_scratch_[kScratchSamples]{};
245 float stereo_left_scratch_[kScratchSamples]{};
246 float stereo_right_scratch_[kScratchSamples]{};
bool is_active() const
Whether the voice still has something to render.
Definition voice.hpp:97
virtual OutputStage * output_stage() noexcept
The terminal saturation and degradation stage, at the generic voice boundary.
Definition voice.hpp:124
double sample_rate() const
Definition voice.hpp:105
void reset()
Silences the voice immediately, without a fade.
Definition voice.hpp:71
const OutputStage * output_stage() const noexcept
Definition voice.hpp:125
void set_velocity_response(const VelocityResponse &r)
Definition voice.hpp:129
Voice(const Voice &)=delete
void choke(float fade_ms=4.0f)
Fades the voice out over fade_ms and then silences it.
Definition voice.hpp:88
VoiceState state() const
Definition voice.hpp:99
virtual void on_reset()=0
Clears every piece of state the voice carries, so is_active() becomes false and the next render start...
Voice & operator=(const Voice &)=delete
void process(float *out, int num_samples)
Adds num_samples of this voice's output into out.
Definition voice.hpp:133
virtual int latency_samples() const noexcept
Fixed host-rate delay introduced by this voice's selected output quality.
Definition voice.hpp:110
void prepare(double sample_rate)
Fixes the sample rate and clears all state.
Definition voice.hpp:62
virtual void set_output_oversampling(OutputOversampling)
Definition voice.hpp:117
virtual void on_note_on(float velocity)=0
Starts a hit at the given velocity, already clamped to [0, 1].
virtual void render_add(float *out, int num_samples)=0
Adds the voice's output into out. Must add, never assign.
virtual OutputOversampling output_oversampling() const noexcept
Output quality at the generic voice boundary.
Definition voice.hpp:114
virtual bool on_is_active() const =0
void process_stereo(float *left, float *right, int num_samples)
Adds a stereo rendering to left and right.
Definition voice.hpp:167
virtual void render_add_stereo(float *left, float *right, int num_samples)
Optional stereo realization.
Definition voice.hpp:214
virtual void on_prepare(double sample_rate)=0
Sizes buffers and fixes coefficients.
float velocity() const
Definition voice.hpp:104
void note_on(float velocity)
Starts a hit. velocity is in [0, 1]; values outside are clamped.
Definition voice.hpp:78
const VelocityResponse & velocity_response() const
Definition voice.hpp:130
OutputOversampling
Realtime quality choices for the shared drum output nonlinearity.
Definition output_stage.hpp:20
@ bypass
Definition output_stage.hpp:21
VoiceState
Public lifecycle inspection for a drum voice.
Definition voice.hpp:16
@ ringing
Definition voice.hpp:18
@ choking
Definition voice.hpp:19
@ idle
Definition voice.hpp:17
OutputStageT< float > OutputStage
Definition output_stage.hpp:384
@ right
Definition multi_channel_meter.hpp:67
@ left
Definition multi_channel_meter.hpp:66
@ i
Definition formant_filter_bank.hpp:20
How hard a hit changes the sound, beyond changing how loud it is.
Definition velocity.hpp:33