r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / plugins / denoisefft / denoisefft.C
blob07447ddc9e027bbeb3a84958eea6e06bd368762c
1 #include "bcdisplayinfo.h"
2 #include "clip.h"
3 #include "defaults.h"
4 #include "filesystem.h"
5 #include "filexml.h"
6 #include "guicast.h"
7 #include "mutex.h"
8 #include "fourier.h"
9 #include "picon_png.h"
10 #include "pluginaclient.h"
11 #include "units.h"
12 #include "vframe.h"
14 #include <errno.h>
15 #include <math.h>
16 #include <string.h>
18 #include <libintl.h>
19 #define _(String) gettext(String)
20 #define gettext_noop(String) String
21 #define N_(String) gettext_noop (String)
29 class DenoiseFFTEffect;
30 class DenoiseFFTWindow;
31 #define REFERENCE_FILE BCASTDIR "denoise.ref"
36 class DenoiseFFTConfig
38 public:
39         DenoiseFFTConfig();
40         void copy_from(DenoiseFFTConfig &that);
41         int equivalent(DenoiseFFTConfig &that);
42         void interpolate(DenoiseFFTConfig &prev, 
43                 DenoiseFFTConfig &next, 
44                 int64_t prev_frame, 
45                 int64_t next_frame, 
46                 int64_t current_frame);
48         int window_size;
49         int collecting;
50         double level;
53 class DenoiseFFTCollecting : public BC_CheckBox
55 public:
56         DenoiseFFTCollecting(DenoiseFFTEffect *plugin, int x, int y);
57         int handle_event();
58         DenoiseFFTEffect *plugin;
61 class DenoiseFFTLevel : public BC_FPot
63 public:
64         DenoiseFFTLevel(DenoiseFFTEffect *plugin, int x, int y);
65         int handle_event();
66         DenoiseFFTEffect *plugin;
69 // class DenoiseFFTSize : public BC_TextBox
70 // {
71 // public:
72 //      DenoiseFFTSize(DenoiseFFTEffect *plugin, int x, int y);
73 //      int handle_event();
74 //      DenoiseFFTEffect *plugin;
75 // };
77 class DenoiseFFTWindow : public BC_Window
79 public:
80         DenoiseFFTWindow(DenoiseFFTEffect *plugin, int x, int y);
81         void create_objects();
82         int close_event();
83         DenoiseFFTLevel *level;
84         DenoiseFFTCollecting *collect;
85 //      DenoiseFFTSize *size;
86         DenoiseFFTEffect *plugin;
101 PLUGIN_THREAD_HEADER(DenoiseFFTEffect, DenoiseFFTThread, DenoiseFFTWindow)
104 class DenoiseFFTRemove : public CrossfadeFFT
106 public:
107         DenoiseFFTRemove(DenoiseFFTEffect *plugin);
108         int signal_process();
109         DenoiseFFTEffect *plugin;
112 class DenoiseFFTCollect : public CrossfadeFFT
114 public:
115         DenoiseFFTCollect(DenoiseFFTEffect *plugin);
116         int signal_process();
117         DenoiseFFTEffect *plugin;
120 class DenoiseFFTEffect : public PluginAClient
122 public:
123         DenoiseFFTEffect(PluginServer *server);
124         ~DenoiseFFTEffect();
126         int is_realtime();
127         void read_data(KeyFrame *keyframe);
128         void save_data(KeyFrame *keyframe);
129         int process_realtime(int64_t size, double *input_ptr, double *output_ptr);
134         int load_defaults();
135         int save_defaults();
136         void reset();
137         void update_gui();
139         void process_window();
142         PLUGIN_CLASS_MEMBERS(DenoiseFFTConfig, DenoiseFFTThread)
144         int is_collecting;
145         int prev_window_size;
146         double *reference;
147         DenoiseFFTRemove *remove_engine;
148         DenoiseFFTCollect *collect_engine;
160 REGISTER_PLUGIN(DenoiseFFTEffect)
170 DenoiseFFTConfig::DenoiseFFTConfig()
172         window_size = 16384;
173         collecting = 0;
174         level = 0.0;
177 void DenoiseFFTConfig::copy_from(DenoiseFFTConfig &that)
179         window_size = that.window_size;
180         collecting = that.collecting;
181         level = that.level;
184 int DenoiseFFTConfig::equivalent(DenoiseFFTConfig &that)
186         return EQUIV(level, that.level) &&
187                 window_size == that.window_size &&
188                 collecting == that.collecting;
191 void DenoiseFFTConfig::interpolate(DenoiseFFTConfig &prev, 
192         DenoiseFFTConfig &next, 
193         int64_t prev_frame, 
194         int64_t next_frame, 
195         int64_t current_frame)
197         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
198         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
199         this->level = prev.level * prev_scale + next.level * next_scale;
200         this->window_size = prev.window_size;
201         this->collecting = prev.collecting;
218 DenoiseFFTLevel::DenoiseFFTLevel(DenoiseFFTEffect *plugin, int x, int y)
219  : BC_FPot(x, y, (float)plugin->config.level, INFINITYGAIN, 6.0)
221         this->plugin = plugin;
222         set_precision(0.1);
225 int DenoiseFFTLevel::handle_event()
227         plugin->config.level = get_value();
228         plugin->send_configure_change();
229         return 1;
232 DenoiseFFTCollecting::DenoiseFFTCollecting(DenoiseFFTEffect *plugin, int x, int y)
233  : BC_CheckBox(x, y, plugin->config.collecting, _("Collect noise"))
235         this->plugin = plugin;
238 int DenoiseFFTCollecting::handle_event()
240         plugin->config.collecting = get_value();
241         plugin->send_configure_change();
242         return 1;
245 // DenoiseFFTSize::DenoiseFFTSize(DenoiseFFTEffect *plugin, int x, int y)
246 //  : BC_TextBox(x, y, 100, 1, plugin->config.window_size)
247 // {
248 //      this->plugin = plugin;
249 // }
250 // int DenoiseFFTSize::handle_event()
251 // {
252 //      plugin->config.window_size = atol(get_text());
253 //      plugin->send_configure_change();
254 //      return 1;
255 // }
259 DenoiseFFTWindow::DenoiseFFTWindow(DenoiseFFTEffect *plugin, int x, int y)
260  : BC_Window(plugin->gui_string, 
261         x, 
262         y, 
263         220, 
264         120, 
265         220, 
266         120,
267         0, 
268         0,
269         1)
271         this->plugin = plugin;
274 void DenoiseFFTWindow::create_objects()
276         int x = 10, y = 10;
278         add_subwindow(new BC_Title(x, y, _("Denoise power:")));
279         add_subwindow(level = new DenoiseFFTLevel(plugin, x + 130, y));
280         y += 35;
281         add_subwindow(collect = new DenoiseFFTCollecting(plugin, x, y));
282 //      y += 35;
283 //      add_subwindow(new BC_Title(x, y, _("Window size:")));
284 //      add_subwindow(size = new DenoiseFFTSize(plugin, x + 100, y));
285         show_window();
286         flush();
289 int DenoiseFFTWindow::close_event()
291 // Set result to 1 to indicate a client side close
292         set_done(1);
293         return 1;
306 PLUGIN_THREAD_OBJECT(DenoiseFFTEffect, DenoiseFFTThread, DenoiseFFTWindow)
322 DenoiseFFTEffect::DenoiseFFTEffect(PluginServer *server)
323  : PluginAClient(server)
325         reset();
326         PLUGIN_CONSTRUCTOR_MACRO
329 DenoiseFFTEffect::~DenoiseFFTEffect()
331         PLUGIN_DESTRUCTOR_MACRO
332         if(reference) delete [] reference;
333         if(remove_engine) delete remove_engine;
334         if(collect_engine) delete collect_engine;
337 NEW_PICON_MACRO(DenoiseFFTEffect)
339 LOAD_CONFIGURATION_MACRO(DenoiseFFTEffect, DenoiseFFTConfig)
341 SHOW_GUI_MACRO(DenoiseFFTEffect, DenoiseFFTThread)
343 RAISE_WINDOW_MACRO(DenoiseFFTEffect)
345 SET_STRING_MACRO(DenoiseFFTEffect)
348 void DenoiseFFTEffect::reset()
350         reference = 0;
351         remove_engine = 0;
352         collect_engine = 0;
353         is_collecting = 0;
354         prev_window_size = 0;
357 char* DenoiseFFTEffect::plugin_title()
359         return _("DenoiseFFT");
363 int DenoiseFFTEffect::is_realtime()
365         return 1;
370 void DenoiseFFTEffect::read_data(KeyFrame *keyframe)
372         FileXML input;
373         input.set_shared_string(keyframe->data, strlen(keyframe->data));
375         int result = 0;
376         while(!result)
377         {
378                 result = input.read_tag();
380                 if(!result)
381                 {
382                         if(input.tag.title_is("DENOISEFFT"))
383                         {
384                                 config.window_size = input.tag.get_property("WINDOW_SIZE", config.window_size);
385                                 config.level = input.tag.get_property("LEVEL", config.level);
386                                 config.collecting = input.tag.get_property("COLLECTING", config.collecting);
387                         }
388                 }
389         }
392 void DenoiseFFTEffect::save_data(KeyFrame *keyframe)
394         FileXML output;
395         output.set_shared_string(keyframe->data, MESSAGESIZE);
397         output.tag.set_title("DENOISEFFT");
398         output.tag.set_property("WINDOW_SIZE", config.window_size);
399         output.tag.set_property("LEVEL", config.level);
400         output.tag.set_property("COLLECTING", config.collecting);
401         output.append_tag();
402         output.append_newline();
404         output.terminate_string();
407 int DenoiseFFTEffect::load_defaults()
409         defaults = new Defaults(BCASTDIR "denoisefft.rc");
410         defaults->load();
412         config.level = defaults->get("LEVEL", config.level);
413         config.window_size = defaults->get("WINDOW_SIZE", config.window_size);
414         config.collecting = defaults->get("COLLECTING", config.collecting);
415         return 0;
418 int DenoiseFFTEffect::save_defaults()
420         char string[BCTEXTLEN];
422         defaults->update("LEVEL", config.level);
423         defaults->update("WINDOW_SIZE", config.window_size);
424         defaults->update("COLLECTING", config.collecting);
425         defaults->save();
427         return 0;
430 void DenoiseFFTEffect::update_gui()
432         if(thread)
433         {
434                 load_configuration();
435                 thread->window->lock_window();
436                 thread->window->level->update(config.level);
437                 thread->window->collect->update(config.collecting);
438 //              thread->window->size->update((int64_t)config.window_size);
439                 thread->window->unlock_window();
440         }
443 int DenoiseFFTEffect::process_realtime(int64_t size, double *input_ptr, double *output_ptr)
445         load_configuration();
447         if(prev_window_size != config.window_size)
448         {
449                 if(reference) delete [] reference;
450                 if(collect_engine) delete collect_engine;
451                 if(remove_engine) delete remove_engine;
452                 reference = 0;
453                 collect_engine = 0;
454                 remove_engine = 0;
455                 prev_window_size = config.window_size;
456         }
458         if(config.collecting)
459         {
460 // Create reference
461                 if(!reference)
462                 {
463                         reference = new double[config.window_size / 2];
464                 }
466                 if(!is_collecting)
467                         bzero(reference, sizeof(double) * config.window_size / 2);
469                 if(!collect_engine) collect_engine = new DenoiseFFTCollect(this);
470                 collect_engine->process_fifo(size, input_ptr, output_ptr);
472                 memcpy(output_ptr, input_ptr, sizeof(double) * size);
473                 is_collecting = 1;
474         }
475         else
476         {
477                 is_collecting = 0;
478 // Hasn't collected yet.  Load from disk file
479                 if(!reference)
480                 {
481                         reference = new double[config.window_size / 2];
482                         FileSystem fs;
483                         char string[BCTEXTLEN];
484                         strcpy(string, REFERENCE_FILE);
485                         fs.complete_path(string);
486                         FILE *fd = fopen(string, "r");
488                         if(fd)
489                         {
490                                 fread(reference, config.window_size / 2 * sizeof(double), 1, fd);
491                                 fclose(fd);
492                         }
493                         else
494                         {
495                                 bzero(reference, sizeof(double) * config.window_size / 2);
496                         }
498                 }
500                 if(!remove_engine) remove_engine = new DenoiseFFTRemove(this);
501                 remove_engine->process_fifo(size, input_ptr, output_ptr);
502         }
504         return 0;
515 DenoiseFFTRemove::DenoiseFFTRemove(DenoiseFFTEffect *plugin)
517         this->plugin = plugin;
520 int DenoiseFFTRemove::signal_process()
522         double level = DB::fromdb(plugin->config.level);
523         for(int i = 0; i < window_size / 2; i++)
524         {
525                 double result = sqrt(freq_real[i] * freq_real[i] + freq_imag[i] * freq_imag[i]);
526                 double angle = atan2(freq_imag[i], freq_real[i]);
527                 result -= plugin->reference[i] * level;
528                 if(result < 0) result = 0;
529                 freq_real[i] = result * cos(angle);
530                 freq_imag[i] = result * sin(angle);
531         }
532         symmetry(window_size, freq_real, freq_imag);
533         return 0;
540 DenoiseFFTCollect::DenoiseFFTCollect(DenoiseFFTEffect *plugin)
542         this->plugin = plugin;
545 int DenoiseFFTCollect::signal_process()
547         for(int i = 0; i < window_size / 2; i++)
548         {
549 // Moving average of peak so you don't need to stop, play, restart, play to 
550 // collect new data.
551                 double result = sqrt(freq_real[i] * freq_real[i] + freq_imag[i] * freq_imag[i]);
552                 double reference = plugin->reference[i];
553                 if(result < reference) 
554                         plugin->reference[i] = (result + reference * 4) / 5;
555                 else
556                         plugin->reference[i] = result;
557         }
559         FileSystem fs;
560         char string[BCTEXTLEN];
561         strcpy(string, REFERENCE_FILE);
562         fs.complete_path(string);
563         FILE *fd = fopen(string, "w");
564         if(fd)
565         {
566                 fwrite(plugin->reference, window_size / 2 * sizeof(double), 1, fd);
567                 fclose(fd);
568         }
569         else
570                 printf("DenoiseFFTCollect::signal_process: can't open %s for writing. %s.\n",
571                         REFERENCE_FILE, strerror(errno));
572         return 0;