Vital
Loading...
Searching...
No Matches
wavetable_creator.cpp
Go to the documentation of this file.
1#include "wavetable_creator.h"
2#include "line_generator.h"
3#include "load_save.h"
4#include "synth_constants.h"
5#include "wave_frame.h"
6#include "wave_line_source.h"
7#include "wave_source.h"
8#include "wavetable.h"
9
10namespace {
20 int getFirstNonZeroSample(const float* audio_buffer, int num_samples) {
21 for (int i = 0; i < num_samples; ++i) {
22 if (audio_buffer[i])
23 return i;
24 }
25 return 0;
26 }
27}
28
30 for (int i = 0; i < groups_.size(); ++i) {
31 if (groups_[i].get() == group)
32 return i;
33 }
34 return -1;
35}
36
37void WavetableCreator::moveUp(int index) {
38 if (index <= 0)
39 return;
40
41 groups_[index].swap(groups_[index - 1]);
42}
43
45 if (index < 0 || index >= groups_.size() - 1)
46 return;
47
48 groups_[index].swap(groups_[index + 1]);
49}
50
52 if (index < 0 || index >= groups_.size())
53 return;
54
55 std::unique_ptr<WavetableGroup> group = std::move(groups_[index]);
56 groups_.erase(groups_.begin() + index);
57}
58
59float WavetableCreator::render(int position) {
62 compute_frame_.index = position;
63
64 // Render each group and combine their results.
65 for (auto& group : groups_) {
66 group->render(&compute_frame_, position);
68 }
69
70 // If multiple groups, average their output.
71 if (groups_.size() > 1)
73
74 // Optionally remove DC offset from the combined frame.
77
78 float max_value = 0.0f;
79 float min_value = 0.0f;
80 for (int i = 0; i < vital::WaveFrame::kWaveformSize; ++i) {
81 max_value = std::max(compute_frame_combine_.time_domain[i], max_value);
82 min_value = std::min(compute_frame_combine_.time_domain[i], min_value);
83 }
84
86 return max_value - min_value;
87}
88
90 int last_waveframe = 0;
91 bool shepard = groups_.size() > 0;
92 for (auto& group : groups_) {
93 group->prerender();
94 last_waveframe = std::max(last_waveframe, group->getLastKeyframePosition());
95 shepard = shepard && group->isShepardTone();
96 }
97
98 wavetable_->setNumFrames(last_waveframe + 1);
100 float max_span = 0.0f;
101 for (int i = 0; i < last_waveframe + 1; ++i)
102 max_span = std::max(render(i), max_span);
105
106 postRender(max_span);
107}
108
109void WavetableCreator::postRender(float max_span) {
110 // After rendering the entire table, apply normalization if requested.
111 if (full_normalize_)
112 wavetable_->postProcess(max_span);
113 else
114 wavetable_->postProcess(0.0f);
115}
116
117void WavetableCreator::renderToBuffer(float* buffer, int num_frames, int frame_size) {
118 // Render multiple frames into a given buffer. Not fully implemented for different frame sizes.
119 int total_samples = num_frames * frame_size;
120 for (int i = 0; i < num_frames; ++i) {
121 float position = (1.0f * i * vital::kNumOscillatorWaveFrames) / num_frames;
123 compute_frame_combine_.index = position;
124 compute_frame_.index = position;
125
126 for (auto& group : groups_) {
127 group->render(&compute_frame_, position);
129 }
130
131 float* output_buffer = buffer + (i * frame_size);
132
133 if (frame_size != vital::WaveFrame::kWaveformSize)
134 VITAL_ASSERT(false); // TODO: support different waveframe size.
135 else {
136 for (int s = 0; s < vital::WaveFrame::kWaveformSize; ++s)
137 output_buffer[s] = compute_frame_combine_.time_domain[s];
138 }
139 }
140
141 // Normalize the output buffer.
142 float max_value = 1.0f;
143 for (int i = 0; i < total_samples; ++i)
144 max_value = std::max(max_value, fabsf(buffer[i]));
145
146 float scale = 1.0f / max_value;
147 for (int i = 0; i < total_samples; ++i)
148 buffer[i] *= scale;
149}
150
152 clear();
154 render();
155}
156
158 groups_.clear();
159 remove_all_dc_ = true;
160 full_normalize_ = true;
161}
162
164 // Create a default "Init" wavetable with a default group and render it.
165 wavetable_->setName("Init");
166 WavetableGroup* new_group = new WavetableGroup();
167 new_group->loadDefaultGroup();
168 addGroup(new_group);
169}
170
172 // Load predefined wave shapes from a fixed set of waveforms.
173 clear();
174
175 WavetableGroup* new_group = new WavetableGroup();
176 WaveSource* wave_source = new WaveSource();
177
179 for (int i = 0; i < num_shapes; ++i) {
180 int position = (vital::kNumOscillatorWaveFrames * i) / num_shapes;
181 wave_source->insertNewKeyframe(position);
182 WaveSourceKeyframe* keyframe = wave_source->getKeyframe(i);
183
186 }
188 full_normalize_ = false;
189 remove_all_dc_ = false;
190
191 new_group->addComponent(wave_source);
192 addGroup(new_group);
193 render();
194}
195
196void WavetableCreator::initFromAudioFile(const float* audio_buffer, int num_samples, int sample_rate,
197 AudioFileLoadStyle load_style, FileSource::FadeStyle fade_style) {
198 int beginning_sample = getFirstNonZeroSample(audio_buffer, num_samples);
199 int shortened_num_samples = num_samples - beginning_sample;
200 if (load_style == kVocoded)
201 initFromVocodedAudioFile(audio_buffer + beginning_sample, shortened_num_samples, sample_rate, false);
202 else if (load_style == kTtwt)
203 initFromVocodedAudioFile(audio_buffer + beginning_sample, shortened_num_samples, sample_rate, true);
204 else if (load_style == kPitched)
205 initFromPitchedAudioFile(audio_buffer + beginning_sample, shortened_num_samples, sample_rate);
206 else
207 initFromSplicedAudioFile(audio_buffer, num_samples, sample_rate, fade_style);
208}
209
210void WavetableCreator::initFromSplicedAudioFile(const float* audio_buffer, int num_samples, int sample_rate,
211 FileSource::FadeStyle fade_style) {
212 // Load audio file as a spliced wavetable, dividing it into segments that map across the wavetable frames.
213 clear();
214
215 WavetableGroup* new_group = new WavetableGroup();
216 FileSource* file_source = new FileSource();
217
218 file_source->loadBuffer(audio_buffer, num_samples, sample_rate);
219 file_source->setFadeStyle(fade_style);
221 file_source->insertNewKeyframe(0);
222 file_source->detectWaveEditTable();
223
224 double window_size = file_source->getWindowSize();
225 if (fade_style == FileSource::kNoInterpolate) {
226 int num_cycles = std::max<int>(1, num_samples / window_size);
227 int buffer_frames = vital::kNumOscillatorWaveFrames / num_cycles;
228 file_source->insertNewKeyframe(std::max(0, vital::kNumOscillatorWaveFrames - 1 - buffer_frames));
229 }
230 else
232
233 file_source->getKeyframe(0)->setStartPosition(0);
234 int last_sample_position = num_samples - window_size;
235 last_sample_position = std::min<int>(file_source->getKeyframe(1)->position() * window_size, last_sample_position);
236 file_source->getKeyframe(1)->setStartPosition(std::max(0, last_sample_position));
237
238 new_group->addComponent(file_source);
239 addGroup(new_group);
240 render();
241}
242
243void WavetableCreator::initFromVocodedAudioFile(const float* audio_buffer, int num_samples,
244 int sample_rate, bool ttwt) {
245 // Vocoding approach attempts to detect a stable period and vocode a single cycle.
246 static constexpr float kMaxTTWTPeriod = .02f;
247 clear();
248
249 WavetableGroup* new_group = new WavetableGroup();
250 FileSource* file_source = new FileSource();
251
252 file_source->loadBuffer(audio_buffer, num_samples, sample_rate);
253 if (ttwt)
254 file_source->detectPitch(kMaxTTWTPeriod * sample_rate);
255 else
256 file_source->detectPitch();
257
260 file_source->insertNewKeyframe(0);
262 file_source->getKeyframe(0)->setStartPosition(0);
263 int samples_needed = file_source->getKeyframe(1)->getSamplesNeeded();
264 file_source->getKeyframe(1)->setStartPosition(num_samples - samples_needed);
265
266 new_group->addComponent(file_source);
267 addGroup(new_group);
268 render();
269}
270
271void WavetableCreator::initFromPitchedAudioFile(const float* audio_buffer, int num_samples, int sample_rate) {
272 // Tries to detect a pitched period and map it across the wavetable frames.
273 clear();
274
275 WavetableGroup* new_group = new WavetableGroup();
276 FileSource* file_source = new FileSource();
277
278 file_source->loadBuffer(audio_buffer, num_samples, sample_rate);
279 file_source->detectPitch();
281 file_source->insertNewKeyframe(0);
283 file_source->getKeyframe(0)->setStartPosition(0);
284 int samples_needed = file_source->getKeyframe(1)->getSamplesNeeded();
285 file_source->getKeyframe(1)->setStartPosition(num_samples - samples_needed);
286
287 new_group->addComponent(file_source);
288 addGroup(new_group);
289 render();
290}
291
293 // Loads a line-based wave definition from a LineGenerator.
294 clear();
295
296 wavetable_->setName(line_generator->getName());
297 WavetableGroup* new_group = new WavetableGroup();
298
299 WaveLineSource* line_source = new WaveLineSource();
300 line_source->insertNewKeyframe(0);
301 WaveLineSource::WaveLineSourceKeyframe* keyframe = line_source->getKeyframe(0);
302 keyframe->getLineGenerator()->jsonToState(line_generator->stateToJson());
303
304 new_group->addComponent(line_source);
305 addGroup(new_group);
306 render();
307}
308
310 // Checks if data matches either a LineGenerator or a full wavetable creator state.
312 return true;
313
314 if (!data.count("version") || !data.count("groups") || !data.count("name"))
315 return false;
316
317 json groups_data = data["groups"];
318 return groups_data.is_array();
319}
320
322 // Update older versioned states to newer formats, ensuring backward compatibility.
323 // Contains a series of conditional conversions based on version comparisons.
324 std::string version = "0.0.0";
325 if (data.count("version")) {
326 std::string ver = data["version"];
327 version = ver;
328 }
329
330 if (LoadSave::compareVersionStrings(version, "0.3.3") < 0) {
331 // Convert old component type ints to strings
332 const std::string kOldOrder[] = {
333 "Wave Source", "Line Source", "Audio File Source", "Phase Shift", "Wave Window",
334 "Frequency Filter", "Slew Limiter", "Wave Folder", "Wave Warp"
335 };
336 json json_groups = data["groups"];
337 json new_groups;
338 for (json json_group : json_groups) {
339 json json_components = json_group["components"];
340 json new_components;
341 for (json json_component : json_components) {
342 int int_type = json_component["type"];
343 json_component["type"] = kOldOrder[int_type];
344
345 new_components.push_back(json_component);
346 }
347 json_group["components"] = new_components;
348 new_groups.push_back(json_group);
349 }
350 data["groups"] = new_groups;
351 }
352
353 if (LoadSave::compareVersionStrings(version, "0.3.7") < 0) {
354 // Convert PCM data to float buffers in components that use audio_file fields.
355 json json_groups = data["groups"];
356 json new_groups;
357 for (json json_group : json_groups) {
358 json json_components = json_group["components"];
359 json new_components;
360 for (json json_component : json_components) {
361 std::string type = json_component["type"];
362 if (type == "Audio File Source")
363 LoadSave::convertBufferToPcm(json_component, "audio_file");
364
365 new_components.push_back(json_component);
366 }
367
368 json_group["components"] = new_components;
369 new_groups.push_back(json_group);
370 }
371
372 data["groups"] = new_groups;
373 }
374
375 if (LoadSave::compareVersionStrings(version, "0.3.8") < 0)
376 data["remove_all_dc"] = false;
377
378 if (LoadSave::compareVersionStrings(version, "0.3.9") < 0 && LoadSave::compareVersionStrings(version, "0.3.7") >= 0) {
379 // Convert PCM data to float data in wave_data fields for certain components.
380 json json_groups = data["groups"];
381 json new_groups;
382 for (json json_group : json_groups) {
383 json json_components = json_group["components"];
384 json new_components;
385 for (json json_component : json_components) {
386 std::string type = json_component["type"];
387 if (type == "Wave Source" || type == "Shepard Tone Source") {
388 json old_keyframes = json_component["keyframes"];
389 json new_keyframes;
390 for (json json_keyframe : old_keyframes) {
391 LoadSave::convertPcmToFloatBuffer(json_keyframe, "wave_data");
392 new_keyframes.push_back(json_keyframe);
393 }
394
395 json_component["keyframes"] = new_keyframes;
396 }
397
398 new_components.push_back(json_component);
399 }
400
401 json_group["components"] = new_components;
402 new_groups.push_back(json_group);
403 }
404
405 data["groups"] = new_groups;
406 }
407
408 if (LoadSave::compareVersionStrings(version, "0.4.7") < 0)
409 data["full_normalize"] = false;
410
411 if (LoadSave::compareVersionStrings(version, "0.7.7") < 0) {
412 // Update old line source data to new line style including extra boundary points.
413 LineGenerator line_converter;
414
415 json json_groups = data["groups"];
416 json new_groups;
417 for (json json_group : json_groups) {
418 json json_components = json_group["components"];
419 json new_components;
420 for (json json_component : json_components) {
421 std::string type = json_component["type"];
422 if (type == "Line Source") {
423 json old_keyframes = json_component["keyframes"];
424 int num_points = json_component["num_points"];
425 json_component["num_points"] = num_points + 2;
426 line_converter.setNumPoints(num_points + 2);
427
428 json new_keyframes;
429 for (json json_keyframe : old_keyframes) {
430 json point_data = json_keyframe["points"];
431 json power_data = json_keyframe["powers"];
432 for (int i = 0; i < num_points; ++i) {
433 float x = point_data[2 * i];
434 float y = point_data[2 * i + 1];
435 line_converter.setPoint(i + 1, { x, y * 0.5f + 0.5f });
436 line_converter.setPower(i + 1, power_data[i]);
437 }
438 float start_x = point_data[0];
439 float start_y = point_data[1];
440 float end_x = point_data[2 * (num_points - 1)];
441 float end_y = point_data[2 * (num_points - 1) + 1];
442
443 float range_x = start_x - end_x + 1.0f;
444 float y = end_y;
445 if (range_x < 0.001f)
446 y = 0.5f * (start_y + end_y);
447 else {
448 float t = (1.0f - end_x) / range_x;
449 y = vital::utils::interpolate(end_y, start_y, t);
450 }
451
452 line_converter.setPoint(0, { 0.0f, y * 0.5f + 0.5f });
453 line_converter.setPoint(num_points + 1, { 1.0f, y * 0.5f + 0.5f });
454 line_converter.setPower(0, 0.0f);
455 line_converter.setPower(num_points + 1, 0.0f);
456
457 json_keyframe["line"] = line_converter.stateToJson();
458 new_keyframes.push_back(json_keyframe);
459 }
460
461 json_component["keyframes"] = new_keyframes;
462 }
463
464 new_components.push_back(json_component);
465 }
466
467 json_group["components"] = new_components;
468 new_groups.push_back(json_group);
469 }
470
471 data["groups"] = new_groups;
472 }
473
474 return data;
475}
476
478 // Serialize the current wavetable creator state, including all groups and parameters.
479 json json_groups;
480 for (auto& group : groups_)
481 json_groups.push_back(group->stateToJson());
482
483 return {
484 { "groups", json_groups },
485 { "name", wavetable_->getName() },
486 { "author", wavetable_->getAuthor() },
487 { "version", ProjectInfo::versionString },
488 { "remove_all_dc", remove_all_dc_ },
489 { "full_normalize", full_normalize_ },
490 };
491}
492
494 // If data matches a single LineGenerator, treat this as a line-based initialization.
495 if (LineGenerator::isValidJson(data)) {
497 generator.jsonToState(data);
498 initFromLineGenerator(&generator);
499 return;
500 }
501
502 // Otherwise, treat data as full wavetable creator state.
503 clear();
504 data = updateJson(data);
505
506 std::string name = "";
507 if (data.count("name"))
508 name = data["name"].get<std::string>();
509 wavetable_->setName(name);
510
511 std::string author = "";
512 if (data.count("author"))
513 author = data["author"].get<std::string>();
514 wavetable_->setAuthor(author);
515
516 if (data.count("remove_all_dc"))
517 remove_all_dc_ = data["remove_all_dc"];
518 if (data.count("full_normalize"))
519 full_normalize_ = data["full_normalize"];
520 else
521 full_normalize_ = false;
522
523 json json_groups = data["groups"];
524 for (const json& json_group : json_groups) {
525 WavetableGroup* new_group = new WavetableGroup();
526 new_group->jsonToState(json_group);
527 addGroup(new_group);
528 }
529
530 render();
531}
int getSamplesNeeded()
Definition file_source.h:117
force_inline void setStartPosition(double start_position)
Definition file_source.h:119
A WavetableComponent that uses an external audio sample as its source.
Definition file_source.h:23
void loadBuffer(const float *buffer, int size, int sample_rate)
Loads audio data into the file source buffer.
Definition file_source.cpp:363
double getWindowSize()
Definition file_source.h:181
void detectPitch(int max_period=vital::WaveFrame::kWaveformSize)
Attempts to detect pitch in the loaded sample to determine window size automatically.
Definition file_source.cpp:376
FadeStyle
Different methods to blend or interpolate the loaded audio window into a wavetable frame.
Definition file_source.h:38
@ kWaveBlend
Blend windowed segments into each other.
Definition file_source.h:39
@ kNoInterpolate
Use a single segment, no blending.
Definition file_source.h:40
void setFadeStyle(FadeStyle fade_style)
Definition file_source.h:178
void setPhaseStyle(PhaseStyle phase_style)
Definition file_source.cpp:337
void detectWaveEditTable()
Detects if the source audio can form a WaveEdit-style wavetable (special format).
Definition file_source.cpp:384
FileSourceKeyframe * getKeyframe(int index)
Definition file_source.cpp:332
@ kNone
Keep phases as-is.
Definition file_source.h:51
@ kVocode
Assign random phases for vocoding-like effect.
Definition file_source.h:53
A class for generating and storing a line shape, defined by a series of points and associated powers.
Definition line_generator.h:20
std::string getName() const
Gets the current name of the line.
Definition line_generator.h:198
force_inline void setPower(int index, float power)
Sets the power for a specific point.
Definition line_generator.h:349
force_inline void setPoint(int index, std::pair< float, float > point)
Sets the position of a specific point.
Definition line_generator.h:337
static bool isValidJson(json data)
Checks if a given JSON object contains valid line data.
Definition line_generator.cpp:116
void jsonToState(json data)
Restores the line state from a given JSON object.
Definition line_generator.cpp:125
force_inline void setNumPoints(int num_points)
Sets the number of points currently in use.
Definition line_generator.h:360
json stateToJson()
Converts the current state of the line into a JSON object.
Definition line_generator.cpp:96
static void convertPcmToFloatBuffer(json &data, const std::string &field)
Converts a PCM buffer field in JSON to a float buffer in base64.
Definition load_save.cpp:61
static int compareVersionStrings(String a, String b)
Compares two version strings.
Definition load_save.cpp:1895
static void convertBufferToPcm(json &data, const std::string &field)
Converts a float buffer field in JSON to PCM format in base64.
Definition load_save.cpp:44
A keyframe class that represents a particular line-based waveform configuration at a given position.
Definition wave_line_source.h:36
const LineGenerator * getLineGenerator() const
Provides const access to the underlying LineGenerator.
Definition wave_line_source.h:134
A WavetableComponent that generates waveforms from a series of line segments.
Definition wave_line_source.h:23
WaveLineSourceKeyframe * getKeyframe(int index)
Retrieves a WaveLineSourceKeyframe by index.
Definition wave_line_source.cpp:116
A WavetableComponent that acts as a direct source of waveforms.
Definition wave_source.h:25
WaveSourceKeyframe * getKeyframe(int index)
Retrieves a WaveSourceKeyframe by index.
Definition wave_source.cpp:51
A keyframe that holds a single WaveFrame and supports various interpolation methods.
Definition wave_source.h:92
vital::WaveFrame * wave_frame()
Provides direct access to the stored WaveFrame.
Definition wave_source.h:107
@ kNone
No interpolation, just jumps between keyframes.
Definition wavetable_component.h:39
WavetableKeyframe * insertNewKeyframe(int position)
Inserts a new keyframe at the given position, creating and sorting it into the array.
Definition wavetable_component.cpp:8
void setInterpolationStyle(InterpolationStyle type)
Sets the global interpolation style.
Definition wavetable_component.h:209
void initPredefinedWaves()
Definition wavetable_creator.cpp:171
void initFromLineGenerator(LineGenerator *line_generator)
Definition wavetable_creator.cpp:292
bool full_normalize_
Definition wavetable_creator.h:159
void removeGroup(int index)
Definition wavetable_creator.cpp:51
json updateJson(json data)
Definition wavetable_creator.cpp:321
static bool isValidJson(json data)
Checks if a given JSON data represents a valid wavetable creator state.
Definition wavetable_creator.cpp:309
vital::WaveFrame compute_frame_combine_
Definition wavetable_creator.h:153
void moveUp(int index)
Definition wavetable_creator.cpp:37
void initFromPitchedAudioFile(const float *audio_buffer, int num_samples, int sample_rate)
Definition wavetable_creator.cpp:271
void addGroup(WavetableGroup *group)
Definition wavetable_creator.h:53
void loadDefaultCreator()
Definition wavetable_creator.cpp:163
void init()
Definition wavetable_creator.cpp:151
void clear()
Definition wavetable_creator.cpp:157
AudioFileLoadStyle
Defines how audio files are interpreted when loading into a wavetable.
Definition wavetable_creator.h:33
@ kTtwt
Similar to vocoded but optimized for TTWT (text-to-wavetable).
Definition wavetable_creator.h:37
@ kVocoded
Apply vocoder-like analysis to extract fundamental cycles.
Definition wavetable_creator.h:36
@ kPitched
Attempts to extract pitch-based cycles from the audio.
Definition wavetable_creator.h:38
json stateToJson()
Definition wavetable_creator.cpp:477
void jsonToState(json data)
Definition wavetable_creator.cpp:493
int getGroupIndex(WavetableGroup *group)
Definition wavetable_creator.cpp:29
void initFromAudioFile(const float *audio_buffer, int num_samples, int sample_rate, AudioFileLoadStyle load_style, FileSource::FadeStyle fade_style)
Definition wavetable_creator.cpp:196
bool remove_all_dc_
Definition wavetable_creator.h:160
vital::Wavetable * wavetable_
Definition wavetable_creator.h:158
void moveDown(int index)
Definition wavetable_creator.cpp:44
void render()
Definition wavetable_creator.cpp:89
void initFromVocodedAudioFile(const float *audio_buffer, int num_samples, int sample_rate, bool ttwt)
Definition wavetable_creator.cpp:243
std::vector< std::unique_ptr< WavetableGroup > > groups_
Definition wavetable_creator.h:155
vital::WaveFrame compute_frame_
Definition wavetable_creator.h:154
void renderToBuffer(float *buffer, int num_frames, int frame_size)
Definition wavetable_creator.cpp:117
void postRender(float max_span)
Definition wavetable_creator.cpp:109
void initFromSplicedAudioFile(const float *audio_buffer, int num_samples, int sample_rate, FileSource::FadeStyle fade_style)
Definition wavetable_creator.cpp:210
A class representing a group of WavetableComponents combined to form part of a wavetable.
Definition wavetable_group.h:24
void jsonToState(json data)
Restores this group's state from a JSON object.
Definition wavetable_group.cpp:121
void addComponent(WavetableComponent *component)
Adds a new WavetableComponent to this group.
Definition wavetable_group.h:44
void loadDefaultGroup()
Loads a default group configuration (e.g., a basic wave source).
Definition wavetable_group.cpp:86
int position() const
Gets the wavetable frame position of this keyframe.
Definition wavetable_keyframe.h:81
static const WaveFrame * getWaveFrame(Shape shape)
Retrieves a pointer to a WaveFrame representing a predefined shape.
Definition wave_frame.h:167
Shape
Supported predefined shapes.
Definition wave_frame.h:146
@ kNumShapes
Definition wave_frame.h:153
void copy(const WaveFrame *other)
Copies another WaveFrame's time and frequency domain data into this one.
Definition wave_frame.cpp:57
float sample_rate
The sample rate associated with this frame.
Definition wave_frame.h:123
void addFrom(WaveFrame *source)
Adds another WaveFrame's data to this one, sample-by-sample, in both time and frequency domains.
Definition wave_frame.cpp:50
float frequency_ratio
The frequency ratio for this frame (e.g., for pitch scaling).
Definition wave_frame.h:122
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
int index
The index of this frame in a wavetable.
Definition wave_frame.h:121
void removedDc()
Removes the DC offset from the waveform.
Definition wave_frame.cpp:90
void multiply(mono_float value)
Multiplies all samples in both time and frequency domains by a given value.
Definition wave_frame.cpp:16
void clear()
Clears the waveform data, resetting it to default states.
Definition wave_frame.cpp:7
void loadWaveFrame(const WaveFrame *wave_frame)
Load a WaveFrame into the wavetable at the frame index specified by the WaveFrame.
Definition wavetable.cpp:89
std::string getAuthor()
Get the author of this wavetable.
Definition wavetable.h:122
force_inline void setShepardTable(bool shepard)
Enable or disable "Shepard" table mode.
Definition wavetable.h:338
std::string getName()
Get the user-defined name of this wavetable.
Definition wavetable.h:115
void setName(const std::string &name)
Set a user-defined name for this wavetable.
Definition wavetable.h:129
void setAuthor(const std::string &author)
Set the author for this wavetable.
Definition wavetable.h:136
void setFrequencyRatio(float frequency_ratio)
Set the frequency ratio for this wavetable.
Definition wavetable.cpp:81
void setSampleRate(float rate)
Set the sample rate associated with this wavetable.
Definition wavetable.cpp:85
void setNumFrames(int num_frames)
Set the number of frames in the wavetable.
Definition wavetable.cpp:27
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
nlohmann::json json
Definition line_generator.h:7
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
constexpr int kNumOscillatorWaveFrames
Number of wave frames in each oscillator’s wavetable.
Definition synth_constants.h:19