21 processControlRate(num_samples);
23 processAudioRate(num_samples);
26 void Envelope::processControlRate(
int num_samples) {
41 poly_state_ =
utils::maskLoad(poly_state_, trigger_value, trigger_mask);
59 position_ += delta_delay & delay_mask;
62 poly_float delta_attack = delta_time / attack_time;
63 position_ += delta_attack & attack_mask;
68 position_ += delta_hold & hold_mask;
71 poly_float delta_decay = delta_time / decay_time;
72 position_ += delta_decay & decay_mask;
75 poly_float delta_release = delta_time / release_time;
76 position_ += delta_release & release_mask;
79 position_ += delta_kill & kill_mask;
95 value_ = (attack_value & attack_mask) +
97 (decay_value & decay_mask) +
98 (release_value & release_mask) +
99 (kill_value & kill_mask);
111 poly_mask decay_turn_mask = (attack_mask & ~has_hold_mask) | hold_mask;
118 poly_mask transition_mask = attack_transition_mask | hold_transition_mask | decay_transition_mask;
119 position_ = position_ & ~transition_mask;
125 poly_float Envelope::processSection(poly_float* audio_out,
int from,
int to,
126 poly_float power, poly_float delta_power,
127 poly_float position, poly_float delta_position,
128 poly_float start, poly_float end, poly_float delta_end) {
136 int num_samples = to - from;
137 poly_float current_power = power;
138 poly_float current_position = position;
139 poly_float current_end = end;
141 for (
int i = from; i < to; ++i) {
145 current_power += delta_power;
146 current_position =
utils::clamp(current_position + delta_position, 0.0f, 1.0f);
147 current_end += delta_end;
150 return utils::clamp(position + delta_position * num_samples, 0.0f, 1.0f);
153 void Envelope::processAudioRate(
int num_samples) {
167 poly_float delta_delay = delta_time /
utils::max(delay_time, 0.0000001f);
170 poly_float delta_attack = delta_time / attack_time;
175 poly_float delta_hold = delta_time /
utils::max(hold_time, 0.0000001f);
178 poly_float delta_decay = delta_time / decay_time;
182 poly_float delta_release = delta_time / release_time;
194 triggered_position =
utils::maskLoad(num_samples, triggered_position, trigger_mask);
196 poly_float current_position = position_;
200 for (
int i = 0; i < num_samples;) {
202 triggered_position =
utils::maskLoad(triggered_position, num_samples, triggering);
204 current_position =
utils::maskLoad(current_position, 0.0f, triggering);
208 attack_power_ =
utils::maskLoad(attack_power_, attack_power_end, triggering);
209 decay_power_ =
utils::maskLoad(decay_power_, decay_power_end, triggering);
210 release_power_ =
utils::maskLoad(release_power_, release_power_end, triggering);
222 poly_float delta_position = (delta_delay & delay_mask) + (delta_attack & attack_mask) +
223 (delta_hold & hold_mask) + (delta_decay & decay_mask) +
224 (delta_release & release_mask) + (delta_kill & kill_mask);
226 poly_float from_power = (attack_power_ & attack_mask) +
227 (decay_power_ & decay_mask) +
228 (release_power_ & release_mask);
229 poly_float to_power = (attack_power_end & attack_mask) +
230 (decay_power_end & decay_mask) +
231 (release_power_end & release_mask);
234 poly_float power =
utils::interpolate(from_power, to_power, i / (1.0f * num_samples));
235 poly_float delta_power = (to_power - from_power) * delta_sample;
237 poly_float cycles_remaining = (
utils::ceil(current_position) - current_position) / delta_position;
238 poly_float end_cycle =
utils::maskLoad(num_samples, cycles_remaining + i, attack_mask);
242 poly_float current_sustain =
utils::interpolate(sustain_, sustain_end, i / (1.0f * num_samples));
243 poly_float start =
utils::maskLoad(start_value_, 1.0f, decay_mask | hold_mask);
244 poly_float end = (poly_float(1.0f) & (attack_mask | hold_mask)) + (current_sustain & decay_mask);
245 poly_float delta_end = ((sustain_end - sustain_) * delta_sample) & decay_mask;
248 current_position = processSection(audio_out, i, last_cycle, power, delta_power,
249 current_position, delta_position, start, end, delta_end);
252 value_ = audio_out[i - 1];
257 poly_mask decay_turn_mask = (attack_mask & ~has_hold_mask) | hold_mask;
264 poly_mask transition_mask = attack_transition_mask | hold_transition_mask | decay_transition_mask;
265 current_position = current_position & ~transition_mask;
272 position_ = current_position;
273 attack_power_ = attack_power_end;
274 decay_power_ = decay_power_end;
275 release_power_ = release_power_end;
276 sustain_ = sustain_end;
virtual void process(int num_samples) override
Processes a block of samples. The processing mode (control-rate or audio-rate) is determined by the p...
Definition envelope.cpp:18
@ kReleasePower
Definition envelope.h:41
@ kDelay
Definition envelope.h:33
@ kDecay
Definition envelope.h:37
@ kAttackPower
Definition envelope.h:35
@ kSustain
Definition envelope.h:39
@ kTrigger
Definition envelope.h:42
@ kHold
Definition envelope.h:36
@ kAttack
Definition envelope.h:34
@ kRelease
Definition envelope.h:40
@ kDecayPower
Definition envelope.h:38
@ kValue
Definition envelope.h:53
@ kPhase
Definition envelope.h:54
Envelope()
Constructs a new Envelope processor with default parameters.
Definition envelope.cpp:6
Base class for all signal-processing units in Vital.
Definition processor.h:212
force_inline Input * input(unsigned int index=0) const
Retrieves the Input pointer at a given index.
Definition processor.h:587
force_inline int getSampleRate() const
Retrieves the current (effective) sample rate.
Definition processor.h:326
force_inline bool isControlRate() const
Checks if this Processor is running at control rate (buffer_size == 1).
Definition processor.h:342
force_inline Output * output(unsigned int index=0) const
Retrieves the Output pointer at a given index.
Definition processor.h:616
Contains faster but less accurate versions of utility math functions, such as exponential,...
force_inline mono_float powerScale(mono_float value, mono_float power)
A power-scaling function to map a linear range to a curved response.
Definition futils.h:455
force_inline poly_float clamp(poly_float value, mono_float min, mono_float max)
Clamps each lane of a vector to [min, max].
Definition poly_utils.h:306
force_inline poly_float toFloat(poly_int integers)
Casts a poly_int to poly_float lane-by-lane.
Definition poly_utils.h:733
force_inline poly_float min(poly_float left, poly_float right)
Returns the minimum of two poly_floats lane-by-lane.
Definition poly_utils.h:334
force_inline poly_float max(poly_float left, poly_float right)
Returns the maximum of two poly_floats lane-by-lane.
Definition poly_utils.h:327
force_inline mono_float minFloat(poly_float values)
Returns the minimum lane value from a poly_float.
Definition poly_utils.h:534
force_inline poly_float maskLoad(poly_float zero_value, poly_float one_value, poly_mask reset_mask)
Selects between two values (zero_value or one_value) based on a mask in each lane.
Definition poly_utils.h:351
force_inline poly_float interpolate(poly_float from, poly_float to, mono_float t)
Performs a linear interpolation between two poly_floats using a scalar t in [0..1].
Definition poly_utils.h:182
force_inline poly_float ceil(poly_float value)
Ceils each lane in value.
Definition poly_utils.h:799
Contains classes and functions used within the Vital synthesizer framework.
@ kVoiceIdle
Definition common.h:76
@ kVoiceOn
Definition common.h:77
@ kVoiceKill
Definition common.h:81
@ kVoiceDecay
Definition common.h:79
@ kVoiceHold
Definition common.h:78
@ kVoiceOff
Definition common.h:80
poly_int poly_mask
Alias for clarity; used as a mask type in poly_float.
Definition poly_values.h:590
constexpr mono_float kVoiceKillTime
Time in seconds after which a silent voice is considered dead.
Definition common.h:56
float mono_float
Definition common.h:33
poly_float * buffer
Pointer to the output buffer.
Definition processor.h:110
poly_int trigger_offset
Sample offset (per voice) for triggers.
Definition processor.h:117
poly_mask trigger_mask
Mask for triggered voices.
Definition processor.h:115
poly_float trigger_value
Trigger values for voices.
Definition processor.h:116
Represents a vector of floating-point values using SIMD instructions.
Definition poly_values.h:600
static force_inline mask_simd_type vector_call equal(simd_type one, simd_type two)
Compares two SIMD float registers for equality, element-wise.
Definition poly_values.h:954
static force_inline mask_simd_type vector_call notEqual(simd_type one, simd_type two)
Compares two SIMD float registers for non-equality, element-wise.
Definition poly_values.h:1003
Represents a vector of integer values using SIMD instructions.
Definition poly_values.h:56
static force_inline simd_type vector_call equal(simd_type one, simd_type two)
Compares two SIMD integer registers for equality, element-wise.
Definition poly_values.h:291