X-Git-Url: https://git.cinelerra-gg.org/git/?a=blobdiff_plain;ds=sidebyside;f=cinelerra-5.1%2Fplugins%2Freverb%2Freverb.C;h=7d38fe5f5d9d3538857158c4d4dc81ca25c6e160;hb=HEAD;hp=b5bddf2ae77ae67bf6032cef72e258001338e37c;hpb=7fd85fb66168f6b518c5f2d73e04036e87faa0e1;p=goodguy%2Fcinelerra.git diff --git a/cinelerra-5.1/plugins/reverb/reverb.C b/cinelerra-5.1/plugins/reverb/reverb.C index b5bddf2a..7d38fe5f 100644 --- a/cinelerra-5.1/plugins/reverb/reverb.C +++ b/cinelerra-5.1/plugins/reverb/reverb.C @@ -1,7 +1,6 @@ - /* * CINELERRA - * Copyright (C) 2017 Adam Williams + * Copyright (C) 2017-2019 Adam Williams * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include "clip.h" @@ -29,6 +27,7 @@ #include "reverb.h" #include "reverbwindow.h" #include "samples.h" +#include "transportque.inc" #include "units.h" #include "vframe.h" @@ -39,63 +38,48 @@ #include - PluginClient* new_plugin(PluginServer *server) { return new Reverb(server); } - - Reverb::Reverb(PluginServer *server) : PluginAClient(server) { srand(time(0)); - redo_buffers = 1; // set to redo buffers before the first render - dsp_in_length = 0; ref_channels = 0; ref_offsets = 0; ref_levels = 0; - ref_lowpass = 0; dsp_in = 0; - lowpass_in1 = 0; - lowpass_in2 = 0; - initialized = 0; - + dsp_in_length = 0; + dsp_in_allocated = 0; + need_reconfigure = 1; + envelope = 0; + last_position = 0; + start_pos = 0; + dir = 0; + fft = 0; } Reverb::~Reverb() { - - - if(initialized) - { - for(int i = 0; i < total_in_buffers; i++) - { + if( fft ) { + for( int i = 0; i < total_in_buffers; i++ ) { delete [] dsp_in[i]; delete [] ref_channels[i]; delete [] ref_offsets[i]; delete [] ref_levels[i]; - delete [] ref_lowpass[i]; - delete [] lowpass_in1[i]; - delete [] lowpass_in2[i]; + delete fft[i]; } + delete [] fft; delete [] dsp_in; delete [] ref_channels; delete [] ref_offsets; delete [] ref_levels; - delete [] ref_lowpass; - delete [] lowpass_in1; - delete [] lowpass_in2; - - for(int i = 0; i < (smp + 1); i++) - { - delete engine[i]; - } - delete [] engine; - initialized = 0; + delete engine; } + delete [] envelope; } const char* Reverb::plugin_title() { return N_("Reverb"); } @@ -103,184 +87,220 @@ int Reverb::is_realtime() { return 1; } int Reverb::is_multichannel() { return 1; } int Reverb::is_synthesis() { return 1; } -int Reverb::process_realtime(int64_t size, - Samples **input_ptr, - Samples **output_ptr) -{ - int64_t new_dsp_length, i, j; - main_in = new double*[total_in_buffers]; - main_out = new double*[total_in_buffers]; - for(i = 0; i < total_in_buffers; i++) - { - main_in[i] = input_ptr[i]->get_data(); - main_out[i] = output_ptr[i]->get_data(); +void Reverb::reset() +{ + dsp_in_length = 0; + if( fft ) { + for( int i = 0; i < PluginClient::total_in_buffers; i++ ) + if( fft[i] ) fft[i]->delete_fft(); } - -//printf("Reverb::process_realtime 1\n"); - redo_buffers |= load_configuration(); - -//printf("Reverb::process_realtime 1\n"); - if(!config.ref_total) - { - delete [] main_in; - delete [] main_out; - return 0; + if( dsp_in ) { + for( int i = 0; i < PluginClient::total_in_buffers; i++ ) { + if( !dsp_in[i] ) continue; + bzero(dsp_in[i], sizeof(double) * dsp_in_allocated); + } } + need_reconfigure = 1; +} + +void Reverb::render_stop() +{ + reset(); +} - if(!initialized) - { - dsp_in = new double*[total_in_buffers]; - ref_channels = new int64_t*[total_in_buffers]; - ref_offsets = new int64_t*[total_in_buffers]; - ref_levels = new double*[total_in_buffers]; - ref_lowpass = new int64_t*[total_in_buffers]; - lowpass_in1 = new double*[total_in_buffers]; - lowpass_in2 = new double*[total_in_buffers]; +int Reverb::process_buffer(int64_t size, Samples **buffer, + int64_t start_position, int sample_rate) +{ + start_pos = (double)start_position / sample_rate; + dir = get_direction() == PLAY_REVERSE ? -1 : 1; + need_reconfigure |= load_configuration(); + if( need_reconfigure ) { + need_reconfigure = 0; + calculate_envelope(); - for(i = 0; i < total_in_buffers; i++) - { - dsp_in[i] = new double[1]; - ref_channels[i] = new int64_t[1]; - ref_offsets[i] = new int64_t[1]; - ref_levels[i] = new double[1]; - ref_lowpass[i] = new int64_t[1]; - lowpass_in1[i] = new double[1]; - lowpass_in2[i] = new double[1]; + if( fft && fft[0]->window_size != config.window_size ) { + for( int i = 0; i < PluginClient::total_in_buffers; i++ ) + delete fft[i]; + delete [] fft; fft = 0; } - engine = new ReverbEngine*[(smp + 1)]; - for(i = 0; i < (smp + 1); i++) - { - engine[i] = new ReverbEngine(this); -//printf("Reverb::start_realtime %d\n", Thread::calculate_realtime()); -// Realtime priority moved to sound driver -// engine[i]->set_realtime(realtime_priority); - engine[i]->start(); + if( !fft ) { + fft = new ReverbFFT*[PluginClient::total_in_buffers]; + for( int i = 0; i < PluginClient::total_in_buffers; i++ ) { + fft[i] = new ReverbFFT(this, i); + fft[i]->initialize(config.window_size); + } } - initialized = 1; - redo_buffers = 1; - } - new_dsp_length = size + - ((int64_t)config.delay_init + config.ref_length) * project_sample_rate / 1000 + 1; +// allocate the stuff + if( !dsp_in ) { + dsp_in = new double*[PluginClient::total_in_buffers]; + ref_channels = new int*[PluginClient::total_in_buffers]; + ref_offsets = new int*[PluginClient::total_in_buffers]; + ref_levels = new double*[PluginClient::total_in_buffers]; + for( int i = 0; i < PluginClient::total_in_buffers; i++ ) { + dsp_in[i] = 0; + ref_channels[i] = 0; + ref_offsets[i] = 0; + ref_levels[i] = 0; + } + engine = new ReverbEngine(this); + } - if(redo_buffers || new_dsp_length != dsp_in_length) - { - for(i = 0; i < total_in_buffers; i++) - { - double *old_dsp = dsp_in[i]; - double *new_dsp = new double[new_dsp_length]; - for(j = 0; j < dsp_in_length && j < new_dsp_length; j++) - new_dsp[j] = old_dsp[j]; + for( int i = 0; i < PluginClient::total_in_buffers; i++ ) { + delete [] ref_channels[i]; ref_channels[i] = new int[config.ref_total]; + delete [] ref_offsets[i]; ref_offsets[i] = new int[config.ref_total]; + delete [] ref_levels[i]; ref_levels[i] = new double[config.ref_total]; - for( ; j < new_dsp_length; j++) new_dsp[j] = 0; - delete [] old_dsp; - dsp_in[i] = new_dsp; - } +// 1st reflection is fixed by the user + ref_channels[i][0] = i; + ref_offsets[i][0] = config.delay_init * project_sample_rate / 1000; + ref_levels[i][0] = db.fromdb(config.ref_level1); - dsp_in_length = new_dsp_length; - redo_buffers = 1; - } -//printf("Reverb::process_realtime 1\n"); - - if(redo_buffers) - { - for(i = 0; i < total_in_buffers; i++) - { - delete [] ref_channels[i]; - delete [] ref_offsets[i]; - delete [] ref_lowpass[i]; - delete [] ref_levels[i]; - delete [] lowpass_in1[i]; - delete [] lowpass_in2[i]; - - ref_channels[i] = new int64_t[config.ref_total + 1]; - ref_offsets[i] = new int64_t[config.ref_total + 1]; - ref_lowpass[i] = new int64_t[config.ref_total + 1]; - ref_levels[i] = new double[config.ref_total + 1]; - lowpass_in1[i] = new double[config.ref_total + 1]; - lowpass_in2[i] = new double[config.ref_total + 1]; - -// set channels - ref_channels[i][0] = i; // primary noise - ref_channels[i][1] = i; // first reflection -// set offsets - ref_offsets[i][0] = 0; - ref_offsets[i][1] = config.delay_init * project_sample_rate / 1000; -// set levels - ref_levels[i][0] = db.fromdb(config.level_init); - ref_levels[i][1] = db.fromdb(config.ref_level1); -// set lowpass - ref_lowpass[i][0] = -1; // ignore first noise - ref_lowpass[i][1] = config.lowpass1; - lowpass_in1[i][0] = 0; - lowpass_in2[i][0] = 0; - lowpass_in1[i][1] = 0; - lowpass_in2[i][1] = 0; - - int64_t ref_division = config.ref_length * project_sample_rate / 1000 / (config.ref_total + 1); - for(j = 2; j < config.ref_total + 1; j++) - { + int64_t ref_division = config.ref_length * + project_sample_rate / 1000 / (config.ref_total + 1); + for( int j = 1; j < config.ref_total; j++ ) { // set random channels for remaining reflections ref_channels[i][j] = rand() % total_in_buffers; // set random offsets after first reflection - ref_offsets[i][j] = ref_offsets[i][1]; - if( ref_division > 0 ) - ref_offsets[i][j] += ref_division * j - (rand() % ref_division) / 2; - + ref_offsets[i][j] = ref_offsets[i][0]; + ref_offsets[i][j] += ref_division * j - (rand() % ref_division) / 2; // set changing levels - ref_levels[i][j] = db.fromdb(config.ref_level1 + (config.ref_level2 - config.ref_level1) / (config.ref_total - 1) * (j - 2)); - //ref_levels[i][j] /= 100; - -// set changing lowpass as linear - ref_lowpass[i][j] = (int64_t)(config.lowpass1 + (double)(config.lowpass2 - config.lowpass1) / (config.ref_total - 1) * (j - 2)); - lowpass_in1[i][j] = 0; - lowpass_in2[i][j] = 0; + double level_db = config.ref_level1 + + (config.ref_level2 - config.ref_level1) * + (j - 1) / (config.ref_total - 1); + ref_levels[i][j] = DB::fromdb(level_db); } } + } - redo_buffers = 0; +// guess DSP allocation from the reflection time & requested samples + int new_dsp_allocated = size + + ((int64_t)config.delay_init + config.ref_length) * + project_sample_rate / 1000 + 1; + reallocate_dsp(new_dsp_allocated); + +// Always read in the new samples & process the bandpass, even if there is no +// bandpass. This way the user can tweek the bandpass without causing glitches. + for( int i = 0; i < PluginClient::total_in_buffers; i++ ) { + new_dsp_length = dsp_in_length; + new_spectrogram_frames = 0; + fft[i]->process_buffer(start_position, size, + buffer[i], // temporary storage for the bandpassed output + get_direction()); } -//printf("Reverb::process_realtime 1\n"); - for(i = 0; i < total_in_buffers; ) - { - for(j = 0; j < (smp + 1) && (i + j) < total_in_buffers; j++) - { - engine[j]->process_overlays(i + j, size); - } +// update the length with what the FFT reads appended + dsp_in_length = new_dsp_length; - for(j = 0; j < (smp + 1) && i < total_in_buffers; j++, i++) - { - engine[j]->wait_process_overlays(); - } +// now paint the reflections + engine->process_packages(); + +// copy the DSP buffer to the output + for( int i = 0; i < PluginClient::total_in_buffers; i++ ) { + memcpy(buffer[i]->get_data(), dsp_in[i], size * sizeof(double)); } -//printf("Reverb::process_realtime 2 %d %d\n", total_in_buffers, size); - for(i = 0; i < total_in_buffers; i++) - { - double *current_out = main_out[i]; - double *current_in = dsp_in[i]; +// shift the DSP buffer forward + int remain = dsp_in_allocated - size; + for( int i = 0; i < PluginClient::total_in_buffers; i++ ) { + memcpy(dsp_in[i], dsp_in[i] + size, remain * sizeof(double)); + bzero(dsp_in[i] + remain, size * sizeof(double)); + } + + dsp_in_length -= size; + last_position = start_position + dir * size; + return 0; +} - for(j = 0; j < size; j++) current_out[j] = current_in[j]; - int64_t k; - for(k = 0; j < dsp_in_length; j++, k++) current_in[k] = current_in[j]; +void Reverb::reallocate_dsp(int new_dsp_allocated) +{ + if( new_dsp_allocated > dsp_in_allocated ) { +// copy samples already read into the new buffers + for( int i = 0; i < PluginClient::total_in_buffers; i++ ) { + double *old_dsp = dsp_in[i]; + double *new_dsp = new double[new_dsp_allocated]; - for(; k < dsp_in_length; k++) current_in[k] = 0; + if( old_dsp ) { + memcpy(new_dsp, old_dsp, sizeof(double) * dsp_in_length); + delete [] old_dsp; + } + bzero(new_dsp + dsp_in_allocated, + sizeof(double) * (new_dsp_allocated - dsp_in_allocated)); + dsp_in[i] = new_dsp; + } + dsp_in_allocated = new_dsp_allocated; } -//printf("Reverb::process_realtime 2 %d %d\n", total_in_buffers, size); +} - delete [] main_in; - delete [] main_out; - return 0; + +double Reverb::gauss(double sigma, double center, double x) +{ + if( EQUIV(sigma, 0) ) sigma = 0.01; + + double result = 1.0 / sqrt(2 * M_PI * sigma * sigma) * + exp(-(x - center) * (x - center) / (2 * sigma * sigma)); + return result; +} + +void Reverb::calculate_envelope() +{ +// assume the window size changed + delete [] envelope; + int window_size2 = config.window_size/2; + envelope = new double[window_size2]; + + int max_freq = Freq::tofreq_f(TOTALFREQS-1); + int nyquist = PluginAClient::project_sample_rate/2; + int low = config.low; + int high = config.high; + +// limit the frequencies + if( high >= max_freq ) high = nyquist; + if( low > high ) low = high; + +// frequency slots of the edge + double edge = (1.0 - config.q) * TOTALFREQS/2; + double low_slot = Freq::fromfreq_f(low); + double high_slot = Freq::fromfreq_f(high); + for( int i = 0; i < window_size2; i++ ) { + double freq = i * nyquist / window_size2; + double slot = Freq::fromfreq_f(freq); + +// printf("Reverb::calculate_envelope %d i=%d freq=%f slot=%f slot1=%f\n", +// __LINE__, i, freq, slot, low_slot - edge); + if( slot < low_slot - edge ) { + envelope[i] = 0.0; + } + else if( slot < low_slot ) { +#ifndef LOG_CROSSOVER + envelope[i] = 1.0 - (low_slot - slot) / edge; +#else + envelope[i] = DB::fromdb((low_slot - slot) * INFINITYGAIN / edge); +#endif + } + else if( slot < high_slot ) { + envelope[i] = 1.0; + } + else if( slot < high_slot + edge ) { +#ifndef LOG_CROSSOVER + envelope[i] = 1.0 - (slot - high_slot) / edge; +#else + envelope[i] = DB::fromdb((slot - high_slot) * INFINITYGAIN / edge); +#endif + } + else { + envelope[i] = 0.0; + } + } } @@ -292,54 +312,41 @@ LOAD_CONFIGURATION_MACRO(Reverb, ReverbConfig) void Reverb::save_data(KeyFrame *keyframe) { -//printf("Reverb::save_data 1\n"); FileXML output; -//printf("Reverb::save_data 1\n"); - -// cause xml file to store data directly in text output.set_shared_output(keyframe->xbuf); -//printf("Reverb::save_data 1\n"); - output.tag.set_title("REVERB"); output.tag.set_property("LEVELINIT", config.level_init); output.tag.set_property("DELAY_INIT", config.delay_init); output.tag.set_property("REF_LEVEL1", config.ref_level1); output.tag.set_property("REF_LEVEL2", config.ref_level2); output.tag.set_property("REF_TOTAL", config.ref_total); -//printf("Reverb::save_data 1\n"); output.tag.set_property("REF_LENGTH", config.ref_length); - output.tag.set_property("LOWPASS1", config.lowpass1); - output.tag.set_property("LOWPASS2", config.lowpass2); -//printf("Reverb::save_data config.ref_level2 %f\n", config.ref_level2); - output.append_tag(); - output.tag.set_title("/REVERB"); + output.tag.set_property("HIGH", config.high); + output.tag.set_property("LOW", config.low); + output.tag.set_property("Q", config.q); + output.tag.set_property("WINDOW_SIZE", config.window_size); output.append_tag(); output.append_newline(); output.terminate_string(); -//printf("Reverb::save_data 2\n"); } void Reverb::read_data(KeyFrame *keyframe) { FileXML input; -// cause xml file to read directly from text input.set_shared_input(keyframe->xbuf); int result = 0; - - result = input.read_tag(); - - if(!result) - { - if(input.tag.title_is("REVERB")) - { + while( !(result = input.read_tag()) ) { + if( input.tag.title_is("REVERB") ) { config.level_init = input.tag.get_property("LEVELINIT", config.level_init); config.delay_init = input.tag.get_property("DELAY_INIT", config.delay_init); config.ref_level1 = input.tag.get_property("REF_LEVEL1", config.ref_level1); config.ref_level2 = input.tag.get_property("REF_LEVEL2", config.ref_level2); config.ref_total = input.tag.get_property("REF_TOTAL", config.ref_total); config.ref_length = input.tag.get_property("REF_LENGTH", config.ref_length); - config.lowpass1 = input.tag.get_property("LOWPASS1", config.lowpass1); - config.lowpass2 = input.tag.get_property("LOWPASS2", config.lowpass2); + config.high = input.tag.get_property("HIGH", config.high); + config.low = input.tag.get_property("LOW", config.low); + config.q = input.tag.get_property("Q", config.q); + config.window_size = input.tag.get_property("WINDOW_SIZE", config.window_size); } } @@ -348,186 +355,182 @@ void Reverb::read_data(KeyFrame *keyframe) void Reverb::update_gui() { - if(thread) - { - if(load_configuration()) - { -//printf("Reverb::update_gui %d %d\n", __LINE__, config.ref_length); - thread->window->lock_window("Reverb::update_gui"); - ((ReverbWindow*)thread->window)->level_init->update(config.level_init); - ((ReverbWindow*)thread->window)->delay_init->update(config.delay_init); - ((ReverbWindow*)thread->window)->ref_level1->update(config.ref_level1); - ((ReverbWindow*)thread->window)->ref_level2->update(config.ref_level2); - ((ReverbWindow*)thread->window)->ref_total->update(config.ref_total); - ((ReverbWindow*)thread->window)->ref_length->update(config.ref_length); - ((ReverbWindow*)thread->window)->lowpass1->update(config.lowpass1); - ((ReverbWindow*)thread->window)->lowpass2->update(config.lowpass2); - thread->window->unlock_window(); - } - } + if( !thread ) return; + ReverbWindow *window = (ReverbWindow *)thread->window; + if( !window ) return; + int reconfigured = load_configuration(); + int pending = pending_gui_frame(); + if( !reconfigured && !pending ) return; + window->lock_window("Reverb::update_gui 1"); + if( reconfigured ) + window->update(); + if( pending ) + window->update_canvas(); + window->unlock_window(); } +ReverbClientFrame::ReverbClientFrame(int size) + : CompressorFreqFrame() +{ + data = new double[size]; + bzero(data, sizeof(double) * size); + data_size = size; +} +ReverbClientFrame::~ReverbClientFrame() +{ + delete [] data; data = 0; +} - -// int Reverb::load_from_file(char *path) -// { -// FILE *in; -// int result = 0; -// int length; -// char string[1024]; -// -// if(in = fopen(path, "rb")) -// { -// fseek(in, 0, SEEK_END); -// length = ftell(in); -// fseek(in, 0, SEEK_SET); -// int temp = fread(string, length, 1, in); -// fclose(in); -// // read_data(string); -// } -// else -// { -// perror("fopen:"); -// // failed -// ErrorBox errorbox(""); -// char string[1024]; -// sprintf(string, _("Couldn't open %s."), path); -// errorbox.create_objects(string); -// errorbox.run_window(); -// result = 1; -// } -// -// return result; -// } -// -// int Reverb::save_to_file(char *path) -// { -// FILE *out; -// int result = 0; -// char string[1024]; -// -// { -// // ConfirmSave confirm; -// // result = confirm.test_file("", path); -// } -// -// if(!result) -// { -// if(out = fopen(path, "wb")) -// { -// // save_data(string); -// fwrite(string, strlen(string), 1, out); -// fclose(out); -// } -// else -// { -// result = 1; -// // failed -// ErrorBox errorbox(""); -// char string[1024]; -// sprintf(string, _("Couldn't save %s."), path); -// errorbox.create_objects(string); -// errorbox.run_window(); -// result = 1; -// } -// } -// -// return result; -// } - -ReverbEngine::ReverbEngine(Reverb *plugin) - : Thread(1, 0, 0) +ReverbFFT::ReverbFFT(Reverb *plugin, int channel) { this->plugin = plugin; - completed = 0; - input_lock.lock(); - output_lock.lock(); + this->channel = channel; } -ReverbEngine::~ReverbEngine() +ReverbFFT::~ReverbFFT() { - completed = 1; - input_lock.unlock(); - join(); } -int ReverbEngine::process_overlays(int output_buffer, int64_t size) +int ReverbFFT::signal_process() { - this->output_buffer = output_buffer; - this->size = size; - input_lock.unlock(); +// Create new spectrogram for updating the GUI + frame = new ReverbClientFrame(window_size/2); + frame->nyquist = plugin->PluginAClient::project_sample_rate/2; + frame->position = plugin->start_pos + plugin->dir * + (double)plugin->new_spectrogram_frames * frame->data_size / + plugin->get_samplerate(); + plugin->add_gui_frame(frame); + + for( int i=0; idata_size; i++ ) { + double env = plugin->envelope[i]; + double fr = freq_real[i], fi = freq_imag[i]; +// scale complex signal by envelope + freq_real[i] = fr * env; + freq_imag[i] = fi * env; + double mag = sqrt(fr*fr + fi*fi); + double out = mag * env; +// update the spectrogram with the output + if( frame->data[i] < out ) + frame->data[i] = out; +// get the maximum output in the frequency domain + if( frame->freq_max < out ) + frame->freq_max = out; + } + + symmetry(window_size, freq_real, freq_imag); return 0; } -int ReverbEngine::wait_process_overlays() +int ReverbFFT::post_process() { - output_lock.lock(); +// get the maximum output in the time domain + double time_max = 0; + for( int i=0; i time_max ) + time_max = fabs(output_real[i]); + } + if( time_max > frame->time_max ) + frame->time_max = time_max; + + ++plugin->new_spectrogram_frames; return 0; } -int ReverbEngine::process_overlay(double *in, double *out, double &out1, double &out2, double level, int64_t lowpass, int64_t samplerate, int64_t size) + +int ReverbFFT::read_samples(int64_t output_sample, int samples, Samples *buffer) { -// Modern niquist frequency is 44khz but pot limit is 20khz so can't use -// niquist - if(lowpass == -1 || lowpass >= 20000) - { -// no lowpass filter - for(int i = 0; i < size; i++) out[i] += in[i] * level; + int result = plugin->read_samples(buffer, + channel, plugin->get_samplerate(), output_sample, samples); + +// append original samples to the DSP buffer as the initial reflection + int new_dsp_allocation = plugin->new_dsp_length + samples; + plugin->reallocate_dsp(new_dsp_allocation); + double *dst = plugin->dsp_in[channel] + plugin->new_dsp_length; + double *src = buffer->get_data(); + double level = DB::fromdb(plugin->config.level_init); + if( plugin->config.level_init <= INFINITYGAIN ) { + level = 0; } - else - { - double coef = 0.25 * 2.0 * M_PI * (double)lowpass / (double)plugin->project_sample_rate; - double a = coef * 0.25; - double b = coef * 0.50; - - for(int i = 0; i < size; i++) - { - out2 += a * (3 * out1 + in[i] - out2); - out2 += b * (out1 + in[i] - out2); - out2 += a * (out1 + 3 * in[i] - out2); - out2 += coef * (in[i] - out2); - out1 = in[i]; - out[i] += out2 * level; - } + + for( int i = 0; i < samples; i++ ) { + *dst++ += *src++ * level; } - return 0; + + plugin->new_dsp_length += samples; + return result; } -void ReverbEngine::run() -{ - int j, i; -//printf("ReverbEngine::run 1 %d\n", calculate_realtime()); - while(1) - { - input_lock.lock(); - if(completed) return; - -// Process reverb - for(i = 0; i < plugin->total_in_buffers; i++) - { - for(j = 0; j < plugin->config.ref_total + 1; j++) - { - if(plugin->ref_channels[i][j] == output_buffer) - process_overlay(plugin->main_in[i], - &(plugin->dsp_in[plugin->ref_channels[i][j]][plugin->ref_offsets[i][j]]), - plugin->lowpass_in1[i][j], - plugin->lowpass_in2[i][j], - plugin->ref_levels[i][j], - plugin->ref_lowpass[i][j], - plugin->project_sample_rate, - size); - } + +ReverbPackage::ReverbPackage() + : LoadPackage() +{ +} + + +ReverbUnit::ReverbUnit(ReverbEngine *engine, Reverb *plugin) + : LoadClient(engine) +{ + this->plugin = plugin; +} + +ReverbUnit::~ReverbUnit() +{ +} + +void ReverbUnit::process_package(LoadPackage *package) +{ + ReverbPackage *pkg = (ReverbPackage*)package; + int channel = pkg->channel; + + for( int i = 0; i < plugin->config.ref_total; i++ ) { + int src_channel = plugin->ref_channels[channel][i]; + int dst_offset = plugin->ref_offsets[channel][i]; + double level = plugin->ref_levels[channel][i]; + double *dst = plugin->dsp_in[channel] + dst_offset; + double *src = plugin->get_output(src_channel)->get_data(); + int size = plugin->get_buffer_size(); + + if( size + dst_offset > plugin->dsp_in_allocated ) { + printf("ReverbUnit::process_package %d size=%d dst_offset=%d needed=%d allocated=%d\n", + __LINE__, size, dst_offset, size + dst_offset, plugin->dsp_in_allocated); } - output_lock.unlock(); + for( int j = 0; j < size; j++ ) + *dst++ += *src++ * level; } } +ReverbEngine::ReverbEngine(Reverb *plugin) + : LoadServer(plugin->PluginClient::smp + 1, plugin->total_in_buffers) +{ + this->plugin = plugin; +} + +ReverbEngine::~ReverbEngine() +{ +} + + +void ReverbEngine::init_packages() +{ + for( int i = 0; i < LoadServer::get_total_packages(); i++ ) { + ReverbPackage *package = (ReverbPackage*)LoadServer::get_package(i); + package->channel = i; + } +} +LoadClient* ReverbEngine::new_client() +{ + return new ReverbUnit(this, plugin); +} +LoadPackage* ReverbEngine::new_package() +{ + return new ReverbPackage; +} ReverbConfig::ReverbConfig() @@ -536,11 +539,12 @@ ReverbConfig::ReverbConfig() delay_init = 0; ref_level1 = -20; ref_level2 = INFINITYGAIN; - ref_total = 100; + ref_total = 128; ref_length = 600; - lowpass1 = Freq::tofreq(TOTALFREQS); - lowpass2 = Freq::tofreq(TOTALFREQS); - + high = Freq::tofreq(TOTALFREQS); + low = Freq::tofreq(0); + q = 1.0; + window_size = 4096; } int ReverbConfig::equivalent(ReverbConfig &that) @@ -551,8 +555,10 @@ int ReverbConfig::equivalent(ReverbConfig &that) EQUIV(ref_level2, that.ref_level2) && ref_total == that.ref_total && ref_length == that.ref_length && - lowpass1 == that.lowpass1 && - lowpass2 == that.lowpass2); + high == that.high && + low == that.low && + EQUIV(q, that.q) && + window_size == that.window_size); } void ReverbConfig::copy_from(ReverbConfig &that) @@ -563,15 +569,14 @@ void ReverbConfig::copy_from(ReverbConfig &that) ref_level2 = that.ref_level2; ref_total = that.ref_total; ref_length = that.ref_length; - lowpass1 = that.lowpass1; - lowpass2 = that.lowpass2; + high = that.high; + low = that.low; + q = that.q; + window_size = that.window_size; } -void ReverbConfig::interpolate(ReverbConfig &prev, - ReverbConfig &next, - int64_t prev_frame, - int64_t next_frame, - int64_t current_frame) +void ReverbConfig::interpolate(ReverbConfig &prev, ReverbConfig &next, + int64_t prev_frame, int64_t next_frame, int64_t current_frame) { level_init = prev.level_init; delay_init = prev.delay_init; @@ -579,28 +584,30 @@ void ReverbConfig::interpolate(ReverbConfig &prev, ref_level2 = prev.ref_level2; ref_total = prev.ref_total; ref_length = prev.ref_length; - lowpass1 = prev.lowpass1; - lowpass2 = prev.lowpass2; + high = prev.high; + low = prev.low; + q = prev.q; + window_size = prev.window_size; } void ReverbConfig::boundaries() { - CLAMP(level_init, INFINITYGAIN, 0); CLAMP(delay_init, 0, MAX_DELAY_INIT); CLAMP(ref_level1, INFINITYGAIN, 0); CLAMP(ref_level2, INFINITYGAIN, 0); CLAMP(ref_total, MIN_REFLECTIONS, MAX_REFLECTIONS); - CLAMP(ref_length, 0, MAX_REFLENGTH); - CLAMP(lowpass1, 0, Freq::tofreq(TOTALFREQS)); - CLAMP(lowpass2, 0, Freq::tofreq(TOTALFREQS)); + CLAMP(ref_length, MIN_REFLENGTH, MAX_REFLENGTH); + CLAMP(high, 0, Freq::tofreq(TOTALFREQS)); + CLAMP(low, 0, Freq::tofreq(TOTALFREQS)); + CLAMP(q, 0.0, 1.0); } void ReverbConfig::dump() { - printf("ReverbConfig::dump %f %jd %f %f %jd %jd %jd %jd\n", - level_init, delay_init, ref_level1, ref_level2, - ref_total, ref_length, lowpass1, lowpass2); + printf("ReverbConfig::dump %d level_init=%f delay_init=%d ref_level1=%f" + " ref_level2=%f ref_total=%d ref_length=%d high=%d low=%d q=%f\n", + __LINE__, level_init, (int)delay_init, ref_level1, ref_level2, + (int)ref_total, (int)ref_length, (int)high, (int)low, q); } -