r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / plugins / reverb / reverb.C
blob6b6a583637c6989a24af61824e0efc50719fcb92
1 #include "clip.h"
2 #include "confirmsave.h"
3 #include "defaults.h"
4 #include "errorbox.h"
5 #include "filexml.h"
6 #include "picon_png.h"
7 #include "reverb.h"
8 #include "reverbwindow.h"
10 #include "vframe.h"
12 #include <math.h>
13 #include <string.h>
14 #include <time.h>
15 #include <unistd.h>
17 #include <libintl.h>
18 #define _(String) gettext(String)
19 #define gettext_noop(String) String
20 #define N_(String) gettext_noop (String)
24 PluginClient* new_plugin(PluginServer *server)
26         return new Reverb(server);
31 Reverb::Reverb(PluginServer *server)
32  : PluginAClient(server)
34         srand(time(0));
35         redo_buffers = 1;       // set to redo buffers before the first render
36         dsp_in_length = 0;
37         ref_channels = 0;
38         ref_offsets = 0;
39         ref_levels = 0;
40         ref_lowpass = 0;
41         dsp_in = 0;
42         lowpass_in1 = 0;
43         lowpass_in2 = 0;
44         initialized = 0;
45         PLUGIN_CONSTRUCTOR_MACRO
48 Reverb::~Reverb()
50         PLUGIN_DESTRUCTOR_MACRO
52         if(initialized)
53         {
54                 for(int i = 0; i < total_in_buffers; i++)
55                 {
56                         delete [] dsp_in[i];
57                         delete [] ref_channels[i];
58                         delete [] ref_offsets[i];
59                         delete [] ref_levels[i];
60                         delete [] ref_lowpass[i];
61                         delete [] lowpass_in1[i];
62                         delete [] lowpass_in2[i];
63                 }
65                 delete [] dsp_in;
66                 delete [] ref_channels;
67                 delete [] ref_offsets;
68                 delete [] ref_levels;
69                 delete [] ref_lowpass;
70                 delete [] lowpass_in1;
71                 delete [] lowpass_in2;
73                 for(int i = 0; i < (smp + 1); i++)
74                 {
75                         delete engine[i];
76                 }
77                 delete [] engine;
78                 initialized = 0;
79         }
82 char* Reverb::plugin_title() { return _("Heroine College Concert Hall"); }
83 int Reverb::is_realtime() { return 1; }
84 int Reverb::is_multichannel() { return 1; }
86 int Reverb::process_realtime(int64_t size, double **input_ptr, double **output_ptr)
88         int64_t new_dsp_length, i, j;
89         main_in = input_ptr;
90         main_out = output_ptr;
91 //printf("Reverb::process_realtime 1\n");
92         redo_buffers |= load_configuration();
94 //printf("Reverb::process_realtime 1\n");
95         if(!config.ref_total) return 0;
98         if(!initialized)
99         {
100                 dsp_in = new double*[total_in_buffers];
101                 ref_channels = new int64_t*[total_in_buffers];
102                 ref_offsets = new int64_t*[total_in_buffers];
103                 ref_levels = new double*[total_in_buffers];
104                 ref_lowpass = new int64_t*[total_in_buffers];
105                 lowpass_in1 = new double*[total_in_buffers];
106                 lowpass_in2 = new double*[total_in_buffers];
108                 for(i = 0; i < total_in_buffers; i++)
109                 {
110                         dsp_in[i] = new double[1];
111                         ref_channels[i] = new int64_t[1];
112                         ref_offsets[i] = new int64_t[1];
113                         ref_levels[i] = new double[1];
114                         ref_lowpass[i] = new int64_t[1];
115                         lowpass_in1[i] = new double[1];
116                         lowpass_in2[i] = new double[1];
117                 }
119                 engine = new ReverbEngine*[(smp + 1)];
120                 for(i = 0; i < (smp + 1); i++)
121                 {
122                         engine[i] = new ReverbEngine(this);
123 //printf("Reverb::start_realtime %d\n", Thread::calculate_realtime());
124 // Realtime priority moved to sound driver
125 //              engine[i]->set_realtime(realtime_priority);
126                         engine[i]->start();
127                 }
128                 initialized = 1;
129                 redo_buffers = 1;
130         }
132         new_dsp_length = size + 
133                 (config.delay_init + config.ref_length) * project_sample_rate / 1000 + 1;
134 //printf("Reverb::process_realtime 1 %d %d\n", in_buffer_size, size);
136         if(redo_buffers || new_dsp_length != dsp_in_length)
137         {
138                 for(i = 0; i < total_in_buffers; i++)
139                 {
140                         double *old_dsp = dsp_in[i];
141                         double *new_dsp = new double[new_dsp_length];
142                         for(j = 0; j < dsp_in_length && j < new_dsp_length; j++) 
143                                 new_dsp[j] = old_dsp[j];
144                         for( ; j < new_dsp_length; j++) new_dsp[j] = 0;
145                         delete [] old_dsp;
146                         dsp_in[i] = new_dsp;
147                 }
149                 dsp_in_length = new_dsp_length;
150                 redo_buffers = 1;
151         }
152 //printf("Reverb::process_realtime 1\n");
154         if(redo_buffers)
155         {
156                 for(i = 0; i < total_in_buffers; i++)
157                 {
158                         delete [] ref_channels[i];
159                         delete [] ref_offsets[i];
160                         delete [] ref_lowpass[i];
161                         delete [] ref_levels[i];
162                         delete [] lowpass_in1[i];
163                         delete [] lowpass_in2[i];
164                         
165                         ref_channels[i] = new int64_t[config.ref_total + 1];
166                         ref_offsets[i] = new int64_t[config.ref_total + 1];
167                         ref_lowpass[i] = new int64_t[config.ref_total + 1];
168                         ref_levels[i] = new double[config.ref_total + 1];
169                         lowpass_in1[i] = new double[config.ref_total + 1];
170                         lowpass_in2[i] = new double[config.ref_total + 1];
172 // set channels                 
173                         ref_channels[i][0] = i;         // primary noise
174                         ref_channels[i][1] = i;         // first reflection
175 // set offsets
176                         ref_offsets[i][0] = 0;
177                         ref_offsets[i][1] = config.delay_init * project_sample_rate / 1000;
178 // set levels
179                         ref_levels[i][0] = db.fromdb(config.level_init);
180                         ref_levels[i][1] = db.fromdb(config.ref_level1);
181 // set lowpass
182                         ref_lowpass[i][0] = -1;     // ignore first noise
183                         ref_lowpass[i][1] = config.lowpass1;
184                         lowpass_in1[i][0] = 0;
185                         lowpass_in2[i][0] = 0;
186                         lowpass_in1[i][1] = 0;
187                         lowpass_in2[i][1] = 0;
189                         int64_t ref_division = config.ref_length * project_sample_rate / 1000 / (config.ref_total + 1);
190                         for(j = 2; j < config.ref_total + 1; j++)
191                         {
192 // set random channels for remaining reflections
193                                 ref_channels[i][j] = rand() % total_in_buffers;
195 // set random offsets after first reflection
196                                 ref_offsets[i][j] = ref_offsets[i][1];
197                                 ref_offsets[i][j] += ref_division * j - (rand() % ref_division) / 2;
199 // set changing levels
200                                 ref_levels[i][j] = db.fromdb(config.ref_level1 + (config.ref_level2 - config.ref_level1) / (config.ref_total - 1) * (j - 2));
201                                 //ref_levels[i][j] /= 100;
203 // set changing lowpass as linear
204                                 ref_lowpass[i][j] = (int64_t)(config.lowpass1 + (double)(config.lowpass2 - config.lowpass1) / (config.ref_total - 1) * (j - 2));
205                                 lowpass_in1[i][j] = 0;
206                                 lowpass_in2[i][j] = 0;
207                         }
208                 }
209                 
210                 redo_buffers = 0;
211         }
212 //printf("Reverb::process_realtime 1\n");
214         for(i = 0; i < total_in_buffers; )
215         {
216                 for(j = 0; j < (smp + 1) && (i + j) < total_in_buffers; j++)
217                 {
218                         engine[j]->process_overlays(i + j, size);
219                 }
220                 
221                 for(j = 0; j < (smp + 1) && i < total_in_buffers; j++, i++)
222                 {
223                         engine[j]->wait_process_overlays();
224                 }
225         }
226 //printf("Reverb::process_realtime 2 %d %d\n", total_in_buffers, size);
228         for(i = 0; i < total_in_buffers; i++)
229         {
230                 double *current_out = main_out[i];
231                 double *current_in = dsp_in[i];
233                 for(j = 0; j < size; j++) current_out[j] = current_in[j];
235                 int64_t k;
236                 for(k = 0; j < dsp_in_length; j++, k++) current_in[k] = current_in[j];
237                 
238                 for(; k < dsp_in_length; k++) current_in[k] = 0;
239         }
240 //printf("Reverb::process_realtime 2 %d %d\n", total_in_buffers, size);
241         return 0;
244 NEW_PICON_MACRO(Reverb)
246 SHOW_GUI_MACRO(Reverb, ReverbThread)
248 SET_STRING_MACRO(Reverb)
250 RAISE_WINDOW_MACRO(Reverb)
252 int Reverb::load_defaults()
254         char directory[1024];
256 // set the default directory
257         sprintf(directory, "%sreverb.rc", get_defaultdir());
259 // load the defaults
261         defaults = new Defaults(directory);
263         defaults->load();
265         config.level_init = defaults->get("LEVEL_INIT", (double)0);
266         config.delay_init = defaults->get("DELAY_INIT", 100);
267         config.ref_level1 = defaults->get("REF_LEVEL1", (double)-6);
268         config.ref_level2 = defaults->get("REF_LEVEL2", (double)INFINITYGAIN);
269         config.ref_total = defaults->get("REF_TOTAL", 12);
270         config.ref_length = defaults->get("REF_LENGTH", 1000);
271         config.lowpass1 = defaults->get("LOWPASS1", 20000);
272         config.lowpass2 = defaults->get("LOWPASS2", 20000);
274         sprintf(config_directory, "~");
275         defaults->get("CONFIG_DIRECTORY", config_directory);
277 //printf("Reverb::load_defaults config.ref_level2 %f\n", config.ref_level2);
278         return 0;
281 int Reverb::save_defaults()
283         defaults->update("LEVEL_INIT", config.level_init);
284         defaults->update("DELAY_INIT", config.delay_init);
285         defaults->update("REF_LEVEL1", config.ref_level1);
286         defaults->update("REF_LEVEL2", config.ref_level2);
287         defaults->update("REF_TOTAL", config.ref_total);
288         defaults->update("REF_LENGTH", config.ref_length);
289         defaults->update("LOWPASS1", config.lowpass1);
290         defaults->update("LOWPASS2", config.lowpass2);
291         defaults->update("CONFIG_DIRECTORY", config_directory);
292         defaults->save();
293         return 0;
296 LOAD_CONFIGURATION_MACRO(Reverb, ReverbConfig)
299 void Reverb::save_data(KeyFrame *keyframe)
301 //printf("Reverb::save_data 1\n");
302         FileXML output;
303 //printf("Reverb::save_data 1\n");
305 // cause xml file to store data directly in text
306         output.set_shared_string(keyframe->data, MESSAGESIZE);
307 //printf("Reverb::save_data 1\n");
309         output.tag.set_title("REVERB");
310         output.tag.set_property("LEVELINIT", config.level_init);
311         output.tag.set_property("DELAY_INIT", config.delay_init);
312         output.tag.set_property("REF_LEVEL1", config.ref_level1);
313         output.tag.set_property("REF_LEVEL2", config.ref_level2);
314         output.tag.set_property("REF_TOTAL", config.ref_total);
315 //printf("Reverb::save_data 1\n");
316         output.tag.set_property("REF_LENGTH", config.ref_length);
317         output.tag.set_property("LOWPASS1", config.lowpass1);
318         output.tag.set_property("LOWPASS2", config.lowpass2);
319 //printf("Reverb::save_data config.ref_level2 %f\n", config.ref_level2);
320         output.append_tag();
321         output.append_newline();
322 //printf("Reverb::save_data 1\n");
323         
324         
325         
326         output.terminate_string();
327 //printf("Reverb::save_data 2\n");
330 void Reverb::read_data(KeyFrame *keyframe)
332         FileXML input;
333 // cause xml file to read directly from text
334         input.set_shared_string(keyframe->data, strlen(keyframe->data));
335         int result = 0;
337         result = input.read_tag();
339         if(!result)
340         {
341                 if(input.tag.title_is("REVERB"))
342                 {
343                         config.level_init = input.tag.get_property("LEVELINIT", config.level_init);
344                         config.delay_init = input.tag.get_property("DELAY_INIT", config.delay_init);
345                         config.ref_level1 = input.tag.get_property("REF_LEVEL1", config.ref_level1);
346                         config.ref_level2 = input.tag.get_property("REF_LEVEL2", config.ref_level2);
347                         config.ref_total = input.tag.get_property("REF_TOTAL", config.ref_total);
348                         config.ref_length = input.tag.get_property("REF_LENGTH", config.ref_length);
349                         config.lowpass1 = input.tag.get_property("LOWPASS1", config.lowpass1);
350                         config.lowpass2 = input.tag.get_property("LOWPASS2", config.lowpass2);
351                 }
352         }
355 void Reverb::update_gui()
357         if(thread)
358         {
359                 thread->window->lock_window();
360                 thread->window->level_init->update(config.level_init);
361                 thread->window->delay_init->update(config.delay_init);
362                 thread->window->ref_level1->update(config.ref_level1);
363                 thread->window->ref_level2->update(config.ref_level2);
364                 thread->window->ref_total->update(config.ref_total);
365                 thread->window->ref_length->update(config.ref_length);
366                 thread->window->lowpass1->update(config.lowpass1);
367                 thread->window->lowpass2->update(config.lowpass2);
368                 thread->window->unlock_window();
369         }
375 int Reverb::load_from_file(char *path)
377         FILE *in;
378         int result = 0;
379         int length;
380         char string[1024];
381         
382         if(in = fopen(path, "rb"))
383         {
384                 fseek(in, 0, SEEK_END);
385                 length = ftell(in);
386                 fseek(in, 0, SEEK_SET);
387                 fread(string, length, 1, in);
388                 fclose(in);
389 //              read_data(string);
390         }
391         else
392         {
393                 perror("fopen:");
394 // failed
395                 ErrorBox errorbox("");
396                 char string[1024];
397                 sprintf(string, _("Couldn't open %s."), path);
398                 errorbox.create_objects(string);
399                 errorbox.run_window();
400                 result = 1;
401         }
402         
403         return result;
406 int Reverb::save_to_file(char *path)
408         FILE *out;
409         int result = 0;
410         char string[1024];
411         
412         {
413 //              ConfirmSave confirm;
414 //              result = confirm.test_file("", path);
415         }
416         
417         if(!result)
418         {
419                 if(out = fopen(path, "wb"))
420                 {
421 //                      save_data(string);
422                         fwrite(string, strlen(string), 1, out);
423                         fclose(out);
424                 }
425                 else
426                 {
427                         result = 1;
428 // failed
429                         ErrorBox errorbox("");
430                         char string[1024];
431                         sprintf(string, _("Couldn't save %s."), path);
432                         errorbox.create_objects(string);
433                         errorbox.run_window();
434                         result = 1;
435                 }
436         }
437         
438         return result;
441 ReverbEngine::ReverbEngine(Reverb *plugin)
442  : Thread()
444         this->plugin = plugin;
445         completed = 0;
446         input_lock.lock();
447         output_lock.lock();
450 ReverbEngine::~ReverbEngine()
452         completed = 1;
453         input_lock.unlock();
454         join();
457 int ReverbEngine::process_overlays(int output_buffer, int64_t size)
459         this->output_buffer = output_buffer;
460         this->size = size;
461         input_lock.unlock();
464 int ReverbEngine::wait_process_overlays()
466         output_lock.lock();
468         
469 int ReverbEngine::process_overlay(double *in, double *out, double &out1, double &out2, double level, int64_t lowpass, int64_t samplerate, int64_t size)
471 // Modern niquist frequency is 44khz but pot limit is 20khz so can't use
472 // niquist
473         if(lowpass == -1 || lowpass >= 20000)
474         {
475 // no lowpass filter
476                 for(int i = 0; i < size; i++) out[i] += in[i] * level;
477         }
478         else
479         {
480                 double coef = 0.25 * 2.0 * M_PI * (double)lowpass / (double)plugin->project_sample_rate;
481                 double a = coef * 0.25;
482                 double b = coef * 0.50;
484                 for(int i = 0; i < size; i++)
485                 {
486                         out2 += a * (3 * out1 + in[i] - out2);
487                         out2 += b * (out1 + in[i] - out2);
488                         out2 += a * (out1 + 3 * in[i] - out2);
489                         out2 += coef * (in[i] - out2);
490                         out1 = in[i];
491                         out[i] += out2 * level;
492                 }
493         }
496 void ReverbEngine::run()
498         int j, i;
499         while(1)
500         {
501                 input_lock.lock();
502                 if(completed) return;
504 // Process reverb
505                 for(i = 0; i < plugin->total_in_buffers; i++)
506                 {
507                         for(j = 0; j < plugin->config.ref_total + 1; j++)
508                         {
509                                 if(plugin->ref_channels[i][j] == output_buffer)
510                                         process_overlay(plugin->main_in[i], 
511                                                                 &(plugin->dsp_in[plugin->ref_channels[i][j]][plugin->ref_offsets[i][j]]), 
512                                                                 plugin->lowpass_in1[i][j], 
513                                                                 plugin->lowpass_in2[i][j], 
514                                                                 plugin->ref_levels[i][j], 
515                                                                 plugin->ref_lowpass[i][j], 
516                                                                 plugin->project_sample_rate, 
517                                                                 size);
518                         }
519                 }
521                 output_lock.unlock();
522         }
531 ReverbConfig::ReverbConfig()
535 int ReverbConfig::equivalent(ReverbConfig &that)
537         return (EQUIV(level_init, that.level_init) &&
538                 delay_init == that.delay_init &&
539                 EQUIV(ref_level1, that.ref_level1) &&
540                 EQUIV(ref_level2, that.ref_level2) &&
541                 ref_total == that.ref_total &&
542                 ref_length == that.ref_length &&
543                 lowpass1 == that.lowpass1 &&
544                 lowpass2 == that.lowpass2);
547 void ReverbConfig::copy_from(ReverbConfig &that)
549         level_init = that.level_init;
550         delay_init = that.delay_init;
551         ref_level1 = that.ref_level1;
552         ref_level2 = that.ref_level2;
553         ref_total = that.ref_total;
554         ref_length = that.ref_length;
555         lowpass1 = that.lowpass1;
556         lowpass2 = that.lowpass2;
559 void ReverbConfig::interpolate(ReverbConfig &prev, 
560         ReverbConfig &next, 
561         int64_t prev_frame, 
562         int64_t next_frame, 
563         int64_t current_frame)
565         level_init = prev.level_init;
566         delay_init = prev.delay_init;
567         ref_level1 = prev.ref_level1;
568         ref_level2 = prev.ref_level2;
569         ref_total = prev.ref_total;
570         ref_length = prev.ref_length;
571         lowpass1 = prev.lowpass1;
572         lowpass2 = prev.lowpass2;
575 void ReverbConfig::dump()
577         printf("ReverbConfig::dump %f %d %f %f %d %d %d %d\n", 
578         level_init,
579         delay_init, 
580         ref_level1, 
581         ref_level2, 
582         ref_total, 
583         ref_length, 
584         lowpass1, 
585         lowpass2);