/* * ZamEQ2 2 band parametric equaliser * Copyright (C) 2014 Damien Zammit * * 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 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. * * For a full copy of the GNU General Public License see the doc/GPL.txt file. */ #include "ZamEQ2UI.hpp" using DGL::Point; START_NAMESPACE_DISTRHO // ----------------------------------------------------------------------- ZamEQ2UI::ZamEQ2UI() : UI() { setSize(ZamEQ2Artwork::zameq2Width, ZamEQ2Artwork::zameq2Height); // background fImgBackground = Image(ZamEQ2Artwork::zameq2Data, ZamEQ2Artwork::zameq2Width, ZamEQ2Artwork::zameq2Height, GL_BGR); // toggle image Image sliderImage(ZamEQ2Artwork::togglesliderData, ZamEQ2Artwork::togglesliderWidth, ZamEQ2Artwork::togglesliderHeight); // knob Image knobImage(ZamEQ2Artwork::knobData, ZamEQ2Artwork::knobWidth, ZamEQ2Artwork::knobHeight); // knob fKnobGain1 = new ImageKnob(this, knobImage); fKnobGain1->setAbsolutePos(91, 172); fKnobGain1->setRange(-50.f, 20.0f); fKnobGain1->setRotationAngle(240); fKnobGain1->setDefault(0.0f); fKnobGain1->setCallback(this); fKnobQ1 = new ImageKnob(this, knobImage); fKnobQ1->setAbsolutePos(91, 122); fKnobQ1->setRange(0.1f, 6.0f); fKnobQ1->setRotationAngle(240); fKnobQ1->setDefault(1.0f); fKnobQ1->setCallback(this); fKnobFreq1 = new ImageKnob(this, knobImage); fKnobFreq1->setAbsolutePos(23, 144); fKnobFreq1->setUsingLogScale(true); fKnobFreq1->setRange(20.f, 14000.0f); fKnobFreq1->setRotationAngle(240); fKnobFreq1->setDefault(500.0f); fKnobFreq1->setCallback(this); fKnobGain2 = new ImageKnob(this, knobImage); fKnobGain2->setAbsolutePos(567, 172); fKnobGain2->setRange(-50.f, 20.0f); fKnobGain2->setRotationAngle(240); fKnobGain2->setDefault(0.0f); fKnobGain2->setCallback(this); fKnobQ2 = new ImageKnob(this, knobImage); fKnobQ2->setAbsolutePos(567, 122); fKnobQ2->setRange(0.1f, 6.0f); fKnobQ2->setRotationAngle(240); fKnobQ2->setDefault(1.0f); fKnobQ2->setCallback(this); fKnobFreq2 = new ImageKnob(this, knobImage); fKnobFreq2->setAbsolutePos(499, 144); fKnobFreq2->setUsingLogScale(true); fKnobFreq2->setRange(20.f, 14000.0f); fKnobFreq2->setRotationAngle(240); fKnobFreq2->setDefault(3000.0f); fKnobFreq2->setCallback(this); fKnobGainL = new ImageKnob(this, knobImage); fKnobGainL->setAbsolutePos(91, 52); fKnobGainL->setRange(-50.f, 20.0f); fKnobGainL->setRotationAngle(240); fKnobGainL->setDefault(0.0f); fKnobGainL->setCallback(this); fKnobFreqL = new ImageKnob(this, knobImage); fKnobFreqL->setAbsolutePos(23, 23); fKnobFreqL->setUsingLogScale(true); fKnobFreqL->setRange(20.f, 14000.0f); fKnobFreqL->setRotationAngle(240); fKnobFreqL->setDefault(250.0f); fKnobFreqL->setCallback(this); fKnobGainH = new ImageKnob(this, knobImage); fKnobGainH->setAbsolutePos(567, 53); fKnobGainH->setRange(-50.f, 20.0f); fKnobGainH->setRotationAngle(240); fKnobGainH->setDefault(0.0f); fKnobGainH->setCallback(this); fKnobFreqH = new ImageKnob(this, knobImage); fKnobFreqH->setAbsolutePos(499, 24); fKnobFreqH->setUsingLogScale(true); fKnobFreqH->setRange(20.f, 14000.0f); fKnobFreqH->setRotationAngle(240); fKnobFreqH->setDefault(8000.0f); fKnobFreqH->setCallback(this); Point masterPosStart(211,204); Point masterPosEnd(288,204); fSliderMaster = new ImageSlider(this, sliderImage); fSliderMaster->setStartPos(masterPosStart); fSliderMaster->setEndPos(masterPosEnd); fSliderMaster->setRange(-12.f,12.f); fSliderMaster->setValue(0.f); fSliderMaster->setStep(6.f); fSliderMaster->setCallback(this); fCanvasArea.setPos(165,10); fCanvasArea.setSize(305,180); // set default values programLoaded(0); } // ----------------------------------------------------------------------- // DSP Callbacks void ZamEQ2UI::parameterChanged(uint32_t index, float value) { switch (index) { case ZamEQ2Plugin::paramGain1: fKnobGain1->setValue(value); break; case ZamEQ2Plugin::paramQ1: fKnobQ1->setValue(value); break; case ZamEQ2Plugin::paramFreq1: fKnobFreq1->setValue(value); break; case ZamEQ2Plugin::paramGain2: fKnobGain2->setValue(value); break; case ZamEQ2Plugin::paramQ2: fKnobQ2->setValue(value); break; case ZamEQ2Plugin::paramFreq2: fKnobFreq2->setValue(value); break; case ZamEQ2Plugin::paramGainL: fKnobGainL->setValue(value); break; case ZamEQ2Plugin::paramFreqL: fKnobFreqL->setValue(value); break; case ZamEQ2Plugin::paramGainH: fKnobGainH->setValue(value); break; case ZamEQ2Plugin::paramFreqH: fKnobFreqH->setValue(value); break; case ZamEQ2Plugin::paramMaster: fSliderMaster->setValue(value); break; } } void ZamEQ2UI::programLoaded(uint32_t index) { if (index != 0) return; // Default values fKnobGain1->setValue(0.0f); fKnobQ1->setValue(1.0f); fKnobFreq1->setValue(500.0f); fKnobGain2->setValue(0.0f); fKnobQ2->setValue(1.0f); fKnobFreq2->setValue(3000.0f); fKnobGainL->setValue(0.0f); fKnobFreqL->setValue(250.0f); fKnobGainH->setValue(0.0f); fKnobFreqH->setValue(8000.0f); fSliderMaster->setValue(0.f); } // ----------------------------------------------------------------------- // Widget Callbacks void ZamEQ2UI::imageKnobDragStarted(ImageKnob* knob) { if (knob == fKnobGain1) editParameter(ZamEQ2Plugin::paramGain1, true); else if (knob == fKnobQ1) editParameter(ZamEQ2Plugin::paramQ1, true); else if (knob == fKnobFreq1) editParameter(ZamEQ2Plugin::paramFreq1, true); else if (knob == fKnobGain2) editParameter(ZamEQ2Plugin::paramGain2, true); else if (knob == fKnobQ2) editParameter(ZamEQ2Plugin::paramQ2, true); else if (knob == fKnobFreq2) editParameter(ZamEQ2Plugin::paramFreq2, true); else if (knob == fKnobGainL) editParameter(ZamEQ2Plugin::paramGainL, true); else if (knob == fKnobFreqL) editParameter(ZamEQ2Plugin::paramFreqL, true); else if (knob == fKnobGainH) editParameter(ZamEQ2Plugin::paramGainH, true); else if (knob == fKnobFreqH) editParameter(ZamEQ2Plugin::paramFreqH, true); } void ZamEQ2UI::imageKnobDragFinished(ImageKnob* knob) { if (knob == fKnobGain1) editParameter(ZamEQ2Plugin::paramGain1, false); else if (knob == fKnobQ1) editParameter(ZamEQ2Plugin::paramQ1, false); else if (knob == fKnobFreq1) editParameter(ZamEQ2Plugin::paramFreq1, false); else if (knob == fKnobGain2) editParameter(ZamEQ2Plugin::paramGain2, false); else if (knob == fKnobQ2) editParameter(ZamEQ2Plugin::paramQ2, false); else if (knob == fKnobFreq2) editParameter(ZamEQ2Plugin::paramFreq2, false); else if (knob == fKnobGainL) editParameter(ZamEQ2Plugin::paramGainL, false); else if (knob == fKnobFreqL) editParameter(ZamEQ2Plugin::paramFreqL, false); else if (knob == fKnobGainH) editParameter(ZamEQ2Plugin::paramGainH, false); else if (knob == fKnobFreqH) editParameter(ZamEQ2Plugin::paramFreqH, false); } void ZamEQ2UI::imageKnobValueChanged(ImageKnob* knob, float value) { if (knob == fKnobGain1) setParameterValue(ZamEQ2Plugin::paramGain1, value); else if (knob == fKnobQ1) setParameterValue(ZamEQ2Plugin::paramQ1, value); else if (knob == fKnobFreq1) setParameterValue(ZamEQ2Plugin::paramFreq1, value); else if (knob == fKnobGain2) setParameterValue(ZamEQ2Plugin::paramGain2, value); else if (knob == fKnobQ2) setParameterValue(ZamEQ2Plugin::paramQ2, value); else if (knob == fKnobFreq2) setParameterValue(ZamEQ2Plugin::paramFreq2, value); else if (knob == fKnobGainL) setParameterValue(ZamEQ2Plugin::paramGainL, value); else if (knob == fKnobFreqL) setParameterValue(ZamEQ2Plugin::paramFreqL, value); else if (knob == fKnobGainH) setParameterValue(ZamEQ2Plugin::paramGainH, value); else if (knob == fKnobFreqH) setParameterValue(ZamEQ2Plugin::paramFreqH, value); } void ZamEQ2UI::imageSliderDragStarted(ImageSlider* slider) { if (slider == fSliderMaster) editParameter(ZamEQ2Plugin::paramMaster, true); } void ZamEQ2UI::imageSliderDragFinished(ImageSlider* slider) { if (slider == fSliderMaster) editParameter(ZamEQ2Plugin::paramMaster, false); } void ZamEQ2UI::imageSliderValueChanged(ImageSlider* slider, float value) { if (slider == fSliderMaster) setParameterValue(ZamEQ2Plugin::paramMaster, value); } void ZamEQ2UI::lowshelf(int i, int ch, float srate, float fc, float g) { float k, v0; k = tanf(M_PI * fc / srate); v0 = powf(10., g / 20.); if (g < 0.f) { // LF cut float denom = v0 + sqrt(2. * v0)*k + k*k; b0[ch][i] = v0 * (1. + sqrt(2.)*k + k*k) / denom; b1[ch][i] = 2. * v0*(k*k - 1.) / denom; b2[ch][i] = v0 * (1. - sqrt(2.)*k + k*k) / denom; a1[ch][i] = 2. * (k*k - v0) / denom; a2[ch][i] = (v0 - sqrt(2. * v0)*k + k*k) / denom; } else { // LF boost float denom = 1. + sqrt(2.)*k + k*k; b0[ch][i] = (1. + sqrt(2. * v0)*k + v0*k*k) / denom; b1[ch][i] = 2. * (v0*k*k - 1.) / denom; b2[ch][i] = (1. - sqrt(2. * v0)*k + v0*k*k) / denom; a1[ch][i] = 2. * (k*k - 1.) / denom; a2[ch][i] = (1. - sqrt(2.)*k + k*k) / denom; } } void ZamEQ2UI::highshelf(int i, int ch, float srate, float fc, float g) { float k, v0; k = tanf(M_PI * fc / srate); v0 = powf(10., g / 20.); if (g < 0.f) { // HF cut float denom = 1. + sqrt(2. * v0)*k + v0*k*k; b0[ch][i] = v0*(1. + sqrt(2.)*k + k*k) / denom; b1[ch][i] = 2. * v0*(k*k - 1.) / denom; b2[ch][i] = v0*(1. - sqrt(2.)*k + k*k) / denom; a1[ch][i] = 2. * (v0*k*k - 1.) / denom; a2[ch][i] = (1. - sqrt(2. * v0)*k + v0*k*k) / denom; } else { // HF boost float denom = 1. + sqrt(2.)*k + k*k; b0[ch][i] = (v0 + sqrt(2. * v0)*k + k*k) / denom; b1[ch][i] = 2. * (k*k - v0) / denom; b2[ch][i] = (v0 - sqrt(2. * v0)*k + k*k) / denom; a1[ch][i] = 2. * (k*k - 1.) / denom; a2[ch][i] = (1. - sqrt(2.)*k + k*k) / denom; } } void ZamEQ2UI::peq(int i, int ch, float srate, float fc, float g, float bw) { float k, v0, q; k = tanf(M_PI * fc / srate); v0 = powf(10., g / 20.); q = powf(2., 1./bw)/(powf(2., bw) - 1.); //q from octave bw if (g < 0.f) { // cut float denom = 1. + k/(v0*q) + k*k; b0[ch][i] = (1. + k/q + k*k) / denom; b1[ch][i] = 2. * (k*k - 1.) / denom; b2[ch][i] = (1. - k/q + k*k) / denom; a1[ch][i] = b1[ch][i]; a2[ch][i] = (1. - k/(v0*q) + k*k) / denom; } else { // boost float denom = 1. + k/q + k*k; b0[ch][i] = (1. + k*v0/q + k*k) / denom; b1[ch][i] = 2. * (k*k - 1.) / denom; b2[ch][i] = (1. - k*v0/q + k*k) / denom; a1[ch][i] = b1[ch][i]; a2[ch][i] = (1. - k/q + k*k) / denom; } } void ZamEQ2UI::calceqcurve(float x[], float y[]) { float SR = getSampleRate(); float p1 = 10000.; float p2 = 5000.; float c2 = log10(1.+SR); float c1 = (1.+p1/SR)/(EQPOINTS*(p2/SR)*(p2/SR)); double bw1 = fKnobQ1->getValue(); double boost1 = fKnobGain1->getValue(); double freq1 = fKnobFreq1->getValue(); double bw2 = fKnobQ2->getValue(); double boost2 = fKnobGain2->getValue(); double freq2 = fKnobFreq2->getValue(); double boostl = fKnobGainL->getValue(); double freql = fKnobFreqL->getValue(); double boosth = fKnobGainH->getValue(); double freqh = fKnobFreqH->getValue(); for (uint32_t i = 0; i < EQPOINTS; ++i) { x[i] = 1.5*log10(1.+i+c1)/c2; std::complex H; double theta = -(i+0.005)*M_PI/EQPOINTS*20./(SR/1000.); std::complex expiw = std::polar(1.0, theta); std::complex exp2iw = std::polar(1.0, 2.0*theta); double freqH; //phaseH; lowshelf(0, 0, SR, freql, boostl); peq(1, 0, SR, freq1, boost1, bw1); peq(2, 0, SR, freq2, boost2, bw2); highshelf(3, 0, SR, freqh, boosth); H = (1. + a1[0][0]*expiw + a2[0][0]*exp2iw)/(b0[0][0] + b1[0][0]*expiw + b2[0][0]*exp2iw); H += (1. + a1[0][1]*expiw + a2[0][1]*exp2iw)/(b0[0][1] + b1[0][1]*expiw + b2[0][1]*exp2iw); H += (1. + a1[0][2]*expiw + a2[0][2]*exp2iw)/(b0[0][2] + b1[0][2]*expiw + b2[0][2]*exp2iw); H += (1. + a1[0][3]*expiw + a2[0][3]*exp2iw)/(b0[0][3] + b1[0][3]*expiw + b2[0][3]*exp2iw); freqH = std::abs(H); y[i] = (to_dB(freqH/4.)/5.)-(fSliderMaster->getValue())/24.f+0.5; x[i] = fCanvasArea.getX() + x[i]*fCanvasArea.getWidth(); y[i] = fCanvasArea.getY() + y[i]*fCanvasArea.getHeight(); } } void ZamEQ2UI::onDisplay() { fImgBackground.draw(); calceqcurve(eqx, eqy); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_LINE_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); glLineWidth(2); int i; glColor4f(1.f, 1.f, 0.235f, 1.0f); for (i = 1; i < EQPOINTS; ++i) { glBegin(GL_LINES); if (eqy[i-1] < fCanvasArea.getY() + fCanvasArea.getHeight() && eqy[i] < fCanvasArea.getY() + fCanvasArea.getHeight() && eqy[i-1] > fCanvasArea.getY() && eqy[i] > fCanvasArea.getY()) { glVertex2i(eqx[i-1], eqy[i-1]); glVertex2i(eqx[i], eqy[i]); } glEnd(); } // reset color glColor4f(1.0f, 1.0f, 1.0f, 1.0f); } // ----------------------------------------------------------------------- UI* createUI() { return new ZamEQ2UI(); } // ----------------------------------------------------------------------- END_NAMESPACE_DISTRHO