Vital
Loading...
Searching...
No Matches
phaser.cpp
Go to the documentation of this file.
1#include "phaser.h"
2
3#include "operators.h"
4#include "phaser_filter.h"
5
6#include <climits>
7
8namespace vital {
9
17 : ProcessorRouter(kNumInputs, kNumOutputs),
18 mix_(0.0f),
19 mod_depth_(0.0f),
20 phase_offset_(0.0f),
21 phase_(0) {
22 phaser_filter_ = new PhaserFilter(/* oversample= */ true);
23 addIdleProcessor(phaser_filter_);
24 }
25
29 void Phaser::init() {
30 // Connect feedback gain and blend from the Phaser inputs to the PhaserFilter
33 // Connect the cutoff output to the filter's MIDI cutoff input
34 phaser_filter_->plug(&cutoff_, PhaserFilter::kMidiCutoff);
35
36 phaser_filter_->init();
38 }
39
44 phaser_filter_->reset(constants::kFullMask);
45 mod_depth_ = input(kModDepth)->at(0);
46 phase_offset_ = input(kPhaseOffset)->at(0);
47 }
48
54 void Phaser::process(int num_samples) {
55 processWithInput(input(kAudio)->source->buffer, num_samples);
56 }
57
67 void Phaser::processWithInput(const poly_float* audio_in, int num_samples) {
69
70 // Compute how much the phase increments for each sample
71 poly_float tick_delta = input(kRate)->at(0) * (1.0f / getSampleRate());
72 poly_int tick_delta_phase = utils::toInt(tick_delta * UINT_MAX);
73
74 // For gradually changing stereo phase offset
75 mono_float tick_inc = 1.0f / num_samples;
76 poly_float phase_spread = phase_offset_ * constants::kStereoSplit;
77 poly_int phase_offset = utils::toInt(phase_spread * INT_MAX);
78 phase_offset_ = input(kPhaseOffset)->at(0);
79 poly_float end_spread = phase_offset_ * constants::kStereoSplit;
80 poly_float delta_spread = (end_spread - phase_spread) * tick_inc;
81 poly_int delta_phase_offset = utils::toInt(delta_spread * INT_MAX);
82
83 // Smoothly transition the mod depth
84 poly_float current_mod_depth = mod_depth_;
85 mod_depth_ = input(kModDepth)->at(0);
86 poly_float delta_depth = (mod_depth_ - current_mod_depth) * tick_inc;
87
88 // Generate the cutoff values for each sample
89 const poly_float* center_buffer = input(kCenter)->source->buffer;
90 poly_int current_phase = phase_;
91 for (int i = 0; i < num_samples; ++i) {
92 phase_offset += delta_phase_offset;
93 current_mod_depth += delta_depth;
94
95 // Phase mod with potential folding
96 poly_int shifted_phase = current_phase + phase_offset;
97 poly_mask fold_mask = poly_int::greaterThan(shifted_phase, INT_MAX);
98 poly_int folded_phase = utils::maskLoad(shifted_phase, -shifted_phase, fold_mask);
99
100 // Convert folded_phase to a [-1..1] range
101 poly_float modulation = utils::toFloat(folded_phase) * (2.0f / INT_MAX) - 1.0f;
102
103 // Write cutoff in MIDI note space
104 cutoff_.buffer[i] = center_buffer[i] + modulation * current_mod_depth;
105 }
106
107 // Process the audio through the phaser filter
108 phaser_filter_->processWithInput(audio_in, num_samples);
109
110 // Update the LFO phase
111 phase_ += utils::toInt((tick_delta * num_samples) * UINT_MAX);
112
113 // Blend the phaser output with the dry input
114 poly_float current_mix = mix_;
115 mix_ = utils::clamp(input(kMix)->at(0), 0.0f, 1.0f);
116 poly_float delta_mix = (mix_ - current_mix) * (1.0f / num_samples);
117
118 const poly_float* phaser_out = phaser_filter_->output()->buffer;
119 poly_float* audio_out = output(kAudioOutput)->buffer;
120 for (int i = 0; i < num_samples; ++i) {
121 current_mix += delta_mix;
122 audio_out[i] = utils::interpolate(audio_in[i], phaser_out[i], current_mix);
123 }
124
125 // Store the final cutoff value for UI or further processing
126 output(kCutoffOutput)->buffer[0] = cutoff_.buffer[num_samples - 1];
127 }
128
134 void Phaser::correctToTime(double seconds) {
135 poly_float rate = input(kRate)->at(0);
136 poly_float offset = utils::getCycleOffsetFromSeconds(seconds, rate);
137 phase_ = utils::toInt((offset - 0.5f) * UINT_MAX) + INT_MAX / 2;
138 }
139} // namespace vital
A multi-stage phaser filter for the Vital synthesizer.
Definition phaser_filter.h:19
void reset(poly_mask reset_mask) override
Resets internal filter states for the specified voices.
Definition phaser_filter.cpp:22
void processWithInput(const poly_float *audio_in, int num_samples) override
Processes a given input buffer through the phaser effect.
Definition phaser_filter.cpp:58
void correctToTime(double seconds)
Corrects LFO phase according to an absolute time offset.
Definition phaser.cpp:134
@ kMix
Dry/wet mix control.
Definition phaser.h:27
@ kRate
LFO rate for cutoff modulation.
Definition phaser.h:28
@ kModDepth
Modulation depth (amount of sweep)
Definition phaser.h:31
@ kAudio
Audio input buffer.
Definition phaser.h:26
@ kPhaseOffset
LFO phase offset for stereo spread.
Definition phaser.h:32
@ kFeedbackGain
Amount of feedback in the phaser filter.
Definition phaser.h:29
@ kBlend
Amount of pass/comb blend in the phaser.
Definition phaser.h:33
@ kCenter
Center frequency (MIDI note) for the phaser.
Definition phaser.h:30
void hardReset() override
Resets internal states, filters, and stored parameters.
Definition phaser.cpp:43
void init() override
Initializes the phaser, hooking up internal connections.
Definition phaser.cpp:29
void process(int num_samples) override
Processes a block of audio by pulling from the audio input buffer.
Definition phaser.cpp:54
Phaser()
Constructs a Phaser ProcessorRouter with default settings.
Definition phaser.cpp:16
@ kAudioOutput
Phaser audio output.
Definition phaser.h:42
@ kCutoffOutput
Current cutoff (MIDI note) at the final sample.
Definition phaser.h:43
void processWithInput(const poly_float *audio_in, int num_samples) override
Processes a block of audio using the provided input buffer.
Definition phaser.cpp:67
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
void useInput(Input *input)
Uses an existing Input object as this Processor's first input.
Definition processor.cpp:126
bool checkInputAndOutputSize(int num_samples)
Checks if all inputs and outputs have buffers big enough for num_samples.
Definition processor.cpp:52
void plug(const Output *source)
Connects an external Output to this Processor's first input.
Definition processor.cpp:79
force_inline Output * output(unsigned int index=0) const
Retrieves the Output pointer at a given index.
Definition processor.h:616
virtual void init()
Called after constructor, used for any additional initialization. Subclasses can override....
Definition processor.h:258
A specialized Processor that manages a directed graph of Processors and ensures correct processing or...
Definition processor_router.h:34
virtual void init() override
Initializes the ProcessorRouter and all its Processors.
Definition processor_router.cpp:84
virtual void addIdleProcessor(Processor *processor)
Adds a Processor that should remain idle (not processed) in the router.
Definition processor_router.cpp:146
@ kPassBlend
Blending parameter for low-pass, high-pass, band-pass.
Definition synth_filter.h:62
@ kResonance
Resonance parameter.
Definition synth_filter.h:58
@ kMidiCutoff
MIDI-based cutoff parameter.
Definition synth_filter.h:57
#define VITAL_ASSERT(x)
Definition common.h:11
const poly_mask kFullMask
A mask covering all lanes of a poly_float vector.
Definition synth_constants.h:257
const poly_float kStereoSplit
Splits stereo channels into left and right components.
Definition synth_constants.h:251
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 getCycleOffsetFromSeconds(double seconds, poly_float frequency)
Computes a cycle offset given a time in seconds and a frequency.
Definition poly_utils.h:885
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_int toInt(poly_float floats)
Casts a poly_float to poly_int by truncation.
Definition poly_utils.h:748
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
Contains classes and functions used within the Vital synthesizer framework.
float mono_float
Definition common.h:33
force_inline poly_float at(int i) const
Returns the sample at index i from the source buffer.
Definition processor.h:141
const Output * source
The output from which this input reads samples.
Definition processor.h:134
poly_float * buffer
Pointer to the output buffer.
Definition processor.h:110
Represents a vector of floating-point values using SIMD instructions.
Definition poly_values.h:600
Represents a vector of integer values using SIMD instructions.
Definition poly_values.h:56
static force_inline simd_type vector_call greaterThan(simd_type one, simd_type two)
Compares two SIMD integer registers, element-wise, for greater than.
Definition poly_values.h:309