1 #include "bcdisplayinfo.h"
4 #include "filesystem.h"
10 #include "picon_png.h"
11 #include "pluginaclient.h"
12 #include "transportque.inc"
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
44 class DenoiseFFTLevel : public BC_FPot
47 DenoiseFFTLevel(DenoiseFFTEffect *plugin, int x, int y);
49 DenoiseFFTEffect *plugin;
52 class DenoiseFFTSamples : public BC_PopupMenu
55 DenoiseFFTSamples(DenoiseFFTEffect *plugin, int x, int y, char *text);
57 DenoiseFFTEffect *plugin;
60 class DenoiseFFTWindow : public BC_Window
63 DenoiseFFTWindow(DenoiseFFTEffect *plugin, int x, int y);
64 void create_objects();
66 DenoiseFFTLevel *level;
67 DenoiseFFTSamples *samples;
68 DenoiseFFTEffect *plugin;
83 PLUGIN_THREAD_HEADER(DenoiseFFTEffect, DenoiseFFTThread, DenoiseFFTWindow)
86 class DenoiseFFTRemove : public CrossfadeFFT
89 DenoiseFFTRemove(DenoiseFFTEffect *plugin);
91 int read_samples(int64_t output_sample,
94 DenoiseFFTEffect *plugin;
97 class DenoiseFFTCollect : public CrossfadeFFT
100 DenoiseFFTCollect(DenoiseFFTEffect *plugin);
101 int signal_process();
102 int read_samples(int64_t output_sample,
105 DenoiseFFTEffect *plugin;
108 class DenoiseFFTEffect : public PluginAClient
111 DenoiseFFTEffect(PluginServer *server);
115 void read_data(KeyFrame *keyframe);
116 void save_data(KeyFrame *keyframe);
117 int process_buffer(int64_t size,
119 int64_t start_position,
121 void collect_noise();
130 void process_window();
133 PLUGIN_CLASS_MEMBERS(DenoiseFFTConfig, DenoiseFFTThread)
135 // Need to sample noise now.
137 // Start of sample of noise to collect
138 int64_t collection_sample;
140 DenoiseFFTRemove *remove_engine;
141 DenoiseFFTCollect *collect_engine;
153 REGISTER_PLUGIN(DenoiseFFTEffect)
163 DenoiseFFTConfig::DenoiseFFTConfig()
165 samples = WINDOW_SIZE;
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;
187 int DenoiseFFTLevel::handle_event()
189 plugin->config.level = get_value();
190 plugin->send_configure_change();
194 DenoiseFFTSamples::DenoiseFFTSamples(DenoiseFFTEffect *plugin,
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();
212 DenoiseFFTWindow::DenoiseFFTWindow(DenoiseFFTEffect *plugin, int x, int y)
213 : BC_Window(plugin->gui_string,
224 this->plugin = plugin;
227 void DenoiseFFTWindow::create_objects()
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:")));
236 add_subwindow(new BC_Title(x, y, _("The keyframe is the start of the reference")));
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; )
244 sprintf(string, "%d", i);
245 samples->add_item(new BC_MenuItem(string));
252 WINDOW_CLOSE_EVENT(DenoiseFFTWindow)
264 PLUGIN_THREAD_OBJECT(DenoiseFFTEffect, DenoiseFFTThread, DenoiseFFTWindow)
274 DenoiseFFTEffect::DenoiseFFTEffect(PluginServer *server)
275 : PluginAClient(server)
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()
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)
317 input.set_shared_string(keyframe->data, strlen(keyframe->data));
322 result = input.read_tag();
326 if(input.tag.title_is("DENOISEFFT"))
328 config.samples = input.tag.get_property("SAMPLES", config.samples);
329 config.level = input.tag.get_property("LEVEL", config.level);
335 void DenoiseFFTEffect::save_data(KeyFrame *keyframe)
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);
344 output.append_newline();
346 output.terminate_string();
349 int DenoiseFFTEffect::load_defaults()
351 defaults = new BC_Hash(BCASTDIR "denoisefft.rc");
354 config.level = defaults->get("LEVEL", config.level);
355 config.samples = defaults->get("SAMPLES", config.samples);
359 int DenoiseFFTEffect::save_defaults()
361 char string[BCTEXTLEN];
363 defaults->update("LEVEL", config.level);
364 defaults->update("SAMPLES", config.samples);
370 void DenoiseFFTEffect::update_gui()
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();
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)
393 collection_sample = prev_position;
399 int DenoiseFFTEffect::process_buffer(int64_t size,
401 int64_t start_position,
404 load_configuration();
406 // Do noise collection
416 remove_engine = new DenoiseFFTRemove(this);
417 remove_engine->initialize(WINDOW_SIZE);
419 remove_engine->process_buffer(start_position,
428 void DenoiseFFTEffect::collect_noise()
430 if(!reference) reference = new double[WINDOW_SIZE / 2];
433 collect_engine = new DenoiseFFTCollect(this);
434 collect_engine->initialize(WINDOW_SIZE);
436 bzero(reference, sizeof(double) * WINDOW_SIZE / 2);
438 int64_t collection_start = collection_sample;
440 int total_windows = 0;
442 if(get_direction() == PLAY_REVERSE)
444 collection_start += config.samples;
448 for(int i = 0; i < config.samples; i += WINDOW_SIZE)
450 collect_engine->process_buffer(collection_start,
455 collection_start += step * WINDOW_SIZE;
459 for(int i = 0; i < WINDOW_SIZE / 2; i++)
461 reference[i] /= total_windows;
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++)
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);
489 symmetry(window_size, freq_real, freq_imag);
493 int DenoiseFFTRemove::read_samples(int64_t output_sample,
497 return plugin->read_samples(buffer,
499 plugin->get_samplerate(),
508 DenoiseFFTCollect::DenoiseFFTCollect(DenoiseFFTEffect *plugin)
510 this->plugin = plugin;
513 int DenoiseFFTCollect::signal_process()
515 for(int i = 0; i < window_size / 2; i++)
517 double result = sqrt(freq_real[i] * freq_real[i] + freq_imag[i] * freq_imag[i]);
518 plugin->reference[i] += result;
523 int DenoiseFFTCollect::read_samples(int64_t output_sample,
527 return plugin->read_samples(buffer,
529 plugin->get_samplerate(),