1 #include "bcdisplayinfo.h"
5 #include "parametric.h"
14 #define _(String) gettext(String)
15 #define gettext_noop(String) String
16 #define N_(String) gettext_noop (String)
25 PluginClient* new_plugin(PluginServer *server)
27 return new ParametricEQ(server);
37 ParametricBand::ParametricBand()
46 int ParametricBand::equivalent(ParametricBand &that)
48 if(freq == that.freq &&
49 EQUIV(quality, that.quality) &&
50 EQUIV(magnitude, that.magnitude) &&
60 void ParametricBand::copy_from(ParametricBand &that)
63 quality = that.quality;
64 magnitude = that.magnitude;
68 void ParametricBand::interpolate(ParametricBand &prev,
73 freq = (int)(prev.freq * prev_scale + next.freq * next_scale + 0.5);
74 quality = prev.quality * prev_scale + next.quality * next_scale;
75 magnitude = prev.magnitude * prev_scale + next.magnitude * next_scale;
83 ParametricConfig::ParametricConfig()
85 wetness = INFINITYGAIN;
89 int ParametricConfig::equivalent(ParametricConfig &that)
91 for(int i = 0; i < BANDS; i++)
92 if(!band[i].equivalent(that.band[i])) return 0;
94 if(!EQUIV(wetness, that.wetness)) return 0;
98 void ParametricConfig::copy_from(ParametricConfig &that)
100 wetness = that.wetness;
101 for(int i = 0; i < BANDS; i++)
102 band[i].copy_from(that.band[i]);
105 void ParametricConfig::interpolate(ParametricConfig &prev,
106 ParametricConfig &next,
109 int64_t current_frame)
111 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
112 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
113 wetness = prev.wetness;
114 for(int i = 0; i < BANDS; i++)
116 band[i].interpolate(prev.band[i], next.band[i], prev_scale, next_scale);
138 ParametricFreq::ParametricFreq(ParametricEQ *plugin, int x, int y, int band)
139 : BC_QPot(x, y, plugin->config.band[band].freq)
141 this->plugin = plugin;
145 int ParametricFreq::handle_event()
147 plugin->config.band[band].freq = get_value();
148 plugin->send_configure_change();
149 plugin->thread->window->update_canvas();
160 ParametricQuality::ParametricQuality(ParametricEQ *plugin, int x, int y, int band)
161 : BC_FPot(x, y, plugin->config.band[band].quality, 0, 1)
163 this->plugin = plugin;
168 int ParametricQuality::handle_event()
170 plugin->config.band[band].quality = get_value();
171 plugin->send_configure_change();
172 plugin->thread->window->update_canvas();
186 ParametricMagnitude::ParametricMagnitude(ParametricEQ *plugin, int x, int y, int band)
187 : BC_FPot(x, y, plugin->config.band[band].magnitude, -MAXMAGNITUDE, MAXMAGNITUDE)
189 this->plugin = plugin;
193 int ParametricMagnitude::handle_event()
195 plugin->config.band[band].magnitude = get_value();
196 plugin->send_configure_change();
197 plugin->thread->window->update_canvas();
209 ParametricMode::ParametricMode(ParametricEQ *plugin, int x, int y, int band)
213 mode_to_text(plugin->config.band[band].mode))
215 //printf("ParametricMode::ParametricMode %d %d\n", band, plugin->config.band[band].mode);
216 this->plugin = plugin;
220 void ParametricMode::create_objects()
222 add_item(new BC_MenuItem(mode_to_text(ParametricBand::LOWPASS)));
223 add_item(new BC_MenuItem(mode_to_text(ParametricBand::HIGHPASS)));
224 add_item(new BC_MenuItem(mode_to_text(ParametricBand::BANDPASS)));
225 add_item(new BC_MenuItem(mode_to_text(ParametricBand::NONE)));
229 int ParametricMode::handle_event()
231 plugin->config.band[band].mode = text_to_mode(get_text());
232 plugin->send_configure_change();
233 plugin->thread->window->update_canvas();
237 int ParametricMode::text_to_mode(char *text)
239 if(!strcmp(mode_to_text(ParametricBand::LOWPASS), text)) return ParametricBand::LOWPASS;
240 if(!strcmp(mode_to_text(ParametricBand::HIGHPASS), text)) return ParametricBand::HIGHPASS;
241 if(!strcmp(mode_to_text(ParametricBand::BANDPASS), text)) return ParametricBand::BANDPASS;
242 if(!strcmp(mode_to_text(ParametricBand::NONE), text)) return ParametricBand::NONE;
243 return ParametricBand::BANDPASS;
248 char* ParametricMode::mode_to_text(int mode)
252 case ParametricBand::LOWPASS:
255 case ParametricBand::HIGHPASS:
256 return _("Highpass");
258 case ParametricBand::BANDPASS:
259 return _("Bandpass");
261 case ParametricBand::NONE:
278 ParametricBandGUI::ParametricBandGUI(ParametricEQ *plugin, ParametricWindow *window, int x, int y, int band)
280 this->plugin = plugin;
282 this->window = window;
287 ParametricBandGUI::~ParametricBandGUI()
298 void ParametricBandGUI::create_objects()
300 window->add_subwindow(freq = new ParametricFreq(plugin, X1, y, band));
301 window->add_subwindow(quality = new ParametricQuality(plugin, X2, y, band));
302 window->add_subwindow(magnitude = new ParametricMagnitude(plugin, X3, y, band));
303 window->add_subwindow(mode = new ParametricMode(plugin, X4, y, band));
304 mode->create_objects();
307 void ParametricBandGUI::update_gui()
309 freq->update(plugin->config.band[band].freq);
310 quality->update(plugin->config.band[band].quality);
311 magnitude->update(plugin->config.band[band].magnitude);
319 ParametricWetness::ParametricWetness(ParametricEQ *plugin, int x, int y)
320 : BC_FPot(x, y, plugin->config.wetness, INFINITYGAIN, 0)
322 this->plugin = plugin;
325 int ParametricWetness::handle_event()
327 plugin->config.wetness = get_value();
328 plugin->send_configure_change();
329 plugin->thread->window->update_canvas();
338 ParametricWindow::ParametricWindow(ParametricEQ *plugin, int x, int y)
339 : BC_Window(plugin->gui_string,
350 this->plugin = plugin;
353 ParametricWindow::~ParametricWindow()
355 for(int i = 0; i < BANDS; i++)
359 void ParametricWindow::create_objects()
364 add_subwindow(new BC_Title(X1, 10, _("Freq")));
365 add_subwindow(new BC_Title(X2, 10, _("Qual")));
366 add_subwindow(new BC_Title(X3, 10, _("Level")));
367 add_subwindow(new BC_Title(X4, 10, _("Mode")));
368 for(int i = 0; i < BANDS; i++)
370 bands[i] = new ParametricBandGUI(plugin, this, 10, y, i);
371 bands[i]->create_objects();
375 add_subwindow(new BC_Title(10, y + 10, _("Wetness:")));
376 add_subwindow(wetness = new ParametricWetness(plugin, 80, y));
378 add_subwindow(canvas = new BC_SubWindow(10, y, get_w() - 20, get_h() - y - 10, WHITE));
386 int ParametricWindow::close_event()
388 // Set result to 1 to indicate a client side close
393 void ParametricWindow::update_gui()
395 for(int i = 0; i < BANDS; i++)
396 bands[i]->update_gui();
397 wetness->update(plugin->config.wetness);
402 void ParametricWindow::update_canvas()
404 //printf("ParametricWindow::update_canvas 1\n");
406 int y1 = canvas->get_h() / 2;
407 double normalize = DB::fromdb(MAXMAGNITUDE);
408 int niquist = plugin->PluginAClient::project_sample_rate / 2;
410 canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
411 canvas->set_color(GREEN);
413 canvas->get_h() - (int)((double)canvas->get_h() / normalize),
415 canvas->get_h() - (int)((double)canvas->get_h() / normalize));
417 canvas->set_color(BLACK);
419 plugin->calculate_envelope();
420 for(int i = 0; i < canvas->get_w(); i++)
422 int freq = Freq::tofreq((int)((float)i / canvas->get_w() * TOTALFREQS));
423 int index = (int)((float)freq / niquist * WINDOW_SIZE / 2);
424 double magnitude = plugin->envelope[index];
425 int y2 = canvas->get_h() -
426 (int)((double)canvas->get_h() / normalize * magnitude);
427 if(i > 0) canvas->draw_line(i - 1, y1, i, y2);
441 PLUGIN_THREAD_OBJECT(ParametricEQ, ParametricThread, ParametricWindow)
449 ParametricFFT::ParametricFFT(ParametricEQ *plugin)
452 this->plugin = plugin;
455 ParametricFFT::~ParametricFFT()
460 int ParametricFFT::signal_process()
462 //printf("ParametricFFT::signal_process 1\n");
463 for(int i = 0; i < window_size / 2; i++)
465 double result = plugin->envelope[i] * sqrt(freq_real[i] * freq_real[i] + freq_imag[i] * freq_imag[i]);
466 double angle = atan2(freq_imag[i], freq_real[i]);
467 freq_real[i] = result * cos(angle);
468 freq_imag[i] = result * sin(angle);
470 //printf("ParametricFFT::signal_process 2\n");
472 symmetry(window_size, freq_real, freq_imag);
473 //printf("ParametricFFT::signal_process 3\n");
486 ParametricEQ::ParametricEQ(PluginServer *server)
487 : PluginAClient(server)
489 //printf("ParametricEQ::ParametricEQ 1\n");
492 //printf("ParametricEQ::ParametricEQ 2\n");
495 ParametricEQ::~ParametricEQ()
499 thread->window->set_done(0);
500 thread->completion.lock();
510 NEW_PICON_MACRO(ParametricEQ)
512 SHOW_GUI_MACRO(ParametricEQ, ParametricThread)
514 RAISE_WINDOW_MACRO(ParametricEQ)
516 SET_STRING_MACRO(ParametricEQ)
518 LOAD_CONFIGURATION_MACRO(ParametricEQ, ParametricConfig)
521 char* ParametricEQ::plugin_title()
523 return _("EQ Parametric");
526 int ParametricEQ::is_realtime()
531 void ParametricEQ::read_data(KeyFrame *keyframe)
534 input.set_shared_string(keyframe->data, strlen(keyframe->data));
539 result = input.read_tag();
543 if(input.tag.title_is("PARAMETRICEQ"))
545 config.wetness = input.tag.get_property("WETNESS", config.wetness);
548 if(input.tag.title_is("BAND"))
550 int band = input.tag.get_property("NUMBER", 0);
551 config.band[band].freq = input.tag.get_property("FREQ", config.band[band].freq);
552 config.band[band].quality = input.tag.get_property("QUALITY", config.band[band].quality);
553 config.band[band].magnitude = input.tag.get_property("MAGNITUDE", config.band[band].magnitude);
554 config.band[band].mode = input.tag.get_property("MODE", config.band[band].mode);
560 void ParametricEQ::save_data(KeyFrame *keyframe)
563 output.set_shared_string(keyframe->data, MESSAGESIZE);
565 output.tag.set_title("PARAMETRICEQ");
566 output.tag.set_property("WETNESS", config.wetness);
568 output.append_newline();
570 for(int i = 0; i < BANDS; i++)
572 output.tag.set_title("BAND");
573 output.tag.set_property("NUMBER", i);
574 output.tag.set_property("FREQ", config.band[i].freq);
575 output.tag.set_property("QUALITY", config.band[i].quality);
576 output.tag.set_property("MAGNITUDE", config.band[i].magnitude);
577 output.tag.set_property("MODE", config.band[i].mode);
579 output.append_newline();
582 output.terminate_string();
585 void ParametricEQ::reconfigure()
589 fft = new ParametricFFT(this);
590 fft->initialize(WINDOW_SIZE);
595 //printf("ParametricEQ::reconfigure %f\n", wetness);
596 calculate_envelope();
598 for(int i = 0; i < WINDOW_SIZE / 2; i++)
600 if(envelope[i] < 0) envelope[i] = 0;
603 need_reconfigure = 0;
606 double ParametricEQ::calculate_envelope()
608 double wetness = DB::fromdb(config.wetness);
609 int niquist = PluginAClient::project_sample_rate / 2;
610 //printf("ParametricEQ::calculate_envelope %d %d\n", niquist, PluginAClient::project_sample_rate);
613 for(int i = 0; i < WINDOW_SIZE / 2; i++)
615 envelope[i] = wetness;
618 for(int pass = 0; pass < 2; pass++)
620 for(int band = 0; band < BANDS; band++)
622 switch(config.band[band].mode)
624 case ParametricBand::LOWPASS:
627 double magnitude = DB::fromdb(config.band[band].magnitude);
628 int cutoff = (int)((float)config.band[band].freq / niquist * WINDOW_SIZE / 2);
629 for(int i = 0; i < WINDOW_SIZE / 2; i++)
632 envelope[i] += magnitude;
637 case ParametricBand::HIGHPASS:
640 double magnitude = DB::fromdb(config.band[band].magnitude);
641 int cutoff = (int)((float)config.band[band].freq / niquist * WINDOW_SIZE / 2);
642 for(int i = 0; i < WINDOW_SIZE / 2; i++)
645 envelope[i] += magnitude;
650 case ParametricBand::BANDPASS:
653 double magnitude = (config.band[band].magnitude > 0) ?
654 (DB::fromdb(config.band[band].magnitude) - 1) :
655 (-1 + DB::fromdb(config.band[band].magnitude));
656 double sigma = (config.band[band].quality < 1) ?
657 (1.0 - config.band[band].quality) :
660 double a = (double)config.band[band].freq / niquist;
661 double normalize = gauss(sigma, 0, 0);
662 if(config.band[band].magnitude <= -MAXMAGNITUDE)
665 for(int i = 0; i < WINDOW_SIZE / 2; i++)
666 envelope[i] += magnitude *
667 gauss(sigma, a, (double)i / (WINDOW_SIZE / 2)) /
677 double ParametricEQ::gauss(double sigma, double a, double x)
679 if(EQUIV(sigma, 0)) sigma = 0.01;
682 sqrt(2 * M_PI * sigma * sigma) *
683 exp(-(x - a) * (x - a) /
684 (2 * sigma * sigma));
687 int ParametricEQ::process_realtime(int64_t size,
691 need_reconfigure |= load_configuration();
692 if(need_reconfigure) reconfigure();
695 fft->process_fifo(size, input_ptr, output_ptr);
706 int ParametricEQ::load_defaults()
708 char directory[BCTEXTLEN], string[BCTEXTLEN];
709 sprintf(directory, "%sparametriceq.rc", BCASTDIR);
710 defaults = new Defaults(directory);
713 config.wetness = defaults->get("WETNESS", config.wetness);
714 for(int i = 0; i < BANDS; i++)
716 sprintf(string, "FREQ_%d", i);
717 config.band[i].freq = defaults->get(string, config.band[i].freq);
718 sprintf(string, "QUALITY_%d", i);
719 config.band[i].quality = defaults->get(string, config.band[i].quality);
720 sprintf(string, "MAGNITUDE_%d", i);
721 config.band[i].magnitude = defaults->get(string, config.band[i].magnitude);
722 sprintf(string, "MODE_%d", i);
723 config.band[i].mode = defaults->get(string, config.band[i].mode);
728 int ParametricEQ::save_defaults()
730 char string[BCTEXTLEN];
732 defaults->update("WETNESS", config.wetness);
735 for(int i = 0; i < BANDS; i++)
737 sprintf(string, "FREQ_%d", i);
738 defaults->update(string, config.band[i].freq);
739 sprintf(string, "QUALITY_%d", i);
740 defaults->update(string, config.band[i].quality);
741 sprintf(string, "MAGNITUDE_%d", i);
742 defaults->update(string, config.band[i].magnitude);
743 sprintf(string, "MODE_%d", i);
744 defaults->update(string, config.band[i].mode);
754 void ParametricEQ::reset()
756 need_reconfigure = 1;
761 void ParametricEQ::update_gui()
765 load_configuration();
766 thread->window->lock_window();
767 thread->window->update_gui();
768 thread->window->unlock_window();