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, 100, 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()
243 add_subwindow(new BC_Title(x, y, _("Denoise power:")));
244 add_subwindow(level = new DenoiseFFTLevel(plugin, x + 130, y));
245 y += level->get_h() + 10;
246 add_subwindow(new BC_Title(x, y, _("Number of samples for reference:")));
248 add_subwindow(new BC_Title(x, y, _("The keyframe is the start of the reference")));
251 char string[BCTEXTLEN];
252 sprintf(string, "%d\n", plugin->config.samples);
253 add_subwindow(samples = new DenoiseFFTSamples(plugin, x + 100, y, string));
254 for(int i = WINDOW_SIZE; i < 0x100000; )
256 sprintf(string, "%d", i);
257 samples->add_item(new BC_MenuItem(string));
283 DenoiseFFTEffect::DenoiseFFTEffect(PluginServer *server)
284 : PluginAClient(server)
290 DenoiseFFTEffect::~DenoiseFFTEffect()
293 if(reference) delete [] reference;
294 if(remove_engine) delete remove_engine;
295 if(collect_engine) delete collect_engine;
298 NEW_WINDOW_MACRO(DenoiseFFTEffect, DenoiseFFTWindow)
301 void DenoiseFFTEffect::reset()
307 collection_sample = 0;
310 int DenoiseFFTEffect::is_realtime() { return 1; }
311 const char* DenoiseFFTEffect::plugin_title() { return N_("DenoiseFFT"); }
317 void DenoiseFFTEffect::read_data(KeyFrame *keyframe)
320 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
325 result = input.read_tag();
329 if(input.tag.title_is("DENOISEFFT"))
331 config.samples = input.tag.get_property("SAMPLES", config.samples);
332 config.level = input.tag.get_property("LEVEL", config.level);
338 void DenoiseFFTEffect::save_data(KeyFrame *keyframe)
341 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
343 output.tag.set_title("DENOISEFFT");
344 output.tag.set_property("SAMPLES", config.samples);
345 output.tag.set_property("LEVEL", config.level);
347 output.tag.set_title("/DENOISEFFT");
349 output.append_newline();
350 output.terminate_string();
354 void DenoiseFFTEffect::update_gui()
358 load_configuration();
359 ((DenoiseFFTWindow*)thread->window)->lock_window();
360 ((DenoiseFFTWindow*)thread->window)->level->update(config.level);
361 char string[BCTEXTLEN];
362 sprintf(string, "%d", config.samples);
363 ((DenoiseFFTWindow*)thread->window)->samples->set_text(string);
364 ((DenoiseFFTWindow*)thread->window)->unlock_window();
368 int DenoiseFFTEffect::load_configuration()
370 KeyFrame *prev_keyframe = get_prev_keyframe(get_source_position());
371 int64_t prev_position = edl_to_local(prev_keyframe->position);
372 read_data(prev_keyframe);
373 if(prev_position == 0) prev_position = get_source_start();
375 if(prev_position != collection_sample)
377 collection_sample = prev_position;
383 int DenoiseFFTEffect::process_buffer(int64_t size,
385 int64_t start_position,
388 load_configuration();
390 // Do noise collection
400 remove_engine = new DenoiseFFTRemove(this);
401 remove_engine->initialize(WINDOW_SIZE);
403 remove_engine->process_buffer(start_position,
412 void DenoiseFFTEffect::collect_noise()
414 if(!reference) reference = new double[WINDOW_SIZE / 2];
417 collect_engine = new DenoiseFFTCollect(this);
418 collect_engine->initialize(WINDOW_SIZE);
420 bzero(reference, sizeof(double) * WINDOW_SIZE / 2);
422 int64_t collection_start = collection_sample;
424 int total_windows = 0;
426 if(get_direction() == PLAY_REVERSE)
428 collection_start += config.samples;
432 for(int i = 0; i < config.samples; i += WINDOW_SIZE)
434 collect_engine->process_buffer(collection_start,
439 collection_start += step * WINDOW_SIZE;
443 for(int i = 0; i < WINDOW_SIZE / 2; i++)
445 reference[i] /= total_windows;
456 DenoiseFFTRemove::DenoiseFFTRemove(DenoiseFFTEffect *plugin)
458 this->plugin = plugin;
461 int DenoiseFFTRemove::signal_process()
463 double level = DB::fromdb(plugin->config.level);
464 for(int i = 0; i < window_size / 2; i++)
466 double result = sqrt(freq_real[i] * freq_real[i] + freq_imag[i] * freq_imag[i]);
467 double angle = atan2(freq_imag[i], freq_real[i]);
468 result -= plugin->reference[i] * level;
469 if(result < 0) result = 0;
470 freq_real[i] = result * cos(angle);
471 freq_imag[i] = result * sin(angle);
473 symmetry(window_size, freq_real, freq_imag);
477 int DenoiseFFTRemove::read_samples(int64_t output_sample,
481 return plugin->read_samples(buffer,
483 plugin->get_samplerate(),
492 DenoiseFFTCollect::DenoiseFFTCollect(DenoiseFFTEffect *plugin)
494 this->plugin = plugin;
497 int DenoiseFFTCollect::signal_process()
499 for(int i = 0; i < window_size / 2; i++)
501 double result = sqrt(freq_real[i] * freq_real[i] + freq_imag[i] * freq_imag[i]);
502 plugin->reference[i] += result;
507 int DenoiseFFTCollect::read_samples(int64_t output_sample,
511 return plugin->read_samples(buffer,
513 plugin->get_samplerate(),