1 #include "bcdisplayinfo.h"
4 #include "filesystem.h"
10 #include "pluginaclient.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
40 void copy_from(DenoiseFFTConfig &that);
41 int equivalent(DenoiseFFTConfig &that);
42 void interpolate(DenoiseFFTConfig &prev,
43 DenoiseFFTConfig &next,
46 int64_t current_frame);
53 class DenoiseFFTCollecting : public BC_CheckBox
56 DenoiseFFTCollecting(DenoiseFFTEffect *plugin, int x, int y);
58 DenoiseFFTEffect *plugin;
61 class DenoiseFFTLevel : public BC_FPot
64 DenoiseFFTLevel(DenoiseFFTEffect *plugin, int x, int y);
66 DenoiseFFTEffect *plugin;
69 // class DenoiseFFTSize : public BC_TextBox
72 // DenoiseFFTSize(DenoiseFFTEffect *plugin, int x, int y);
73 // int handle_event();
74 // DenoiseFFTEffect *plugin;
77 class DenoiseFFTWindow : public BC_Window
80 DenoiseFFTWindow(DenoiseFFTEffect *plugin, int x, int y);
81 void create_objects();
83 DenoiseFFTLevel *level;
84 DenoiseFFTCollecting *collect;
85 // DenoiseFFTSize *size;
86 DenoiseFFTEffect *plugin;
101 PLUGIN_THREAD_HEADER(DenoiseFFTEffect, DenoiseFFTThread, DenoiseFFTWindow)
104 class DenoiseFFTRemove : public CrossfadeFFT
107 DenoiseFFTRemove(DenoiseFFTEffect *plugin);
108 int signal_process();
109 DenoiseFFTEffect *plugin;
112 class DenoiseFFTCollect : public CrossfadeFFT
115 DenoiseFFTCollect(DenoiseFFTEffect *plugin);
116 int signal_process();
117 DenoiseFFTEffect *plugin;
120 class DenoiseFFTEffect : public PluginAClient
123 DenoiseFFTEffect(PluginServer *server);
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);
139 void process_window();
142 PLUGIN_CLASS_MEMBERS(DenoiseFFTConfig, DenoiseFFTThread)
145 int prev_window_size;
147 DenoiseFFTRemove *remove_engine;
148 DenoiseFFTCollect *collect_engine;
160 REGISTER_PLUGIN(DenoiseFFTEffect)
170 DenoiseFFTConfig::DenoiseFFTConfig()
177 void DenoiseFFTConfig::copy_from(DenoiseFFTConfig &that)
179 window_size = that.window_size;
180 collecting = that.collecting;
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,
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;
225 int DenoiseFFTLevel::handle_event()
227 plugin->config.level = get_value();
228 plugin->send_configure_change();
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();
245 // DenoiseFFTSize::DenoiseFFTSize(DenoiseFFTEffect *plugin, int x, int y)
246 // : BC_TextBox(x, y, 100, 1, plugin->config.window_size)
248 // this->plugin = plugin;
250 // int DenoiseFFTSize::handle_event()
252 // plugin->config.window_size = atol(get_text());
253 // plugin->send_configure_change();
259 DenoiseFFTWindow::DenoiseFFTWindow(DenoiseFFTEffect *plugin, int x, int y)
260 : BC_Window(plugin->gui_string,
271 this->plugin = plugin;
274 void DenoiseFFTWindow::create_objects()
278 add_subwindow(new BC_Title(x, y, _("Denoise power:")));
279 add_subwindow(level = new DenoiseFFTLevel(plugin, x + 130, y));
281 add_subwindow(collect = new DenoiseFFTCollecting(plugin, x, y));
283 // add_subwindow(new BC_Title(x, y, _("Window size:")));
284 // add_subwindow(size = new DenoiseFFTSize(plugin, x + 100, y));
289 int DenoiseFFTWindow::close_event()
291 // Set result to 1 to indicate a client side close
306 PLUGIN_THREAD_OBJECT(DenoiseFFTEffect, DenoiseFFTThread, DenoiseFFTWindow)
322 DenoiseFFTEffect::DenoiseFFTEffect(PluginServer *server)
323 : PluginAClient(server)
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()
354 prev_window_size = 0;
357 char* DenoiseFFTEffect::plugin_title()
359 return _("DenoiseFFT");
363 int DenoiseFFTEffect::is_realtime()
370 void DenoiseFFTEffect::read_data(KeyFrame *keyframe)
373 input.set_shared_string(keyframe->data, strlen(keyframe->data));
378 result = input.read_tag();
382 if(input.tag.title_is("DENOISEFFT"))
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);
392 void DenoiseFFTEffect::save_data(KeyFrame *keyframe)
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);
402 output.append_newline();
404 output.terminate_string();
407 int DenoiseFFTEffect::load_defaults()
409 defaults = new Defaults(BCASTDIR "denoisefft.rc");
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);
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);
430 void DenoiseFFTEffect::update_gui()
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();
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)
449 if(reference) delete [] reference;
450 if(collect_engine) delete collect_engine;
451 if(remove_engine) delete remove_engine;
455 prev_window_size = config.window_size;
458 if(config.collecting)
463 reference = new double[config.window_size / 2];
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);
478 // Hasn't collected yet. Load from disk file
481 reference = new double[config.window_size / 2];
483 char string[BCTEXTLEN];
484 strcpy(string, REFERENCE_FILE);
485 fs.complete_path(string);
486 FILE *fd = fopen(string, "r");
490 fread(reference, config.window_size / 2 * sizeof(double), 1, fd);
495 bzero(reference, sizeof(double) * config.window_size / 2);
500 if(!remove_engine) remove_engine = new DenoiseFFTRemove(this);
501 remove_engine->process_fifo(size, input_ptr, output_ptr);
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++)
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);
532 symmetry(window_size, freq_real, freq_imag);
540 DenoiseFFTCollect::DenoiseFFTCollect(DenoiseFFTEffect *plugin)
542 this->plugin = plugin;
545 int DenoiseFFTCollect::signal_process()
547 for(int i = 0; i < window_size / 2; i++)
549 // Moving average of peak so you don't need to stop, play, restart, play to
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;
556 plugin->reference[i] = result;
560 char string[BCTEXTLEN];
561 strcpy(string, REFERENCE_FILE);
562 fs.complete_path(string);
563 FILE *fd = fopen(string, "w");
566 fwrite(plugin->reference, window_size / 2 * sizeof(double), 1, fd);
570 printf("DenoiseFFTCollect::signal_process: can't open %s for writing. %s.\n",
571 REFERENCE_FILE, strerror(errno));