1 #include "bcdisplayinfo.h"
6 #include "parametric.h"
22 REGISTER_PLUGIN(ParametricEQ)
31 ParametricBand::ParametricBand()
40 int ParametricBand::equivalent(ParametricBand &that)
42 if(freq == that.freq &&
43 EQUIV(quality, that.quality) &&
44 EQUIV(magnitude, that.magnitude) &&
54 void ParametricBand::copy_from(ParametricBand &that)
57 quality = that.quality;
58 magnitude = that.magnitude;
62 void ParametricBand::interpolate(ParametricBand &prev,
67 freq = (int)(prev.freq * prev_scale + next.freq * next_scale + 0.5);
68 quality = prev.quality * prev_scale + next.quality * next_scale;
69 magnitude = prev.magnitude * prev_scale + next.magnitude * next_scale;
77 ParametricConfig::ParametricConfig()
79 wetness = INFINITYGAIN;
83 int ParametricConfig::equivalent(ParametricConfig &that)
85 for(int i = 0; i < BANDS; i++)
86 if(!band[i].equivalent(that.band[i])) return 0;
88 if(!EQUIV(wetness, that.wetness)) return 0;
92 void ParametricConfig::copy_from(ParametricConfig &that)
94 wetness = that.wetness;
95 for(int i = 0; i < BANDS; i++)
96 band[i].copy_from(that.band[i]);
99 void ParametricConfig::interpolate(ParametricConfig &prev,
100 ParametricConfig &next,
103 int64_t current_frame)
105 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
106 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
107 wetness = prev.wetness;
108 for(int i = 0; i < BANDS; i++)
110 band[i].interpolate(prev.band[i], next.band[i], prev_scale, next_scale);
132 ParametricFreq::ParametricFreq(ParametricEQ *plugin, int x, int y, int band)
133 : BC_QPot(x, y, plugin->config.band[band].freq)
135 this->plugin = plugin;
139 int ParametricFreq::handle_event()
141 plugin->config.band[band].freq = get_value();
142 plugin->send_configure_change();
143 plugin->thread->window->update_canvas();
154 ParametricQuality::ParametricQuality(ParametricEQ *plugin, int x, int y, int band)
155 : BC_FPot(x, y, plugin->config.band[band].quality, 0, 1)
157 this->plugin = plugin;
162 int ParametricQuality::handle_event()
164 plugin->config.band[band].quality = get_value();
165 plugin->send_configure_change();
166 plugin->thread->window->update_canvas();
180 ParametricMagnitude::ParametricMagnitude(ParametricEQ *plugin, int x, int y, int band)
181 : BC_FPot(x, y, plugin->config.band[band].magnitude, -MAXMAGNITUDE, MAXMAGNITUDE)
183 this->plugin = plugin;
187 int ParametricMagnitude::handle_event()
189 plugin->config.band[band].magnitude = get_value();
190 plugin->send_configure_change();
191 plugin->thread->window->update_canvas();
203 ParametricMode::ParametricMode(ParametricEQ *plugin, int x, int y, int band)
207 mode_to_text(plugin->config.band[band].mode))
209 //printf("ParametricMode::ParametricMode %d %d\n", band, plugin->config.band[band].mode);
210 this->plugin = plugin;
214 void ParametricMode::create_objects()
216 add_item(new BC_MenuItem(mode_to_text(ParametricBand::LOWPASS)));
217 add_item(new BC_MenuItem(mode_to_text(ParametricBand::HIGHPASS)));
218 add_item(new BC_MenuItem(mode_to_text(ParametricBand::BANDPASS)));
219 add_item(new BC_MenuItem(mode_to_text(ParametricBand::NONE)));
223 int ParametricMode::handle_event()
225 plugin->config.band[band].mode = text_to_mode(get_text());
226 plugin->send_configure_change();
227 plugin->thread->window->update_canvas();
231 int ParametricMode::text_to_mode(char *text)
233 if(!strcmp(mode_to_text(ParametricBand::LOWPASS), text)) return ParametricBand::LOWPASS;
234 if(!strcmp(mode_to_text(ParametricBand::HIGHPASS), text)) return ParametricBand::HIGHPASS;
235 if(!strcmp(mode_to_text(ParametricBand::BANDPASS), text)) return ParametricBand::BANDPASS;
236 if(!strcmp(mode_to_text(ParametricBand::NONE), text)) return ParametricBand::NONE;
237 return ParametricBand::BANDPASS;
242 char* ParametricMode::mode_to_text(int mode)
246 case ParametricBand::LOWPASS:
249 case ParametricBand::HIGHPASS:
250 return _("Highpass");
252 case ParametricBand::BANDPASS:
253 return _("Bandpass");
255 case ParametricBand::NONE:
272 ParametricBandGUI::ParametricBandGUI(ParametricEQ *plugin, ParametricWindow *window, int x, int y, int band)
274 this->plugin = plugin;
276 this->window = window;
281 ParametricBandGUI::~ParametricBandGUI()
292 void ParametricBandGUI::create_objects()
294 window->add_subwindow(freq = new ParametricFreq(plugin, X1, y, band));
295 window->add_subwindow(quality = new ParametricQuality(plugin, X2, y, band));
296 window->add_subwindow(magnitude = new ParametricMagnitude(plugin, X3, y, band));
297 window->add_subwindow(mode = new ParametricMode(plugin, X4, y, band));
298 mode->create_objects();
301 void ParametricBandGUI::update_gui()
303 freq->update(plugin->config.band[band].freq);
304 quality->update(plugin->config.band[band].quality);
305 magnitude->update(plugin->config.band[band].magnitude);
313 ParametricWetness::ParametricWetness(ParametricEQ *plugin, int x, int y)
314 : BC_FPot(x, y, plugin->config.wetness, INFINITYGAIN, 0)
316 this->plugin = plugin;
319 int ParametricWetness::handle_event()
321 plugin->config.wetness = get_value();
322 plugin->send_configure_change();
323 plugin->thread->window->update_canvas();
332 ParametricWindow::ParametricWindow(ParametricEQ *plugin, int x, int y)
333 : BC_Window(plugin->gui_string,
344 this->plugin = plugin;
347 ParametricWindow::~ParametricWindow()
349 for(int i = 0; i < BANDS; i++)
353 void ParametricWindow::create_objects()
358 add_subwindow(new BC_Title(X1, 10, _("Freq")));
359 add_subwindow(new BC_Title(X2, 10, _("Qual")));
360 add_subwindow(new BC_Title(X3, 10, _("Level")));
361 add_subwindow(new BC_Title(X4, 10, _("Mode")));
362 for(int i = 0; i < BANDS; i++)
364 bands[i] = new ParametricBandGUI(plugin, this, 10, y, i);
365 bands[i]->create_objects();
369 add_subwindow(new BC_Title(10, y + 10, _("Wetness:")));
370 add_subwindow(wetness = new ParametricWetness(plugin, 80, y));
374 int canvas_w = get_w() - canvas_x - 10;
375 int canvas_h = get_h() - canvas_y - 30;
376 add_subwindow(canvas = new BC_SubWindow(canvas_x,
382 // Draw canvas titles
384 #define MAJOR_DIVISIONS 4
385 #define MINOR_DIVISIONS 5
386 for(int i = 0; i <= MAJOR_DIVISIONS; i++)
388 int y1 = canvas_y + canvas_h - i * (canvas_h / MAJOR_DIVISIONS) - 2;
390 int x1 = canvas_x - 25;
391 int x2 = canvas_x - 10;
392 int x3 = canvas_x - 2;
394 char string[BCTEXTLEN];
396 sprintf(string, "oo");
398 sprintf(string, "%d", i * 5 - 5);
401 draw_text(x1 + 1, y2 + 1, string);
402 draw_line(x2 + 1, y1 + 1, x3 + 1, y1 + 1);
404 draw_text(x1, y2, string);
405 draw_line(x2, y1, x3, y1);
407 if(i < MAJOR_DIVISIONS)
409 for(int j = 1; j < MINOR_DIVISIONS; j++)
411 int y3 = y1 - j * (canvas_h / MAJOR_DIVISIONS) / MINOR_DIVISIONS;
414 draw_line(x4 + 1, y3 + 1, x3 + 1, y3 + 1);
416 draw_line(x4, y3, x3, y3);
421 #undef MAJOR_DIVISIONS
422 #define MAJOR_DIVISIONS 5
423 for(int i = 0; i <= MAJOR_DIVISIONS; i++)
425 int freq = Freq::tofreq(i * TOTALFREQS / MAJOR_DIVISIONS);
426 int x1 = canvas_x + i * canvas_w / MAJOR_DIVISIONS;
427 int y1 = canvas_y + canvas_h + 20;
428 char string[BCTEXTLEN];
429 sprintf(string, "%d", freq);
430 int x2 = x1 - get_text_width(SMALLFONT, string);
433 int y4 = canvas_y + canvas_h;
436 draw_text(x2 + 1, y1 + 1, string);
437 draw_line(x1 + 1, y4 + 1, x1 + 1, y2 + 1);
439 draw_text(x2, y1, string);
440 draw_line(x1, y4, x1, y2);
442 if(i < MAJOR_DIVISIONS)
444 #undef MINOR_DIVISIONS
445 #define MINOR_DIVISIONS 5
446 for(int j = 0; j < MINOR_DIVISIONS; j++)
449 (canvas_w / MAJOR_DIVISIONS) -
450 exp(-(double)j * 0.7) *
451 (canvas_w / MAJOR_DIVISIONS));
453 draw_line(x3 + 1, y4 + 1, x3 + 1, y3 + 1);
455 draw_line(x3, y4, x3, y3);
465 int ParametricWindow::close_event()
467 // Set result to 1 to indicate a client side close
472 void ParametricWindow::update_gui()
474 for(int i = 0; i < BANDS; i++)
475 bands[i]->update_gui();
476 wetness->update(plugin->config.wetness);
481 void ParametricWindow::update_canvas()
484 int y1 = canvas->get_h() / 2;
485 int niquist = plugin->PluginAClient::project_sample_rate / 2;
486 int wetness = canvas->get_h() -
487 (int)((plugin->config.wetness - INFINITYGAIN) /
492 canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
493 // canvas->set_color(GREEN);
494 // canvas->draw_line(0,
499 canvas->set_color(BLACK);
501 plugin->calculate_envelope();
502 for(int i = 0; i < canvas->get_w() - 1; i++)
504 int freq = Freq::tofreq(i * TOTALFREQS / canvas->get_w());
505 int index = freq * WINDOW_SIZE / 2 / niquist;
506 double magnitude = plugin->envelope[index];
507 int y2 = canvas->get_h() * 3 / 4;
511 y2 -= (int)(DB::todb(magnitude) *
519 y2 += (int)((1 - magnitude) * canvas->get_h() / 4);
520 // y2 += (int)(DB::todb(magnitude) /
525 if(i > 0) canvas->draw_line(i - 1, y1, i, y2);
530 // for(int i = 0; i < canvas->get_w(); i++)
532 // int freq = Freq::tofreq((int)((float)i / canvas->get_w() * TOTALFREQS));
533 // int index = (int)((float)freq / niquist * WINDOW_SIZE / 2);
534 // double magnitude = plugin->envelope[index];
535 // int y2 = canvas->get_h() -
536 // (int)((double)canvas->get_h() / normalize * magnitude);
537 // if(i > 0) canvas->draw_line(i - 1, y1, i, y2);
551 PLUGIN_THREAD_OBJECT(ParametricEQ, ParametricThread, ParametricWindow)
559 ParametricFFT::ParametricFFT(ParametricEQ *plugin)
562 this->plugin = plugin;
565 ParametricFFT::~ParametricFFT()
570 int ParametricFFT::signal_process()
572 for(int i = 0; i < window_size / 2; i++)
574 double result = plugin->envelope[i] * sqrt(freq_real[i] * freq_real[i] + freq_imag[i] * freq_imag[i]);
575 double angle = atan2(freq_imag[i], freq_real[i]);
576 freq_real[i] = result * cos(angle);
577 freq_imag[i] = result * sin(angle);
580 symmetry(window_size, freq_real, freq_imag);
584 int ParametricFFT::read_samples(int64_t output_sample,
588 return plugin->read_samples(buffer,
590 plugin->get_samplerate(),
602 ParametricEQ::ParametricEQ(PluginServer *server)
603 : PluginAClient(server)
605 PLUGIN_CONSTRUCTOR_MACRO
607 need_reconfigure = 1;
610 ParametricEQ::~ParametricEQ()
612 PLUGIN_DESTRUCTOR_MACRO
617 NEW_PICON_MACRO(ParametricEQ)
619 SHOW_GUI_MACRO(ParametricEQ, ParametricThread)
621 RAISE_WINDOW_MACRO(ParametricEQ)
623 SET_STRING_MACRO(ParametricEQ)
625 LOAD_CONFIGURATION_MACRO(ParametricEQ, ParametricConfig)
628 char* ParametricEQ::plugin_title() { return N_("EQ Parametric"); }
629 int ParametricEQ::is_realtime() { return 1; }
631 void ParametricEQ::read_data(KeyFrame *keyframe)
634 input.set_shared_string(keyframe->data, strlen(keyframe->data));
639 result = input.read_tag();
643 if(input.tag.title_is("PARAMETRICEQ"))
645 config.wetness = input.tag.get_property("WETNESS", config.wetness);
648 if(input.tag.title_is("BAND"))
650 int band = input.tag.get_property("NUMBER", 0);
651 config.band[band].freq = input.tag.get_property("FREQ", config.band[band].freq);
652 config.band[band].quality = input.tag.get_property("QUALITY", config.band[band].quality);
653 config.band[band].magnitude = input.tag.get_property("MAGNITUDE", config.band[band].magnitude);
654 config.band[band].mode = input.tag.get_property("MODE", config.band[band].mode);
660 void ParametricEQ::save_data(KeyFrame *keyframe)
663 output.set_shared_string(keyframe->data, MESSAGESIZE);
665 output.tag.set_title("PARAMETRICEQ");
666 output.tag.set_property("WETNESS", config.wetness);
668 output.append_newline();
670 for(int i = 0; i < BANDS; i++)
672 output.tag.set_title("BAND");
673 output.tag.set_property("NUMBER", i);
674 output.tag.set_property("FREQ", config.band[i].freq);
675 output.tag.set_property("QUALITY", config.band[i].quality);
676 output.tag.set_property("MAGNITUDE", config.band[i].magnitude);
677 output.tag.set_property("MODE", config.band[i].mode);
679 output.append_newline();
682 output.terminate_string();
685 void ParametricEQ::reconfigure()
689 fft = new ParametricFFT(this);
690 fft->initialize(WINDOW_SIZE);
695 //printf("ParametricEQ::reconfigure %f\n", wetness);
696 calculate_envelope();
698 for(int i = 0; i < WINDOW_SIZE / 2; i++)
700 if(envelope[i] < 0) envelope[i] = 0;
703 need_reconfigure = 0;
706 double ParametricEQ::calculate_envelope()
708 double wetness = DB::fromdb(config.wetness);
709 int niquist = PluginAClient::project_sample_rate / 2;
710 //printf("ParametricEQ::calculate_envelope %d %d\n", niquist, PluginAClient::project_sample_rate);
713 for(int i = 0; i < WINDOW_SIZE / 2; i++)
715 envelope[i] = wetness;
718 for(int pass = 0; pass < 2; pass++)
720 for(int band = 0; band < BANDS; band++)
722 switch(config.band[band].mode)
724 case ParametricBand::LOWPASS:
727 double magnitude = DB::fromdb(config.band[band].magnitude);
728 int cutoff = (int)((float)config.band[band].freq / niquist * WINDOW_SIZE / 2);
729 for(int i = 0; i < WINDOW_SIZE / 2; i++)
732 envelope[i] += magnitude;
737 case ParametricBand::HIGHPASS:
740 double magnitude = DB::fromdb(config.band[band].magnitude);
741 int cutoff = (int)((float)config.band[band].freq / niquist * WINDOW_SIZE / 2);
742 for(int i = 0; i < WINDOW_SIZE / 2; i++)
745 envelope[i] += magnitude;
750 case ParametricBand::BANDPASS:
753 double magnitude = (config.band[band].magnitude > 0) ?
754 (DB::fromdb(config.band[band].magnitude) - 1) :
755 (-1 + DB::fromdb(config.band[band].magnitude));
756 double sigma = (config.band[band].quality < 1) ?
757 (1.0 - config.band[band].quality) :
760 double a = (double)config.band[band].freq / niquist;
761 double normalize = gauss(sigma, 0, 0);
762 if(config.band[band].magnitude <= -MAXMAGNITUDE)
765 for(int i = 0; i < WINDOW_SIZE / 2; i++)
766 envelope[i] += magnitude *
767 gauss(sigma, a, (double)i / (WINDOW_SIZE / 2)) /
777 double ParametricEQ::gauss(double sigma, double a, double x)
779 if(EQUIV(sigma, 0)) sigma = 0.01;
782 sqrt(2 * M_PI * sigma * sigma) *
783 exp(-(x - a) * (x - a) /
784 (2 * sigma * sigma));
789 int ParametricEQ::process_buffer(int64_t size,
791 int64_t start_position,
794 need_reconfigure |= load_configuration();
795 if(need_reconfigure) reconfigure();
798 fft->process_buffer(start_position, size, buffer, get_direction());
810 int ParametricEQ::load_defaults()
812 char directory[BCTEXTLEN], string[BCTEXTLEN];
813 sprintf(directory, "%sparametriceq.rc", BCASTDIR);
814 defaults = new Defaults(directory);
817 config.wetness = defaults->get("WETNESS", config.wetness);
818 for(int i = 0; i < BANDS; i++)
820 sprintf(string, "FREQ_%d", i);
821 config.band[i].freq = defaults->get(string, config.band[i].freq);
822 sprintf(string, "QUALITY_%d", i);
823 config.band[i].quality = defaults->get(string, config.band[i].quality);
824 sprintf(string, "MAGNITUDE_%d", i);
825 config.band[i].magnitude = defaults->get(string, config.band[i].magnitude);
826 sprintf(string, "MODE_%d", i);
827 config.band[i].mode = defaults->get(string, config.band[i].mode);
832 int ParametricEQ::save_defaults()
834 char string[BCTEXTLEN];
836 defaults->update("WETNESS", config.wetness);
839 for(int i = 0; i < BANDS; i++)
841 sprintf(string, "FREQ_%d", i);
842 defaults->update(string, config.band[i].freq);
843 sprintf(string, "QUALITY_%d", i);
844 defaults->update(string, config.band[i].quality);
845 sprintf(string, "MAGNITUDE_%d", i);
846 defaults->update(string, config.band[i].magnitude);
847 sprintf(string, "MODE_%d", i);
848 defaults->update(string, config.band[i].mode);
858 void ParametricEQ::reset()
860 need_reconfigure = 1;
865 void ParametricEQ::update_gui()
869 load_configuration();
870 thread->window->lock_window("ParametricEQ::update_gui");
871 thread->window->update_gui();
872 thread->window->unlock_window();