4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #include "bcdisplayinfo.h"
25 #include "filesystem.h"
31 #include "pluginaclient.h"
32 #include "transportque.inc"
42 #define WINDOW_SIZE 16384
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.
49 class DenoiseFFTEffect;
50 class DenoiseFFTWindow;
55 class DenoiseFFTConfig
64 class DenoiseFFTLevel : public BC_FPot
67 DenoiseFFTLevel(DenoiseFFTEffect *plugin, int x, int y);
69 DenoiseFFTEffect *plugin;
72 class DenoiseFFTSamples : public BC_PopupMenu
75 DenoiseFFTSamples(DenoiseFFTEffect *plugin, int x, int y, char *text);
77 DenoiseFFTEffect *plugin;
80 class DenoiseFFTWindow : public PluginClientWindow
83 DenoiseFFTWindow(DenoiseFFTEffect *plugin);
84 void create_objects();
85 DenoiseFFTLevel *level;
86 DenoiseFFTSamples *samples;
87 DenoiseFFTEffect *plugin;
104 class DenoiseFFTRemove : public CrossfadeFFT
107 DenoiseFFTRemove(DenoiseFFTEffect *plugin);
108 int signal_process();
109 int read_samples(int64_t output_sample,
112 DenoiseFFTEffect *plugin;
115 class DenoiseFFTCollect : public CrossfadeFFT
118 DenoiseFFTCollect(DenoiseFFTEffect *plugin);
119 int signal_process();
120 int read_samples(int64_t output_sample,
123 DenoiseFFTEffect *plugin;
126 class DenoiseFFTEffect : public PluginAClient
129 DenoiseFFTEffect(PluginServer *server);
133 void read_data(KeyFrame *keyframe);
134 void save_data(KeyFrame *keyframe);
135 int process_buffer(int64_t size,
137 int64_t start_position,
139 void collect_noise();
146 void process_window();
149 PLUGIN_CLASS_MEMBERS(DenoiseFFTConfig)
151 // Need to sample noise now.
153 // Start of sample of noise to collect
154 int64_t collection_sample;
156 DenoiseFFTRemove *remove_engine;
157 DenoiseFFTCollect *collect_engine;
169 REGISTER_PLUGIN(DenoiseFFTEffect)
179 DenoiseFFTConfig::DenoiseFFTConfig()
181 samples = WINDOW_SIZE;
196 DenoiseFFTLevel::DenoiseFFTLevel(DenoiseFFTEffect *plugin, int x, int y)
197 : BC_FPot(x, y, (float)plugin->config.level, INFINITYGAIN, 6.0)
199 this->plugin = plugin;
203 int DenoiseFFTLevel::handle_event()
205 plugin->config.level = get_value();
206 plugin->send_configure_change();
210 DenoiseFFTSamples::DenoiseFFTSamples(DenoiseFFTEffect *plugin,
214 : BC_PopupMenu(x, y, xS(140), text, 1)
216 this->plugin = plugin;
219 int DenoiseFFTSamples::handle_event()
221 plugin->config.samples = atol(get_text());
222 plugin->send_configure_change();
228 DenoiseFFTWindow::DenoiseFFTWindow(DenoiseFFTEffect *plugin)
229 : PluginClientWindow(plugin,
236 this->plugin = plugin;
239 void DenoiseFFTWindow::create_objects()
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;
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:")));
250 add_subwindow(new BC_Title(x, y, _("The keyframe is the start of the reference")));
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; )
258 sprintf(string, "%d", i);
259 samples->add_item(new BC_MenuItem(string));
285 DenoiseFFTEffect::DenoiseFFTEffect(PluginServer *server)
286 : PluginAClient(server)
292 DenoiseFFTEffect::~DenoiseFFTEffect()
295 if(reference) delete [] reference;
296 if(remove_engine) delete remove_engine;
297 if(collect_engine) delete collect_engine;
300 NEW_WINDOW_MACRO(DenoiseFFTEffect, DenoiseFFTWindow)
303 void DenoiseFFTEffect::reset()
309 collection_sample = 0;
312 int DenoiseFFTEffect::is_realtime() { return 1; }
313 const char* DenoiseFFTEffect::plugin_title() { return N_("DenoiseFFT"); }
319 void DenoiseFFTEffect::read_data(KeyFrame *keyframe)
322 input.set_shared_input(keyframe->xbuf);
327 result = input.read_tag();
331 if(input.tag.title_is("DENOISEFFT"))
333 config.samples = input.tag.get_property("SAMPLES", config.samples);
334 config.level = input.tag.get_property("LEVEL", config.level);
340 void DenoiseFFTEffect::save_data(KeyFrame *keyframe)
343 output.set_shared_output(keyframe->xbuf);
345 output.tag.set_title("DENOISEFFT");
346 output.tag.set_property("SAMPLES", config.samples);
347 output.tag.set_property("LEVEL", config.level);
349 output.tag.set_title("/DENOISEFFT");
351 output.append_newline();
352 output.terminate_string();
356 void DenoiseFFTEffect::update_gui()
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();
370 int DenoiseFFTEffect::load_configuration()
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();
377 if(prev_position != collection_sample)
379 collection_sample = prev_position;
385 int DenoiseFFTEffect::process_buffer(int64_t size,
387 int64_t start_position,
390 load_configuration();
392 // Do noise collection
402 remove_engine = new DenoiseFFTRemove(this);
403 remove_engine->initialize(WINDOW_SIZE);
405 remove_engine->process_buffer(start_position,
414 void DenoiseFFTEffect::collect_noise()
416 if(!reference) reference = new double[WINDOW_SIZE / 2];
419 collect_engine = new DenoiseFFTCollect(this);
420 collect_engine->initialize(WINDOW_SIZE);
422 bzero(reference, sizeof(double) * WINDOW_SIZE / 2);
424 int64_t collection_start = collection_sample;
426 int total_windows = 0;
428 if(get_direction() == PLAY_REVERSE)
430 collection_start += config.samples;
434 for(int i = 0; i < config.samples; i += WINDOW_SIZE)
436 collect_engine->process_buffer(collection_start,
437 WINDOW_SIZE, (Samples**)0, get_direction());
438 collection_start += step * WINDOW_SIZE;
442 for(int i = 0; i < WINDOW_SIZE / 2; i++)
444 reference[i] /= total_windows;
455 DenoiseFFTRemove::DenoiseFFTRemove(DenoiseFFTEffect *plugin)
457 this->plugin = plugin;
460 int DenoiseFFTRemove::signal_process()
462 double level = DB::fromdb(plugin->config.level);
463 for(int i = 0; i < window_size / 2; i++)
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);
472 symmetry(window_size, freq_real, freq_imag);
476 int DenoiseFFTRemove::read_samples(int64_t output_sample,
480 return plugin->read_samples(buffer,
482 plugin->get_samplerate(),
491 DenoiseFFTCollect::DenoiseFFTCollect(DenoiseFFTEffect *plugin)
493 this->plugin = plugin;
496 int DenoiseFFTCollect::signal_process()
498 for(int i = 0; i < window_size / 2; i++)
500 double result = sqrt(freq_real[i] * freq_real[i] + freq_imag[i] * freq_imag[i]);
501 plugin->reference[i] += result;
506 int DenoiseFFTCollect::read_samples(int64_t output_sample,
510 return plugin->read_samples(buffer,
512 plugin->get_samplerate(),