--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 2011 Adam Williams <broadcast at earthling dot net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "bcdisplayinfo.h"
+#include "bcsignals.h"
+#include "clip.h"
+#include "bchash.h"
+#include "filexml.h"
+#include "language.h"
+#include "parametric.h"
+#include "samples.h"
+#include "theme.h"
+#include "units.h"
+#include "vframe.h"
+
+#include <math.h>
+#include <string.h>
+#include <unistd.h>
+
+
+
+
+
+
+
+
+
+REGISTER_PLUGIN(ParametricEQ)
+
+
+
+
+
+
+
+
+ParametricBand::ParametricBand()
+{
+ freq = 440;
+ quality = 1;
+ magnitude = 0;
+ mode = NONE;
+}
+
+
+int ParametricBand::equivalent(ParametricBand &that)
+{
+ if(freq == that.freq &&
+ EQUIV(quality, that.quality) &&
+ EQUIV(magnitude, that.magnitude) &&
+ mode == that.mode)
+ {
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+void ParametricBand::copy_from(ParametricBand &that)
+{
+ freq = that.freq;
+ quality = that.quality;
+ magnitude = that.magnitude;
+ mode = that.mode;
+}
+
+void ParametricBand::interpolate(ParametricBand &prev,
+ ParametricBand &next,
+ double prev_scale,
+ double next_scale)
+{
+ freq = (int)(prev.freq * prev_scale + next.freq * next_scale + 0.5);
+ quality = prev.quality * prev_scale + next.quality * next_scale;
+ magnitude = prev.magnitude * prev_scale + next.magnitude * next_scale;
+ mode = prev.mode;
+}
+
+
+
+
+
+ParametricConfig::ParametricConfig()
+{
+ wetness = INFINITYGAIN;
+ window_size = 4096;
+}
+
+
+int ParametricConfig::equivalent(ParametricConfig &that)
+{
+ for(int i = 0; i < BANDS; i++)
+ if(!band[i].equivalent(that.band[i])) return 0;
+
+ if(!EQUIV(wetness, that.wetness) ||
+ window_size != that.window_size) return 0;
+ return 1;
+}
+
+void ParametricConfig::copy_from(ParametricConfig &that)
+{
+ wetness = that.wetness;
+ window_size = that.window_size;
+ for(int i = 0; i < BANDS; i++)
+ band[i].copy_from(that.band[i]);
+}
+
+void ParametricConfig::interpolate(ParametricConfig &prev,
+ ParametricConfig &next,
+ int64_t prev_frame,
+ int64_t next_frame,
+ int64_t current_frame)
+{
+ double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
+ double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
+ wetness = prev.wetness;
+ window_size = prev.window_size;
+ for(int i = 0; i < BANDS; i++)
+ {
+ band[i].interpolate(prev.band[i], next.band[i], prev_scale, next_scale);
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ParametricFreq::ParametricFreq(ParametricEQ *plugin, int x, int y, int band)
+ : BC_QPot(x, y, plugin->config.band[band].freq)
+{
+ this->plugin = plugin;
+ this->band = band;
+}
+
+int ParametricFreq::handle_event()
+{
+ plugin->config.band[band].freq = get_value();
+ plugin->send_configure_change();
+ ((ParametricWindow*)plugin->thread->window)->update_canvas();
+ return 1;
+}
+
+
+
+
+
+
+
+
+ParametricQuality::ParametricQuality(ParametricEQ *plugin, int x, int y, int band)
+ : BC_FPot(x, y, plugin->config.band[band].quality, 0, 1)
+{
+ this->plugin = plugin;
+ this->band = band;
+ set_precision(0.01);
+}
+
+int ParametricQuality::handle_event()
+{
+ plugin->config.band[band].quality = get_value();
+ plugin->send_configure_change();
+ ((ParametricWindow*)plugin->thread->window)->update_canvas();
+ return 1;
+}
+
+
+
+
+
+
+
+
+
+
+
+ParametricMagnitude::ParametricMagnitude(ParametricEQ *plugin, int x, int y, int band)
+ : BC_FPot(x, y, plugin->config.band[band].magnitude, -MAXMAGNITUDE, MAXMAGNITUDE)
+{
+ this->plugin = plugin;
+ this->band = band;
+}
+
+int ParametricMagnitude::handle_event()
+{
+ plugin->config.band[band].magnitude = get_value();
+ plugin->send_configure_change();
+ ((ParametricWindow*)plugin->thread->window)->update_canvas();
+ return 1;
+}
+
+
+
+
+
+
+
+
+
+ParametricMode::ParametricMode(ParametricEQ *plugin, int x, int y, int band)
+ : BC_PopupMenu(x,
+ y,
+ 150,
+ mode_to_text(plugin->config.band[band].mode))
+{
+//printf("ParametricMode::ParametricMode %d %d\n", band, plugin->config.band[band].mode);
+ this->plugin = plugin;
+ this->band = band;
+}
+
+void ParametricMode::create_objects()
+{
+ add_item(new BC_MenuItem(mode_to_text(ParametricBand::LOWPASS)));
+ add_item(new BC_MenuItem(mode_to_text(ParametricBand::HIGHPASS)));
+ add_item(new BC_MenuItem(mode_to_text(ParametricBand::BANDPASS)));
+ add_item(new BC_MenuItem(mode_to_text(ParametricBand::NONE)));
+}
+
+
+int ParametricMode::handle_event()
+{
+ plugin->config.band[band].mode = text_to_mode(get_text());
+ plugin->send_configure_change();
+ ((ParametricWindow*)plugin->thread->window)->update_canvas();
+ return 1;
+}
+
+int ParametricMode::text_to_mode(char *text)
+{
+ if(!strcmp(mode_to_text(ParametricBand::LOWPASS), text)) return ParametricBand::LOWPASS;
+ if(!strcmp(mode_to_text(ParametricBand::HIGHPASS), text)) return ParametricBand::HIGHPASS;
+ if(!strcmp(mode_to_text(ParametricBand::BANDPASS), text)) return ParametricBand::BANDPASS;
+ if(!strcmp(mode_to_text(ParametricBand::NONE), text)) return ParametricBand::NONE;
+ return ParametricBand::BANDPASS;
+}
+
+
+
+const char* ParametricMode::mode_to_text(int mode)
+{
+ switch(mode)
+ {
+ case ParametricBand::LOWPASS:
+ return _("Lowpass");
+ break;
+ case ParametricBand::HIGHPASS:
+ return _("Highpass");
+ break;
+ case ParametricBand::BANDPASS:
+ return _("Bandpass");
+ break;
+ case ParametricBand::NONE:
+ return _("None");
+ break;
+ }
+ return "";
+}
+
+
+
+
+
+
+
+
+
+
+
+ParametricBandGUI::ParametricBandGUI(ParametricEQ *plugin, ParametricWindow *window, int x, int y, int band)
+{
+ this->plugin = plugin;
+ this->band = band;
+ this->window = window;
+ this->x = x;
+ this->y = y;
+}
+
+ParametricBandGUI::~ParametricBandGUI()
+{
+}
+
+
+#define X1 10
+#define X2 60
+#define X3 110
+#define X4 160
+
+
+void ParametricBandGUI::create_objects()
+{
+ window->add_subwindow(freq = new ParametricFreq(plugin, X1, y, band));
+ window->add_subwindow(quality = new ParametricQuality(plugin, X2, y, band));
+ window->add_subwindow(magnitude = new ParametricMagnitude(plugin, X3, y, band));
+ window->add_subwindow(mode = new ParametricMode(plugin, X4, y, band));
+ mode->create_objects();
+}
+
+void ParametricBandGUI::update_gui()
+{
+ freq->update(plugin->config.band[band].freq);
+ quality->update(plugin->config.band[band].quality);
+ magnitude->update(plugin->config.band[band].magnitude);
+ mode->set_text(ParametricMode::mode_to_text(plugin->config.band[band].mode));
+}
+
+
+
+
+
+
+ParametricWetness::ParametricWetness(ParametricEQ *plugin, int x, int y)
+ : BC_FPot(x, y, plugin->config.wetness, INFINITYGAIN, 0)
+{
+ this->plugin = plugin;
+}
+
+int ParametricWetness::handle_event()
+{
+ plugin->config.wetness = get_value();
+ plugin->send_configure_change();
+ ((ParametricWindow*)plugin->thread->window)->update_canvas();
+ return 1;
+}
+
+
+
+
+
+
+
+ParametricSize::ParametricSize(ParametricWindow *window, ParametricEQ *plugin, int x, int y)
+ : BC_PopupMenu(x, y, 100, "4096", 1)
+{
+ this->plugin = plugin;
+ this->window = window;
+}
+
+int ParametricSize::handle_event()
+{
+ plugin->config.window_size = atoi(get_text());
+ plugin->send_configure_change();
+
+ window->update_canvas();
+ return 1;
+}
+
+void ParametricSize::create_objects()
+{
+ add_item(new BC_MenuItem("2048"));
+ add_item(new BC_MenuItem("4096"));
+ add_item(new BC_MenuItem("8192"));
+ add_item(new BC_MenuItem("16384"));
+ add_item(new BC_MenuItem("32768"));
+ add_item(new BC_MenuItem("65536"));
+ add_item(new BC_MenuItem("131072"));
+ add_item(new BC_MenuItem("262144"));
+}
+
+void ParametricSize::update(int size)
+{
+ char string[BCTEXTLEN];
+ sprintf(string, "%d", size);
+ set_text(string);
+}
+
+
+
+
+
+
+ParametricWindow::ParametricWindow(ParametricEQ *plugin)
+ : PluginClientWindow(plugin,
+ 350,
+ 400,
+ 350,
+ 400,
+ 0)
+{
+ this->plugin = plugin;
+}
+
+ParametricWindow::~ParametricWindow()
+{
+ for(int i = 0; i < BANDS; i++)
+ delete bands[i];
+}
+
+void ParametricWindow::create_objects()
+{
+ int y = 35;
+SET_TRACE
+
+ add_subwindow(new BC_Title(X1, 10, _("Freq")));
+ add_subwindow(new BC_Title(X2, 10, _("Qual")));
+ add_subwindow(new BC_Title(X3, 10, _("Level")));
+ add_subwindow(new BC_Title(X4, 10, _("Mode")));
+ for(int i = 0; i < BANDS; i++)
+ {
+ bands[i] = new ParametricBandGUI(plugin, this, 10, y, i);
+ bands[i]->create_objects();
+ y += 50;
+ }
+
+SET_TRACE
+ BC_Title *title;
+ int x = plugin->get_theme()->widget_border;
+ add_subwindow(title = new BC_Title(x, y + 10, _("Wetness:")));
+ x += title->get_w() + plugin->get_theme()->widget_border;
+ add_subwindow(wetness = new ParametricWetness(plugin,
+ x,
+ y));
+ x += wetness->get_w() + plugin->get_theme()->widget_border;
+
+ add_subwindow(title = new BC_Title(x, y + 10, _("Window:")));
+ x += title->get_w() + plugin->get_theme()->widget_border;
+ add_subwindow(size = new ParametricSize(this,
+ plugin,
+ x,
+ y + 10));
+ size->create_objects();
+ size->update(plugin->config.window_size);
+
+
+
+ y += 50;
+ int canvas_x = 30;
+ int canvas_y = y;
+ int canvas_w = get_w() - canvas_x - 10;
+ int canvas_h = get_h() - canvas_y - 30;
+ add_subwindow(canvas = new BC_SubWindow(canvas_x,
+ canvas_y,
+ canvas_w,
+ canvas_h,
+ BLACK));
+
+SET_TRACE
+// Draw canvas titles
+ set_font(SMALLFONT);
+#define MAJOR_DIVISIONS 4
+#define MINOR_DIVISIONS 5
+ for(int i = 0; i <= MAJOR_DIVISIONS; i++)
+ {
+ int y1 = canvas_y + canvas_h - i * (canvas_h / MAJOR_DIVISIONS) - 2;
+ int y2 = y1 + 3;
+ int x1 = canvas_x - 25;
+ int x2 = canvas_x - 10;
+ int x3 = canvas_x - 2;
+
+ char string[BCTEXTLEN];
+ if(i == 0)
+ sprintf(string, "oo");
+ else
+ sprintf(string, "%d", i * 5 - 5);
+
+ set_color(BLACK);
+ draw_text(x1 + 1, y2 + 1, string);
+ draw_line(x2 + 1, y1 + 1, x3 + 1, y1 + 1);
+ set_color(RED);
+ draw_text(x1, y2, string);
+ draw_line(x2, y1, x3, y1);
+
+ if(i < MAJOR_DIVISIONS)
+ {
+ for(int j = 1; j < MINOR_DIVISIONS; j++)
+ {
+ int y3 = y1 - j * (canvas_h / MAJOR_DIVISIONS) / MINOR_DIVISIONS;
+ int x4 = x3 - 5;
+ set_color(BLACK);
+ draw_line(x4 + 1, y3 + 1, x3 + 1, y3 + 1);
+ set_color(RED);
+ draw_line(x4, y3, x3, y3);
+ }
+ }
+ }
+
+SET_TRACE
+#undef MAJOR_DIVISIONS
+#define MAJOR_DIVISIONS 5
+ for(int i = 0; i <= MAJOR_DIVISIONS; i++)
+ {
+ int freq = Freq::tofreq(i * TOTALFREQS / MAJOR_DIVISIONS);
+ int x1 = canvas_x + i * canvas_w / MAJOR_DIVISIONS;
+ int y1 = canvas_y + canvas_h + 20;
+ char string[BCTEXTLEN];
+ sprintf(string, "%d", freq);
+ int x2 = x1 - get_text_width(SMALLFONT, string);
+ int y2 = y1 - 10;
+ int y3 = y2 - 5;
+ int y4 = canvas_y + canvas_h;
+
+ set_color(BLACK);
+ draw_text(x2 + 1, y1 + 1, string);
+ draw_line(x1 + 1, y4 + 1, x1 + 1, y2 + 1);
+ set_color(RED);
+ draw_text(x2, y1, string);
+ draw_line(x1, y4, x1, y2);
+
+ if(i < MAJOR_DIVISIONS)
+ {
+#undef MINOR_DIVISIONS
+#define MINOR_DIVISIONS 5
+ for(int j = 0; j < MINOR_DIVISIONS; j++)
+ {
+ int x3 = (int)(x1 +
+ (canvas_w / MAJOR_DIVISIONS) -
+ exp(-(double)j * 0.7) *
+ (canvas_w / MAJOR_DIVISIONS));
+ set_color(BLACK);
+ draw_line(x3 + 1, y4 + 1, x3 + 1, y3 + 1);
+ set_color(RED);
+ draw_line(x3, y4, x3, y3);
+ }
+ }
+ }
+
+SET_TRACE
+ update_canvas();
+ show_window();
+SET_TRACE
+}
+
+
+
+void ParametricWindow::update_gui()
+{
+ for(int i = 0; i < BANDS; i++)
+ bands[i]->update_gui();
+ wetness->update(plugin->config.wetness);
+ size->update(plugin->config.window_size);
+ update_canvas();
+}
+
+
+void ParametricWindow::update_canvas()
+{
+ int y1 = canvas->get_h() / 2;
+ int niquist = plugin->PluginAClient::project_sample_rate / 2;
+
+ canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
+
+
+
+// Draw spectrogram
+ int total_frames = plugin->get_gui_update_frames();
+ ParametricGUIFrame *frame = (ParametricGUIFrame*)plugin->get_gui_frame();
+
+ if(frame)
+ {
+ delete plugin->last_frame;
+ plugin->last_frame = frame;
+ }
+ else
+ {
+ frame = plugin->last_frame;
+ }
+
+// Draw most recent frame
+ if(frame)
+ {
+ canvas->set_color(MEGREY);
+ int y1 = 0;
+ int y2 = 0;
+ for(int i = 0; i < canvas->get_w(); i++)
+ {
+ int freq = Freq::tofreq(i * TOTALFREQS / canvas->get_w());
+ int index = (int64_t)freq * (int64_t)frame->window_size / 2 / niquist;
+ if(index < frame->window_size / 2)
+ {
+ double magnitude = frame->data[index] /
+ frame->freq_max *
+ frame->time_max;
+ y2 = (int)(canvas->get_h() -
+ (DB::todb(magnitude) - INFINITYGAIN) *
+ canvas->get_h() /
+ -INFINITYGAIN);
+ CLAMP(y2, 0, canvas->get_h() - 1);
+ if(i > 0)
+ {
+ canvas->draw_line(i - 1, y1, i, y2);
+ }
+ y1 = y2;
+ }
+ }
+
+ total_frames--;
+ }
+
+
+
+
+
+
+// Delete remaining frames
+ while(total_frames > 0)
+ {
+ PluginClientFrame *frame = plugin->get_gui_frame();
+
+ if(frame) delete frame;
+ total_frames--;
+ }
+
+
+
+
+
+// canvas->set_color(GREEN);
+// canvas->draw_line(0, wetness, canvas->get_w(), wetness);
+// canvas->draw_line(0,
+// wetness,
+// canvas->get_w(),
+// wetness);
+
+ canvas->set_color(WHITE);
+ canvas->set_line_width(2);
+
+ plugin->calculate_envelope();
+ for(int i = 0; i < canvas->get_w(); i++)
+ {
+ int freq = Freq::tofreq(i * TOTALFREQS / canvas->get_w());
+ int index = (int64_t)freq * (int64_t)plugin->config.window_size / 2 / niquist;
+ if(freq < niquist && index < plugin->config.window_size / 2)
+ {
+//printf("ParametricWindow::update_canvas %d %d\n", __LINE__, index);
+ double magnitude = plugin->envelope[index];
+ int y2 = canvas->get_h() * 3 / 4;
+
+ if(magnitude > 1)
+ {
+ y2 -= (int)(DB::todb(magnitude) *
+ canvas->get_h() *
+ 3 /
+ 4 /
+ 15);
+ }
+ else
+ {
+ y2 += (int)((1 - magnitude) * canvas->get_h() / 4);
+ }
+ if(i > 0) canvas->draw_line(i - 1, y1, i, y2);
+ y1 = y2;
+ }
+ else
+ {
+ canvas->draw_line(i - 1, y1, i, y1);
+ }
+ }
+ canvas->set_line_width(1);
+
+
+// for(int i = 0; i < canvas->get_w(); i++)
+// {
+// int freq = Freq::tofreq((int)((float)i / canvas->get_w() * TOTALFREQS));
+// int index = (int)((float)freq / niquist * plugin->config.window_size / 2);
+// double magnitude = plugin->envelope[index];
+// int y2 = canvas->get_h() -
+// (int)((double)canvas->get_h() / normalize * magnitude);
+// if(i > 0) canvas->draw_line(i - 1, y1, i, y2);
+// y1 = y2;
+// }
+
+ canvas->flash(1);
+}
+
+
+
+
+
+
+
+ParametricGUIFrame::ParametricGUIFrame(int window_size, int sample_rate)
+ : PluginClientFrame(window_size / 2, window_size / 2, sample_rate)
+{
+ this->window_size = window_size;
+ data = new double[window_size / 2];
+ freq_max = 0;
+ time_max = 0;
+}
+
+ParametricGUIFrame::~ParametricGUIFrame()
+{
+ delete [] data;
+}
+
+
+
+
+
+
+
+
+
+
+ParametricFFT::ParametricFFT(ParametricEQ *plugin)
+ : CrossfadeFFT()
+{
+ this->plugin = plugin;
+}
+
+ParametricFFT::~ParametricFFT()
+{
+}
+
+
+int ParametricFFT::signal_process()
+{
+// Create new frame for updating GUI
+ frame = new ParametricGUIFrame(window_size,
+ plugin->PluginAClient::project_sample_rate);
+ plugin->add_gui_frame(frame);
+
+ double freq_max = 0;
+ for(int i = 0; i < window_size / 2; i++)
+ {
+
+// if(i == 10) printf("ParametricFFT::signal_process %d %f\n",
+// __LINE__,
+// plugin->envelope[i]);
+
+ double result = plugin->envelope[i] *
+ sqrt(freq_real[i] * freq_real[i] + freq_imag[i] * freq_imag[i]);
+ double angle = atan2(freq_imag[i], freq_real[i]);
+ freq_real[i] = result * cos(angle);
+ freq_imag[i] = result * sin(angle);
+
+ frame->data[i] = result;
+ if(result > freq_max) freq_max = result;
+ }
+ frame->freq_max = freq_max;
+
+
+ symmetry(window_size, freq_real, freq_imag);
+ return 0;
+}
+
+int ParametricFFT::post_process()
+{
+ double time_max = 0;
+ for(int i = 0; i < window_size; i++)
+ {
+ if(output_real[i] > time_max) time_max = output_real[i];
+ }
+ frame->time_max = time_max;
+ return 0;
+}
+
+
+
+int ParametricFFT::read_samples(int64_t output_sample,
+ int samples,
+ Samples *buffer)
+{
+ return plugin->read_samples(buffer,
+ 0,
+ plugin->get_samplerate(),
+ output_sample,
+ samples);
+}
+
+
+
+
+
+
+
+
+ParametricEQ::ParametricEQ(PluginServer *server)
+ : PluginAClient(server)
+{
+
+ fft = 0;
+ need_reconfigure = 1;
+ envelope = 0;
+ last_frame = 0;
+}
+
+ParametricEQ::~ParametricEQ()
+{
+ delete last_frame;
+ delete [] envelope;
+ if(fft) delete fft;
+}
+
+NEW_WINDOW_MACRO(ParametricEQ, ParametricWindow)
+
+LOAD_CONFIGURATION_MACRO(ParametricEQ, ParametricConfig)
+
+
+const char* ParametricEQ::plugin_title() { return _("EQ Parametric"); }
+int ParametricEQ::is_realtime() { return 1; }
+
+void ParametricEQ::read_data(KeyFrame *keyframe)
+{
+ FileXML input;
+ input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
+
+ int result = 0;
+ while(!result)
+ {
+ result = input.read_tag();
+
+ if(!result)
+ {
+ if(input.tag.title_is("PARAMETRICEQ"))
+ {
+ config.wetness = input.tag.get_property("WETNESS", config.wetness);
+ config.window_size = input.tag.get_property("WINDOW_SIZE", config.window_size);
+ }
+ else
+ if(input.tag.title_is("BAND"))
+ {
+ int band = input.tag.get_property("NUMBER", 0);
+ config.band[band].freq = input.tag.get_property("FREQ", config.band[band].freq);
+ config.band[band].quality = input.tag.get_property("QUALITY", config.band[band].quality);
+ config.band[band].magnitude = input.tag.get_property("MAGNITUDE", config.band[band].magnitude);
+ config.band[band].mode = input.tag.get_property("MODE", config.band[band].mode);
+ }
+ }
+ }
+}
+
+void ParametricEQ::save_data(KeyFrame *keyframe)
+{
+ FileXML output;
+ output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
+
+ output.tag.set_title("PARAMETRICEQ");
+ output.tag.set_property("WETNESS", config.wetness);
+ output.tag.set_property("WINDOW_SIZE", config.window_size);
+ output.append_tag();
+ output.append_newline();
+
+ for(int i = 0; i < BANDS; i++)
+ {
+ output.tag.set_title("BAND");
+ output.tag.set_property("NUMBER", i);
+ output.tag.set_property("FREQ", config.band[i].freq);
+ output.tag.set_property("QUALITY", config.band[i].quality);
+ output.tag.set_property("MAGNITUDE", config.band[i].magnitude);
+ output.tag.set_property("MODE", config.band[i].mode);
+ output.append_tag();
+ output.tag.set_title("/BAND");
+ output.append_tag();
+ output.append_newline();
+ }
+
+ output.tag.set_title("/PARAMETRICEQ");
+ output.append_tag();
+ output.append_newline();
+ output.terminate_string();
+}
+
+void ParametricEQ::reconfigure()
+{
+ if(fft &&
+ config.window_size != fft->window_size)
+ {
+//printf("ParametricEQ::reconfigure %d %d\n", __LINE__, config.window_size);
+ delete fft;
+ fft = 0;
+ }
+
+ if(!fft)
+ {
+//printf("ParametricEQ::reconfigure %d %d\n", __LINE__, config.window_size);
+ fft = new ParametricFFT(this);
+ fft->initialize(config.window_size);
+ }
+
+// Reset envelope
+
+//printf("ParametricEQ::reconfigure %f\n", wetness);
+ calculate_envelope();
+
+ for(int i = 0; i < config.window_size / 2; i++)
+ {
+ if(envelope[i] < 0) envelope[i] = 0;
+ }
+
+ need_reconfigure = 0;
+}
+
+double ParametricEQ::calculate_envelope()
+{
+ double wetness = DB::fromdb(config.wetness);
+ if(EQUIV(config.wetness, INFINITYGAIN)) wetness = 0;
+ int niquist = PluginAClient::project_sample_rate / 2;
+
+ if(!envelope) envelope = new double[MAX_WINDOW / 2];
+
+//printf("ParametricEQ::calculate_envelope %d %f\n", __LINE__, wetness);
+ for(int i = 0; i < config.window_size / 2; i++)
+ {
+ envelope[i] = wetness;
+ }
+
+ for(int pass = 0; pass < 2; pass++)
+ {
+ for(int band = 0; band < BANDS; band++)
+ {
+ switch(config.band[band].mode)
+ {
+ case ParametricBand::LOWPASS:
+ if(pass == 1)
+ {
+ double magnitude = DB::fromdb(config.band[band].magnitude);
+ int cutoff = (int)((double)config.band[band].freq / niquist * config.window_size / 2);
+ for(int i = 0; i < config.window_size / 2; i++)
+ {
+ if(i < cutoff)
+ envelope[i] += magnitude;
+ }
+ }
+ break;
+
+ case ParametricBand::HIGHPASS:
+ if(pass == 1)
+ {
+ double magnitude = DB::fromdb(config.band[band].magnitude);
+ int cutoff = (int)((double)config.band[band].freq / niquist * config.window_size / 2);
+ for(int i = 0; i < config.window_size / 2; i++)
+ {
+ if(i > cutoff)
+ envelope[i] += magnitude;
+ }
+ }
+ break;
+
+ case ParametricBand::BANDPASS:
+ if(pass == 0)
+ {
+ double magnitude = (config.band[band].magnitude > 0) ?
+ (DB::fromdb(config.band[band].magnitude) - 1) :
+ (-1 + DB::fromdb(config.band[band].magnitude));
+ double sigma = (config.band[band].quality < 1) ?
+ (1.0 - config.band[band].quality) :
+ 0.01;
+ sigma /= 4;
+ double center = (double)Freq::fromfreq(config.band[band].freq) /
+ TOTALFREQS;
+ double normalize = gauss(sigma, 0, 0);
+ if(config.band[band].magnitude <= -MAXMAGNITUDE)
+ magnitude = -1;
+
+ for(int i = 0; i < config.window_size / 2; i++)
+ {
+ int freq = i * niquist / (config.window_size / 2);
+ int current_slot = Freq::fromfreq(freq);
+ envelope[i] += magnitude *
+ gauss(sigma, center, (double)current_slot / TOTALFREQS) /
+ normalize;
+// printf("freq=%d magnitude=%f gauss=%f normalize=%f envelope[i]=%f\n",
+// freq,
+// magnitude,
+// gauss(sigma, center, (double)current_slot / TOTALFREQS),
+// normalize,
+// envelope[i]);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+double ParametricEQ::gauss(double sigma, double center, double x)
+{
+ if(EQUIV(sigma, 0)) sigma = 0.01;
+
+ double result = 1.0 /
+ sqrt(2 * M_PI * sigma * sigma) *
+ exp(-(x - center) * (x - center) /
+ (2 * sigma * sigma));
+
+
+ return result;
+}
+
+
+
+int ParametricEQ::process_buffer(int64_t size,
+ Samples *buffer,
+ int64_t start_position,
+ int sample_rate)
+{
+ need_reconfigure |= load_configuration();
+ if(need_reconfigure) reconfigure();
+
+
+ fft->process_buffer(start_position,
+ size,
+ buffer,
+ get_direction());
+
+
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+void ParametricEQ::reset()
+{
+ need_reconfigure = 1;
+ thread = 0;
+ fft = 0;
+}
+
+void ParametricEQ::update_gui()
+{
+ if(thread)
+ {
+ if(load_configuration())
+ {
+ ((ParametricWindow*)thread->window)->lock_window("ParametricEQ::update_gui");
+ calculate_envelope();
+ ((ParametricWindow*)thread->window)->update_gui();
+ ((ParametricWindow*)thread->window)->unlock_window();
+ }
+ else
+ {
+ int total_frames = get_gui_update_frames();
+//printf("ParametricEQ::update_gui %d %d\n", __LINE__, total_frames);
+ if(total_frames)
+ {
+ ((ParametricWindow*)thread->window)->lock_window("ParametricEQ::update_gui");
+ ((ParametricWindow*)thread->window)->update_canvas();
+ ((ParametricWindow*)thread->window)->unlock_window();
+ }
+ }
+ }
+}
+
+
+