1 #include "bcdisplayinfo.h"
7 #include "parametric.h"
23 REGISTER_PLUGIN(ParametricEQ)
32 ParametricBand::ParametricBand()
41 int ParametricBand::equivalent(ParametricBand &that)
43 if(freq == that.freq &&
44 EQUIV(quality, that.quality) &&
45 EQUIV(magnitude, that.magnitude) &&
55 void ParametricBand::copy_from(ParametricBand &that)
58 quality = that.quality;
59 magnitude = that.magnitude;
63 void ParametricBand::interpolate(ParametricBand &prev,
68 freq = (int)(prev.freq * prev_scale + next.freq * next_scale + 0.5);
69 quality = prev.quality * prev_scale + next.quality * next_scale;
70 magnitude = prev.magnitude * prev_scale + next.magnitude * next_scale;
78 ParametricConfig::ParametricConfig()
80 wetness = INFINITYGAIN;
84 int ParametricConfig::equivalent(ParametricConfig &that)
86 for(int i = 0; i < BANDS; i++)
87 if(!band[i].equivalent(that.band[i])) return 0;
89 if(!EQUIV(wetness, that.wetness)) return 0;
93 void ParametricConfig::copy_from(ParametricConfig &that)
95 wetness = that.wetness;
96 for(int i = 0; i < BANDS; i++)
97 band[i].copy_from(that.band[i]);
100 void ParametricConfig::interpolate(ParametricConfig &prev,
101 ParametricConfig &next,
104 int64_t current_frame)
106 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
107 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
108 wetness = prev.wetness;
109 for(int i = 0; i < BANDS; i++)
111 band[i].interpolate(prev.band[i], next.band[i], prev_scale, next_scale);
133 ParametricFreq::ParametricFreq(ParametricEQ *plugin, int x, int y, int band)
134 : BC_QPot(x, y, plugin->config.band[band].freq)
136 this->plugin = plugin;
140 int ParametricFreq::handle_event()
142 plugin->config.band[band].freq = get_value();
143 plugin->send_configure_change();
144 plugin->thread->window->update_canvas();
155 ParametricQuality::ParametricQuality(ParametricEQ *plugin, int x, int y, int band)
156 : BC_FPot(x, y, plugin->config.band[band].quality, 0, 1)
158 this->plugin = plugin;
163 int ParametricQuality::handle_event()
165 plugin->config.band[band].quality = get_value();
166 plugin->send_configure_change();
167 plugin->thread->window->update_canvas();
181 ParametricMagnitude::ParametricMagnitude(ParametricEQ *plugin, int x, int y, int band)
182 : BC_FPot(x, y, plugin->config.band[band].magnitude, -MAXMAGNITUDE, MAXMAGNITUDE)
184 this->plugin = plugin;
188 int ParametricMagnitude::handle_event()
190 plugin->config.band[band].magnitude = get_value();
191 plugin->send_configure_change();
192 plugin->thread->window->update_canvas();
204 ParametricMode::ParametricMode(ParametricEQ *plugin, int x, int y, int band)
208 mode_to_text(plugin->config.band[band].mode))
210 //printf("ParametricMode::ParametricMode %d %d\n", band, plugin->config.band[band].mode);
211 this->plugin = plugin;
215 void ParametricMode::create_objects()
217 add_item(new BC_MenuItem(mode_to_text(ParametricBand::LOWPASS)));
218 add_item(new BC_MenuItem(mode_to_text(ParametricBand::HIGHPASS)));
219 add_item(new BC_MenuItem(mode_to_text(ParametricBand::BANDPASS)));
220 add_item(new BC_MenuItem(mode_to_text(ParametricBand::NONE)));
224 int ParametricMode::handle_event()
226 plugin->config.band[band].mode = text_to_mode(get_text());
227 plugin->send_configure_change();
228 plugin->thread->window->update_canvas();
232 int ParametricMode::text_to_mode(char *text)
234 if(!strcmp(mode_to_text(ParametricBand::LOWPASS), text)) return ParametricBand::LOWPASS;
235 if(!strcmp(mode_to_text(ParametricBand::HIGHPASS), text)) return ParametricBand::HIGHPASS;
236 if(!strcmp(mode_to_text(ParametricBand::BANDPASS), text)) return ParametricBand::BANDPASS;
237 if(!strcmp(mode_to_text(ParametricBand::NONE), text)) return ParametricBand::NONE;
238 return ParametricBand::BANDPASS;
243 char* ParametricMode::mode_to_text(int mode)
247 case ParametricBand::LOWPASS:
250 case ParametricBand::HIGHPASS:
251 return _("Highpass");
253 case ParametricBand::BANDPASS:
254 return _("Bandpass");
256 case ParametricBand::NONE:
273 ParametricBandGUI::ParametricBandGUI(ParametricEQ *plugin, ParametricWindow *window, int x, int y, int band)
275 this->plugin = plugin;
277 this->window = window;
282 ParametricBandGUI::~ParametricBandGUI()
293 void ParametricBandGUI::create_objects()
295 window->add_subwindow(freq = new ParametricFreq(plugin, X1, y, band));
296 window->add_subwindow(quality = new ParametricQuality(plugin, X2, y, band));
297 window->add_subwindow(magnitude = new ParametricMagnitude(plugin, X3, y, band));
298 window->add_subwindow(mode = new ParametricMode(plugin, X4, y, band));
299 mode->create_objects();
302 void ParametricBandGUI::update_gui()
304 freq->update(plugin->config.band[band].freq);
305 quality->update(plugin->config.band[band].quality);
306 magnitude->update(plugin->config.band[band].magnitude);
314 ParametricWetness::ParametricWetness(ParametricEQ *plugin, int x, int y)
315 : BC_FPot(x, y, plugin->config.wetness, INFINITYGAIN, 0)
317 this->plugin = plugin;
320 int ParametricWetness::handle_event()
322 plugin->config.wetness = get_value();
323 plugin->send_configure_change();
324 plugin->thread->window->update_canvas();
333 ParametricWindow::ParametricWindow(ParametricEQ *plugin, int x, int y)
334 : BC_Window(plugin->gui_string,
345 this->plugin = plugin;
348 ParametricWindow::~ParametricWindow()
350 for(int i = 0; i < BANDS; i++)
354 void ParametricWindow::create_objects()
359 add_subwindow(new BC_Title(X1, 10, _("Freq")));
360 add_subwindow(new BC_Title(X2, 10, _("Qual")));
361 add_subwindow(new BC_Title(X3, 10, _("Level")));
362 add_subwindow(new BC_Title(X4, 10, _("Mode")));
363 for(int i = 0; i < BANDS; i++)
365 bands[i] = new ParametricBandGUI(plugin, this, 10, y, i);
366 bands[i]->create_objects();
371 add_subwindow(new BC_Title(10, y + 10, _("Wetness:")));
372 add_subwindow(wetness = new ParametricWetness(plugin, 80, y));
376 int canvas_w = get_w() - canvas_x - 10;
377 int canvas_h = get_h() - canvas_y - 30;
378 add_subwindow(canvas = new BC_SubWindow(canvas_x,
385 // Draw canvas titles
387 #define MAJOR_DIVISIONS 4
388 #define MINOR_DIVISIONS 5
389 for(int i = 0; i <= MAJOR_DIVISIONS; i++)
391 int y1 = canvas_y + canvas_h - i * (canvas_h / MAJOR_DIVISIONS) - 2;
393 int x1 = canvas_x - 25;
394 int x2 = canvas_x - 10;
395 int x3 = canvas_x - 2;
397 char string[BCTEXTLEN];
399 sprintf(string, "oo");
401 sprintf(string, "%d", i * 5 - 5);
404 draw_text(x1 + 1, y2 + 1, string);
405 draw_line(x2 + 1, y1 + 1, x3 + 1, y1 + 1);
407 draw_text(x1, y2, string);
408 draw_line(x2, y1, x3, y1);
410 if(i < MAJOR_DIVISIONS)
412 for(int j = 1; j < MINOR_DIVISIONS; j++)
414 int y3 = y1 - j * (canvas_h / MAJOR_DIVISIONS) / MINOR_DIVISIONS;
417 draw_line(x4 + 1, y3 + 1, x3 + 1, y3 + 1);
419 draw_line(x4, y3, x3, y3);
425 #undef MAJOR_DIVISIONS
426 #define MAJOR_DIVISIONS 5
427 for(int i = 0; i <= MAJOR_DIVISIONS; i++)
429 int freq = Freq::tofreq(i * TOTALFREQS / MAJOR_DIVISIONS);
430 int x1 = canvas_x + i * canvas_w / MAJOR_DIVISIONS;
431 int y1 = canvas_y + canvas_h + 20;
432 char string[BCTEXTLEN];
433 sprintf(string, "%d", freq);
434 int x2 = x1 - get_text_width(SMALLFONT, string);
437 int y4 = canvas_y + canvas_h;
440 draw_text(x2 + 1, y1 + 1, string);
441 draw_line(x1 + 1, y4 + 1, x1 + 1, y2 + 1);
443 draw_text(x2, y1, string);
444 draw_line(x1, y4, x1, y2);
446 if(i < MAJOR_DIVISIONS)
448 #undef MINOR_DIVISIONS
449 #define MINOR_DIVISIONS 5
450 for(int j = 0; j < MINOR_DIVISIONS; j++)
453 (canvas_w / MAJOR_DIVISIONS) -
454 exp(-(double)j * 0.7) *
455 (canvas_w / MAJOR_DIVISIONS));
457 draw_line(x3 + 1, y4 + 1, x3 + 1, y3 + 1);
459 draw_line(x3, y4, x3, y3);
470 int ParametricWindow::close_event()
472 // Set result to 1 to indicate a client side close
477 void ParametricWindow::update_gui()
479 for(int i = 0; i < BANDS; i++)
480 bands[i]->update_gui();
481 wetness->update(plugin->config.wetness);
486 void ParametricWindow::update_canvas()
489 int y1 = canvas->get_h() / 2;
490 int niquist = plugin->PluginAClient::project_sample_rate / 2;
491 int wetness = canvas->get_h() -
492 (int)((plugin->config.wetness - INFINITYGAIN) /
497 canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
498 // canvas->set_color(GREEN);
499 // canvas->draw_line(0,
504 canvas->set_color(BLACK);
506 plugin->calculate_envelope();
507 for(int i = 0; i < canvas->get_w() - 1; i++)
509 int freq = Freq::tofreq(i * TOTALFREQS / canvas->get_w());
510 int index = freq * WINDOW_SIZE / 2 / niquist;
513 double magnitude = plugin->envelope[index];
514 int y2 = canvas->get_h() * 3 / 4;
518 y2 -= (int)(DB::todb(magnitude) *
526 y2 += (int)((1 - magnitude) * canvas->get_h() / 4);
528 if(i > 0) canvas->draw_line(i - 1, y1, i, y2);
533 canvas->draw_line(i - 1, y1, i, y1);
538 // for(int i = 0; i < canvas->get_w(); i++)
540 // int freq = Freq::tofreq((int)((float)i / canvas->get_w() * TOTALFREQS));
541 // int index = (int)((float)freq / niquist * WINDOW_SIZE / 2);
542 // double magnitude = plugin->envelope[index];
543 // int y2 = canvas->get_h() -
544 // (int)((double)canvas->get_h() / normalize * magnitude);
545 // if(i > 0) canvas->draw_line(i - 1, y1, i, y2);
558 PLUGIN_THREAD_OBJECT(ParametricEQ, ParametricThread, ParametricWindow)
566 ParametricFFT::ParametricFFT(ParametricEQ *plugin)
569 this->plugin = plugin;
572 ParametricFFT::~ParametricFFT()
577 int ParametricFFT::signal_process()
579 for(int i = 0; i < window_size / 2; i++)
581 double result = plugin->envelope[i] * sqrt(freq_real[i] * freq_real[i] + freq_imag[i] * freq_imag[i]);
582 double angle = atan2(freq_imag[i], freq_real[i]);
583 freq_real[i] = result * cos(angle);
584 freq_imag[i] = result * sin(angle);
587 symmetry(window_size, freq_real, freq_imag);
591 int ParametricFFT::read_samples(int64_t output_sample,
595 return plugin->read_samples(buffer,
597 plugin->get_samplerate(),
609 ParametricEQ::ParametricEQ(PluginServer *server)
610 : PluginAClient(server)
612 PLUGIN_CONSTRUCTOR_MACRO
614 need_reconfigure = 1;
617 ParametricEQ::~ParametricEQ()
619 PLUGIN_DESTRUCTOR_MACRO
624 NEW_PICON_MACRO(ParametricEQ)
626 SHOW_GUI_MACRO(ParametricEQ, ParametricThread)
628 RAISE_WINDOW_MACRO(ParametricEQ)
630 SET_STRING_MACRO(ParametricEQ)
632 LOAD_CONFIGURATION_MACRO(ParametricEQ, ParametricConfig)
635 char* ParametricEQ::plugin_title() { return N_("EQ Parametric"); }
636 int ParametricEQ::is_realtime() { return 1; }
638 void ParametricEQ::read_data(KeyFrame *keyframe)
641 input.set_shared_string(keyframe->data, strlen(keyframe->data));
646 result = input.read_tag();
650 if(input.tag.title_is("PARAMETRICEQ"))
652 config.wetness = input.tag.get_property("WETNESS", config.wetness);
655 if(input.tag.title_is("BAND"))
657 int band = input.tag.get_property("NUMBER", 0);
658 config.band[band].freq = input.tag.get_property("FREQ", config.band[band].freq);
659 config.band[band].quality = input.tag.get_property("QUALITY", config.band[band].quality);
660 config.band[band].magnitude = input.tag.get_property("MAGNITUDE", config.band[band].magnitude);
661 config.band[band].mode = input.tag.get_property("MODE", config.band[band].mode);
667 void ParametricEQ::save_data(KeyFrame *keyframe)
670 output.set_shared_string(keyframe->data, MESSAGESIZE);
672 output.tag.set_title("PARAMETRICEQ");
673 output.tag.set_property("WETNESS", config.wetness);
675 output.append_newline();
677 for(int i = 0; i < BANDS; i++)
679 output.tag.set_title("BAND");
680 output.tag.set_property("NUMBER", i);
681 output.tag.set_property("FREQ", config.band[i].freq);
682 output.tag.set_property("QUALITY", config.band[i].quality);
683 output.tag.set_property("MAGNITUDE", config.band[i].magnitude);
684 output.tag.set_property("MODE", config.band[i].mode);
686 output.append_newline();
689 output.terminate_string();
692 void ParametricEQ::reconfigure()
696 fft = new ParametricFFT(this);
697 fft->initialize(WINDOW_SIZE);
702 //printf("ParametricEQ::reconfigure %f\n", wetness);
703 calculate_envelope();
705 for(int i = 0; i < WINDOW_SIZE / 2; i++)
707 if(envelope[i] < 0) envelope[i] = 0;
710 need_reconfigure = 0;
713 double ParametricEQ::calculate_envelope()
715 double wetness = DB::fromdb(config.wetness);
716 int niquist = PluginAClient::project_sample_rate / 2;
717 //printf("ParametricEQ::calculate_envelope %d %d\n", niquist, PluginAClient::project_sample_rate);
720 for(int i = 0; i < WINDOW_SIZE / 2; i++)
722 envelope[i] = wetness;
725 for(int pass = 0; pass < 2; pass++)
727 for(int band = 0; band < BANDS; band++)
729 switch(config.band[band].mode)
731 case ParametricBand::LOWPASS:
734 double magnitude = DB::fromdb(config.band[band].magnitude);
735 int cutoff = (int)((float)config.band[band].freq / niquist * WINDOW_SIZE / 2);
736 for(int i = 0; i < WINDOW_SIZE / 2; i++)
739 envelope[i] += magnitude;
744 case ParametricBand::HIGHPASS:
747 double magnitude = DB::fromdb(config.band[band].magnitude);
748 int cutoff = (int)((float)config.band[band].freq / niquist * WINDOW_SIZE / 2);
749 for(int i = 0; i < WINDOW_SIZE / 2; i++)
752 envelope[i] += magnitude;
757 case ParametricBand::BANDPASS:
760 double magnitude = (config.band[band].magnitude > 0) ?
761 (DB::fromdb(config.band[band].magnitude) - 1) :
762 (-1 + DB::fromdb(config.band[band].magnitude));
763 double sigma = (config.band[band].quality < 1) ?
764 (1.0 - config.band[band].quality) :
767 double a = (double)config.band[band].freq / niquist;
768 double normalize = gauss(sigma, 0, 0);
769 if(config.band[band].magnitude <= -MAXMAGNITUDE)
772 for(int i = 0; i < WINDOW_SIZE / 2; i++)
773 envelope[i] += magnitude *
774 gauss(sigma, a, (double)i / (WINDOW_SIZE / 2)) /
784 double ParametricEQ::gauss(double sigma, double a, double x)
786 if(EQUIV(sigma, 0)) sigma = 0.01;
789 sqrt(2 * M_PI * sigma * sigma) *
790 exp(-(x - a) * (x - a) /
791 (2 * sigma * sigma));
796 int ParametricEQ::process_buffer(int64_t size,
798 int64_t start_position,
801 need_reconfigure |= load_configuration();
802 if(need_reconfigure) reconfigure();
805 fft->process_buffer(start_position, size, buffer, get_direction());
817 int ParametricEQ::load_defaults()
819 char directory[BCTEXTLEN], string[BCTEXTLEN];
820 sprintf(directory, "%sparametriceq.rc", BCASTDIR);
821 defaults = new BC_Hash(directory);
824 config.wetness = defaults->get("WETNESS", config.wetness);
825 for(int i = 0; i < BANDS; i++)
827 sprintf(string, "FREQ_%d", i);
828 config.band[i].freq = defaults->get(string, config.band[i].freq);
829 sprintf(string, "QUALITY_%d", i);
830 config.band[i].quality = defaults->get(string, config.band[i].quality);
831 sprintf(string, "MAGNITUDE_%d", i);
832 config.band[i].magnitude = defaults->get(string, config.band[i].magnitude);
833 sprintf(string, "MODE_%d", i);
834 config.band[i].mode = defaults->get(string, config.band[i].mode);
839 int ParametricEQ::save_defaults()
841 char string[BCTEXTLEN];
843 defaults->update("WETNESS", config.wetness);
846 for(int i = 0; i < BANDS; i++)
848 sprintf(string, "FREQ_%d", i);
849 defaults->update(string, config.band[i].freq);
850 sprintf(string, "QUALITY_%d", i);
851 defaults->update(string, config.band[i].quality);
852 sprintf(string, "MAGNITUDE_%d", i);
853 defaults->update(string, config.band[i].magnitude);
854 sprintf(string, "MODE_%d", i);
855 defaults->update(string, config.band[i].mode);
865 void ParametricEQ::reset()
867 need_reconfigure = 1;
872 void ParametricEQ::update_gui()
876 load_configuration();
877 thread->window->lock_window("ParametricEQ::update_gui");
878 thread->window->update_gui();
879 thread->window->unlock_window();