1 // Copyright 2014 Emilie Gillet.
2 //
3 // Author: Emilie Gillet (emilie.o.gillet@gmail.com)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // THE SOFTWARE.
22 //
23 // See http://creativecommons.org/licenses/MIT/ for more information.
24 //
25 // -----------------------------------------------------------------------------
26 //
27 // Main processing class.
28
29 #include "clouds/dsp/granular_processor.h"
30
31 #include <cstring>
32
33 #include "clouds/drivers/debug_pin.h"
34
35 #include "stmlib/dsp/parameter_interpolator.h"
36 #include "stmlib/utils/buffer_allocator.h"
37
38 #include "clouds/resources.h"
39
40 namespace clouds {
41
42 using namespace std;
43 using namespace stmlib;
44
Init(void * large_buffer,size_t large_buffer_size,void * small_buffer,size_t small_buffer_size)45 void GranularProcessor::Init(
46 void* large_buffer, size_t large_buffer_size,
47 void* small_buffer, size_t small_buffer_size) {
48 buffer_[0] = large_buffer;
49 buffer_[1] = small_buffer;
50 buffer_size_[0] = large_buffer_size;
51 buffer_size_[1] = small_buffer_size;
52
53 num_channels_ = 2;
54 low_fidelity_ = false;
55 bypass_ = false;
56
57 src_down_.Init();
58 src_up_.Init();
59
60 ResetFilters();
61
62 previous_playback_mode_ = PLAYBACK_MODE_LAST;
63 reset_buffers_ = true;
64 dry_wet_ = 0.0f;
65 }
66
ResetFilters()67 void GranularProcessor::ResetFilters() {
68 for (int32_t i = 0; i < 2; ++i) {
69 fb_filter_[i].Init();
70 lp_filter_[i].Init();
71 hp_filter_[i].Init();
72 }
73 }
74
ProcessGranular(FloatFrame * input,FloatFrame * output,size_t size)75 void GranularProcessor::ProcessGranular(
76 FloatFrame* input,
77 FloatFrame* output,
78 size_t size) {
79 // At the exception of the spectral mode, all modes require the incoming
80 // audio signal to be written to the recording buffer.
81 if (playback_mode_ != PLAYBACK_MODE_SPECTRAL) {
82 const float* input_samples = &input[0].l;
83 for (int32_t i = 0; i < num_channels_; ++i) {
84 if (resolution() == 8) {
85 buffer_8_[i].WriteFade(
86 &input_samples[i], size, 2, !parameters_.freeze);
87 } else {
88 buffer_16_[i].WriteFade(
89 &input_samples[i], size, 2, !parameters_.freeze);
90 }
91 }
92 }
93
94 switch (playback_mode_) {
95 case PLAYBACK_MODE_GRANULAR:
96 // In Granular mode, DENSITY is a meta parameter.
97 parameters_.granular.use_deterministic_seed = parameters_.density < 0.5f;
98 if (parameters_.density >= 0.53f) {
99 parameters_.granular.overlap = (parameters_.density - 0.53f) * 2.12f;
100 } else if (parameters_.density <= 0.47f) {
101 parameters_.granular.overlap = (0.47f - parameters_.density) * 2.12f;
102 } else {
103 parameters_.granular.overlap = 0.0f;
104 }
105 // And TEXTURE too.
106 parameters_.granular.window_shape = parameters_.texture < 0.75f
107 ? parameters_.texture * 1.333f : 1.0f;
108
109 if (resolution() == 8) {
110 player_.Play(buffer_8_, parameters_, &output[0].l, size);
111 } else {
112 player_.Play(buffer_16_, parameters_, &output[0].l, size);
113 }
114 break;
115
116 case PLAYBACK_MODE_STRETCH:
117 if (resolution() == 8) {
118 ws_player_.Play(buffer_8_, parameters_, &output[0].l, size);
119 } else {
120 ws_player_.Play(buffer_16_, parameters_, &output[0].l, size);
121 }
122 break;
123
124 case PLAYBACK_MODE_LOOPING_DELAY:
125 if (resolution() == 8) {
126 looper_.Play(buffer_8_, parameters_, &output[0].l, size);
127 } else {
128 looper_.Play(buffer_16_, parameters_, &output[0].l, size);
129 }
130 break;
131
132 case PLAYBACK_MODE_SPECTRAL:
133 {
134 parameters_.spectral.quantization = parameters_.texture;
135 parameters_.spectral.refresh_rate = 0.01f + 0.99f * parameters_.density;
136 float warp = parameters_.size - 0.5f;
137 parameters_.spectral.warp = 4.0f * warp * warp * warp + 0.5f;
138
139 float randomization = parameters_.density - 0.5f;
140 randomization *= randomization * 4.2f;
141 randomization -= 0.05f;
142 CONSTRAIN(randomization, 0.0f, 1.0f);
143 parameters_.spectral.phase_randomization = randomization;
144 phase_vocoder_.Process(parameters_, input, output, size);
145
146 if (num_channels_ == 1) {
147 for (size_t i = 0; i < size; ++i) {
148 output[i].r = output[i].l;
149 }
150 }
151 }
152 break;
153
154 default:
155 break;
156 }
157 }
158
Process(ShortFrame * input,ShortFrame * output,size_t size)159 void GranularProcessor::Process(
160 ShortFrame* input,
161 ShortFrame* output,
162 size_t size) {
163 // TIC
164 if (bypass_) {
165 copy(&input[0], &input[size], &output[0]);
166 return;
167 }
168
169 if (silence_ || reset_buffers_ ||
170 previous_playback_mode_ != playback_mode_) {
171 short* output_samples = &output[0].l;
172 fill(&output_samples[0], &output_samples[size << 1], 0);
173 return;
174 }
175
176 // Convert input buffers to float, and mixdown for mono processing.
177 for (size_t i = 0; i < size; ++i) {
178 in_[i].l = static_cast<float>(input[i].l) / 32768.0f;
179 in_[i].r = static_cast<float>(input[i].r) / 32768.0f;
180 }
181 if (num_channels_ == 1) {
182 for (size_t i = 0; i < size; ++i) {
183 in_[i].l = (in_[i].l + in_[i].r) * 0.5f;
184 in_[i].r = in_[i].l;
185 }
186 }
187
188 // Apply feedback, with high-pass filtering to prevent build-ups at very
189 // low frequencies (causing large DC swings).
190 ONE_POLE(freeze_lp_, parameters_.freeze ? 1.0f : 0.0f, 0.0005f)
191 float feedback = parameters_.feedback;
192 float cutoff = (20.0f + 100.0f * feedback * feedback) / sample_rate();
193 fb_filter_[0].set_f_q<FREQUENCY_FAST>(cutoff, 1.0f);
194 fb_filter_[1].set(fb_filter_[0]);
195 fb_filter_[0].Process<FILTER_MODE_HIGH_PASS>(&fb_[0].l, &fb_[0].l, size, 2);
196 fb_filter_[1].Process<FILTER_MODE_HIGH_PASS>(&fb_[0].r, &fb_[0].r, size, 2);
197 float fb_gain = feedback * (1.0f - freeze_lp_);
198 for (size_t i = 0; i < size; ++i) {
199 in_[i].l += fb_gain * (
200 SoftLimit(fb_gain * 1.4f * fb_[i].l + in_[i].l) - in_[i].l);
201 in_[i].r += fb_gain * (
202 SoftLimit(fb_gain * 1.4f * fb_[i].r + in_[i].r) - in_[i].r);
203 }
204
205 if (low_fidelity_) {
206 size_t downsampled_size = size / kDownsamplingFactor;
207 src_down_.Process(in_, in_downsampled_,size);
208 ProcessGranular(in_downsampled_, out_downsampled_, downsampled_size);
209 src_up_.Process(out_downsampled_, out_, downsampled_size);
210 } else {
211 ProcessGranular(in_, out_, size);
212 }
213
214 // Diffusion and pitch-shifting post-processings.
215 if (playback_mode_ != PLAYBACK_MODE_SPECTRAL) {
216 float texture = parameters_.texture;
217 float diffusion = playback_mode_ == PLAYBACK_MODE_GRANULAR
218 ? texture > 0.75f ? (texture - 0.75f) * 4.0f : 0.0f
219 : parameters_.density;
220 diffuser_.set_amount(diffusion);
221 diffuser_.Process(out_, size);
222 }
223
224 if (playback_mode_ == PLAYBACK_MODE_LOOPING_DELAY &&
225 (!parameters_.freeze || looper_.synchronized())) {
226 pitch_shifter_.set_ratio(SemitonesToRatio(parameters_.pitch));
227 pitch_shifter_.set_size(parameters_.size);
228 pitch_shifter_.Process(out_, size);
229 }
230
231 // Apply filters.
232 if (playback_mode_ == PLAYBACK_MODE_LOOPING_DELAY ||
233 playback_mode_ == PLAYBACK_MODE_STRETCH) {
234 float cutoff = parameters_.texture;
235 float lp_cutoff = 0.5f * SemitonesToRatio(
236 (cutoff < 0.5f ? cutoff - 0.5f : 0.0f) * 216.0f);
237 float hp_cutoff = 0.25f * SemitonesToRatio(
238 (cutoff < 0.5f ? -0.5f : cutoff - 1.0f) * 216.0f);
239 CONSTRAIN(lp_cutoff, 0.0f, 0.499f);
240 CONSTRAIN(hp_cutoff, 0.0f, 0.499f);
241 float lpq = 1.0f + 3.0f * (1.0f - feedback) * (0.5f - lp_cutoff);
242 lp_filter_[0].set_f_q<FREQUENCY_FAST>(lp_cutoff, lpq);
243 lp_filter_[0].Process<FILTER_MODE_LOW_PASS>(
244 &out_[0].l, &out_[0].l, size, 2);
245
246 lp_filter_[1].set(lp_filter_[0]);
247 lp_filter_[1].Process<FILTER_MODE_LOW_PASS>(
248 &out_[0].r, &out_[0].r, size, 2);
249
250 hp_filter_[0].set_f_q<FREQUENCY_FAST>(hp_cutoff, 1.0f);
251 hp_filter_[0].Process<FILTER_MODE_HIGH_PASS>(
252 &out_[0].l, &out_[0].l, size, 2);
253
254 hp_filter_[1].set(hp_filter_[0]);
255 hp_filter_[1].Process<FILTER_MODE_HIGH_PASS>(
256 &out_[0].r, &out_[0].r, size, 2);
257 }
258
259 // This is what is fed back. Reverb is not fed back.
260 copy(&out_[0], &out_[size], &fb_[0]);
261
262 // Apply reverb.
263 float reverb_amount = parameters_.reverb * 0.95f;
264 reverb_amount += feedback * (2.0f - feedback) * freeze_lp_;
265 CONSTRAIN(reverb_amount, 0.0f, 1.0f);
266
267 reverb_.set_amount(reverb_amount * 0.54f);
268 reverb_.set_diffusion(0.7f);
269 reverb_.set_time(0.35f + 0.63f * reverb_amount);
270 reverb_.set_input_gain(0.2f);
271 reverb_.set_lp(0.6f + 0.37f * feedback);
272 reverb_.Process(out_, size);
273
274 const float post_gain = 1.2f;
275 ParameterInterpolator dry_wet_mod(&dry_wet_, parameters_.dry_wet, size);
276 for (size_t i = 0; i < size; ++i) {
277 float dry_wet = dry_wet_mod.Next();
278 float fade_in = Interpolate(lut_xfade_in, dry_wet, 16.0f);
279 float fade_out = Interpolate(lut_xfade_out, dry_wet, 16.0f);
280 float l = static_cast<float>(input[i].l) / 32768.0f * fade_out;
281 float r = static_cast<float>(input[i].r) / 32768.0f * fade_out;
282 l += out_[i].l * post_gain * fade_in;
283 r += out_[i].r * post_gain * fade_in;
284 output[i].l = SoftConvert(l);
285 output[i].r = SoftConvert(r);
286 }
287 }
288
PreparePersistentData()289 void GranularProcessor::PreparePersistentData() {
290 persistent_state_.write_head[0] = low_fidelity_ ?
291 buffer_8_[0].head() : buffer_16_[0].head();
292 persistent_state_.write_head[1] = low_fidelity_ ?
293 buffer_8_[1].head() : buffer_16_[1].head();
294 persistent_state_.quality = quality();
295 persistent_state_.spectral = playback_mode() == PLAYBACK_MODE_SPECTRAL;
296 }
297
GetPersistentData(PersistentBlock * block,size_t * num_blocks)298 void GranularProcessor::GetPersistentData(
299 PersistentBlock* block, size_t *num_blocks) {
300 PersistentBlock* first_block = block;
301
302 block->tag = FourCC<'s', 't', 'a', 't'>::value;
303 block->data = &persistent_state_;
304 block->size = sizeof(PersistentState);
305 ++block;
306
307 // Create save block holding the audio buffers.
308 for (int32_t i = 0; i < num_channels_; ++i) {
309 block->tag = FourCC<'b', 'u', 'f', 'f'>::value;
310 block->data = buffer_[i];
311 block->size = buffer_size_[num_channels_ - 1];
312 ++block;
313 }
314 *num_blocks = block - first_block;
315 }
316
LoadPersistentData(const uint32_t * data)317 bool GranularProcessor::LoadPersistentData(const uint32_t* data) {
318 // Force a silent output while the swapping of buffers takes place.
319 silence_ = true;
320
321 PersistentBlock block[4];
322 size_t num_blocks;
323 GetPersistentData(block, &num_blocks);
324
325 for (size_t i = 0; i < num_blocks; ++i) {
326 // Check that the format is correct.
327 if (block[i].tag != data[0] || block[i].size != data[1]) {
328 silence_ = false;
329 return false;
330 }
331
332 // All good. Load the data. 2 words have already been used for the block tag
333 // and the block size.
334 data += 2;
335 memcpy(block[i].data, data, block[i].size);
336 data += block[i].size / sizeof(uint32_t);
337
338 if (i == 0) {
339 // We now know from which mode the data was saved.
340 bool currently_spectral = playback_mode_ == PLAYBACK_MODE_SPECTRAL;
341 bool requires_spectral = persistent_state_.spectral;
342 if (currently_spectral ^ requires_spectral) {
343 set_playback_mode(requires_spectral
344 ? PLAYBACK_MODE_SPECTRAL
345 : PLAYBACK_MODE_GRANULAR);
346 }
347 set_quality(persistent_state_.quality);
348
349 // We can force a switch to this mode, and once everything has been
350 // initialized for this mode, we continue with the loop to copy the
351 // actual buffer data - with all state variables correctly initialized.
352 Prepare();
353 GetPersistentData(block, &num_blocks);
354 }
355 }
356
357 // We can finally reset the position of the write heads.
358 if (low_fidelity_) {
359 buffer_8_[0].Resync(persistent_state_.write_head[0]);
360 buffer_8_[1].Resync(persistent_state_.write_head[1]);
361 } else {
362 buffer_16_[0].Resync(persistent_state_.write_head[0]);
363 buffer_16_[1].Resync(persistent_state_.write_head[1]);
364 }
365 parameters_.freeze = true;
366 silence_ = false;
367 return true;
368 }
369
Prepare()370 void GranularProcessor::Prepare() {
371 bool playback_mode_changed = previous_playback_mode_ != playback_mode_;
372 bool benign_change = previous_playback_mode_ != PLAYBACK_MODE_SPECTRAL
373 && playback_mode_ != PLAYBACK_MODE_SPECTRAL
374 && previous_playback_mode_ != PLAYBACK_MODE_LAST;
375
376 if (!reset_buffers_ && playback_mode_changed && benign_change) {
377 ResetFilters();
378 pitch_shifter_.Clear();
379 previous_playback_mode_ = playback_mode_;
380 }
381
382 if ((playback_mode_changed && !benign_change) || reset_buffers_) {
383 parameters_.freeze = false;
384 }
385
386 if (reset_buffers_ || (playback_mode_changed && !benign_change)) {
387 void* buffer[2];
388 size_t buffer_size[2];
389 void* workspace;
390 size_t workspace_size;
391 if (num_channels_ == 1) {
392 // Large buffer: 120k of sample memory.
393 // small buffer: fully allocated to FX workspace.
394 buffer[0] = buffer_[0];
395 buffer_size[0] = buffer_size_[0];
396 buffer[1] = NULL;
397 buffer_size[1] = 0;
398 workspace = buffer_[1];
399 workspace_size = buffer_size_[1];
400 } else {
401 // Large buffer: 64k of sample memory + FX workspace.
402 // small buffer: 64k of sample memory.
403 buffer_size[0] = buffer_size[1] = buffer_size_[1];
404 buffer[0] = buffer_[0];
405 buffer[1] = buffer_[1];
406
407 workspace_size = buffer_size_[0] - buffer_size_[1];
408 workspace = static_cast<uint8_t*>(buffer[0]) + buffer_size[0];
409 }
410 float sr = sample_rate();
411
412 BufferAllocator allocator(workspace, workspace_size);
413 diffuser_.Init(allocator.Allocate<float>(2048));
414 reverb_.Init(allocator.Allocate<uint16_t>(16384));
415
416 size_t correlator_block_size = (kMaxWSOLASize / 32) + 2;
417 uint32_t* correlator_data = allocator.Allocate<uint32_t>(
418 correlator_block_size * 3);
419 correlator_.Init(
420 &correlator_data[0],
421 &correlator_data[correlator_block_size]);
422 pitch_shifter_.Init((uint16_t*)correlator_data);
423
424 if (playback_mode_ == PLAYBACK_MODE_SPECTRAL) {
425 phase_vocoder_.Init(
426 buffer, buffer_size,
427 lut_sine_window_4096, 4096,
428 num_channels_, resolution(), sr);
429 } else {
430 for (int32_t i = 0; i < num_channels_; ++i) {
431 if (resolution() == 8) {
432 buffer_8_[i].Init(
433 buffer[i],
434 (buffer_size[i]),
435 tail_buffer_[i]);
436 } else {
437 buffer_16_[i].Init(
438 buffer[i],
439 ((buffer_size[i]) >> 1),
440 tail_buffer_[i]);
441 }
442 }
443 int32_t num_grains = (num_channels_ == 1 ? 40 : 32) * \
444 (low_fidelity_ ? 23 : 16) >> 4;
445 player_.Init(num_channels_, num_grains);
446 ws_player_.Init(&correlator_, num_channels_);
447 looper_.Init(num_channels_);
448 }
449 reset_buffers_ = false;
450 previous_playback_mode_ = playback_mode_;
451 }
452
453 if (playback_mode_ == PLAYBACK_MODE_SPECTRAL) {
454 phase_vocoder_.Buffer();
455 } else if (playback_mode_ == PLAYBACK_MODE_STRETCH) {
456 if (resolution() == 8) {
457 ws_player_.LoadCorrelator(buffer_8_);
458 } else {
459 ws_player_.LoadCorrelator(buffer_16_);
460 }
461 correlator_.EvaluateSomeCandidates();
462 }
463 }
464
465 } // namespace clouds
466