dynamic keyframes, textbox rework, andrea ffmpeg.opts, perpetual chkpt undo, lv2...
[goodguy/history.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         180,
298         250,
299         180,
300         250,
301         0)
302 {
303         this->plugin = plugin;
304 }
305
306 void FreeverbWindow::create_objects()
307 {
308         int x1 = 10, x2 = 100, x3 = 135, y1 = 10, y2 = 20, margin = 30;
309
310         add_subwindow(new BC_Title(x1, y2, _("Gain:")));
311         add_subwindow(gain = new FreeverbGain(plugin, x3, y1));
312         y1 += margin;
313         y2 += margin;
314         add_subwindow(new BC_Title(x1, y2, _("Roomsize:")));
315         add_subwindow(roomsize = new FreeverbRoomsize(plugin, x2, y1));
316         y1 += margin;
317         y2 += margin;
318         add_subwindow(new BC_Title(x1, y2, _("Damp:")));
319         add_subwindow(damp = new FreeverbDamp(plugin, x3, y1));
320         y1 += margin;
321         y2 += margin;
322         add_subwindow(new BC_Title(x1, y2, _("Wet:")));
323         add_subwindow(wet = new FreeverbWet(plugin, x2, y1));
324         y1 += margin;
325         y2 += margin;
326         add_subwindow(new BC_Title(x1, y2, _("Dry:")));
327         add_subwindow(dry = new FreeverbDry(plugin, x3, y1));
328         y1 += margin;
329         y2 += margin;
330         add_subwindow(new BC_Title(x1, y2, _("Width:")));
331         add_subwindow(width = new FreeverbWidth(plugin, x2, y1));
332         y1 += margin;
333         y2 += margin;
334         add_subwindow(mode = new FreeverbMode(plugin, x1, y2));
335         show_window();
336         flush();
337 }
338
339
340
341
342
343
344
345
346
347
348
349
350
351 FreeverbConfig::FreeverbConfig()
352 {
353         gain = -6.0;
354         wet = -6.0;
355         dry = 0;
356         roomsize = -6.0;
357         damp = 0;
358         width = 0;
359         mode = 0;
360 }
361
362 int FreeverbConfig::equivalent(FreeverbConfig &that)
363 {
364         return EQUIV(gain, that.gain) &&
365                 EQUIV(wet, that.wet) &&
366                 EQUIV(roomsize, that.roomsize) &&
367                 EQUIV(dry, that.dry) &&
368                 EQUIV(damp, that.damp) &&
369                 EQUIV(width, that.width) &&
370                 EQUIV(mode, that.mode);
371 }
372
373 void FreeverbConfig::copy_from(FreeverbConfig &that)
374 {
375         gain = that.gain;
376         wet = that.wet;
377         roomsize = that.roomsize;
378         dry = that.dry;
379         damp = that.damp;
380         width = that.width;
381         mode = that.mode;
382 }
383
384 void FreeverbConfig::interpolate(FreeverbConfig &prev,
385         FreeverbConfig &next,
386         int64_t prev_frame,
387         int64_t next_frame,
388         int64_t current_frame)
389 {
390         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
391         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
392
393         gain = prev.gain * prev_scale + next.gain * next_scale;
394         wet = prev.wet * prev_scale + next.wet * next_scale;
395         roomsize = prev.roomsize * prev_scale + next.roomsize * next_scale;
396         dry = prev.dry * prev_scale + next.dry * next_scale;
397         damp = prev.damp * prev_scale + next.damp * next_scale;
398         width = prev.width * prev_scale + next.width * next_scale;
399         mode = prev.mode;
400 }
401
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 FreeverbEffect::FreeverbEffect(PluginServer *server)
431  : PluginAClient(server)
432 {
433         engine = 0;
434         temp = 0;
435         temp_out = 0;
436         temp_allocated = 0;
437
438 }
439
440 FreeverbEffect::~FreeverbEffect()
441 {
442         if(engine) delete engine;
443         if(temp)
444         {
445                 for(int i = 0; i < total_in_buffers; i++)
446                 {
447                         delete [] temp[i];
448                         delete [] temp_out[i];
449                 }
450                 delete [] temp;
451                 delete [] temp_out;
452         }
453
454 }
455
456 NEW_WINDOW_MACRO(FreeverbEffect, FreeverbWindow)
457
458
459 const char* FreeverbEffect::plugin_title() { return N_("Freeverb"); }
460 int FreeverbEffect::is_realtime() { return 1; }
461 int FreeverbEffect::is_multichannel() { return 1; }
462
463
464
465 void FreeverbEffect::read_data(KeyFrame *keyframe)
466 {
467         FileXML input;
468         input.set_shared_input(keyframe->xbuf);
469
470         int result = 0;
471         while(!result)
472         {
473                 result = input.read_tag();
474
475                 if(!result)
476                 {
477                         if(input.tag.title_is("FREEVERB"))
478                         {
479                                 config.gain = input.tag.get_property("GAIN", config.gain);
480                                 config.roomsize = input.tag.get_property("ROOMSIZE", config.roomsize);
481                                 config.damp = input.tag.get_property("DAMP", config.damp);
482                                 config.wet = input.tag.get_property("WET", config.wet);
483                                 config.dry = input.tag.get_property("DRY", config.dry);
484                                 config.width = input.tag.get_property("WIDTH", config.width);
485                                 config.mode = input.tag.get_property("MODE", config.mode);
486                         }
487                 }
488         }
489 }
490
491 void FreeverbEffect::save_data(KeyFrame *keyframe)
492 {
493         FileXML output;
494         output.set_shared_output(keyframe->xbuf);
495
496         output.tag.set_title("FREEVERB");
497         output.tag.set_property("GAIN", config.gain);
498         output.tag.set_property("ROOMSIZE", config.roomsize);
499         output.tag.set_property("DAMP", config.damp);
500         output.tag.set_property("WET", config.wet);
501         output.tag.set_property("DRY", config.dry);
502         output.tag.set_property("WIDTH", config.width);
503         output.tag.set_property("MODE", config.mode);
504         output.append_tag();
505         output.tag.set_title("/FREEVERB");
506         output.append_tag();
507         output.append_newline();
508         output.terminate_string();
509 }
510
511
512 LOAD_CONFIGURATION_MACRO(FreeverbEffect, FreeverbConfig)
513
514 void FreeverbEffect::update_gui()
515 {
516         if(thread)
517         {
518                 load_configuration();
519                 thread->window->lock_window();
520                 ((FreeverbWindow*)thread->window)->gain->update(config.gain);
521                 ((FreeverbWindow*)thread->window)->roomsize->update(config.roomsize);
522                 ((FreeverbWindow*)thread->window)->damp->update(config.damp);
523                 ((FreeverbWindow*)thread->window)->wet->update(config.wet);
524                 ((FreeverbWindow*)thread->window)->dry->update(config.dry);
525                 ((FreeverbWindow*)thread->window)->width->update(config.width);
526                 ((FreeverbWindow*)thread->window)->mode->update((int)config.mode);
527                 thread->window->unlock_window();
528         }
529 }
530
531 int FreeverbEffect::process_realtime(int64_t size,
532         Samples **input_ptr,
533         Samples **output_ptr)
534 {
535         load_configuration();
536         if(!engine) engine = new revmodel;
537
538         engine->setroomsize(DB::fromdb(config.roomsize));
539         engine->setdamp(DB::fromdb(config.damp));
540         engine->setwet(DB::fromdb(config.wet));
541         engine->setdry(DB::fromdb(config.dry));
542         engine->setwidth(DB::fromdb(config.width));
543         engine->setmode(config.mode);
544
545 // printf("FreeverbEffect::process_realtime %d %f %f %f %f %f %d\n",
546 // __LINE__,
547 // DB::fromdb(config.roomsize),
548 // DB::fromdb(config.damp),
549 // DB::fromdb(config.wet),
550 // DB::fromdb(config.dry),
551 // DB::fromdb(config.width),
552 // (int)config.mode);
553
554         float gain_f = DB::fromdb(config.gain);
555
556         if(size > temp_allocated)
557         {
558                 if(temp)
559                 {
560                         for(int i = 0; i < total_in_buffers; i++)
561                         {
562                                 delete [] temp[i];
563                                 delete [] temp_out[i];
564                         }
565                         delete [] temp;
566                         delete [] temp_out;
567                 }
568                 temp = 0;
569                 temp_out = 0;
570         }
571
572         if(!temp)
573         {
574                 temp_allocated = size * 2;
575                 temp = new float*[total_in_buffers];
576                 temp_out = new float*[total_in_buffers];
577                 for(int i = 0; i < total_in_buffers; i++)
578                 {
579                         temp[i] = new float[temp_allocated];
580                         temp_out[i] = new float[temp_allocated];
581                 }
582         }
583
584         for(int i = 0; i < 2 && i < total_in_buffers; i++)
585         {
586                 float *out = temp[i];
587                 double *in = input_ptr[i]->get_data();
588                 for(int j = 0; j < size; j++)
589                 {
590                         out[j] = in[j];
591                 }
592         }
593
594         if(total_in_buffers < 2)
595         {
596                 engine->processreplace(temp[0],
597                         temp[0],
598                         temp_out[0],
599                         temp_out[0],
600                         size,
601                         1);
602         }
603         else
604         {
605 // 2 channels max
606                 engine->processreplace(temp[0],
607                         temp[1],
608                         temp_out[0],
609                         temp_out[1],
610                         size,
611                         1);
612         }
613
614         for(int i = 0; i < 2 && i < total_in_buffers; i++)
615         {
616                 double *out = output_ptr[i]->get_data();
617                 float *in = temp_out[i];
618                 for(int j = 0; j < size; j++)
619                 {
620                         out[j] = gain_f * in[j];
621                 }
622         }
623
624         return 0;
625 }
626
627