Vital
Loading...
Searching...
No Matches
phase_modifier.cpp
Go to the documentation of this file.
1/*
2Summary:
3PhaseModifier manipulates the phase relationships among a wavetable’s harmonic components to achieve various timbral effects. By selecting a PhaseStyle and controlling parameters like phase offset and mix, it can produce harmonic shifts, alternate even/odd phase patterns, or clear all phase differences. Interpolating between keyframes allows for dynamic phase evolutions across the wavetable’s dimension.
4 */
5
6#include "phase_modifier.h"
7#include "wave_frame.h"
9
10namespace {
19 std::complex<float> multiplyAndMix(std::complex<float> value, std::complex<float> mult, float mix) {
20 std::complex<float> result = value * mult;
21 return mix * result + (1.0f - mix) * value;
22 }
23} // namespace
24
25PhaseModifier::PhaseModifierKeyframe::PhaseModifierKeyframe() : phase_(0.0f), mix_(1.0f), phase_style_(kNormal) { }
26
28 const PhaseModifierKeyframe* source = dynamic_cast<const PhaseModifierKeyframe*>(keyframe);
29 phase_ = source->phase_;
30 mix_ = source->mix_;
31}
32
34 const WavetableKeyframe* to_keyframe,
35 float t) {
36 const PhaseModifierKeyframe* from = dynamic_cast<const PhaseModifierKeyframe*>(from_keyframe);
37 const PhaseModifierKeyframe* to = dynamic_cast<const PhaseModifierKeyframe*>(to_keyframe);
38
39 phase_ = linearTween(from->phase_, to->phase_, t);
40 mix_ = linearTween(from->mix_, to->mix_, t);
41}
42
44 // Depending on phase_style_, apply different phase transformations to the frequency domain.
45 std::complex<float> phase_shift = std::polar(1.0f, -phase_);
46
47 if (phase_style_ == kHarmonic) {
48 // Uniform phase shift to all harmonics.
49 for (int i = 0; i < vital::WaveFrame::kWaveformSize; ++i)
50 wave_frame->frequency_domain[i] = multiplyAndMix(wave_frame->frequency_domain[i], phase_shift, mix_);
51 }
52 else if (phase_style_ == kHarmonicEvenOdd) {
53 // Even and odd harmonics get different phase shifts.
54 std::complex<float> odd_shift = 1.0f / phase_shift;
55 for (int i = 0; i < vital::WaveFrame::kWaveformSize; i += 2) {
56 wave_frame->frequency_domain[i] = multiplyAndMix(wave_frame->frequency_domain[i], phase_shift, mix_);
57 wave_frame->frequency_domain[i + 1] = multiplyAndMix(wave_frame->frequency_domain[i + 1], odd_shift, mix_);
58 }
59 }
60 else if (phase_style_ == kNormal) {
61 // Iteratively rotate phases through the harmonic series.
62 std::complex<float> current_phase_shift = 1.0f;
63
64 for (int i = 0; i < vital::WaveFrame::kWaveformSize; ++i) {
65 wave_frame->frequency_domain[i] = multiplyAndMix(wave_frame->frequency_domain[i], current_phase_shift, mix_);
66 current_phase_shift *= phase_shift;
67 }
68 }
69 else if (phase_style_ == kEvenOdd) {
70 // Assign different phase shifts for even and odd harmonics based on successive multiplications.
71 std::complex<float> current_phase_shift = 1.0f;
72
73 for (int i = 0; i < vital::WaveFrame::kWaveformSize; i += 2) {
74 wave_frame->frequency_domain[i] = multiplyAndMix(wave_frame->frequency_domain[i], current_phase_shift, mix_);
75 std::complex<float> odd_shift = 1.0f / (current_phase_shift * phase_shift);
76 wave_frame->frequency_domain[i + 1] = multiplyAndMix(wave_frame->frequency_domain[i + 1], odd_shift, mix_);
77 current_phase_shift *= phase_shift * phase_shift;
78 }
79 }
80 else if (phase_style_ == kClear) {
81 // Remove phase differences, leaving only magnitude.
82 for (int i = 0; i < vital::WaveFrame::kWaveformSize; ++i)
83 wave_frame->frequency_domain[i] = std::abs(wave_frame->frequency_domain[i]);
84 }
85 wave_frame->toTimeDomain();
86}
87
90 data["phase"] = phase_;
91 data["mix"] = mix_;
92 return data;
93}
94
97 phase_ = data["phase"];
98 mix_ = data["mix"];
99}
100
103 interpolate(keyframe, position);
104 return keyframe;
105}
106
107void PhaseModifier::render(vital::WaveFrame* wave_frame, float position) {
109 interpolate(&compute_frame_, position);
110 compute_frame_.render(wave_frame);
111}
112
116
119 data["style"] = phase_style_;
120 return data;
121}
122
125 phase_style_ = data["style"];
126}
127
129 WavetableKeyframe* wavetable_keyframe = keyframes_[index].get();
130 return dynamic_cast<PhaseModifier::PhaseModifierKeyframe*>(wavetable_keyframe);
131}
A keyframe class holding parameters for phase modification at a given position.
Definition phase_modifier.h:41
void jsonToState(json data) override
Restores the keyframe's state from a JSON object.
Definition phase_modifier.cpp:95
void copy(const WavetableKeyframe *keyframe) override
Copies the state from another keyframe of the same type.
Definition phase_modifier.cpp:27
PhaseModifierKeyframe()
Constructs a keyframe with default phase and mix values.
Definition phase_modifier.cpp:25
json stateToJson() override
Serializes the state of this keyframe to a JSON object.
Definition phase_modifier.cpp:88
void interpolate(const WavetableKeyframe *from_keyframe, const WavetableKeyframe *to_keyframe, float t) override
Linearly interpolates between two keyframes.
Definition phase_modifier.cpp:33
void setPhaseStyle(PhaseStyle style)
Sets the phase modification style.
Definition phase_modifier.h:89
void render(vital::WaveFrame *wave_frame) override
Renders the waveform of this keyframe into a WaveFrame.
Definition phase_modifier.cpp:43
float phase_
The phase offset in radians.
Definition phase_modifier.h:92
float mix_
The blend between original and modified harmonic phases.
Definition phase_modifier.h:93
PhaseStyle phase_style_
The selected style of phase modification.
Definition phase_modifier.h:135
virtual WavetableKeyframe * createKeyframe(int position) override
Creates a new keyframe at a given position.
Definition phase_modifier.cpp:101
virtual WavetableComponentFactory::ComponentType getType() override
Returns the type of this WavetableComponent.
Definition phase_modifier.cpp:113
PhaseModifierKeyframe * getKeyframe(int index)
Retrieves a PhaseModifierKeyframe by index.
Definition phase_modifier.cpp:128
PhaseModifierKeyframe compute_frame_
A keyframe for intermediate computation.
Definition phase_modifier.h:134
virtual void render(vital::WaveFrame *wave_frame, float position) override
Renders the waveform at a given position into a WaveFrame.
Definition phase_modifier.cpp:107
virtual json stateToJson() override
Serializes the component’s state and all keyframes to a JSON object.
Definition phase_modifier.cpp:117
@ kClear
Clear phase information, making all harmonics in phase.
Definition phase_modifier.h:30
@ kHarmonicEvenOdd
Apply a harmonic-based shift with separate handling of even/odd harmonics.
Definition phase_modifier.h:29
@ kNormal
Apply a harmonic phase shift cumulatively up the harmonic series.
Definition phase_modifier.h:26
@ kEvenOdd
Apply different phase treatments to even and odd harmonics.
Definition phase_modifier.h:27
@ kHarmonic
Uniformly shift phase for all harmonics directly.
Definition phase_modifier.h:28
virtual void jsonToState(json data) override
Restores the component’s state from a JSON object.
Definition phase_modifier.cpp:123
ComponentType
Enumerates all known WavetableComponents, including sources and modifiers.
Definition wavetable_component_factory.h:28
@ kPhaseModifier
Modifier that shifts phase.
Definition wavetable_component_factory.h:36
virtual json stateToJson()
Serializes the component’s state and all keyframes to a JSON object.
Definition wavetable_component.cpp:49
void interpolate(WavetableKeyframe *dest, float position)
Interpolates a destination keyframe at a given position.
Definition wavetable_component.cpp:68
virtual void jsonToState(json data)
Restores the component’s state from a JSON object.
Definition wavetable_component.cpp:37
std::vector< std::unique_ptr< WavetableKeyframe > > keyframes_
The list of keyframes sorted by position.
Definition wavetable_component.h:219
Represents a single state of a waveform at a specific position in a wavetable.
Definition wavetable_keyframe.h:35
virtual json stateToJson()
Serializes the state of this keyframe to a JSON object.
Definition wavetable_keyframe.cpp:37
virtual void jsonToState(json data)
Restores the keyframe's state from a JSON object.
Definition wavetable_keyframe.cpp:41
Represents a single frame of a wavetable, containing both time-domain and frequency-domain data.
Definition wave_frame.h:16
std::complex< float > frequency_domain[kWaveformSize]
The frequency-domain representation (complex spectrum).
Definition wave_frame.h:125
static constexpr int kWaveformSize
The size of the waveform (number of samples per frame).
Definition wave_frame.h:21
void toTimeDomain()
Converts the currently loaded frequency-domain data into time-domain representation.
Definition wave_frame.cpp:77
nlohmann::json json
Definition line_generator.h:7