3 * Copyright (C) 2017-2019 Adam Williams <broadcast at earthling dot net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "confirmsave.h"
23 #include "bcsignals.h"
28 #include "reverbwindow.h"
30 #include "transportque.inc"
41 PluginClient* new_plugin(PluginServer *server)
43 return new Reverb(server);
46 Reverb::Reverb(PluginServer *server)
47 : PluginAClient(server)
67 for( int i = 0; i < total_in_buffers; i++ ) {
69 delete [] ref_channels[i];
70 delete [] ref_offsets[i];
71 delete [] ref_levels[i];
77 delete [] ref_channels;
78 delete [] ref_offsets;
85 const char* Reverb::plugin_title() { return N_("Reverb"); }
86 int Reverb::is_realtime() { return 1; }
87 int Reverb::is_multichannel() { return 1; }
88 int Reverb::is_synthesis() { return 1; }
95 for( int i = 0; i < PluginClient::total_in_buffers; i++ )
96 if( fft[i] ) fft[i]->delete_fft();
99 for( int i = 0; i < PluginClient::total_in_buffers; i++ ) {
100 if( !dsp_in[i] ) continue;
101 bzero(dsp_in[i], sizeof(double) * dsp_in_allocated);
104 need_reconfigure = 1;
107 void Reverb::render_stop()
113 int Reverb::process_buffer(int64_t size, Samples **buffer,
114 int64_t start_position, int sample_rate)
116 start_pos = (double)start_position / sample_rate;
117 dir = get_direction() == PLAY_REVERSE ? -1 : 1;
118 need_reconfigure |= load_configuration();
120 if( need_reconfigure ) {
121 need_reconfigure = 0;
123 calculate_envelope();
125 if( fft && fft[0]->window_size != config.window_size ) {
126 for( int i = 0; i < PluginClient::total_in_buffers; i++ )
128 delete [] fft; fft = 0;
132 fft = new ReverbFFT*[PluginClient::total_in_buffers];
133 for( int i = 0; i < PluginClient::total_in_buffers; i++ ) {
134 fft[i] = new ReverbFFT(this, i);
135 fft[i]->initialize(config.window_size);
139 // allocate the stuff
141 dsp_in = new double*[PluginClient::total_in_buffers];
142 ref_channels = new int*[PluginClient::total_in_buffers];
143 ref_offsets = new int*[PluginClient::total_in_buffers];
144 ref_levels = new double*[PluginClient::total_in_buffers];
145 for( int i = 0; i < PluginClient::total_in_buffers; i++ ) {
151 engine = new ReverbEngine(this);
155 for( int i = 0; i < PluginClient::total_in_buffers; i++ ) {
156 delete [] ref_channels[i]; ref_channels[i] = new int[config.ref_total];
157 delete [] ref_offsets[i]; ref_offsets[i] = new int[config.ref_total];
158 delete [] ref_levels[i]; ref_levels[i] = new double[config.ref_total];
160 // 1st reflection is fixed by the user
161 ref_channels[i][0] = i;
162 ref_offsets[i][0] = config.delay_init * project_sample_rate / 1000;
163 ref_levels[i][0] = db.fromdb(config.ref_level1);
165 int64_t ref_division = config.ref_length *
166 project_sample_rate / 1000 / (config.ref_total + 1);
167 for( int j = 1; j < config.ref_total; j++ ) {
168 // set random channels for remaining reflections
169 ref_channels[i][j] = rand() % total_in_buffers;
171 // set random offsets after first reflection
172 ref_offsets[i][j] = ref_offsets[i][0];
173 ref_offsets[i][j] += ref_division * j - (rand() % ref_division) / 2;
174 // set changing levels
175 double level_db = config.ref_level1 +
176 (config.ref_level2 - config.ref_level1) *
177 (j - 1) / (config.ref_total - 1);
178 ref_levels[i][j] = DB::fromdb(level_db);
183 // guess DSP allocation from the reflection time & requested samples
184 int new_dsp_allocated = size +
185 ((int64_t)config.delay_init + config.ref_length) *
186 project_sample_rate / 1000 + 1;
187 reallocate_dsp(new_dsp_allocated);
189 // Always read in the new samples & process the bandpass, even if there is no
190 // bandpass. This way the user can tweek the bandpass without causing glitches.
191 for( int i = 0; i < PluginClient::total_in_buffers; i++ ) {
192 new_dsp_length = dsp_in_length;
193 new_spectrogram_frames = 0;
194 fft[i]->process_buffer(start_position, size,
195 buffer[i], // temporary storage for the bandpassed output
199 // update the length with what the FFT reads appended
200 dsp_in_length = new_dsp_length;
202 // now paint the reflections
203 engine->process_packages();
205 // copy the DSP buffer to the output
206 for( int i = 0; i < PluginClient::total_in_buffers; i++ ) {
207 memcpy(buffer[i]->get_data(), dsp_in[i], size * sizeof(double));
210 // shift the DSP buffer forward
211 int remain = dsp_in_allocated - size;
212 for( int i = 0; i < PluginClient::total_in_buffers; i++ ) {
213 memcpy(dsp_in[i], dsp_in[i] + size, remain * sizeof(double));
214 bzero(dsp_in[i] + remain, size * sizeof(double));
217 dsp_in_length -= size;
218 last_position = start_position + dir * size;
223 void Reverb::reallocate_dsp(int new_dsp_allocated)
225 if( new_dsp_allocated > dsp_in_allocated ) {
226 // copy samples already read into the new buffers
227 for( int i = 0; i < PluginClient::total_in_buffers; i++ ) {
228 double *old_dsp = dsp_in[i];
229 double *new_dsp = new double[new_dsp_allocated];
232 memcpy(new_dsp, old_dsp, sizeof(double) * dsp_in_length);
235 bzero(new_dsp + dsp_in_allocated,
236 sizeof(double) * (new_dsp_allocated - dsp_in_allocated));
239 dsp_in_allocated = new_dsp_allocated;
245 double Reverb::gauss(double sigma, double center, double x)
247 if( EQUIV(sigma, 0) ) sigma = 0.01;
249 double result = 1.0 / sqrt(2 * M_PI * sigma * sigma) *
250 exp(-(x - center) * (x - center) / (2 * sigma * sigma));
254 void Reverb::calculate_envelope()
256 // assume the window size changed
258 int window_size2 = config.window_size/2;
259 envelope = new double[window_size2];
261 int max_freq = Freq::tofreq_f(TOTALFREQS-1);
262 int nyquist = PluginAClient::project_sample_rate/2;
263 int low = config.low;
264 int high = config.high;
266 // limit the frequencies
267 if( high >= max_freq ) high = nyquist;
268 if( low > high ) low = high;
270 // frequency slots of the edge
271 double edge = (1.0 - config.q) * TOTALFREQS/2;
272 double low_slot = Freq::fromfreq_f(low);
273 double high_slot = Freq::fromfreq_f(high);
274 for( int i = 0; i < window_size2; i++ ) {
275 double freq = i * nyquist / window_size2;
276 double slot = Freq::fromfreq_f(freq);
278 // printf("Reverb::calculate_envelope %d i=%d freq=%f slot=%f slot1=%f\n",
279 // __LINE__, i, freq, slot, low_slot - edge);
280 if( slot < low_slot - edge ) {
283 else if( slot < low_slot ) {
284 #ifndef LOG_CROSSOVER
285 envelope[i] = 1.0 - (low_slot - slot) / edge;
287 envelope[i] = DB::fromdb((low_slot - slot) * INFINITYGAIN / edge);
290 else if( slot < high_slot ) {
293 else if( slot < high_slot + edge ) {
294 #ifndef LOG_CROSSOVER
295 envelope[i] = 1.0 - (slot - high_slot) / edge;
297 envelope[i] = DB::fromdb((slot - high_slot) * INFINITYGAIN / edge);
307 NEW_WINDOW_MACRO(Reverb, ReverbWindow)
310 LOAD_CONFIGURATION_MACRO(Reverb, ReverbConfig)
313 void Reverb::save_data(KeyFrame *keyframe)
316 output.set_shared_output(keyframe->xbuf);
317 output.tag.set_title("REVERB");
318 output.tag.set_property("LEVELINIT", config.level_init);
319 output.tag.set_property("DELAY_INIT", config.delay_init);
320 output.tag.set_property("REF_LEVEL1", config.ref_level1);
321 output.tag.set_property("REF_LEVEL2", config.ref_level2);
322 output.tag.set_property("REF_TOTAL", config.ref_total);
323 output.tag.set_property("REF_LENGTH", config.ref_length);
324 output.tag.set_property("HIGH", config.high);
325 output.tag.set_property("LOW", config.low);
326 output.tag.set_property("Q", config.q);
327 output.tag.set_property("WINDOW_SIZE", config.window_size);
329 output.append_newline();
330 output.terminate_string();
333 void Reverb::read_data(KeyFrame *keyframe)
336 input.set_shared_input(keyframe->xbuf);
338 while( !(result = input.read_tag()) ) {
339 if( input.tag.title_is("REVERB") ) {
340 config.level_init = input.tag.get_property("LEVELINIT", config.level_init);
341 config.delay_init = input.tag.get_property("DELAY_INIT", config.delay_init);
342 config.ref_level1 = input.tag.get_property("REF_LEVEL1", config.ref_level1);
343 config.ref_level2 = input.tag.get_property("REF_LEVEL2", config.ref_level2);
344 config.ref_total = input.tag.get_property("REF_TOTAL", config.ref_total);
345 config.ref_length = input.tag.get_property("REF_LENGTH", config.ref_length);
346 config.high = input.tag.get_property("HIGH", config.high);
347 config.low = input.tag.get_property("LOW", config.low);
348 config.q = input.tag.get_property("Q", config.q);
349 config.window_size = input.tag.get_property("WINDOW_SIZE", config.window_size);
356 void Reverb::update_gui()
358 if( !thread ) return;
359 ReverbWindow *window = (ReverbWindow *)thread->window;
360 if( !window ) return;
361 int reconfigured = load_configuration();
362 int pending = pending_gui_frame();
363 if( !reconfigured && !pending ) return;
364 window->lock_window("Reverb::update_gui 1");
368 window->update_canvas();
369 window->unlock_window();
372 ReverbClientFrame::ReverbClientFrame(int size)
373 : CompressorFreqFrame()
375 data = new double[size];
376 bzero(data, sizeof(double) * size);
380 ReverbClientFrame::~ReverbClientFrame()
382 delete [] data; data = 0;
385 ReverbFFT::ReverbFFT(Reverb *plugin, int channel)
387 this->plugin = plugin;
388 this->channel = channel;
391 ReverbFFT::~ReverbFFT()
395 int ReverbFFT::signal_process()
397 // Create new spectrogram for updating the GUI
398 frame = new ReverbClientFrame(window_size/2);
399 frame->nyquist = plugin->PluginAClient::project_sample_rate/2;
400 frame->position = plugin->start_pos + plugin->dir *
401 (double)plugin->new_spectrogram_frames * frame->data_size /
402 plugin->get_samplerate();
403 plugin->add_gui_frame(frame);
405 for( int i=0; i<frame->data_size; i++ ) {
406 double env = plugin->envelope[i];
407 double fr = freq_real[i], fi = freq_imag[i];
408 // scale complex signal by envelope
409 freq_real[i] = fr * env;
410 freq_imag[i] = fi * env;
411 double mag = sqrt(fr*fr + fi*fi);
412 double out = mag * env;
413 // update the spectrogram with the output
414 if( frame->data[i] < out )
415 frame->data[i] = out;
416 // get the maximum output in the frequency domain
417 if( frame->freq_max < out )
418 frame->freq_max = out;
421 symmetry(window_size, freq_real, freq_imag);
425 int ReverbFFT::post_process()
427 // get the maximum output in the time domain
429 for( int i=0; i<window_size; ++i ) {
430 if( fabs(output_real[i]) > time_max )
431 time_max = fabs(output_real[i]);
433 if( time_max > frame->time_max )
434 frame->time_max = time_max;
436 ++plugin->new_spectrogram_frames;
441 int ReverbFFT::read_samples(int64_t output_sample, int samples, Samples *buffer)
443 int result = plugin->read_samples(buffer,
444 channel, plugin->get_samplerate(), output_sample, samples);
446 // append original samples to the DSP buffer as the initial reflection
447 int new_dsp_allocation = plugin->new_dsp_length + samples;
448 plugin->reallocate_dsp(new_dsp_allocation);
449 double *dst = plugin->dsp_in[channel] + plugin->new_dsp_length;
450 double *src = buffer->get_data();
451 double level = DB::fromdb(plugin->config.level_init);
452 if( plugin->config.level_init <= INFINITYGAIN ) {
456 for( int i = 0; i < samples; i++ ) {
457 *dst++ += *src++ * level;
460 plugin->new_dsp_length += samples;
465 ReverbPackage::ReverbPackage()
471 ReverbUnit::ReverbUnit(ReverbEngine *engine, Reverb *plugin)
474 this->plugin = plugin;
477 ReverbUnit::~ReverbUnit()
481 void ReverbUnit::process_package(LoadPackage *package)
483 ReverbPackage *pkg = (ReverbPackage*)package;
484 int channel = pkg->channel;
486 for( int i = 0; i < plugin->config.ref_total; i++ ) {
487 int src_channel = plugin->ref_channels[channel][i];
488 int dst_offset = plugin->ref_offsets[channel][i];
489 double level = plugin->ref_levels[channel][i];
490 double *dst = plugin->dsp_in[channel] + dst_offset;
491 double *src = plugin->get_output(src_channel)->get_data();
492 int size = plugin->get_buffer_size();
494 if( size + dst_offset > plugin->dsp_in_allocated ) {
495 printf("ReverbUnit::process_package %d size=%d dst_offset=%d needed=%d allocated=%d\n",
496 __LINE__, size, dst_offset, size + dst_offset, plugin->dsp_in_allocated);
499 for( int j = 0; j < size; j++ )
500 *dst++ += *src++ * level;
506 ReverbEngine::ReverbEngine(Reverb *plugin)
507 : LoadServer(plugin->PluginClient::smp + 1, plugin->total_in_buffers)
509 this->plugin = plugin;
512 ReverbEngine::~ReverbEngine()
517 void ReverbEngine::init_packages()
519 for( int i = 0; i < LoadServer::get_total_packages(); i++ ) {
520 ReverbPackage *package = (ReverbPackage*)LoadServer::get_package(i);
521 package->channel = i;
525 LoadClient* ReverbEngine::new_client()
527 return new ReverbUnit(this, plugin);
530 LoadPackage* ReverbEngine::new_package()
532 return new ReverbPackage;
536 ReverbConfig::ReverbConfig()
541 ref_level2 = INFINITYGAIN;
544 high = Freq::tofreq(TOTALFREQS);
545 low = Freq::tofreq(0);
550 int ReverbConfig::equivalent(ReverbConfig &that)
552 return (EQUIV(level_init, that.level_init) &&
553 delay_init == that.delay_init &&
554 EQUIV(ref_level1, that.ref_level1) &&
555 EQUIV(ref_level2, that.ref_level2) &&
556 ref_total == that.ref_total &&
557 ref_length == that.ref_length &&
561 window_size == that.window_size);
564 void ReverbConfig::copy_from(ReverbConfig &that)
566 level_init = that.level_init;
567 delay_init = that.delay_init;
568 ref_level1 = that.ref_level1;
569 ref_level2 = that.ref_level2;
570 ref_total = that.ref_total;
571 ref_length = that.ref_length;
575 window_size = that.window_size;
578 void ReverbConfig::interpolate(ReverbConfig &prev, ReverbConfig &next,
579 int64_t prev_frame, int64_t next_frame, int64_t current_frame)
581 level_init = prev.level_init;
582 delay_init = prev.delay_init;
583 ref_level1 = prev.ref_level1;
584 ref_level2 = prev.ref_level2;
585 ref_total = prev.ref_total;
586 ref_length = prev.ref_length;
590 window_size = prev.window_size;
593 void ReverbConfig::boundaries()
595 CLAMP(level_init, INFINITYGAIN, 0);
596 CLAMP(delay_init, 0, MAX_DELAY_INIT);
597 CLAMP(ref_level1, INFINITYGAIN, 0);
598 CLAMP(ref_level2, INFINITYGAIN, 0);
599 CLAMP(ref_total, MIN_REFLECTIONS, MAX_REFLECTIONS);
600 CLAMP(ref_length, MIN_REFLENGTH, MAX_REFLENGTH);
601 CLAMP(high, 0, Freq::tofreq(TOTALFREQS));
602 CLAMP(low, 0, Freq::tofreq(TOTALFREQS));
606 void ReverbConfig::dump()
608 printf("ReverbConfig::dump %d level_init=%f delay_init=%d ref_level1=%f"
609 " ref_level2=%f ref_total=%d ref_length=%d high=%d low=%d q=%f\n",
610 __LINE__, level_init, (int)delay_init, ref_level1, ref_level2,
611 (int)ref_total, (int)ref_length, (int)high, (int)low, q);