Vital
Loading...
Searching...
No Matches
wave_source.cpp
Go to the documentation of this file.
1/*
2Summary:
3WaveSource and WaveSourceKeyframe provide a direct representation of wavetables via WaveFrames. By storing entire waveforms and supporting time or frequency domain interpolation (including cubic methods for smoothness), they enable flexible and sophisticated transitions between keyframes. This results in dynamic and evolving sounds that can be tailored by controlling interpolation modes and parameters.
4 */
5
6#include "wave_source.h"
7#include "wave_frame.h"
9
11 compute_frame_ = std::make_unique<WaveSourceKeyframe>();
12 interpolation_mode_ = kFrequency; // Default to frequency interpolation.
13}
14
16
18 WaveSourceKeyframe* keyframe = new WaveSourceKeyframe();
19 // Renders the initial WaveFrame at this position into the keyframe's frame.
20 render(keyframe->wave_frame(), position);
21 return keyframe;
22}
23
24void WaveSource::render(vital::WaveFrame* wave_frame, float position) {
25 // Set the interpolation mode for the compute_frame_ and interpolate into it.
27 interpolate(compute_frame_.get(), position);
28 wave_frame->copy(compute_frame_->wave_frame());
29}
30
34
37 data["interpolation"] = interpolation_mode_;
38 return data;
39}
40
43 interpolation_mode_ = data["interpolation"];
44 compute_frame_->setInterpolationMode(interpolation_mode_);
45}
46
48 return getKeyframe(index)->wave_frame();
49}
50
52 WavetableKeyframe* wavetable_keyframe = keyframes_[index].get();
53 return dynamic_cast<WaveSourceKeyframe*>(wavetable_keyframe);
54}
55
57 // Copies the WaveFrame data from another WaveSourceKeyframe.
58 const WaveSourceKeyframe* source = dynamic_cast<const WaveSourceKeyframe*>(keyframe);
59 wave_frame_->copy(source->wave_frame_.get());
60}
61
63 // Perform a simple linear interpolation of time-domain samples between two WaveFrames.
64 for (int i = 0; i < vital::WaveFrame::kWaveformSize; ++i)
65 wave_frame_->time_domain[i] = linearTween(from->time_domain[i], to->time_domain[i], t);
66 wave_frame_->toFrequencyDomain();
67}
68
70 const vital::WaveFrame* to, const vital::WaveFrame* next,
71 float range_prev, float range, float range_next, float t) {
72
73 // Cubic interpolation for an even smoother transition in the time domain.
74 for (int i = 0; i < vital::WaveFrame::kWaveformSize; ++i) {
75 wave_frame_->time_domain[i] = cubicTween(prev->time_domain[i], from->time_domain[i],
76 to->time_domain[i], next->time_domain[i],
77 range_prev, range, range_next, t);
78 }
79 wave_frame_->toFrequencyDomain();
80}
81
83 const vital::WaveFrame* to, float t) {
84 // Linear interpolation in frequency domain: smoothly blend magnitudes and phases of harmonics.
85 for (int i = 0; i < vital::WaveFrame::kNumRealComplex; ++i) {
86 float amplitude_from = sqrtf(std::abs(from->frequency_domain[i]));
87 float amplitude_to = sqrtf(std::abs(to->frequency_domain[i]));
88 float amplitude = linearTween(amplitude_from, amplitude_to, t);
89 amplitude *= amplitude;
90
91 // Interpolate DC and last harmonic separately for consistency.
92 float phase_from = std::arg(from->frequency_domain[i]);
93 float phase_delta = std::arg(std::conj(from->frequency_domain[i]) * to->frequency_domain[i]);
94 float phase = phase_from + t * phase_delta;
95 if (amplitude_from == 0)
96 phase = std::arg(to->frequency_domain[i]);
97 wave_frame_->frequency_domain[i] = std::polar(amplitude, phase);
98 }
99
100 float dc_from = from->frequency_domain[0].real();
101 float dc_to = to->frequency_domain[0].real();
102 wave_frame_->frequency_domain[0] = linearTween(dc_from, dc_to, t);
103
105 float last_harmonic_from = from->frequency_domain[last].real();
106 float last_harmonic_to = to->frequency_domain[last].real();
107 wave_frame_->frequency_domain[last] = linearTween(last_harmonic_from, last_harmonic_to, t);
108
109 wave_frame_->toTimeDomain();
110}
111
113 const vital::WaveFrame* to, const vital::WaveFrame* next,
114 float range_prev, float range, float range_next, float t) {
115 // Cubic interpolation in frequency domain for very smooth harmonic transitions across multiple frames.
116 for (int i = 0; i < vital::WaveFrame::kNumRealComplex; ++i) {
117 float amplitude_prev = sqrtf(std::abs(prev->frequency_domain[i]));
118 float amplitude_from = sqrtf(std::abs(from->frequency_domain[i]));
119 float amplitude_to = sqrtf(std::abs(to->frequency_domain[i]));
120 float amplitude_next = sqrtf(std::abs(next->frequency_domain[i]));
121 float amplitude = cubicTween(amplitude_prev, amplitude_from, amplitude_to, amplitude_next,
122 range_prev, range, range_next, t);
123 amplitude *= amplitude;
124
125 // Calculate phase transitions similarly, ensuring continuous phase evolution.
126 float phase_delta_from = std::arg(std::conj(prev->frequency_domain[i]) * from->frequency_domain[i]);
127 float phase_delta_to = std::arg(std::conj(from->frequency_domain[i]) * to->frequency_domain[i]);
128 float phase_delta_next = std::arg(std::conj(to->frequency_domain[i]) * next->frequency_domain[i]);
129 float phase_prev = std::arg(prev->frequency_domain[i]);
130 float phase_from = phase_prev;
131 if (amplitude_from)
132 phase_from += phase_delta_from;
133 float phase_to = phase_from;
134 if (amplitude_to)
135 phase_to += phase_delta_to;
136 float phase_next = phase_to;
137 if (amplitude_next)
138 phase_next += phase_delta_next;
139
140 float phase = cubicTween(phase_prev, phase_from, phase_to, phase_next, range_prev, range, range_next, t);
141 wave_frame_->frequency_domain[i] = std::polar(amplitude, phase);
142 }
143
144 // Handle DC and last harmonic separately with cubic interpolation.
145 float dc_prev = prev->frequency_domain[0].real();
146 float dc_from = from->frequency_domain[0].real();
147 float dc_to = to->frequency_domain[0].real();
148 float dc_next = next->frequency_domain[0].real();
149 wave_frame_->frequency_domain[0] = cubicTween(dc_prev, dc_from, dc_to, dc_next, range_prev, range, range_next, t);
150
152 float last_harmonic_prev = prev->frequency_domain[last].real();
153 float last_harmonic_from = from->frequency_domain[last].real();
154 float last_harmonic_to = to->frequency_domain[last].real();
155 float last_harmonic_next = next->frequency_domain[last].real();
156 wave_frame_->frequency_domain[last] = cubicTween(last_harmonic_prev, last_harmonic_from,
157 last_harmonic_to, last_harmonic_next,
158 range_prev, range, range_next, t);
159 wave_frame_->toTimeDomain();
160}
161
163 const WavetableKeyframe* to_keyframe, float t) {
164 const WaveSourceKeyframe* from = dynamic_cast<const WaveSourceKeyframe*>(from_keyframe);
165 const WaveSourceKeyframe* to = dynamic_cast<const WaveSourceKeyframe*>(to_keyframe);
166
168 linearFrequencyInterpolate(from->wave_frame_.get(), to->wave_frame_.get(), t);
169 else
170 linearTimeInterpolate(from->wave_frame_.get(), to->wave_frame_.get(), t);
171}
172
174 const WavetableKeyframe* from_keyframe,
175 const WavetableKeyframe* to_keyframe,
176 const WavetableKeyframe* next_keyframe, float t) {
177 // Uses cubic interpolation if possible for even smoother transitions.
178 const vital::WaveFrame* prev = dynamic_cast<const WaveSourceKeyframe*>(prev_keyframe)->wave_frame_.get();
179 const vital::WaveFrame* from = dynamic_cast<const WaveSourceKeyframe*>(from_keyframe)->wave_frame_.get();
180 const vital::WaveFrame* to = dynamic_cast<const WaveSourceKeyframe*>(to_keyframe)->wave_frame_.get();
181 const vital::WaveFrame* next = dynamic_cast<const WaveSourceKeyframe*>(next_keyframe)->wave_frame_.get();
182
183 float range_prev = from_keyframe->position() - prev_keyframe->position();
184 float range = to_keyframe->position() - from_keyframe->position();
185 float range_next = next_keyframe->position() - to_keyframe->position();
186
188 cubicFrequencyInterpolate(prev, from, to, next, range_prev, range, range_next, t);
189 else
190 cubicTimeInterpolate(prev, from, to, next, range_prev, range, range_next, t);
191}
192
194 // Serialize the waveform’s time-domain data as Base64.
195 String encoded = Base64::toBase64(wave_frame_->time_domain, sizeof(float) * vital::WaveFrame::kWaveformSize);
197 data["wave_data"] = encoded.toStdString();
198 return data;
199}
200
203
204 MemoryOutputStream decoded(sizeof(float) * vital::WaveFrame::kWaveformSize);
205 std::string wave_data = data["wave_data"];
206 Base64::convertFromBase64(decoded, wave_data);
207 memcpy(wave_frame_->time_domain, decoded.getData(), sizeof(float) * vital::WaveFrame::kWaveformSize);
208 wave_frame_->toFrequencyDomain();
209}
json stateToJson() override
Serializes the component’s state and all keyframes to a JSON object.
Definition wave_source.cpp:35
std::unique_ptr< WaveSourceKeyframe > compute_frame_
A keyframe for intermediate interpolation computations.
Definition wave_source.h:79
virtual ~WaveSource()
Definition wave_source.cpp:15
InterpolationMode interpolation_mode_
The mode of interpolation.
Definition wave_source.h:80
void jsonToState(json data) override
Restores the component’s state from a JSON object.
Definition wave_source.cpp:41
vital::WaveFrame * getWaveFrame(int index)
Gets a WaveFrame from a specified keyframe index.
Definition wave_source.cpp:47
void render(vital::WaveFrame *wave_frame, float position) override
Renders the waveform at a given position into a WaveFrame.
Definition wave_source.cpp:24
WaveSourceKeyframe * getKeyframe(int index)
Retrieves a WaveSourceKeyframe by index.
Definition wave_source.cpp:51
WavetableKeyframe * createKeyframe(int position) override
Creates a new keyframe at a given position.
Definition wave_source.cpp:17
@ kFrequency
Interpolate in frequency domain.
Definition wave_source.h:33
WaveSource()
Constructs a WaveSource with a default frequency-domain interpolation mode.
Definition wave_source.cpp:10
WavetableComponentFactory::ComponentType getType() override
Returns the type of this WavetableComponent.
Definition wave_source.cpp:31
A keyframe that holds a single WaveFrame and supports various interpolation methods.
Definition wave_source.h:92
WaveSource::InterpolationMode interpolation_mode_
The mode (time or frequency) used for this keyframe's interpolation.
Definition wave_source.h:199
void copy(const WavetableKeyframe *keyframe) override
Copies the state from another keyframe of the same type.
Definition wave_source.cpp:56
void smoothInterpolate(const WavetableKeyframe *prev_keyframe, const WavetableKeyframe *from_keyframe, const WavetableKeyframe *to_keyframe, const WavetableKeyframe *next_keyframe, float t) override
Performs a smooth (cubic) interpolation using four keyframes for even smoother transitions.
Definition wave_source.cpp:173
void cubicTimeInterpolate(const vital::WaveFrame *prev, const vital::WaveFrame *from, const vital::WaveFrame *to, const vital::WaveFrame *next, float range_prev, float range, float range_next, float t)
Cubic interpolation in time domain using four WaveFrames for smooth transitions.
Definition wave_source.cpp:69
void linearFrequencyInterpolate(const vital::WaveFrame *from, const vital::WaveFrame *to, float t)
Linear interpolation in frequency domain.
Definition wave_source.cpp:82
json stateToJson() override
Serializes the state of this keyframe to a JSON object.
Definition wave_source.cpp:193
void setInterpolationMode(WaveSource::InterpolationMode mode)
Sets the interpolation mode for this keyframe.
Definition wave_source.h:188
void jsonToState(json data) override
Restores the keyframe's state from a JSON object.
Definition wave_source.cpp:201
void linearTimeInterpolate(const vital::WaveFrame *from, const vital::WaveFrame *to, float t)
Linearly interpolate two WaveFrames in the time domain.
Definition wave_source.cpp:62
std::unique_ptr< vital::WaveFrame > wave_frame_
The WaveFrame representing this keyframe’s waveform.
Definition wave_source.h:198
vital::WaveFrame * wave_frame()
Provides direct access to the stored WaveFrame.
Definition wave_source.h:107
void cubicFrequencyInterpolate(const vital::WaveFrame *prev, const vital::WaveFrame *from, const vital::WaveFrame *to, const vital::WaveFrame *next, float range_prev, float range, float range_next, float t)
Cubic interpolation in frequency domain using four WaveFrames.
Definition wave_source.cpp:112
void interpolate(const WavetableKeyframe *from_keyframe, const WavetableKeyframe *to_keyframe, float t) override
Linearly interpolates between two keyframes.
Definition wave_source.cpp:162
ComponentType
Enumerates all known WavetableComponents, including sources and modifiers.
Definition wavetable_component_factory.h:28
@ kWaveSource
A basic wave source.
Definition wavetable_component_factory.h:29
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
static float linearTween(float point_from, float point_to, float t)
Performs linear interpolation between two points.
Definition wavetable_keyframe.cpp:11
int position() const
Gets the wavetable frame position of this keyframe.
Definition wavetable_keyframe.h:81
static float cubicTween(float point_prev, float point_from, float point_to, float point_next, float range_prev, float range, float range_next, float t)
Performs cubic interpolation taking into account a previous and next point for smoother curves.
Definition wavetable_keyframe.cpp:16
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
void copy(const WaveFrame *other)
Copies another WaveFrame's time and frequency domain data into this one.
Definition wave_frame.cpp:57
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
mono_float time_domain[2 *kWaveformSize]
The time-domain data, extended buffer size for FFT alignment.
Definition wave_frame.h:124
static constexpr int kNumRealComplex
The number of real-valued frequency components (half the size + 1).
Definition wave_frame.h:23
nlohmann::json json
Definition line_generator.h:7