ffmpeg versioning mods from Andrew
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / denoisefft / denoisefft.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 "filesystem.h"
26 #include "filexml.h"
27 #include "guicast.h"
28 #include "language.h"
29 #include "mutex.h"
30 #include "fourier.h"
31 #include "pluginaclient.h"
32 #include "transportque.inc"
33 #include "units.h"
34 #include "vframe.h"
35
36 #include <errno.h>
37 #include <math.h>
38 #include <string.h>
39
40
41
42 #define WINDOW_SIZE 16384
43
44
45 // Noise collection is done either from the start of the effect or the start
46 // of the previous keyframe.  It always covers the higher numbered samples
47 // after the keyframe.
48
49 class DenoiseFFTEffect;
50 class DenoiseFFTWindow;
51
52
53
54
55 class DenoiseFFTConfig
56 {
57 public:
58         DenoiseFFTConfig();
59
60         int samples;
61         double level;
62 };
63
64 class DenoiseFFTLevel : public BC_FPot
65 {
66 public:
67         DenoiseFFTLevel(DenoiseFFTEffect *plugin, int x, int y);
68         int handle_event();
69         DenoiseFFTEffect *plugin;
70 };
71
72 class DenoiseFFTSamples : public BC_PopupMenu
73 {
74 public:
75         DenoiseFFTSamples(DenoiseFFTEffect *plugin, int x, int y, char *text);
76         int handle_event();
77         DenoiseFFTEffect *plugin;
78 };
79
80 class DenoiseFFTWindow : public PluginClientWindow
81 {
82 public:
83         DenoiseFFTWindow(DenoiseFFTEffect *plugin);
84         void create_objects();
85         DenoiseFFTLevel *level;
86         DenoiseFFTSamples *samples;
87         DenoiseFFTEffect *plugin;
88 };
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 class DenoiseFFTRemove : public CrossfadeFFT
105 {
106 public:
107         DenoiseFFTRemove(DenoiseFFTEffect *plugin);
108         int signal_process();
109         int read_samples(int64_t output_sample,
110                 int samples,
111                 Samples *buffer);
112         DenoiseFFTEffect *plugin;
113 };
114
115 class DenoiseFFTCollect : public CrossfadeFFT
116 {
117 public:
118         DenoiseFFTCollect(DenoiseFFTEffect *plugin);
119         int signal_process();
120         int read_samples(int64_t output_sample,
121                 int samples,
122                 Samples *buffer);
123         DenoiseFFTEffect *plugin;
124 };
125
126 class DenoiseFFTEffect : public PluginAClient
127 {
128 public:
129         DenoiseFFTEffect(PluginServer *server);
130         ~DenoiseFFTEffect();
131
132         int is_realtime();
133         void read_data(KeyFrame *keyframe);
134         void save_data(KeyFrame *keyframe);
135         int process_buffer(int64_t size,
136                 Samples *buffer,
137                 int64_t start_position,
138                 int sample_rate);
139         void collect_noise();
140
141
142
143         void reset();
144         void update_gui();
145
146         void process_window();
147
148
149         PLUGIN_CLASS_MEMBERS(DenoiseFFTConfig)
150
151 // Need to sample noise now.
152         int need_collection;
153 // Start of sample of noise to collect
154         int64_t collection_sample;
155         double *reference;
156         DenoiseFFTRemove *remove_engine;
157         DenoiseFFTCollect *collect_engine;
158 };
159
160
161
162
163
164
165
166
167
168
169 REGISTER_PLUGIN(DenoiseFFTEffect)
170
171
172
173
174
175
176
177
178
179 DenoiseFFTConfig::DenoiseFFTConfig()
180 {
181         samples = WINDOW_SIZE;
182         level = 0.0;
183 }
184
185
186
187
188
189
190
191
192
193
194
195
196 DenoiseFFTLevel::DenoiseFFTLevel(DenoiseFFTEffect *plugin, int x, int y)
197  : BC_FPot(x, y, (float)plugin->config.level, INFINITYGAIN, 6.0)
198 {
199         this->plugin = plugin;
200         set_precision(0.1);
201 }
202
203 int DenoiseFFTLevel::handle_event()
204 {
205         plugin->config.level = get_value();
206         plugin->send_configure_change();
207         return 1;
208 }
209
210 DenoiseFFTSamples::DenoiseFFTSamples(DenoiseFFTEffect *plugin,
211         int x,
212         int y,
213         char *text)
214  : BC_PopupMenu(x, y, xS(140), text, 1)
215 {
216         this->plugin = plugin;
217 }
218
219 int DenoiseFFTSamples::handle_event()
220 {
221         plugin->config.samples = atol(get_text());
222         plugin->send_configure_change();
223         return 1;
224 }
225
226
227
228 DenoiseFFTWindow::DenoiseFFTWindow(DenoiseFFTEffect *plugin)
229  : PluginClientWindow(plugin,
230         xS(300),
231         yS(130),
232         xS(300),
233         yS(130),
234         0)
235 {
236         this->plugin = plugin;
237 }
238
239 void DenoiseFFTWindow::create_objects()
240 {
241         int xs10 = xS(10), xs100 = xS(100), xs130 = xS(130);
242         int ys10 = yS(10), ys20 = yS(20);
243         int x = xs10, y = ys10;
244
245         add_subwindow(new BC_Title(x, y, _("Denoise power:")));
246         add_subwindow(level = new DenoiseFFTLevel(plugin, x + xs130, y));
247         y += level->get_h() + ys10;
248         add_subwindow(new BC_Title(x, y, _("Number of samples for reference:")));
249         y += ys20;
250         add_subwindow(new BC_Title(x, y, _("The keyframe is the start of the reference")));
251         y += ys20;
252
253         char string[BCTEXTLEN];
254         sprintf(string, "%d\n", plugin->config.samples);
255         add_subwindow(samples = new DenoiseFFTSamples(plugin, x + xs100, y, string));
256         for(int i = WINDOW_SIZE; i < 0x100000; )
257         {
258                 sprintf(string, "%d", i);
259                 samples->add_item(new BC_MenuItem(string));
260                 i *= 2;
261         }
262         show_window();
263         flush();
264 }
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285 DenoiseFFTEffect::DenoiseFFTEffect(PluginServer *server)
286  : PluginAClient(server)
287 {
288         reset();
289
290 }
291
292 DenoiseFFTEffect::~DenoiseFFTEffect()
293 {
294
295         if(reference) delete [] reference;
296         if(remove_engine) delete remove_engine;
297         if(collect_engine) delete collect_engine;
298 }
299
300 NEW_WINDOW_MACRO(DenoiseFFTEffect, DenoiseFFTWindow)
301
302
303 void DenoiseFFTEffect::reset()
304 {
305         reference = 0;
306         remove_engine = 0;
307         collect_engine = 0;
308         need_collection = 1;
309         collection_sample = 0;
310 }
311
312 int DenoiseFFTEffect::is_realtime() { return 1; }
313 const char* DenoiseFFTEffect::plugin_title() { return N_("DenoiseFFT"); }
314
315
316
317
318
319 void DenoiseFFTEffect::read_data(KeyFrame *keyframe)
320 {
321         FileXML input;
322         input.set_shared_input(keyframe->xbuf);
323
324         int result = 0;
325         while(!result)
326         {
327                 result = input.read_tag();
328
329                 if(!result)
330                 {
331                         if(input.tag.title_is("DENOISEFFT"))
332                         {
333                                 config.samples = input.tag.get_property("SAMPLES", config.samples);
334                                 config.level = input.tag.get_property("LEVEL", config.level);
335                         }
336                 }
337         }
338 }
339
340 void DenoiseFFTEffect::save_data(KeyFrame *keyframe)
341 {
342         FileXML output;
343         output.set_shared_output(keyframe->xbuf);
344
345         output.tag.set_title("DENOISEFFT");
346         output.tag.set_property("SAMPLES", config.samples);
347         output.tag.set_property("LEVEL", config.level);
348         output.append_tag();
349         output.tag.set_title("/DENOISEFFT");
350         output.append_tag();
351         output.append_newline();
352         output.terminate_string();
353 }
354
355
356 void DenoiseFFTEffect::update_gui()
357 {
358         if(thread)
359         {
360                 load_configuration();
361                 ((DenoiseFFTWindow*)thread->window)->lock_window();
362                 ((DenoiseFFTWindow*)thread->window)->level->update(config.level);
363                 char string[BCTEXTLEN];
364                 sprintf(string, "%d", config.samples);
365                 ((DenoiseFFTWindow*)thread->window)->samples->set_text(string);
366                 ((DenoiseFFTWindow*)thread->window)->unlock_window();
367         }
368 }
369
370 int DenoiseFFTEffect::load_configuration()
371 {
372         KeyFrame *prev_keyframe = get_prev_keyframe(get_source_position());
373         int64_t prev_position = edl_to_local(prev_keyframe->position);
374         read_data(prev_keyframe);
375         if(prev_position == 0) prev_position = get_source_start();
376
377         if(prev_position != collection_sample)
378         {
379                 collection_sample = prev_position;
380                 need_collection = 1;
381         }
382         return 0;
383 }
384
385 int DenoiseFFTEffect::process_buffer(int64_t size,
386                 Samples *buffer,
387                 int64_t start_position,
388                 int sample_rate)
389 {
390         load_configuration();
391
392 // Do noise collection
393         if(need_collection)
394         {
395                 need_collection = 0;
396                 collect_noise();
397         }
398
399 // Remove noise
400         if(!remove_engine)
401         {
402                 remove_engine = new DenoiseFFTRemove(this);
403                 remove_engine->initialize(WINDOW_SIZE);
404         }
405         remove_engine->process_buffer(start_position,
406                 size,
407                 buffer,
408                 get_direction());
409
410         return 0;
411 }
412
413
414 void DenoiseFFTEffect::collect_noise()
415 {
416         if(!reference) reference = new double[WINDOW_SIZE / 2];
417         if(!collect_engine)
418         {
419                 collect_engine = new DenoiseFFTCollect(this);
420                 collect_engine->initialize(WINDOW_SIZE);
421         }
422         bzero(reference, sizeof(double) * WINDOW_SIZE / 2);
423
424         int64_t collection_start = collection_sample;
425         int step = 1;
426         int total_windows = 0;
427
428         if(get_direction() == PLAY_REVERSE)
429         {
430                 collection_start += config.samples;
431                 step = -1;
432         }
433
434         for(int i = 0; i < config.samples; i += WINDOW_SIZE)
435         {
436                 collect_engine->process_buffer(collection_start,
437                         WINDOW_SIZE, (Samples**)0, get_direction());
438                 collection_start += step * WINDOW_SIZE;
439                 total_windows++;
440         }
441
442         for(int i = 0; i < WINDOW_SIZE / 2; i++)
443         {
444                 reference[i] /= total_windows;
445         }
446 }
447
448
449
450
451
452
453
454
455 DenoiseFFTRemove::DenoiseFFTRemove(DenoiseFFTEffect *plugin)
456 {
457         this->plugin = plugin;
458 }
459
460 int DenoiseFFTRemove::signal_process()
461 {
462         double level = DB::fromdb(plugin->config.level);
463         for(int i = 0; i < window_size / 2; i++)
464         {
465                 double result = sqrt(freq_real[i] * freq_real[i] + freq_imag[i] * freq_imag[i]);
466                 double angle = atan2(freq_imag[i], freq_real[i]);
467                 result -= plugin->reference[i] * level;
468                 if(result < 0) result = 0;
469                 freq_real[i] = result * cos(angle);
470                 freq_imag[i] = result * sin(angle);
471         }
472         symmetry(window_size, freq_real, freq_imag);
473         return 0;
474 }
475
476 int DenoiseFFTRemove::read_samples(int64_t output_sample,
477         int samples,
478         Samples *buffer)
479 {
480         return plugin->read_samples(buffer,
481                 0,
482                 plugin->get_samplerate(),
483                 output_sample,
484                 samples);
485 }
486
487
488
489
490
491 DenoiseFFTCollect::DenoiseFFTCollect(DenoiseFFTEffect *plugin)
492 {
493         this->plugin = plugin;
494 }
495
496 int DenoiseFFTCollect::signal_process()
497 {
498         for(int i = 0; i < window_size / 2; i++)
499         {
500                 double result = sqrt(freq_real[i] * freq_real[i] + freq_imag[i] * freq_imag[i]);
501                 plugin->reference[i] += result;
502         }
503         return 0;
504 }
505
506 int DenoiseFFTCollect::read_samples(int64_t output_sample,
507         int samples,
508         Samples *buffer)
509 {
510         return plugin->read_samples(buffer,
511                 0,
512                 plugin->get_samplerate(),
513                 output_sample,
514                 samples);
515 }
516