Vital
Loading...
Searching...
No Matches
wavetable.cpp
Go to the documentation of this file.
1#include "wavetable.h"
2#include "fourier_transform.h"
3
4#include <thread>
5
6namespace vital {
7
8 const mono_float Wavetable::kZeroWaveform[kWaveformSize + kExtraValues] = { };
9
15 Wavetable::Wavetable(int max_frames) :
16 max_frames_(max_frames), current_data_(nullptr),
17 active_audio_data_(nullptr), shepard_table_(false), fft_data_() {
19 }
20
22 setNumFrames(1);
23 WaveFrame default_frame;
24 loadWaveFrame(&default_frame);
25 }
26
27 void Wavetable::setNumFrames(int num_frames) {
28 VITAL_ASSERT(active_audio_data_.is_lock_free());
29 VITAL_ASSERT(num_frames <= max_frames_);
30 if (data_ && num_frames == data_->num_frames)
31 return;
32
33 int old_version = 0;
34 int old_num_frames = 0;
35 if (data_) {
36 old_version = data_->version;
37 old_num_frames = data_->num_frames;
38 }
39
40 // Move old data and create new data structure
41 std::unique_ptr<WavetableData> old_data = std::move(data_);
42 data_ = std::make_unique<WavetableData>(num_frames, old_version + 1);
43 data_->wave_data = std::make_unique<mono_float[][kWaveformSize]>(num_frames);
44 data_->frequency_amplitudes = std::make_unique<poly_float[][kPolyFrequencySize]>(num_frames);
45 data_->normalized_frequencies = std::make_unique<poly_float[][kPolyFrequencySize]>(num_frames);
46 data_->phases = std::make_unique<poly_float[][kPolyFrequencySize]>(num_frames);
47
48 int frame_size = kWaveformSize * sizeof(mono_float);
49 int frequency_size = kPolyFrequencySize * sizeof(poly_float);
50 int copy_frames = std::min(num_frames, old_num_frames);
51 for (int i = 0; i < copy_frames; ++i) {
52 memcpy(data_->wave_data[i], old_data->wave_data[i], frame_size);
53 memcpy(data_->frequency_amplitudes[i], old_data->frequency_amplitudes[i], frequency_size);
54 memcpy(data_->normalized_frequencies[i], old_data->normalized_frequencies[i], frequency_size);
55 memcpy(data_->phases[i], old_data->phases[i], frequency_size);
56 }
57
58 if (old_data) {
59 data_->frequency_ratio = old_data->frequency_ratio;
60 data_->sample_rate = old_data->sample_rate;
61
62 int remaining_frames = num_frames - old_num_frames;
63 void* last_old_frame = old_data->wave_data[old_num_frames - 1];
64 void* last_old_amplitudes = old_data->frequency_amplitudes[old_num_frames - 1];
65 void* last_old_normalized = old_data->normalized_frequencies[old_num_frames - 1];
66 void* last_old_phases = old_data->phases[old_num_frames - 1];
67 for (int i = 0; i < remaining_frames; ++i) {
68 memcpy(data_->wave_data[i + old_num_frames], last_old_frame, frame_size);
69 memcpy(data_->frequency_amplitudes[i + old_num_frames], last_old_amplitudes, frequency_size);
70 memcpy(data_->normalized_frequencies[i + old_num_frames], last_old_normalized, frequency_size);
71 memcpy(data_->phases[i + old_num_frames], last_old_phases, frequency_size);
72 }
73 }
74
75 current_data_ = data_.get();
76 // Wait until the old data is not in use by the audio thread before discarding.
77 while (active_audio_data_.load())
78 std::this_thread::yield();
79 }
80
81 void Wavetable::setFrequencyRatio(float frequency_ratio) {
82 current_data_->frequency_ratio = frequency_ratio;
83 }
84
85 void Wavetable::setSampleRate(float rate) {
87 }
88
89 void Wavetable::loadWaveFrame(const WaveFrame* wave_frame) {
90 loadWaveFrame(wave_frame, wave_frame->index);
91 }
92
93 void Wavetable::loadWaveFrame(const WaveFrame* wave_frame, int to_index) {
94 if (to_index >= current_data_->num_frames)
95 return;
96
97 loadFrequencyAmplitudes(wave_frame->frequency_domain, to_index);
98 loadNormalizedFrequencies(wave_frame->frequency_domain, to_index);
99 memcpy(current_data_->wave_data[to_index], wave_frame->time_domain, kWaveformSize * sizeof(mono_float));
100 }
101
102 void Wavetable::postProcess(float max_span) {
103 static constexpr float kMinAmplitudePhase = 0.1f;
104
105 // Scale amplitude and wave data if max_span is provided
106 if (max_span > 0.0f) {
107 float scale = 2.0f / max_span;
108 for (int w = 0; w < current_data_->num_frames; ++w) {
109 poly_float* frequency_amplitudes = current_data_->frequency_amplitudes[w];
110 for (int i = 0; i < kPolyFrequencySize; ++i)
111 frequency_amplitudes[i] *= scale;
112
113 mono_float* wave_data = current_data_->wave_data[w];
114 for (int i = 0; i < kWaveformSize; ++i)
115 wave_data[i] *= scale;
116 }
117 }
118
119 // Interpolate normalized frequencies for frames below the min amplitude threshold
120 std::unique_ptr<std::complex<float>[]> normalized_defaults =
121 std::make_unique<std::complex<float>[]>(kNumHarmonics);
122 for (int i = 0; i < kNumHarmonics; ++i) {
123 int amp_index = 2 * i;
124
125 int last_min_amp_frame = -1;
126 std::complex<float> last_normalized_frequency = std::complex<float>(0.0f, 1.0f);
127 for (int w = 0; w < current_data_->num_frames; ++w) {
128 mono_float amplitude = ((mono_float*)current_data_->frequency_amplitudes[w])[amp_index];
129 std::complex<float> normalized_frequency = ((std::complex<float>*)current_data_->normalized_frequencies[w])[i];
130
131 if (amplitude > kMinAmplitudePhase) {
132 if (last_min_amp_frame < 0) {
133 last_min_amp_frame = 0;
134 last_normalized_frequency = normalized_frequency;
135 }
136
137 std::complex<float> delta_normalized_frequency = normalized_frequency - last_normalized_frequency;
138
139 for (int frame = last_min_amp_frame + 1; frame < w; ++frame) {
140 float t = (frame - last_min_amp_frame) * 1.0f / (w - last_min_amp_frame);
141 std::complex<float> interpolated = delta_normalized_frequency * t + last_normalized_frequency;
142 ((std::complex<float>*)current_data_->normalized_frequencies[frame])[i] = interpolated;
143 }
144 last_normalized_frequency = normalized_frequency;
145 last_min_amp_frame = w;
146 }
147 }
148 for (int frame = last_min_amp_frame + 1; frame < current_data_->num_frames; ++frame)
149 ((std::complex<float>*)current_data_->normalized_frequencies[frame])[i] = last_normalized_frequency;
150 }
151 }
152
153 void Wavetable::loadFrequencyAmplitudes(const std::complex<float>* frequencies, int to_index) {
154 // Convert complex frequencies to amplitude values.
155 mono_float* amplitudes = (mono_float*)current_data_->frequency_amplitudes[to_index];
156 for (int i = 0; i < kNumHarmonics; ++i) {
157 float amplitude = std::abs(frequencies[i]);
158 amplitudes[2 * i] = amplitude;
159 amplitudes[2 * i + 1] = amplitude;
160 }
161 }
162
163 void Wavetable::loadNormalizedFrequencies(const std::complex<float>* frequencies, int to_index) {
164 // Extract and store phase information in normalized form.
165 std::complex<float>* normalized = (std::complex<float>*)current_data_->normalized_frequencies[to_index];
166 mono_float* phases = (mono_float*)current_data_->phases[to_index];
167 for (int i = 0; i < kNumHarmonics; ++i) {
168 mono_float arg = std::arg(frequencies[i]);
169 normalized[i] = std::polar(1.0f, arg);
170 phases[2 * i] = arg;
171 phases[2 * i + 1] = arg;
172 }
173 }
174} // namespace vital
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
mono_float time_domain[2 *kWaveformSize]
The time-domain data, extended buffer size for FFT alignment.
Definition wave_frame.h:124
int index
The index of this frame in a wavetable.
Definition wave_frame.h:121
void loadWaveFrame(const WaveFrame *wave_frame)
Load a WaveFrame into the wavetable at the frame index specified by the WaveFrame.
Definition wavetable.cpp:89
Wavetable()=default
Protected default constructor for the Wavetable, intended for subclassing or internal use.
std::unique_ptr< WavetableData > data_
Owning pointer to the wavetable data.
Definition wavetable.h:377
void setFrequencyRatio(float frequency_ratio)
Set the frequency ratio for this wavetable.
Definition wavetable.cpp:81
static constexpr int kNumHarmonics
Number of harmonics in the waveform (half the size plus one).
Definition wavetable.h:29
void setSampleRate(float rate)
Set the sample rate associated with this wavetable.
Definition wavetable.cpp:85
WavetableData * current_data_
Pointer to the currently editable wavetable data.
Definition wavetable.h:375
void setNumFrames(int num_frames)
Set the number of frames in the wavetable.
Definition wavetable.cpp:27
void loadDefaultWavetable()
Load a default wavetable containing a single, default frame.
Definition wavetable.cpp:21
static const mono_float kZeroWaveform[kWaveformSize+kExtraValues]
A static zeroed-out waveform for reference or fallback.
Definition wavetable.h:370
std::atomic< WavetableData * > active_audio_data_
Pointer to the currently active wavetable data used by the audio thread.
Definition wavetable.h:376
void loadNormalizedFrequencies(const std::complex< float > *frequencies, int to_index)
Load normalized frequency and phase data from a set of complex frequency-domain coefficients.
Definition wavetable.cpp:163
static constexpr int kPolyFrequencySize
The size for poly frequency buffers, ensuring alignment and vectorization.
Definition wavetable.h:31
int max_frames_
Maximum number of frames allocated for this wavetable.
Definition wavetable.h:374
void loadFrequencyAmplitudes(const std::complex< float > *frequencies, int to_index)
Load frequency amplitude data from a set of complex frequency-domain coefficients.
Definition wavetable.cpp:153
static constexpr int kWaveformSize
Size of each waveform frame.
Definition wavetable.h:25
void postProcess(float max_span)
Post-process the loaded wavetable frames, scaling them based on a maximum span.
Definition wavetable.cpp:102
#define VITAL_ASSERT(x)
Definition common.h:11
Contains classes and functions used within the Vital synthesizer framework.
float mono_float
Definition common.h:33
std::unique_ptr< poly_float[][kPolyFrequencySize]> frequency_amplitudes
Frequency amplitudes: an array of [num_frames][kPolyFrequencySize].
Definition wavetable.h:59
mono_float sample_rate
The sample rate associated with the wavetable frames.
Definition wavetable.h:53
int num_frames
The number of frames in the wavetable.
Definition wavetable.h:51
std::unique_ptr< poly_float[][kPolyFrequencySize]> phases
Phase data: an array of [num_frames][kPolyFrequencySize].
Definition wavetable.h:63
mono_float frequency_ratio
The frequency ratio used for playback.
Definition wavetable.h:52
std::unique_ptr< mono_float[][kWaveformSize]> wave_data
Time-domain wave data: an array of [num_frames][kWaveformSize].
Definition wavetable.h:57
std::unique_ptr< poly_float[][kPolyFrequencySize]> normalized_frequencies
Normalized frequency data: an array of [num_frames][kPolyFrequencySize].
Definition wavetable.h:61
Represents a vector of floating-point values using SIMD instructions.
Definition poly_values.h:600