Vital
Loading...
Searching...
No Matches
sample_source.cpp
Go to the documentation of this file.
1
7#include "sample_source.h"
8#include "futils.h"
9#include "synth_constants.h"
10
11#include <thread>
12
13namespace vital {
14
15 namespace {
17 const std::string kDefaultName = "White Noise";
18
19 // Upsampling filter coefficients (half used forward, half backward).
20 const mono_float kUpsampleCoefficients[SampleSource::kNumUpsampleTaps] = {
21 -0.000159813115702086552469274316479186382f,
22 0.000225405365781280835058009159865832771f,
23 -0.000378616814007205900686342525673921955f,
24 0.000594907533596884547516525643118256994f,
25 -0.000890530515941817101682742574553230952f,
26 0.001284040046393844676508866342601322685f,
27 -0.001796543223638378920792302295694753411f,
28 0.002451862103068884121692683208948437823f,
29 -0.003276873018553504678107568537370752892f,
30 0.004302012661141991003987961050825106213f,
31 -0.005561976429934398571952591794342879439f,
32 0.007097105459677621741576558633823879063f,
33 -0.008955232561651555595050311353588767815f,
34 0.011195057708851860467369476737076183781f,
35 -0.013890548104646217864033275191104621626f,
36 0.017139719620821350365424962092220084742f,
37 -0.021077036318492142763503238711564335972f,
38 0.025897497908177177783350941808748757467f,
39 -0.03189749744607761616776997470878995955f,
40 0.039555400754278852160084056777122896165f,
41 -0.049699764879031965714162311087420675904f,
42 0.063901297378209126476278356676630210131f,
43 -0.08553732517833501081128133591846562922f,
44 0.123410206086688845061871688812971115112f,
45 -0.209837893291539345774765479291090741754f,
46 0.63582677174146173815216798175242729485f,
47 0.63582677174146173815216798175242729485f,
48 -0.209837893291539345774765479291090741754f,
49 0.123410206086688845061871688812971115112f,
50 -0.08553732517833501081128133591846562922f,
51 0.063901297378209126476278356676630210131f,
52 -0.049699764879031965714162311087420675904f,
53 0.039555400754278852160084056777122896165f,
54 -0.03189749744607761616776997470878995955f,
55 0.025897497908177177783350941808748757467f,
56 -0.021077036318492142763503238711564335972f,
57 0.017139719620821350365424962092220084742f,
58 -0.013890548104646217864033275191104621626f,
59 0.011195057708851860467369476737076183781f,
60 -0.008955232561651555595050311353588767815f,
61 0.007097105459677621741576558633823879063f,
62 -0.005561976429934398571952591794342879439f,
63 0.004302012661141991003987961050825106213f,
64 -0.003276873018553504678107568537370752892f,
65 0.002451862103068884121692683208948437823f,
66 -0.001796543223638378920792302295694753411f,
67 0.001284040046393844676508866342601322685f,
68 -0.000890530515941817101682742574553230952f,
69 0.000594907533596884547516525643118256994f,
70 -0.000378616814007205900686342525673921955f,
71 0.000225405365781280835058009159865832771f,
72 -0.000159813115702086552469274316479186382f
73 };
74
75 // Downsampling filter coefficients (half used forward, half backward).
76 const mono_float kDownsampleCoefficients[SampleSource::kNumDownsampleTaps] = {
77 -0.0013796309221920304f,
78 -0.0008322130675804714f,
79 0.0030100376204235577f,
80 0.00666031332700994f,
81 0.0040620073330527315f,
82 -0.003019073425031439f,
83 -0.004450269579432283f,
84 0.0030526281279541555f,
85 0.007614361286489334f,
86 -0.000546514301955849f,
87 -0.010099270019478761f,
88 -0.003465846383906444f,
89 0.011760981765402261f,
90 0.009402148654924303f,
91 -0.011429260748035207f,
92 -0.016935843679984037f,
93 0.008026778073943279f,
94 0.025557280950428782f,
95 -0.0002093220301655805f,
96 -0.03448379812688787f,
97 -0.013983156365753766f,
98 0.04279770831566429f,
99 0.03889228625534586f,
100 -0.049566024787935245f,
101 -0.09025827224454164f,
102 0.05398926693924448f,
103 0.31285587793730246f,
104 0.4444714418837066f,
105 0.31285587793730246f,
106 0.05398926693924448f,
107 -0.09025827224454164f,
108 -0.049566024787935245f,
109 0.03889228625534586f,
110 0.04279770831566429f,
111 -0.013983156365753766f,
112 -0.03448379812688787f,
113 -0.0002093220301655805f,
114 0.025557280950428782f,
115 0.008026778073943279f,
116 -0.016935843679984037f,
117 -0.011429260748035207f,
118 0.009402148654924303f,
119 0.011760981765402261f,
120 -0.003465846383906444f,
121 -0.010099270019478761f,
122 -0.000546514301955849f,
123 0.007614361286489334f,
124 0.0030526281279541555f,
125 -0.004450269579432283f,
126 -0.003019073425031439f,
127 0.0040620073330527315f,
128 0.00666031332700994f,
129 0.0030100376204235577f,
130 -0.0008322130675804714f,
131 -0.0013796309221920304f
132 };
133
141 force_inline mono_float getFilteredSample(const mono_float* buffer, int index, int size) {
142 int radius = SampleSource::kNumDownsampleTaps / 2;
143 int start = std::max(0, index - radius);
144 int end = std::min(size - 1, index + radius);
145 mono_float total = 0.0f;
146 for (int i = start; i <= end; ++i) {
147 mono_float coefficient = kDownsampleCoefficients[i - index + radius];
148 total += coefficient * buffer[i];
149 }
150 return total;
151 }
152
156 force_inline mono_float getFilteredLoopSample(const mono_float* buffer, int index, int size) {
157 int radius = SampleSource::kNumDownsampleTaps / 2;
158 int start = index - radius;
159 int end = index + radius;
160 mono_float total = 0.0f;
161 for (int i = start; i <= end; ++i) {
162 int buffer_index = (i + size * radius) % size;
163 mono_float coefficient = kDownsampleCoefficients[i - index + radius];
164 total += coefficient * buffer[buffer_index];
165 }
166 return total;
167 }
168
172 force_inline mono_float getInterpolatedSample(const mono_float* buffer, int index, int size) {
173 int radius = SampleSource::kNumUpsampleTaps / 2;
174 int start = std::max(0, index - radius + 1);
175 int end = std::min(size - 1, index + radius);
176 mono_float total = 0.0f;
177 for (int i = start; i <= end; ++i) {
178 int coefficient_index = i - index + radius - 1;
179 VITAL_ASSERT(coefficient_index >= 0 && coefficient_index < SampleSource::kNumUpsampleTaps);
180 mono_float coefficient = kUpsampleCoefficients[coefficient_index];
181 total += coefficient * buffer[i];
182 }
183 return total;
184 }
185
193 void upsample(const mono_float* original, mono_float* dest, int original_size, int dest_size) {
194 for (int i = 0; i < original_size; ++i) {
195 float value1 = original[i];
196 float value2 = getInterpolatedSample(original, i, original_size);
197 dest[2 * i] = value1;
198 dest[2 * i + 1] = value2;
199 }
200 }
201
205 void downsample(const mono_float* original, mono_float* dest, int original_size, int dest_size) {
206 for (int i = 0; i < dest_size; ++i)
207 dest[i] = getFilteredSample(original, 2 * i, original_size);
208 }
209
213 void downsampleLoop(const mono_float* original, mono_float* dest, int original_size, int dest_size) {
214 for (int i = 0; i < dest_size; ++i)
215 dest[i] = getFilteredLoopSample(original, 2 * i, original_size);
216 }
217
222 void createBandLimitedBuffers(std::vector<std::unique_ptr<mono_float[]>>& destination,
223 std::vector<std::unique_ptr<mono_float[]>>& loop_destination,
224 const mono_float* buffer, int size) {
225 destination.push_back(std::make_unique<mono_float[]>(size + 2 * Sample::kBufferSamples));
226 loop_destination.push_back(std::make_unique<mono_float[]>(size + 2 * Sample::kBufferSamples));
227
228 mono_float* play_buffer = destination.back().get();
229 mono_float* loop_buffer = loop_destination.back().get();
230 memcpy(play_buffer + Sample::kBufferSamples, buffer, size * sizeof(mono_float));
231 memcpy(loop_buffer + Sample::kBufferSamples, buffer, size * sizeof(mono_float));
232
233 for (int i = 0; i < Sample::kBufferSamples; ++i) {
234 play_buffer[i] = 0.0f;
235 play_buffer[size + Sample::kBufferSamples + i] = 0.0f;
236
237 loop_buffer[i] = loop_buffer[size + i];
238 loop_buffer[size + Sample::kBufferSamples + i] = loop_buffer[Sample::kBufferSamples + i];
239 }
240
241 int current_size = size;
242 for (int i = 0; i < Sample::kUpsampleTimes; ++i) {
243 int upsampled_size = current_size * 2;
244 int num_samples = upsampled_size + 2 * Sample::kBufferSamples;
245 destination.insert(destination.begin(), std::make_unique<mono_float[]>(num_samples));
246 loop_destination.insert(loop_destination.begin(), std::make_unique<mono_float[]>(num_samples));
247
248 mono_float* next_buffer = destination.front().get();
249 mono_float* next_loop_buffer = loop_destination.front().get();
250
251 upsample(play_buffer + Sample::kBufferSamples, next_buffer + Sample::kBufferSamples,
252 current_size, upsampled_size);
253 memcpy(next_loop_buffer, next_buffer, num_samples * sizeof(mono_float));
254 current_size = upsampled_size;
255 }
256
257 play_buffer = destination.back().get();
258 loop_buffer = loop_destination.back().get();
259 current_size = size;
260
261 while (current_size >= Sample::kMinSize) {
262 int next_size = (current_size + 1) / 2;
263 destination.push_back(std::make_unique<mono_float[]>(next_size + 2 * Sample::kBufferSamples));
264 loop_destination.push_back(std::make_unique<mono_float[]>(next_size + 2 * Sample::kBufferSamples));
265
266 mono_float* next_buffer = destination.back().get();
267 mono_float* next_loop_buffer = loop_destination.back().get();
268
269 downsample(play_buffer + Sample::kBufferSamples, next_buffer + Sample::kBufferSamples,
270 current_size, next_size);
271 downsampleLoop(loop_buffer + Sample::kBufferSamples, next_loop_buffer + Sample::kBufferSamples,
272 current_size, next_size);
273
274 for (int i = 0; i < Sample::kBufferSamples; ++i) {
275 next_buffer[i] = 0.0f;
276 next_buffer[next_size + Sample::kBufferSamples + i] = 0.0f;
277
278 next_loop_buffer[i] = loop_buffer[next_size + i];
279 next_loop_buffer[next_size + Sample::kBufferSamples + i] = next_loop_buffer[Sample::kBufferSamples + i];
280 }
281
282 play_buffer = next_buffer;
283 loop_buffer = next_loop_buffer;
284 current_size = next_size;
285 }
286 }
287 }
288
289 //===================== Sample Implementation ===========================//
290
291 Sample::Sample() : name_(kDefaultName), current_data_(nullptr), active_audio_data_(nullptr) {
292 init();
293 }
294
295 void Sample::loadSample(const mono_float* buffer, int size, int sample_rate) {
296 static constexpr int kMaxSize = 1764000;
297
298 VITAL_ASSERT(active_audio_data_.is_lock_free());
299
300 size = std::min(size, kMaxSize);
301 std::unique_ptr<SampleData> old_data = std::move(data_);
302 data_ = std::make_unique<SampleData>(size, sample_rate, false);
303 createBandLimitedBuffers(data_->left_buffers, data_->left_loop_buffers, buffer, size);
304
305 current_data_ = data_.get();
306 while (active_audio_data_.load())
307 std::this_thread::yield(); // Wait for audio thread to finish using old_data.
308 }
309
310 void Sample::loadSample(const mono_float* left_buffer, const mono_float* right_buffer, int size, int sample_rate) {
311 std::unique_ptr<SampleData> old_data = std::move(data_);
312 data_ = std::make_unique<SampleData>(size, sample_rate, true);
313 createBandLimitedBuffers(data_->left_buffers, data_->left_loop_buffers, left_buffer, size);
314 createBandLimitedBuffers(data_->right_buffers, data_->right_loop_buffers, right_buffer, size);
315
316 current_data_ = data_.get();
317 while (active_audio_data_.load())
318 std::this_thread::yield(); // Wait for audio thread to finish using old_data.
319 }
320
322 // Creates a default noise buffer and loads it
323 name_ = kDefaultName;
325 utils::RandomGenerator random_generator(-0.9f, 0.9f);
326
327 for (int i = 0; i < kDefaultSampleLength; ++i)
328 buffer[i] = random_generator.next();
329
331 }
332
334 // Serializes sample data into Base64
335 json data;
336 data["name"] = name_;
337 data["length"] = data_->length;
338 data["sample_rate"] = data_->sample_rate;
339 std::unique_ptr<int16_t[]> pcm_data = std::make_unique<int16_t[]>(data_->length);
340 utils::floatToPcmData(pcm_data.get(), data_->left_buffers[kUpsampleTimes].get(), data_->length);
341 String encoded = Base64::toBase64(pcm_data.get(), sizeof(int16_t) * data_->length);
342 data["samples"] = encoded.toStdString();
343 if (data_->stereo) {
344 utils::floatToPcmData(pcm_data.get(), data_->right_buffers[kUpsampleTimes].get(), data_->length);
345 String encoded_stereo = Base64::toBase64(pcm_data.get(), sizeof(int16_t) * data_->length);
346 data["samples_stereo"] = encoded_stereo.toStdString();
347 }
348 return data;
349 }
350
352 // Deserializes Base64 sample data and loads it
353 name_ = "";
354 if (data.count("name"))
355 name_ = data["name"].get<std::string>();
356
357 int length = data["length"];
358 int sample_rate = data["sample_rate"];
359
360 MemoryOutputStream decoded(length * sizeof(int16_t));
361 std::string wave_data = data["samples"];
362 Base64::convertFromBase64(decoded, wave_data);
363 std::unique_ptr<int16_t[]> pcm_data = std::make_unique<int16_t[]>(length);
364 memcpy(pcm_data.get(), decoded.getData(), length * sizeof(int16_t));
365 std::unique_ptr<mono_float[]> buffer = std::make_unique<mono_float[]>(length);
366 utils::pcmToFloatData(buffer.get(), pcm_data.get(), length);
367
368 if (data.count("samples_stereo")) {
369 MemoryOutputStream decoded_stereo(length * sizeof(int16_t));
370 std::string wave_data_stereo = data["samples_stereo"];
371 Base64::convertFromBase64(decoded_stereo, wave_data_stereo);
372 std::unique_ptr<int16_t[]> pcm_data_stereo = std::make_unique<int16_t[]>(length);
373 memcpy(pcm_data_stereo.get(), decoded_stereo.getData(), length * sizeof(int16_t));
374
375 std::unique_ptr<mono_float[]> buffer_stereo = std::make_unique<mono_float[]>(length);
376 utils::pcmToFloatData(buffer_stereo.get(), pcm_data_stereo.get(), length);
377 loadSample(buffer.get(), buffer_stereo.get(), length, sample_rate);
378 }
379 else
380 loadSample(buffer.get(), length, sample_rate);
381 }
382
383 //================== SampleSource Implementation =======================//
384
385 SampleSource::SampleSource() : Processor(kNumInputs, kNumOutputs), pan_amplitude_(0.0f), phase_inc_(0.0f),
386 random_generator_(0.0f, 1.0f) {
387 transpose_quantize_ = 0;
388 last_quantized_transpose_ = 0.0f;
389 sample_index_ = 0;
390 sample_fraction_ = 0.0f;
391
392 sample_ = std::make_shared<Sample>();
393 phase_output_ = std::make_shared<cr::Output>();
394 }
395
396 void SampleSource::process(int num_samples) {
397 // Main audio processing logic: updates sample playback position,
398 // handles loop/bounce logic, applies pitch transposition, and fills outputs.
399 sample_->markUsed();
400
401 poly_float current_pan_amplitude = pan_amplitude_;
402 poly_float input_pan = utils::clamp(input(kPan)->at(0), -1.0f, 1.0f);
403 pan_amplitude_ = futils::panAmplitude(input_pan);
404
405 poly_float input_midi = 0.0f;
406 if (input(kKeytrack)->at(0)[0])
407 input_midi = input(kMidi)->at(0) - kMidiTrackCenter;
408
409 int transpose_quantize = static_cast<int>(input(kTransposeQuantize)->at(0)[0]);
410 poly_float transpose = snapTranspose(input_midi, input(kTranspose)->at(0), transpose_quantize);
411 transpose = utils::clamp(transpose + input(kTune)->at(0), kMinTranspose, kMaxTranspose);
412
413 mono_float sample_rate_ratio = (1.0f * sample_->activeSampleRate()) / getSampleRate();
414 poly_float current_phase_inc = phase_inc_;
415 phase_inc_ = utils::centsToRatio(transpose * kCentsPerNote) * sample_rate_ratio * (1 << Sample::kUpsampleTimes);
416
417 int audio_length = sample_->activeLength();
418 poly_mask reset_mask = getResetMask(kReset);
419 poly_float reset_offset = utils::toFloat(input(kReset)->source->trigger_offset);
420 current_pan_amplitude = utils::maskLoad(current_pan_amplitude, pan_amplitude_, reset_mask);
421 current_phase_inc = utils::maskLoad(current_phase_inc, phase_inc_, reset_mask);
422 bounce_mask_ = bounce_mask_ & ~reset_mask;
423 reset_offset *= current_phase_inc;
424
425 poly_float reset_value = -reset_offset;
426 if (input(kRandomPhase)->at(0)[0]) {
427 reset_value = random_generator_.next() * audio_length;
428 reset_value = utils::maskLoad(reset_value, random_generator_.next() * audio_length, constants::kFirstMask);
429 reset_value -= reset_offset;
430 }
431
432 sample_index_ = utils::maskLoad(sample_index_, utils::floor(reset_value), reset_mask);
433 sample_fraction_ = utils::maskLoad(sample_fraction_, reset_value - sample_index_, reset_mask);
434
435 bool loop = input(kLoop)->at(0)[0] != 0.0f;
436 poly_mask loop_enabled_mask = 0;
437 if (loop)
438 loop_enabled_mask = constants::kFullMask;
439
440 bool bounce = input(kBounce)->at(0)[0] != 0.0f;
441 poly_mask bounce_enabled_mask = 0;
442 if (bounce)
443 bounce_enabled_mask = constants::kFullMask;
444 else
445 bounce_mask_ = 0;
446
447 const mono_float* audio_buffers[poly_float::kSize];
448 poly_float phase_mult = 1.0f;
449 for (int i = 0; i < poly_float::kSize; ++i) {
450 int index = sample_->getActiveIndex(phase_inc_[i]);
451 if (loop && !bounce) {
452 if (i % 2)
453 audio_buffers[i] = sample_->getActiveRightLoopBuffer(index);
454 else
455 audio_buffers[i] = sample_->getActiveLeftLoopBuffer(index);
456 }
457 else {
458 if (i % 2)
459 audio_buffers[i] = sample_->getActiveRightBuffer(index);
460 else
461 audio_buffers[i] = sample_->getActiveLeftBuffer(index);
462 }
463
464 phase_mult.set(i, 1.0f / (1 << index));
465 }
466
467 mono_float sample_inc = 1.0f / num_samples;
468 poly_float delta_pan_amplitude = (pan_amplitude_ - current_pan_amplitude) * sample_inc;
469 poly_float delta_phase_inc = (phase_inc_ - current_phase_inc) * sample_inc;
470
471 poly_float* raw_output = output(kRaw)->buffer;
472 poly_float current_fraction = sample_fraction_;
473 poly_float current_index = utils::min(sample_index_, audio_length);
474
475 poly_mask current_bounce = bounce_mask_;
476 poly_int length = audio_length;
477 for (int i = 0; i < num_samples; ++i) {
478 current_phase_inc += delta_phase_inc;
479
480 poly_float adjusted = utils::maskLoad(current_index, poly_float(audio_length) - current_index, current_bounce);
481 poly_float index_phase = utils::max(adjusted, 0.0f) * phase_mult;
482 poly_float fraction_phase = current_fraction * phase_mult;
483
484 poly_int start_indices = utils::floorToInt(index_phase);
485 poly_float rounded_down_phase = utils::toFloat(start_indices);
486 poly_float t = index_phase - rounded_down_phase + fraction_phase;
487
488 t = utils::maskLoad(t, poly_float(1.0f) - t, current_bounce);
489
490 VITAL_ASSERT(poly_float::lessThan(utils::toFloat(start_indices), 0.0f).anyMask() == 0);
491 VITAL_ASSERT(poly_float::greaterThan(utils::toFloat(start_indices), audio_length).anyMask() == 0);
492
493 matrix interpolation_matrix = utils::getCatmullInterpolationMatrix(t);
494 matrix value_matrix = utils::getValueMatrix(audio_buffers, start_indices);
495 value_matrix.transpose();
496 raw_output[i] = interpolation_matrix.multiplyAndSumRows(value_matrix);
497 VITAL_ASSERT(utils::isContained(raw_output[i]));
498
499 current_fraction += current_phase_inc;
500 poly_float increment = utils::floor(current_fraction);
501 current_fraction -= increment;
502
503 current_index += increment;
504 poly_mask done_mask = poly_float::greaterThanOrEqual(current_index, audio_length);
505 poly_mask bounced_mask = done_mask & ~current_bounce & bounce_enabled_mask;
506 poly_mask loop_over_mask = done_mask & (current_bounce | ~bounce_enabled_mask) & loop_enabled_mask;
507 current_bounce = (bounced_mask | current_bounce) & ~loop_over_mask;
508
509 current_index = utils::maskLoad(current_index, current_index - audio_length, bounced_mask | loop_over_mask);
510 current_index = utils::min(audio_length, current_index);
511 current_fraction = current_fraction & ~done_mask;
512 }
513
514 bounce_mask_ = current_bounce;
515 if (reset_mask.anyMask())
517
518 const poly_float* level_input = input(kLevel)->source->buffer;
519 poly_float* levelled_output = output(kLevelled)->buffer;
520 poly_float zero = 0.0f;
522 for (int i = 0; i < num_samples; ++i) {
523 current_pan_amplitude += delta_pan_amplitude;
524 poly_float level = utils::clamp(level_input[i], zero, max);
525 levelled_output[i] = current_pan_amplitude * level * level * raw_output[i];
526 }
527
528 sample_index_ = current_index;
529 sample_fraction_ = current_fraction;
530 poly_float phase = utils::maskLoad(sample_index_, poly_float(audio_length) - sample_index_, bounce_mask_);
531 phase = phase * (1.0f / audio_length);
532 phase_output_->buffer[0] = utils::encodePhaseAndVoice(phase, input(kNoteCount)->at(0));
533
534 sample_->markUnused();
535 }
536
537 force_inline poly_float SampleSource::snapTranspose(poly_float input_midi, poly_float transpose, int quantize) {
538 // If not quantizing, just return input_midi + transpose.
539 // Otherwise, apply quantization logic, possibly referencing last_quantized_transpose_.
540 if (quantize == 0)
541 return input_midi + transpose;
542
543 bool global_transpose = utils::isTransposeQuantizeGlobal(quantize);
544 poly_float pre_add = 0.0f;
545 poly_float post_add = input_midi;
546 if (global_transpose) {
547 pre_add = input_midi;
548 post_add = 0.0f;
549 }
550
551 poly_float snapped = utils::snapTranspose(pre_add + transpose, quantize);
552
553 if (transpose_quantize_)
554 phase_inc_ *= utils::noteOffsetToRatio(snapped - last_quantized_transpose_);
555
556 last_quantized_transpose_ = snapped;
557 transpose_quantize_ = quantize;
558 return post_add + snapped;
559 }
560} // namespace vital
Base class for all signal-processing units in Vital.
Definition processor.h:212
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
force_inline poly_mask getResetMask(int input_index) const
Retrieves a mask indicating which voices triggered a note-on event. Compares the input's trigger_valu...
Definition processor.h:360
force_inline Output * output(unsigned int index=0) const
Retrieves the Output pointer at a given index.
Definition processor.h:616
force_inline void clearOutputBufferForReset(poly_mask reset_mask, int input_index, int output_index) const
Clears output samples for voices that are about to be reset, based on the trigger offset.
Definition processor.h:373
static constexpr int kMinSize
Minimum sample size for further downsampling.
Definition sample_source.h:34
force_inline const mono_float * buffer() const
Returns a pointer to the (current) left channel buffer at the base upsample level.
Definition sample_source.h:121
SampleData * current_data_
Pointer to the currently loaded data.
Definition sample_source.h:202
Sample()
Default constructor. Initializes the sample with default noise data.
Definition sample_source.cpp:291
static constexpr int kDefaultSampleLength
Default length for a newly created (noise) sample if none is provided.
Definition sample_source.h:28
static constexpr int kBufferSamples
Extra buffer samples at start and end to avoid interpolation issues.
Definition sample_source.h:32
static constexpr int kUpsampleTimes
Upsampling factor exponent (i.e., 1 << kUpsampleTimes).
Definition sample_source.h:30
void loadSample(const mono_float *buffer, int size, int sample_rate)
Loads a mono sample from raw float data.
Definition sample_source.cpp:295
void init()
Generates default data for the sample (e.g., random noise).
Definition sample_source.cpp:321
std::unique_ptr< SampleData > data_
Owned sample data for this sample.
Definition sample_source.h:204
std::atomic< SampleData * > active_audio_data_
Atomic pointer to data in active use.
Definition sample_source.h:203
std::string name_
The user-facing name of the sample.
Definition sample_source.h:200
void jsonToState(json data)
Restores the sample's state from a JSON object (including audio data).
Definition sample_source.cpp:351
json stateToJson()
Exports the sample state (metadata and sample data) to a JSON object.
Definition sample_source.cpp:333
static constexpr int kNumDownsampleTaps
Number of taps used in the downsampling filter.
Definition sample_source.h:224
static constexpr int kNumUpsampleTaps
Number of taps used in the upsampling filter.
Definition sample_source.h:226
@ kRandomPhase
If true, randomize phase on note start.
Definition sample_source.h:237
@ kLevel
Overall amplitude scale.
Definition sample_source.h:236
@ kKeytrack
Boolean-like input indicating if MIDI note should track pitch.
Definition sample_source.h:235
@ kTune
Fine-tune in cents.
Definition sample_source.h:240
@ kTransposeQuantize
Quantize transposition to scale or semitones.
Definition sample_source.h:239
@ kNoteCount
Tracks how many notes have been pressed.
Definition sample_source.h:244
@ kLoop
If non-zero, the sample loops.
Definition sample_source.h:241
@ kMidi
MIDI note input.
Definition sample_source.h:234
@ kPan
Stereo panning control.
Definition sample_source.h:243
@ kReset
Reset signal (trigger) to re-initialize playback.
Definition sample_source.h:233
@ kBounce
If non-zero, sample playback bounces (back/forth).
Definition sample_source.h:242
@ kTranspose
Transposition in semitones from the current note.
Definition sample_source.h:238
SampleSource()
Default constructor initializes internal state and random generator.
Definition sample_source.cpp:385
virtual void process(int num_samples) override
Processes audio for num_samples, reading from the Sample and applying pitch, loop,...
Definition sample_source.cpp:396
static constexpr mono_float kMaxAmplitude
Maximum amplitude scale (usually sqrt(2) for stereo).
Definition sample_source.h:221
static constexpr mono_float kMinTranspose
Minimum negative transposition in semitones.
Definition sample_source.h:219
@ kRaw
The raw sample output (before final amplitude).
Definition sample_source.h:253
@ kLevelled
The amplitude-scaled output.
Definition sample_source.h:254
static constexpr mono_float kMaxTranspose
Maximum positive transposition in semitones.
Definition sample_source.h:217
A basic random number generator for producing uniform distributions of floats.
Definition utils.h:61
force_inline mono_float next()
Returns the next random float in [min, max].
Definition utils.h:85
#define VITAL_ASSERT(x)
Definition common.h:11
#define force_inline
Definition common.h:23
Contains faster but less accurate versions of utility math functions, such as exponential,...
nlohmann::json json
Definition line_generator.h:7
const poly_mask kFullMask
A mask covering all lanes of a poly_float vector.
Definition synth_constants.h:257
const poly_mask kFirstMask
A mask identifying the first voice slots in a polyphonic vector.
Definition synth_constants.h:266
force_inline poly_float panAmplitude(poly_float pan)
Definition futils.h:439
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 encodePhaseAndVoice(poly_float phase, poly_float voice)
Encodes a phase [0..1) and a voice index into a single float, storing the voice in the integer portio...
Definition poly_utils.h:979
force_inline bool isTransposeQuantizeGlobal(int quantize)
Checks if the transpose quantize mask applies globally (over multiple octaves).
Definition poly_utils.h:964
force_inline poly_float floor(poly_float value)
Floors each lane in value.
Definition poly_utils.h:777
force_inline poly_float min(poly_float left, poly_float right)
Returns the minimum of two poly_floats lane-by-lane.
Definition poly_utils.h:334
void floatToPcmData(int16_t *pcm_data, const float *float_data, int size)
Converts floating-point audio data to 16-bit PCM data.
Definition utils.cpp:77
force_inline bool isContained(poly_float value)
Checks if all lanes in a poly_float are within a broad range [-8000..8000].
Definition poly_utils.h:631
force_inline poly_float max(poly_float left, poly_float right)
Returns the maximum of two poly_floats lane-by-lane.
Definition poly_utils.h:327
force_inline matrix getCatmullInterpolationMatrix(poly_float t)
Creates a Catmull-Rom interpolation matrix from a poly_float t.
Definition poly_utils.h:227
force_inline matrix getValueMatrix(const mono_float *buffer, poly_int indices)
Creates a matrix of 4 poly_float lanes from a single buffer at varying indices.
Definition poly_utils.h:262
force_inline poly_float snapTranspose(poly_float transpose, int quantize)
Snaps a MIDI transpose value to a quantization mask (e.g., scale degrees).
Definition poly_utils.h:908
force_inline poly_int floorToInt(poly_float value)
Floors each lane and returns the result as an integer.
Definition poly_utils.h:785
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
void pcmToFloatData(float *float_data, const int16_t *pcm_data, int size)
Converts 16-bit PCM data to floating-point audio data.
Definition utils.cpp:94
force_inline poly_float noteOffsetToRatio(poly_float value)
Converts note offsets to frequency ratios. Similar to centsToRatio, but may differ in how offset is d...
Definition poly_utils.h:102
force_inline poly_float centsToRatio(poly_float value)
Converts semitone cents to a linear frequency ratio (vectorized).
Definition poly_utils.h:95
Contains classes and functions used within the Vital synthesizer framework.
constexpr int kDefaultSampleRate
Default sample rate in Hz.
Definition common.h:41
constexpr int kMidiTrackCenter
MIDI note considered as center (Middle C).
Definition common.h:45
constexpr int kCentsPerNote
Number of cents per semitone.
Definition common.h:52
float mono_float
Definition common.h:33
Declares the Sample and SampleSource classes for loading, managing, and playing back audio samples in...
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
A structure representing a 4x1 matrix of poly_float rows.
Definition matrix.h:19
force_inline poly_float multiplyAndSumRows(const matrix &other)
Multiplies and sums corresponding rows of this matrix with another matrix.
Definition matrix.h:93
force_inline void transpose()
Transposes the matrix in-place.
Definition matrix.h:44
Represents a vector of floating-point values using SIMD instructions.
Definition poly_values.h:600
static force_inline mask_simd_type vector_call greaterThanOrEqual(simd_type one, simd_type two)
Compares two SIMD float registers, element-wise, for greater than or equal.
Definition poly_values.h:987
static force_inline poly_mask vector_call lessThan(poly_float one, poly_float two)
Definition poly_values.h:1105
force_inline void vector_call set(size_t index, float new_value) noexcept
Sets a specific element in the SIMD register.
Definition poly_values.h:1182
static force_inline mask_simd_type vector_call greaterThan(simd_type one, simd_type two)
Compares two SIMD float registers, element-wise, for greater than.
Definition poly_values.h:971
Represents a vector of integer values using SIMD instructions.
Definition poly_values.h:56
static force_inline uint32_t vector_call anyMask(simd_type value)
Returns a bitmask that indicates which bytes/elements in the register are non-zero.
Definition poly_values.h:352