Fixed initialisation of tf in file_open(). Without setting the memory to 0,
[cinelerra_cv/mob.git] / plugins / denoisefft / denoisefft.C
blob3f14a1402d49848b0f5a49208416f3aa9e5a716e
1 #include "bcdisplayinfo.h"
2 #include "clip.h"
3 #include "bchash.h"
4 #include "filesystem.h"
5 #include "filexml.h"
6 #include "guicast.h"
7 #include "language.h"
8 #include "mutex.h"
9 #include "fourier.h"
10 #include "picon_png.h"
11 #include "pluginaclient.h"
12 #include "transportque.inc"
13 #include "units.h"
14 #include "vframe.h"
16 #include <errno.h>
17 #include <math.h>
18 #include <string.h>
22 #define WINDOW_SIZE 16384
25 // Noise collection is done either from the start of the effect or the start
26 // of the previous keyframe.  It always covers the higher numbered samples
27 // after the keyframe.
29 class DenoiseFFTEffect;
30 class DenoiseFFTWindow;
35 class DenoiseFFTConfig
37 public:
38         DenoiseFFTConfig();
40         int samples;
41         double level;
44 class DenoiseFFTLevel : public BC_FPot
46 public:
47         DenoiseFFTLevel(DenoiseFFTEffect *plugin, int x, int y);
48         int handle_event();
49         DenoiseFFTEffect *plugin;
52 class DenoiseFFTSamples : public BC_PopupMenu
54 public:
55         DenoiseFFTSamples(DenoiseFFTEffect *plugin, int x, int y, char *text);
56         int handle_event();
57         DenoiseFFTEffect *plugin;
60 class DenoiseFFTWindow : public BC_Window
62 public:
63         DenoiseFFTWindow(DenoiseFFTEffect *plugin, int x, int y);
64         void create_objects();
65         int close_event();
66         DenoiseFFTLevel *level;
67         DenoiseFFTSamples *samples;
68         DenoiseFFTEffect *plugin;
83 PLUGIN_THREAD_HEADER(DenoiseFFTEffect, DenoiseFFTThread, DenoiseFFTWindow)
86 class DenoiseFFTRemove : public CrossfadeFFT
88 public:
89         DenoiseFFTRemove(DenoiseFFTEffect *plugin);
90         int signal_process();
91         int read_samples(int64_t output_sample, 
92                 int samples, 
93                 double *buffer);
94         DenoiseFFTEffect *plugin;
97 class DenoiseFFTCollect : public CrossfadeFFT
99 public:
100         DenoiseFFTCollect(DenoiseFFTEffect *plugin);
101         int signal_process();
102         int read_samples(int64_t output_sample, 
103                 int samples, 
104                 double *buffer);
105         DenoiseFFTEffect *plugin;
108 class DenoiseFFTEffect : public PluginAClient
110 public:
111         DenoiseFFTEffect(PluginServer *server);
112         ~DenoiseFFTEffect();
114         int is_realtime();
115         void read_data(KeyFrame *keyframe);
116         void save_data(KeyFrame *keyframe);
117         int process_buffer(int64_t size, 
118                 double *buffer,
119                 int64_t start_position,
120                 int sample_rate);
121         void collect_noise();
125         int load_defaults();
126         int save_defaults();
127         void reset();
128         void update_gui();
130         void process_window();
133         PLUGIN_CLASS_MEMBERS(DenoiseFFTConfig, DenoiseFFTThread)
135 // Need to sample noise now.
136         int need_collection;
137 // Start of sample of noise to collect
138         int64_t collection_sample;
139         double *reference;
140         DenoiseFFTRemove *remove_engine;
141         DenoiseFFTCollect *collect_engine;
153 REGISTER_PLUGIN(DenoiseFFTEffect)
163 DenoiseFFTConfig::DenoiseFFTConfig()
165         samples = WINDOW_SIZE;
166         level = 0.0;
180 DenoiseFFTLevel::DenoiseFFTLevel(DenoiseFFTEffect *plugin, int x, int y)
181  : BC_FPot(x, y, (float)plugin->config.level, INFINITYGAIN, 6.0)
183         this->plugin = plugin;
184         set_precision(0.1);
187 int DenoiseFFTLevel::handle_event()
189         plugin->config.level = get_value();
190         plugin->send_configure_change();
191         return 1;
194 DenoiseFFTSamples::DenoiseFFTSamples(DenoiseFFTEffect *plugin, 
195         int x, 
196         int y, 
197         char *text)
198  : BC_PopupMenu(x, y, 100, text, 1)
200         this->plugin = plugin;
203 int DenoiseFFTSamples::handle_event()
205         plugin->config.samples = atol(get_text());
206         plugin->send_configure_change();
207         return 1;
212 DenoiseFFTWindow::DenoiseFFTWindow(DenoiseFFTEffect *plugin, int x, int y)
213  : BC_Window(plugin->gui_string, 
214         x, 
215         y, 
216         300, 
217         130, 
218         300, 
219         130,
220         0, 
221         0,
222         1)
224         this->plugin = plugin;
227 void DenoiseFFTWindow::create_objects()
229         int x = 10, y = 10;
231         add_subwindow(new BC_Title(x, y, _("Denoise power:")));
232         add_subwindow(level = new DenoiseFFTLevel(plugin, x + 130, y));
233         y += level->get_h() + 10;
234         add_subwindow(new BC_Title(x, y, _("Number of samples for reference:")));
235         y += 20;
236         add_subwindow(new BC_Title(x, y, _("The keyframe is the start of the reference")));
237         y += 20;
239         char string[BCTEXTLEN];
240         sprintf(string, "%d\n", plugin->config.samples);
241         add_subwindow(samples = new DenoiseFFTSamples(plugin, x + 100, y, string));
242         for(int i = WINDOW_SIZE; i < 0x100000; )
243         {
244                 sprintf(string, "%d", i);
245                 samples->add_item(new BC_MenuItem(string));
246                 i *= 2;
247         }
248         show_window();
249         flush();
252 WINDOW_CLOSE_EVENT(DenoiseFFTWindow)
264 PLUGIN_THREAD_OBJECT(DenoiseFFTEffect, DenoiseFFTThread, DenoiseFFTWindow)
274 DenoiseFFTEffect::DenoiseFFTEffect(PluginServer *server)
275  : PluginAClient(server)
277         reset();
278         PLUGIN_CONSTRUCTOR_MACRO
281 DenoiseFFTEffect::~DenoiseFFTEffect()
283         PLUGIN_DESTRUCTOR_MACRO
284         if(reference) delete [] reference;
285         if(remove_engine) delete remove_engine;
286         if(collect_engine) delete collect_engine;
289 NEW_PICON_MACRO(DenoiseFFTEffect)
291 SHOW_GUI_MACRO(DenoiseFFTEffect, DenoiseFFTThread)
293 RAISE_WINDOW_MACRO(DenoiseFFTEffect)
295 SET_STRING_MACRO(DenoiseFFTEffect)
298 void DenoiseFFTEffect::reset()
300         reference = 0;
301         remove_engine = 0;
302         collect_engine = 0;
303         need_collection = 1;
304         collection_sample = 0;
307 int DenoiseFFTEffect::is_realtime() { return 1; }
308 char* DenoiseFFTEffect::plugin_title() { return N_("DenoiseFFT"); }
314 void DenoiseFFTEffect::read_data(KeyFrame *keyframe)
316         FileXML input;
317         input.set_shared_string(keyframe->data, strlen(keyframe->data));
319         int result = 0;
320         while(!result)
321         {
322                 result = input.read_tag();
324                 if(!result)
325                 {
326                         if(input.tag.title_is("DENOISEFFT"))
327                         {
328                                 config.samples = input.tag.get_property("SAMPLES", config.samples);
329                                 config.level = input.tag.get_property("LEVEL", config.level);
330                         }
331                 }
332         }
335 void DenoiseFFTEffect::save_data(KeyFrame *keyframe)
337         FileXML output;
338         output.set_shared_string(keyframe->data, MESSAGESIZE);
340         output.tag.set_title("DENOISEFFT");
341         output.tag.set_property("SAMPLES", config.samples);
342         output.tag.set_property("LEVEL", config.level);
343         output.append_tag();
344         output.append_newline();
346         output.terminate_string();
349 int DenoiseFFTEffect::load_defaults()
351         defaults = new BC_Hash(BCASTDIR "denoisefft.rc");
352         defaults->load();
354         config.level = defaults->get("LEVEL", config.level);
355         config.samples = defaults->get("SAMPLES", config.samples);
356         return 0;
359 int DenoiseFFTEffect::save_defaults()
361         char string[BCTEXTLEN];
363         defaults->update("LEVEL", config.level);
364         defaults->update("SAMPLES", config.samples);
365         defaults->save();
367         return 0;
370 void DenoiseFFTEffect::update_gui()
372         if(thread)
373         {
374                 load_configuration();
375                 thread->window->lock_window();
376                 thread->window->level->update(config.level);
377                 char string[BCTEXTLEN];
378                 sprintf(string, "%d", config.samples);
379                 thread->window->samples->set_text(string);
380                 thread->window->unlock_window();
381         }
384 int DenoiseFFTEffect::load_configuration()
386         KeyFrame *prev_keyframe = get_prev_keyframe(get_source_position());
387         int64_t prev_position = edl_to_local(prev_keyframe->position);
388         read_data(prev_keyframe);
389         if(prev_position == 0) prev_position = get_source_start();
391         if(prev_position != collection_sample)
392         {
393                 collection_sample = prev_position;
394                 need_collection = 1;
395         }
396         return 0;
399 int DenoiseFFTEffect::process_buffer(int64_t size, 
400                 double *buffer,
401                 int64_t start_position,
402                 int sample_rate)
404         load_configuration();
406 // Do noise collection
407         if(need_collection)
408         {
409                 need_collection = 0;
410                 collect_noise();
411         }
413 // Remove noise
414         if(!remove_engine)
415         {
416                 remove_engine = new DenoiseFFTRemove(this);
417                 remove_engine->initialize(WINDOW_SIZE);
418         }
419         remove_engine->process_buffer(start_position, 
420                 size,
421                 buffer, 
422                 get_direction());
424         return 0;
428 void DenoiseFFTEffect::collect_noise()
430         if(!reference) reference = new double[WINDOW_SIZE / 2];
431         if(!collect_engine)
432         {
433                 collect_engine = new DenoiseFFTCollect(this);
434                 collect_engine->initialize(WINDOW_SIZE);
435         }
436         bzero(reference, sizeof(double) * WINDOW_SIZE / 2);
438         int64_t collection_start = collection_sample;
439         int step = 1;
440         int total_windows = 0;
442         if(get_direction() == PLAY_REVERSE)
443         {
444                 collection_start += config.samples;
445                 step = -1;
446         }
448         for(int i = 0; i < config.samples; i += WINDOW_SIZE)
449         {
450                 collect_engine->process_buffer(collection_start,
451                         WINDOW_SIZE,
452                         0,
453                         get_direction());
455                 collection_start += step * WINDOW_SIZE;
456                 total_windows++;
457         }
459         for(int i = 0; i < WINDOW_SIZE / 2; i++)
460         {
461                 reference[i] /= total_windows;
462         }
472 DenoiseFFTRemove::DenoiseFFTRemove(DenoiseFFTEffect *plugin)
474         this->plugin = plugin;
477 int DenoiseFFTRemove::signal_process()
479         double level = DB::fromdb(plugin->config.level);
480         for(int i = 0; i < window_size / 2; i++)
481         {
482                 double result = sqrt(freq_real[i] * freq_real[i] + freq_imag[i] * freq_imag[i]);
483                 double angle = atan2(freq_imag[i], freq_real[i]);
484                 result -= plugin->reference[i] * level;
485                 if(result < 0) result = 0;
486                 freq_real[i] = result * cos(angle);
487                 freq_imag[i] = result * sin(angle);
488         }
489         symmetry(window_size, freq_real, freq_imag);
490         return 0;
493 int DenoiseFFTRemove::read_samples(int64_t output_sample, 
494         int samples, 
495         double *buffer)
497         return plugin->read_samples(buffer,
498                 0,
499                 plugin->get_samplerate(),
500                 output_sample,
501                 samples);
508 DenoiseFFTCollect::DenoiseFFTCollect(DenoiseFFTEffect *plugin)
510         this->plugin = plugin;
513 int DenoiseFFTCollect::signal_process()
515         for(int i = 0; i < window_size / 2; i++)
516         {
517                 double result = sqrt(freq_real[i] * freq_real[i] + freq_imag[i] * freq_imag[i]);
518                 plugin->reference[i] += result;
519         }
520         return 0;
523 int DenoiseFFTCollect::read_samples(int64_t output_sample, 
524         int samples, 
525         double *buffer)
527         return plugin->read_samples(buffer,
528                 0,
529                 plugin->get_samplerate(),
530                 output_sample,
531                 samples);