add BC_SCALE env var for hi def monitors, cleanup theme data
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / freeverb / freeverb.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "clip.h"
24 #include "bchash.h"
25 #include "guicast.h"
26 #include "filexml.h"
27 #include "language.h"
28 #include "pluginaclient.h"
29 #include "revmodel.hpp"
30 #include "samples.h"
31 #include "units.h"
32 #include "vframe.h"
33
34 #include <math.h>
35 #include <string.h>
36
37
38
39
40
41
42
43 class FreeverbEffect;
44
45 class FreeverbConfig
46 {
47 public:
48         FreeverbConfig();
49
50
51         int equivalent(FreeverbConfig &that);
52         void copy_from(FreeverbConfig &that);
53         void interpolate(FreeverbConfig &prev,
54                 FreeverbConfig &next,
55                 int64_t prev_frame,
56                 int64_t next_frame,
57                 int64_t current_frame);
58
59
60         float gain;
61         float roomsize;
62         float damp;
63         float wet;
64         float dry;
65         float width;
66         float mode;
67 };
68
69
70 class FreeverbGain : public BC_FPot
71 {
72 public:
73         FreeverbGain(FreeverbEffect *plugin, int x, int y);
74         int handle_event();
75         FreeverbEffect *plugin;
76 };
77
78 class FreeverbRoomsize : public BC_FPot
79 {
80 public:
81         FreeverbRoomsize(FreeverbEffect *plugin, int x, int y);
82         int handle_event();
83         FreeverbEffect *plugin;
84 };
85
86 class FreeverbDamp : public BC_FPot
87 {
88 public:
89         FreeverbDamp(FreeverbEffect *plugin, int x, int y);
90         int handle_event();
91         FreeverbEffect *plugin;
92 };
93
94 class FreeverbWet : public BC_FPot
95 {
96 public:
97         FreeverbWet(FreeverbEffect *plugin, int x, int y);
98         int handle_event();
99         FreeverbEffect *plugin;
100 };
101
102 class FreeverbDry : public BC_FPot
103 {
104 public:
105         FreeverbDry(FreeverbEffect *plugin, int x, int y);
106         int handle_event();
107         FreeverbEffect *plugin;
108 };
109
110 class FreeverbWidth : public BC_FPot
111 {
112 public:
113         FreeverbWidth(FreeverbEffect *plugin, int x, int y);
114         int handle_event();
115         FreeverbEffect *plugin;
116 };
117
118 class FreeverbMode : public BC_CheckBox
119 {
120 public:
121         FreeverbMode(FreeverbEffect *plugin, int x, int y);
122         int handle_event();
123         FreeverbEffect *plugin;
124 };
125
126
127
128 class FreeverbWindow : public PluginClientWindow
129 {
130 public:
131         FreeverbWindow(FreeverbEffect *plugin);
132         void create_objects();
133
134         FreeverbEffect *plugin;
135
136         FreeverbGain *gain;
137         FreeverbRoomsize *roomsize;
138         FreeverbDamp *damp;
139         FreeverbWet *wet;
140         FreeverbDry *dry;
141         FreeverbWidth *width;
142         FreeverbMode *mode;
143 };
144
145
146
147
148
149 class FreeverbEffect : public PluginAClient
150 {
151 public:
152         FreeverbEffect(PluginServer *server);
153         ~FreeverbEffect();
154
155         PLUGIN_CLASS_MEMBERS(FreeverbConfig)
156         int is_realtime();
157         int is_multichannel();
158         void read_data(KeyFrame *keyframe);
159         void save_data(KeyFrame *keyframe);
160         int process_realtime(int64_t size, Samples **input_ptr, Samples **output_ptr);
161
162
163
164
165         void update_gui();
166
167
168         revmodel *engine;
169         float **temp;
170         float **temp_out;
171         int temp_allocated;
172 };
173
174
175
176
177 REGISTER_PLUGIN(FreeverbEffect)
178
179
180
181
182
183
184
185
186
187
188 FreeverbGain::FreeverbGain(FreeverbEffect *plugin, int x, int y)
189  : BC_FPot(x, y, plugin->config.gain, INFINITYGAIN, 6)
190 {
191         this->plugin = plugin;
192         set_precision(.1);
193 }
194
195 int FreeverbGain::handle_event()
196 {
197         plugin->config.gain = get_value();
198         plugin->send_configure_change();
199         return 1;
200 }
201
202 FreeverbRoomsize::FreeverbRoomsize(FreeverbEffect *plugin, int x, int y)
203  : BC_FPot(x, y, plugin->config.roomsize, INFINITYGAIN, 0)
204 {
205         this->plugin = plugin;
206         set_precision(.01);
207 }
208
209 int FreeverbRoomsize::handle_event()
210 {
211         plugin->config.roomsize = get_value();
212         plugin->send_configure_change();
213         return 1;
214 }
215
216 FreeverbDamp::FreeverbDamp(FreeverbEffect *plugin, int x, int y)
217  : BC_FPot(x, y, plugin->config.damp, INFINITYGAIN, 0)
218 {
219         this->plugin = plugin;
220         set_precision(.01);
221 }
222
223 int FreeverbDamp::handle_event()
224 {
225         plugin->config.damp = get_value();
226         plugin->send_configure_change();
227         return 1;
228 }
229
230 FreeverbWet::FreeverbWet(FreeverbEffect *plugin, int x, int y)
231  : BC_FPot(x, y, plugin->config.wet, INFINITYGAIN, 0)
232 {
233         this->plugin = plugin;
234         set_precision(.01);
235 }
236
237 int FreeverbWet::handle_event()
238 {
239         plugin->config.wet = get_value();
240         plugin->send_configure_change();
241         return 1;
242 }
243
244 FreeverbDry::FreeverbDry(FreeverbEffect *plugin, int x, int y)
245  : BC_FPot(x, y, plugin->config.dry, INFINITYGAIN, 0)
246 {
247         this->plugin = plugin;
248         set_precision(.01);
249 }
250
251 int FreeverbDry::handle_event()
252 {
253         plugin->config.dry = get_value();
254         plugin->send_configure_change();
255         return 1;
256 }
257
258 FreeverbWidth::FreeverbWidth(FreeverbEffect *plugin, int x, int y)
259  : BC_FPot(x, y, plugin->config.width, INFINITYGAIN, 0)
260 {
261         this->plugin = plugin;
262         set_precision(.01);
263 }
264
265 int FreeverbWidth::handle_event()
266 {
267         plugin->config.width = get_value();
268         plugin->send_configure_change();
269         return 1;
270 }
271
272 FreeverbMode::FreeverbMode(FreeverbEffect *plugin, int x, int y)
273  : BC_CheckBox(x, y, (int)plugin->config.mode, _("Freeze"))
274 {
275         this->plugin = plugin;
276 }
277
278 int FreeverbMode::handle_event()
279 {
280         plugin->config.mode = get_value();
281         plugin->send_configure_change();
282         return 1;
283 }
284
285
286
287
288
289
290
291
292
293
294
295 FreeverbWindow::FreeverbWindow(FreeverbEffect *plugin)
296  : PluginClientWindow(plugin,
297         xS(180),
298         yS(250),
299         xS(180),
300         yS(250),
301         0)
302 {
303         this->plugin = plugin;
304 }
305
306 void FreeverbWindow::create_objects()
307 {
308         int xs10 = xS(10), xs100 = xS(100), xs135 = xS(135);
309         int ys10 = yS(10), ys20 = yS(20), ys30 = yS(30);
310         int x1 = xs10, x2 = xs100, x3 = xs135, y1 = ys10, y2 = ys20, margin = ys30;
311
312         add_subwindow(new BC_Title(x1, y2, _("Gain:")));
313         add_subwindow(gain = new FreeverbGain(plugin, x3, y1));
314         y1 += margin;
315         y2 += margin;
316         add_subwindow(new BC_Title(x1, y2, _("Roomsize:")));
317         add_subwindow(roomsize = new FreeverbRoomsize(plugin, x2, y1));
318         y1 += margin;
319         y2 += margin;
320         add_subwindow(new BC_Title(x1, y2, _("Damp:")));
321         add_subwindow(damp = new FreeverbDamp(plugin, x3, y1));
322         y1 += margin;
323         y2 += margin;
324         add_subwindow(new BC_Title(x1, y2, _("Wet:")));
325         add_subwindow(wet = new FreeverbWet(plugin, x2, y1));
326         y1 += margin;
327         y2 += margin;
328         add_subwindow(new BC_Title(x1, y2, _("Dry:")));
329         add_subwindow(dry = new FreeverbDry(plugin, x3, y1));
330         y1 += margin;
331         y2 += margin;
332         add_subwindow(new BC_Title(x1, y2, _("Width:")));
333         add_subwindow(width = new FreeverbWidth(plugin, x2, y1));
334         y1 += margin;
335         y2 += margin;
336         add_subwindow(mode = new FreeverbMode(plugin, x1, y2));
337         show_window();
338         flush();
339 }
340
341
342
343
344
345
346
347
348
349
350
351
352
353 FreeverbConfig::FreeverbConfig()
354 {
355         gain = -6.0;
356         wet = -6.0;
357         dry = 0;
358         roomsize = -6.0;
359         damp = 0;
360         width = 0;
361         mode = 0;
362 }
363
364 int FreeverbConfig::equivalent(FreeverbConfig &that)
365 {
366         return EQUIV(gain, that.gain) &&
367                 EQUIV(wet, that.wet) &&
368                 EQUIV(roomsize, that.roomsize) &&
369                 EQUIV(dry, that.dry) &&
370                 EQUIV(damp, that.damp) &&
371                 EQUIV(width, that.width) &&
372                 EQUIV(mode, that.mode);
373 }
374
375 void FreeverbConfig::copy_from(FreeverbConfig &that)
376 {
377         gain = that.gain;
378         wet = that.wet;
379         roomsize = that.roomsize;
380         dry = that.dry;
381         damp = that.damp;
382         width = that.width;
383         mode = that.mode;
384 }
385
386 void FreeverbConfig::interpolate(FreeverbConfig &prev,
387         FreeverbConfig &next,
388         int64_t prev_frame,
389         int64_t next_frame,
390         int64_t current_frame)
391 {
392         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
393         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
394
395         gain = prev.gain * prev_scale + next.gain * next_scale;
396         wet = prev.wet * prev_scale + next.wet * next_scale;
397         roomsize = prev.roomsize * prev_scale + next.roomsize * next_scale;
398         dry = prev.dry * prev_scale + next.dry * next_scale;
399         damp = prev.damp * prev_scale + next.damp * next_scale;
400         width = prev.width * prev_scale + next.width * next_scale;
401         mode = prev.mode;
402 }
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432 FreeverbEffect::FreeverbEffect(PluginServer *server)
433  : PluginAClient(server)
434 {
435         engine = 0;
436         temp = 0;
437         temp_out = 0;
438         temp_allocated = 0;
439
440 }
441
442 FreeverbEffect::~FreeverbEffect()
443 {
444         if(engine) delete engine;
445         if(temp)
446         {
447                 for(int i = 0; i < total_in_buffers; i++)
448                 {
449                         delete [] temp[i];
450                         delete [] temp_out[i];
451                 }
452                 delete [] temp;
453                 delete [] temp_out;
454         }
455
456 }
457
458 NEW_WINDOW_MACRO(FreeverbEffect, FreeverbWindow)
459
460
461 const char* FreeverbEffect::plugin_title() { return N_("Freeverb"); }
462 int FreeverbEffect::is_realtime() { return 1; }
463 int FreeverbEffect::is_multichannel() { return 1; }
464
465
466
467 void FreeverbEffect::read_data(KeyFrame *keyframe)
468 {
469         FileXML input;
470         input.set_shared_input(keyframe->xbuf);
471
472         int result = 0;
473         while(!result)
474         {
475                 result = input.read_tag();
476
477                 if(!result)
478                 {
479                         if(input.tag.title_is("FREEVERB"))
480                         {
481                                 config.gain = input.tag.get_property("GAIN", config.gain);
482                                 config.roomsize = input.tag.get_property("ROOMSIZE", config.roomsize);
483                                 config.damp = input.tag.get_property("DAMP", config.damp);
484                                 config.wet = input.tag.get_property("WET", config.wet);
485                                 config.dry = input.tag.get_property("DRY", config.dry);
486                                 config.width = input.tag.get_property("WIDTH", config.width);
487                                 config.mode = input.tag.get_property("MODE", config.mode);
488                         }
489                 }
490         }
491 }
492
493 void FreeverbEffect::save_data(KeyFrame *keyframe)
494 {
495         FileXML output;
496         output.set_shared_output(keyframe->xbuf);
497
498         output.tag.set_title("FREEVERB");
499         output.tag.set_property("GAIN", config.gain);
500         output.tag.set_property("ROOMSIZE", config.roomsize);
501         output.tag.set_property("DAMP", config.damp);
502         output.tag.set_property("WET", config.wet);
503         output.tag.set_property("DRY", config.dry);
504         output.tag.set_property("WIDTH", config.width);
505         output.tag.set_property("MODE", config.mode);
506         output.append_tag();
507         output.tag.set_title("/FREEVERB");
508         output.append_tag();
509         output.append_newline();
510         output.terminate_string();
511 }
512
513
514 LOAD_CONFIGURATION_MACRO(FreeverbEffect, FreeverbConfig)
515
516 void FreeverbEffect::update_gui()
517 {
518         if(thread)
519         {
520                 load_configuration();
521                 thread->window->lock_window();
522                 ((FreeverbWindow*)thread->window)->gain->update(config.gain);
523                 ((FreeverbWindow*)thread->window)->roomsize->update(config.roomsize);
524                 ((FreeverbWindow*)thread->window)->damp->update(config.damp);
525                 ((FreeverbWindow*)thread->window)->wet->update(config.wet);
526                 ((FreeverbWindow*)thread->window)->dry->update(config.dry);
527                 ((FreeverbWindow*)thread->window)->width->update(config.width);
528                 ((FreeverbWindow*)thread->window)->mode->update((int)config.mode);
529                 thread->window->unlock_window();
530         }
531 }
532
533 int FreeverbEffect::process_realtime(int64_t size,
534         Samples **input_ptr,
535         Samples **output_ptr)
536 {
537         load_configuration();
538         if(!engine) engine = new revmodel;
539
540         engine->setroomsize(DB::fromdb(config.roomsize));
541         engine->setdamp(DB::fromdb(config.damp));
542         engine->setwet(DB::fromdb(config.wet));
543         engine->setdry(DB::fromdb(config.dry));
544         engine->setwidth(DB::fromdb(config.width));
545         engine->setmode(config.mode);
546
547 // printf("FreeverbEffect::process_realtime %d %f %f %f %f %f %d\n",
548 // __LINE__,
549 // DB::fromdb(config.roomsize),
550 // DB::fromdb(config.damp),
551 // DB::fromdb(config.wet),
552 // DB::fromdb(config.dry),
553 // DB::fromdb(config.width),
554 // (int)config.mode);
555
556         float gain_f = DB::fromdb(config.gain);
557
558         if(size > temp_allocated)
559         {
560                 if(temp)
561                 {
562                         for(int i = 0; i < total_in_buffers; i++)
563                         {
564                                 delete [] temp[i];
565                                 delete [] temp_out[i];
566                         }
567                         delete [] temp;
568                         delete [] temp_out;
569                 }
570                 temp = 0;
571                 temp_out = 0;
572         }
573
574         if(!temp)
575         {
576                 temp_allocated = size * 2;
577                 temp = new float*[total_in_buffers];
578                 temp_out = new float*[total_in_buffers];
579                 for(int i = 0; i < total_in_buffers; i++)
580                 {
581                         temp[i] = new float[temp_allocated];
582                         temp_out[i] = new float[temp_allocated];
583                 }
584         }
585
586         for(int i = 0; i < 2 && i < total_in_buffers; i++)
587         {
588                 float *out = temp[i];
589                 double *in = input_ptr[i]->get_data();
590                 for(int j = 0; j < size; j++)
591                 {
592                         out[j] = in[j];
593                 }
594         }
595
596         if(total_in_buffers < 2)
597         {
598                 engine->processreplace(temp[0],
599                         temp[0],
600                         temp_out[0],
601                         temp_out[0],
602                         size,
603                         1);
604         }
605         else
606         {
607 // 2 channels max
608                 engine->processreplace(temp[0],
609                         temp[1],
610                         temp_out[0],
611                         temp_out[1],
612                         size,
613                         1);
614         }
615
616         for(int i = 0; i < 2 && i < total_in_buffers; i++)
617         {
618                 double *out = output_ptr[i]->get_data();
619                 float *in = temp_out[i];
620                 for(int j = 0; j < size; j++)
621                 {
622                         out[j] = gain_f * in[j];
623                 }
624         }
625
626         return 0;
627 }
628
629