diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index cf7a5a94e..63c80538e 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -10,6 +10,7 @@ ADD_SUBDIRECTORY(CrossoverEQ) ADD_SUBDIRECTORY(delay) ADD_SUBDIRECTORY(DualFilter) ADD_SUBDIRECTORY(dynamics_processor) +ADD_SUBDIRECTORY(Eq) ADD_SUBDIRECTORY(flanger) ADD_SUBDIRECTORY(flp_import) ADD_SUBDIRECTORY(HydrogenImport) diff --git a/plugins/Eq/CMakeLists.txt b/plugins/Eq/CMakeLists.txt new file mode 100644 index 000000000..3cd4b8885 --- /dev/null +++ b/plugins/Eq/CMakeLists.txt @@ -0,0 +1,6 @@ +INCLUDE(BuildPlugin) +INCLUDE_DIRECTORIES(${FFTW3F_INCLUDE_DIRS}) +LINK_DIRECTORIES(${FFTW3F_LIBRARY_DIRS}) +LINK_LIBRARIES(${FFTW3F_LIBRARIES}) +BUILD_PLUGIN(eq EqEffect.cpp EqControls.cpp EqControlsDialog.cpp EqFilter.h EqParameterWidget.cpp EqFader.h EqSpectrumView.h +MOCFILES EqControls.h EqParameterWidget.h EqFader.h EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png") diff --git a/plugins/Eq/EqControls.cpp b/plugins/Eq/EqControls.cpp new file mode 100644 index 000000000..19b63fc4a --- /dev/null +++ b/plugins/Eq/EqControls.cpp @@ -0,0 +1,195 @@ +/* + * eqcontrols.cpp - defination of EqControls class. + * + * Copyright (c) 2014 David French + * + * This file is part of LMMS - http://lmms.io + * + * 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 (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#include +#include "EqControls.h" +#include "EqEffect.h" + + + + +EqControls::EqControls( EqEffect *effect ) : + EffectControls( effect ), + m_effect( effect ), + m_inGainModel( 1.0, 0.0, 2.0, 0.001, this, tr( "Input gain") ), + m_outGainModel( 1.0, 0.0, 2.0, 0.001, this, tr( "Output gain" ) ), + m_lowShelfGainModel( 0.0 , -40, 40, 0.001, this, tr( "Low shelf gain" ) ), + m_para1GainModel( 0.0 , -40, 40, 0.001, this, tr( "Peak 1 gain" ) ), + m_para2GainModel( 0.0 , -40, 40, 0.001, this, tr( "Peak 2 gain" ) ), + m_para3GainModel( 0.0 , -40, 40, 0.001, this, tr( "Peak 3 gain" ) ), + m_para4GainModel( 0.0 , -40, 40, 0.001, this, tr( "Peak 4 gain" ) ), + m_highShelfGainModel( 0.0 , -40, 40, 0.001, this, tr( "High Shelf gain" ) ), + m_hpResModel( 0.707,0.003, 10.0 , 0.001, this, tr( "HP res" ) ), + m_lowShelfResModel( 1.4,0.0, 10.0 , 0.001, this , tr( "Low Shelf res" ) ), + m_para1ResModel( 1.4 ,0.55, 10.0 , 0.001, this , tr( "Peak 1 res" ) ), + m_para2ResModel( 1.4, 0.55, 10.0 , 0.001, this , tr( "Peak 2 res" ) ), + m_para3ResModel( 1.4, 0.55, 10.0 , 0.001, this , tr( "Peak 3 res" ) ), + m_para4ResModel( 1.4, 0.55, 10.0 , 0.001, this , tr( "Peak 4 res" ) ), + m_highShelfResModel( 1.4, 0.001, 10.0 , 0.001, this , tr( "High Shelf res" ) ), + m_lpResModel( 0.707,0.003, 10.0 , 0.001, this , tr( "LP res" ) ), + m_hpFeqModel( 31.0, 30.0, 20000, 0.001, this , tr( "HP freq" ) ), + m_lowShelfFreqModel( 80.0, 25.0, 20000, 0.001, this , tr( "Low Shelf freq" ) ), + m_para1FreqModel( 120.0, 27.0, 20000, 0.001, this , tr( "Peak 1 freq" ) ), + m_para2FreqModel( 250.0, 27.0, 20000, 0.001, this, tr( "Peak 2 freq" ) ), + m_para3FreqModel( 2000.0, 27.0, 20000, 0.001, this , tr( "Peak 3 freq" ) ), + m_para4FreqModel( 4000.0, 27.0, 20000, 0.001, this , tr( "Peak 4 freq" ) ), + m_highShelfFreqModel( 12000.0, 27.0, 20000, 0.001, this , tr( "High shelf freq" ) ), + m_lpFreqModel( 18000.0, 27.0, 20000, 0.001, this , tr( "LP freq" ) ), + m_hpActiveModel( false, this , tr( "HP active" ) ), + m_lowShelfActiveModel( false, this , tr( "Low shelf active" ) ), + m_para1ActiveModel(false, this , tr( "Peak 1 active" ) ), + m_para2ActiveModel( false, this , tr( "Peak 2 active" ) ), + m_para3ActiveModel( false, this , tr( "Peak 3 active" ) ), + m_para4ActiveModel( false, this , tr( "Peak 4 active" ) ), + m_highShelfActiveModel( false, this , tr( "High shelf active" ) ), + m_lpActiveModel( false, this , tr( "LP active" ) ), + m_lp12Model( false, this , tr( "LP 12" ) ), + m_lp24Model( false, this , tr( "LP 24" ) ), + m_lp48Model( false, this , tr( "LP 48" ) ), + m_hp12Model( false, this , tr( "HP 12" ) ), + m_hp24Model( false, this , tr( "HP 24" ) ), + m_hp48Model( false, this , tr( "HP 48" ) ), + m_analyzeModel( true, this , tr( "Analyze enable" ) ), + m_lpTypeModel( 0,0,2,this, tr( "low pass type") ) , + m_hpTypeModel( 0,0,2,this, tr( "high pass type") ) +{ + m_hpFeqModel.setScaleLogarithmic( true ); + m_lowShelfFreqModel.setScaleLogarithmic( true ); + m_para1FreqModel.setScaleLogarithmic( true ); + m_para2FreqModel.setScaleLogarithmic( true ); + m_para3FreqModel.setScaleLogarithmic( true ); + m_para4FreqModel.setScaleLogarithmic( true ); + m_highShelfFreqModel.setScaleLogarithmic( true ); + m_lpFreqModel.setScaleLogarithmic( true ); + m_para1GainModel.setScaleLogarithmic( true ); + m_inPeakL = 0; + m_inPeakR = 0; + m_outPeakL = 0; + m_outPeakR = 0; + m_lowShelfPeakL = 0; m_lowShelfPeakR = 0; + m_para1PeakL = 0; m_para1PeakR = 0; + m_para2PeakL = 0; m_para2PeakR = 0; + m_para3PeakL = 0; m_para3PeakR = 0; + m_para4PeakL = 0; m_para4PeakR = 0; + m_highShelfPeakL = 0; m_highShelfPeakR = 0; + m_inProgress = false; +} + + + + +void EqControls::loadSettings( const QDomElement &_this ) +{ + m_inGainModel.loadSettings( _this, "Inputgain" ); + m_outGainModel.loadSettings( _this, "Outputgain"); + m_lowShelfGainModel.loadSettings( _this , "Lowshelfgain" ); + m_para1GainModel.loadSettings( _this, "Peak1gain" ); + m_para2GainModel.loadSettings( _this, "Peak2gain" ); + m_para3GainModel.loadSettings( _this, "Peak3gain" ); + m_para4GainModel.loadSettings( _this, "Peak4gain" ); + m_highShelfGainModel.loadSettings( _this , "HighShelfgain"); + m_hpResModel.loadSettings( _this ,"HPres"); + m_lowShelfResModel.loadSettings( _this, "LowShelfres" ); + m_para1ResModel.loadSettings( _this ,"Peak1res" ); + m_para2ResModel.loadSettings( _this ,"Peak2res" ); + m_para3ResModel.loadSettings( _this ,"Peak3res" ); + m_para4ResModel.loadSettings( _this ,"Peak4res" ); + m_highShelfResModel.loadSettings( _this, "HighShelfres" ); + m_lpResModel.loadSettings( _this, "LPres"); + m_hpFeqModel.loadSettings( _this, "HPfreq" ); + m_lowShelfFreqModel.loadSettings( _this, "LowShelffreq" ); + m_para1FreqModel.loadSettings( _this, "Peak1freq" ); + m_para2FreqModel.loadSettings( _this, "Peak2freq" ); + m_para3FreqModel.loadSettings( _this, "Peak3freq" ); + m_para4FreqModel.loadSettings( _this, "Peak4freq" ); + m_highShelfFreqModel.loadSettings( _this, "Highshelffreq" ); + m_lpFreqModel.loadSettings( _this, "LPfreq" ); + m_hpActiveModel.loadSettings( _this, "HPactive" ); + m_lowShelfActiveModel.loadSettings( _this, "Lowshelfactive" ); + m_para1ActiveModel.loadSettings( _this, "Peak1active"); + m_para2ActiveModel.loadSettings( _this, "Peak2active"); + m_para3ActiveModel.loadSettings( _this, "Peak3active"); + m_para4ActiveModel.loadSettings( _this, "Peak4active"); + m_highShelfActiveModel.loadSettings( _this, "Highshelfactive" ); + m_lpActiveModel.loadSettings( _this, "LPactive" ); + m_lp12Model.loadSettings( _this , "LP12" ); + m_lp24Model.loadSettings( _this , "LP24" ); + m_lp48Model.loadSettings( _this , "LP48" ); + m_hp12Model.loadSettings( _this , "HP12" ); + m_hp24Model.loadSettings( _this , "HP24" ); + m_hp48Model.loadSettings( _this , "HP48" ); + m_analyzeModel.loadSettings( _this, "Analyzeenable"); + m_lpTypeModel.loadSettings( _this, "LP" ); + m_hpTypeModel.loadSettings( _this, "HP" ); +} + + + + +void EqControls::saveSettings( QDomDocument &doc, QDomElement &parent ) +{ + + m_inGainModel.saveSettings( doc, parent, "Inputgain" ); + m_outGainModel.saveSettings( doc, parent, "Outputgain"); + m_lowShelfGainModel.saveSettings( doc, parent , "Lowshelfgain" ); + m_para1GainModel.saveSettings( doc, parent, "Peak1gain" ); + m_para2GainModel.saveSettings( doc, parent, "Peak2gain" ); + m_para3GainModel.saveSettings( doc, parent, "Peak3gain" ); + m_para4GainModel.saveSettings( doc, parent, "Peak4gain" ); + m_highShelfGainModel.saveSettings( doc, parent, "HighShelfgain"); + m_hpResModel.saveSettings( doc, parent ,"HPres"); + m_lowShelfResModel.saveSettings( doc, parent, "LowShelfres" ); + m_para1ResModel.saveSettings( doc, parent,"Peak1res" ); + m_para2ResModel.saveSettings( doc, parent,"Peak2res" ); + m_para3ResModel.saveSettings( doc, parent,"Peak3res" ); + m_para4ResModel.saveSettings( doc, parent,"Peak4res" ); + m_highShelfResModel.saveSettings( doc, parent, "HighShelfres" ); + m_lpResModel.saveSettings( doc, parent, "LPres"); + m_hpFeqModel.saveSettings( doc, parent, "HPfreq" ); + m_lowShelfFreqModel.saveSettings( doc, parent, "LowShelffreq" ); + m_para1FreqModel.saveSettings( doc, parent, "Peak1freq" ); + m_para2FreqModel.saveSettings( doc, parent, "Peak2freq" ); + m_para3FreqModel.saveSettings( doc, parent, "Peak3freq" ); + m_para4FreqModel.saveSettings( doc, parent, "Peak4freq" ); + m_highShelfFreqModel.saveSettings( doc, parent, "Highshelffreq" ); + m_lpFreqModel.saveSettings( doc, parent, "LPfreq" ); + m_hpActiveModel.saveSettings( doc, parent, "HPactive" ); + m_lowShelfActiveModel.saveSettings( doc, parent, "Lowshelfactive" ); + m_para1ActiveModel.saveSettings( doc, parent, "Peak1active" ); + m_para2ActiveModel.saveSettings( doc, parent, "Peak2active" ); + m_para3ActiveModel.saveSettings( doc, parent, "Peak3active" ); + m_para4ActiveModel.saveSettings( doc, parent, "Peak4active" ); + m_highShelfActiveModel.saveSettings( doc, parent, "Highshelfactive" ); + m_lpActiveModel.saveSettings( doc, parent, "LPactive" ); + m_lp12Model.saveSettings( doc, parent, "LP12" ); + m_lp24Model.saveSettings( doc, parent, "LP24" ); + m_lp48Model.saveSettings( doc, parent, "LP48" ); + m_hp12Model.saveSettings( doc, parent, "HP12" ); + m_hp24Model.saveSettings( doc, parent, "HP24" ); + m_hp48Model.saveSettings( doc, parent, "HP48" ); + m_analyzeModel.saveSettings( doc, parent, "Analyzeenable"); + m_lpTypeModel.saveSettings( doc, parent, "LP" ); + m_hpTypeModel.saveSettings( doc, parent, "HP" ); +} + diff --git a/plugins/Eq/EqControls.h b/plugins/Eq/EqControls.h new file mode 100644 index 000000000..eec745b6f --- /dev/null +++ b/plugins/Eq/EqControls.h @@ -0,0 +1,134 @@ +/* + * eqcontrols.h - defination of EqControls class. + * + * Copyright (c) 2014 David French + * + * This file is part of LMMS - http://lmms.io + * + * 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 (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#ifndef EQCONTROLS_H +#define EQCONTROLS_H + +#include "EffectControls.h" +#include "EqControlsDialog.h" +#include "Knob.h" + +class EqEffect; + +class EqControls : public EffectControls +{ + Q_OBJECT +public: + explicit EqControls( EqEffect* effect ); + virtual ~EqControls() + { + } + virtual void saveSettings ( QDomDocument& doc, QDomElement& parent ); + virtual void loadSettings ( const QDomElement &_this ); + inline virtual QString nodeName() const + { + return "Eq"; + } + virtual int controlCount() + { + return 39; + } + virtual EffectControlDialog* createView() + { + return new EqControlsDialog( this ); + } + + float m_inPeakL; + float m_inPeakR; + float m_outPeakL; + float m_outPeakR; + float m_lowShelfPeakL, m_lowShelfPeakR; + float m_para1PeakL, m_para1PeakR; + float m_para2PeakL, m_para2PeakR; + float m_para3PeakL, m_para3PeakR; + float m_para4PeakL, m_para4PeakR; + float m_highShelfPeakL, m_highShelfPeakR; + + EqAnalyser m_inFftBands; + EqAnalyser m_outFftBands; + + bool m_inProgress; + + + + + +private: + EqEffect* m_effect; + + FloatModel m_inGainModel; + FloatModel m_outGainModel; + FloatModel m_lowShelfGainModel; + FloatModel m_para1GainModel; + FloatModel m_para2GainModel; + FloatModel m_para3GainModel; + FloatModel m_para4GainModel; + FloatModel m_highShelfGainModel; + + FloatModel m_hpResModel; + FloatModel m_lowShelfResModel; + FloatModel m_para1ResModel; + FloatModel m_para2ResModel; + FloatModel m_para3ResModel; + FloatModel m_para4ResModel; + FloatModel m_highShelfResModel; + FloatModel m_lpResModel; + + FloatModel m_hpFeqModel; + FloatModel m_lowShelfFreqModel; + FloatModel m_para1FreqModel; + FloatModel m_para2FreqModel; + FloatModel m_para3FreqModel; + FloatModel m_para4FreqModel; + FloatModel m_highShelfFreqModel; + FloatModel m_lpFreqModel; + + BoolModel m_hpActiveModel; + BoolModel m_lowShelfActiveModel; + BoolModel m_para1ActiveModel; + BoolModel m_para2ActiveModel; + BoolModel m_para3ActiveModel; + BoolModel m_para4ActiveModel; + BoolModel m_highShelfActiveModel; + BoolModel m_lpActiveModel; + + BoolModel m_lp12Model; + BoolModel m_lp24Model; + BoolModel m_lp48Model; + + BoolModel m_hp12Model; + BoolModel m_hp24Model; + BoolModel m_hp48Model; + + BoolModel m_analyzeModel; + + IntModel m_lpTypeModel; + IntModel m_hpTypeModel; + + friend class EqControlsDialog; + friend class EqEffect; + +}; + +#endif // EQCONTROLS_H diff --git a/plugins/Eq/EqControlsDialog.cpp b/plugins/Eq/EqControlsDialog.cpp new file mode 100644 index 000000000..950ed1272 --- /dev/null +++ b/plugins/Eq/EqControlsDialog.cpp @@ -0,0 +1,171 @@ +/* + * eqcontrolsdialog.cpp - defination of EqControlsDialog class. + * + * Copyright (c) 2014 David French + * + * This file is part of LMMS - http://lmms.io + * + * 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 (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#include "EqControlsDialog.h" +#include "EqControls.h" +#include "embed.h" +#include "Fader.h" +#include "EqFader.h" +#include "Engine.h" +#include "AutomatableButton.h" +#include "QWidget" +#include "MainWindow.h" +#include "LedCheckbox.h" + + + + + +EqControlsDialog::EqControlsDialog( EqControls *controls ) : + EffectControlDialog( controls ) + +{ + m_controls = controls; + setAutoFillBackground( true ); + QPalette pal; + pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( "artwork" ) ); + setPalette( pal ); + setFixedSize( 350, 275 ); + m_inSpec = new EqSpectrumView( &controls->m_inFftBands, this); + m_inSpec->move( 51, 2 ); + m_inSpec->color = QColor( 238, 154, 120, 80 ); + m_outSpec = new EqSpectrumView( &controls->m_outFftBands, this); + m_outSpec->move( 51, 2 ); + m_outSpec->color = QColor(145, 205, 22, 80); + m_parameterWidget = new EqParameterWidget( this ); + m_parameterWidget->move( 51, 2 ); + + setBand( 0, &controls->m_hpActiveModel, &controls->m_hpFeqModel, &controls->m_hpResModel, 0, QColor(255 ,255, 255), tr( "HP" ) ,0,0); + setBand( 1, &controls->m_lowShelfActiveModel, &controls->m_lowShelfFreqModel, &controls->m_lowShelfResModel, &controls->m_lowShelfGainModel, QColor(255 ,255, 255), tr( "Low Shelf" ), &controls->m_lowShelfPeakL , &controls->m_lowShelfPeakR ); + setBand( 2, &controls->m_para1ActiveModel, &controls->m_para1FreqModel, &controls->m_para1ResModel, &controls->m_para1GainModel, QColor(255 ,255, 255), tr( "Peak 1" ), &controls->m_para1PeakL, &controls->m_para1PeakR ); + setBand( 3, &controls->m_para2ActiveModel, &controls->m_para2FreqModel, &controls->m_para2ResModel, &controls->m_para2GainModel, QColor(255 ,255, 255), tr( "Peak 2" ), &controls->m_para2PeakL, &controls->m_para2PeakR ); + setBand( 4, &controls->m_para3ActiveModel, &controls->m_para3FreqModel, &controls->m_para3ResModel, &controls->m_para3GainModel, QColor(255 ,255, 255), tr( "Peak 3" ), &controls->m_para3PeakL, &controls->m_para3PeakR ); + setBand( 5, &controls->m_para4ActiveModel, &controls->m_para4FreqModel, &controls->m_para4ResModel, &controls->m_para4GainModel, QColor(255 ,255, 255), tr( "Peak 4" ), &controls->m_para4PeakL, &controls->m_para4PeakR ); + setBand( 6, &controls->m_highShelfActiveModel, &controls->m_highShelfFreqModel, &controls->m_highShelfResModel, &controls->m_highShelfGainModel, QColor(255 ,255, 255), tr( "High Shelf" ), &controls->m_highShelfPeakL, &controls->m_highShelfPeakR ); + setBand( 7, &controls->m_lpActiveModel, &controls->m_lpFreqModel, &controls->m_lpResModel, 0, QColor(255 ,255, 255), tr( "LP" ) ,0,0); + int cw = width()/8; //the chanel width in pixels + int ko = ( cw * 0.5 ) - ((new Knob( knobBright_26, 0 ))->width() * 0.5 ); + + m_inGainFader = new EqFader( &controls->m_inGainModel, tr( "In Gain" ), this, &controls->m_inPeakL, &controls->m_inPeakR); + m_inGainFader->move( 10, 5 ); + + + m_outGainFader = new EqFader( &controls->m_outGainModel, tr( "Out Gain" ), this, &controls->m_outPeakL, &controls->m_outPeakR ); + m_outGainFader->move( 315, 5 ); + //gain faders + + int fo = (cw * 0.5) - (m_outGainFader->width() * 0.5 ); + + for( int i = 1; i < m_parameterWidget->bandCount() - 1; i++) + { + m_gainFader = new EqFader( m_parameterWidget->getBandModels(i)->gain, tr( "" ), this ,m_parameterWidget->getBandModels( i )->peakL, m_parameterWidget->getBandModels( i )->peakR ); + m_gainFader->move( cw * i + fo , 123 ); + m_gainFader->setMinimumHeight(80); + m_gainFader->resize(m_gainFader->width() , 80); + m_gainFader->setDisplayConversion( false ); + m_gainFader->setHintText( tr( "Gain") , "dB"); + } + + for( int i = 0; i < m_parameterWidget->bandCount() ; i++) + { + m_resKnob = new Knob( knobBright_26, this ); + if(i ==0 || i == 7) + { + m_resKnob->move( cw * i + ko , 190 ); + } else + { + m_resKnob->move( cw * i + ko , 205 ); + } + m_resKnob->setVolumeKnob(false); + m_resKnob->setModel( m_parameterWidget->getBandModels( i )->res ); + m_resKnob->setHintText( tr( "Resonance:") , ""); + + m_freqKnob = new Knob( knobBright_26, this ); + if( i == 0 || i == 7 ) + { + m_freqKnob->move( cw * i + ko, 222 ); + } else + { + m_freqKnob->move(cw * i + ko, 235 ); + } + m_freqKnob->setVolumeKnob( false ); + m_freqKnob->setModel( m_parameterWidget->getBandModels( i )->freq ); + m_freqKnob->setHintText( tr( "Frequency:" ), "Hz" ); + + m_activeBox = new LedCheckBox( m_parameterWidget->getBandModels( i )->name , this , "" , LedCheckBox::Green ); + m_activeBox->move( cw * i + fo + 3, 260 ); + m_activeBox->setModel( m_parameterWidget->getBandModels( i )->active ); + } + + //hp filter type + + m_hp12Box = new LedCheckBox( tr( "12dB" ), this , "" , LedCheckBox::Green ); + m_hp12Box->move( cw*0 + ko, 170 ); + m_hp12Box->setModel( &controls->m_hp12Model ); + m_hp24Box = new LedCheckBox( tr( "24dB" ), this , "" , LedCheckBox::Green ); + m_hp24Box->move( cw*0 + ko, 150 ); + m_hp24Box->setModel( &controls->m_hp24Model ); + + m_hp48Box = new LedCheckBox( tr( "48dB" ), this , "" , LedCheckBox::Green ); + m_hp48Box->move( cw*0 + ko, 130 ); + m_hp48Box->setModel( &controls->m_hp48Model ); + + //LP filter type + + m_lp12Box = new LedCheckBox( tr( "12dB"), this , "" , LedCheckBox::Green ); + m_lp12Box->move( cw*7 + ko -5 , 170 ); + m_lp12Box->setModel( &controls->m_lp12Model ); + m_lp24Box = new LedCheckBox( tr( "24dB"), this , "" , LedCheckBox::Green ); + m_lp24Box->move( cw*7 + ko - 5, 150 ); + m_lp24Box->setModel( &controls->m_lp24Model ); + m_lp48Box = new LedCheckBox( tr( "48dB"), this , "" , LedCheckBox::Green ); + m_lp48Box->move( cw*7 + ko - 5, 130 ); + m_lp48Box->setModel( &controls->m_lp48Model ); + + automatableButtonGroup *lpBtnGrp = new automatableButtonGroup(this,tr ( "lp grp" ) ); + lpBtnGrp->addButton( m_lp12Box); + lpBtnGrp->addButton( m_lp24Box ); + lpBtnGrp->addButton( m_lp48Box ); + lpBtnGrp->setModel( &m_controls->m_lpTypeModel, false); + + automatableButtonGroup *hpBtnGrp = new automatableButtonGroup( this, tr( "hp grp" ) ); + hpBtnGrp->addButton( m_hp12Box ); + hpBtnGrp->addButton( m_hp24Box ); + hpBtnGrp->addButton( m_hp48Box ); + hpBtnGrp->setModel( &m_controls->m_hpTypeModel,false); + + //Analize Box + m_analyzeBox = new LedCheckBox( tr( "Analyze" ), this , "" , LedCheckBox::Green ); + m_analyzeBox->move( cw*1 + ko + 5, 15 ); + m_analyzeBox->setModel( &controls->m_analyzeModel ); + +} + +void EqControlsDialog::mouseDoubleClickEvent(QMouseEvent *event) +{ + m_originalHeight = parentWidget()->height() == 150 ? m_originalHeight : parentWidget()->height() ; + parentWidget()->setFixedHeight( parentWidget()->height() == m_originalHeight ? 150 : m_originalHeight ); + update(); +} diff --git a/plugins/Eq/EqControlsDialog.h b/plugins/Eq/EqControlsDialog.h new file mode 100644 index 000000000..d220d51ad --- /dev/null +++ b/plugins/Eq/EqControlsDialog.h @@ -0,0 +1,94 @@ +/* + * eqcontrolsdialog.h - defination of EqControlsDialog class. + * + * Copyright (c) 2014 David French + * + * This file is part of LMMS - http://lmms.io + * + * 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 (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#ifndef EQCONTROLSDIALOG_H +#define EQCONTROLSDIALOG_H + +#include "EffectControlDialog.h" +#include "Fader.h" +#include "Knob.h" +#include "LedCheckbox.h" +#include "EqParameterWidget.h" +#include "MainWindow.h" +#include "qpushbutton.h" +#include "EqSpectrumView.h" + + +class EqControls; + +class EqControlsDialog : public EffectControlDialog +{ + +public: + EqControlsDialog( EqControls* controls ); + virtual ~EqControlsDialog() + { + } + + EqBand * setBand(EqControls *controls); + +private slots: + void updateVuMeters(); + +private: + EqControls * m_controls; + + Fader* m_inGainFader; + Fader* m_outGainFader; + Fader* m_gainFader; + Knob* m_resKnob; + Knob* m_freqKnob; + LedCheckBox* m_activeBox; + LedCheckBox* m_lp12Box; + LedCheckBox* m_lp24Box; + LedCheckBox* m_lp48Box; + LedCheckBox* m_hp12Box; + LedCheckBox* m_hp24Box; + LedCheckBox* m_hp48Box; + LedCheckBox* m_analyzeBox; + EqParameterWidget* m_parameterWidget; + EqSpectrumView* m_inSpec; + EqSpectrumView* m_outSpec; + + virtual void mouseDoubleClickEvent(QMouseEvent *event); + + EqBand* setBand( int index, BoolModel* active, FloatModel* freq, FloatModel* res, FloatModel* gain, QColor color, QString name, float* peakL, float* peakR) + { + EqBand* filterModels = m_parameterWidget->getBandModels( index ); + filterModels->active = active; + filterModels->freq = freq; + filterModels->res = res; + filterModels->color = color; + filterModels->gain = gain; + filterModels->peakL = peakL; + filterModels->peakR = peakR; + return filterModels; + } + + int m_originalHeight; +}; + + + +#endif // EQCONTROLSDIALOG_H diff --git a/plugins/Eq/EqEffect.cpp b/plugins/Eq/EqEffect.cpp new file mode 100644 index 000000000..ee78f459d --- /dev/null +++ b/plugins/Eq/EqEffect.cpp @@ -0,0 +1,375 @@ +/* + * eqeffect.cpp - defination of EqEffect class. + * + * Copyright (c) 2014 David French + * + * This file is part of LMMS - http://lmms.io + * + * 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 (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#include "EqEffect.h" +#include "embed.cpp" +#include "lmms_math.h" +#include "BasicFilters.h" +#include "interpolation.h" +#include "Engine.h" +#include "MainWindow.h" + +extern "C" +{ + +Plugin::Descriptor PLUGIN_EXPORT eq_plugin_descriptor = +{ + STRINGIFY( PLUGIN_NAME ), + "Eq", + QT_TRANSLATE_NOOP( "pluginBrowser", "A native eq plugin" ), + "Dave French ", + 0x0100, + Plugin::Effect, + new PluginPixmapLoader( "logo" ), + NULL, + NULL +} ; + +} + + +EqEffect::EqEffect(Model *parent, const Plugin::Descriptor::SubPluginFeatures::Key *key) : + Effect( &eq_plugin_descriptor, parent, key ), + m_eqControls( this ), + m_upBufFrames( 0 ) +{ + m_dFilterCount = 4; + m_downsampleFilters = new EqLinkwitzRiley[m_dFilterCount]; + for( int i = 0; i < m_dFilterCount; i++) + { + m_downsampleFilters[i].setFrequency(21000); + m_downsampleFilters[i].setSR(Engine::mixer()->processingSampleRate() * 2 ); + } + m_upBuf = 0; +} + + + + +EqEffect::~EqEffect() +{ + if(m_upBuf) + { + delete m_upBuf; + } +} + + + + +bool EqEffect::processAudioBuffer(sampleFrame *buf, const fpp_t frames) +{ + if( !isEnabled() || !isRunning () ) + { + return( false ); + } + m_eqControls.m_inProgress = true; + double outSum = 0.0; + const float outGain = m_eqControls.m_outGainModel.value(); + const int sampleRate = Engine::mixer()->processingSampleRate() * 2; + sampleFrame m_inPeak = { 0, 0 }; + + if(m_eqControls.m_analyzeModel.value() ) + { + m_eqControls.m_inFftBands.analyze( buf, frames ); + } + else + { + m_eqControls.m_inFftBands.clear(); + } + upsample( buf, frames ); + gain(m_upBuf , m_upBufFrames, m_eqControls.m_inGainModel.value(), &m_inPeak ); + m_eqControls.m_inPeakL = m_eqControls.m_inPeakL < m_inPeak[0] ? m_inPeak[0] : m_eqControls.m_inPeakL; + m_eqControls.m_inPeakR = m_eqControls.m_inPeakR < m_inPeak[1] ? m_inPeak[0] : m_eqControls.m_inPeakR; + + if(m_eqControls.m_hpActiveModel.value() ){ + m_hp12.setSampleRate( sampleRate ); + m_hp12.setFrequency( m_eqControls.m_hpFeqModel.value() ); + m_hp12.setQ( m_eqControls.m_hpResModel.value() ); + m_hp12.processBuffer( m_upBuf , m_upBufFrames ); + + if( m_eqControls.m_hp24Model.value() || m_eqControls.m_hp48Model.value() ) + { + m_hp24.setSampleRate( sampleRate ); + m_hp24.setFrequency( m_eqControls.m_hpFeqModel.value() ); + m_hp24.setQ( m_eqControls.m_hpResModel.value() ); + m_hp24.processBuffer( m_upBuf , m_upBufFrames ); + } + + if( m_eqControls.m_hp48Model.value() ) + { + m_hp480.setSampleRate( sampleRate ); + m_hp480.setFrequency( m_eqControls.m_hpFeqModel.value() ); + m_hp480.setQ( m_eqControls.m_hpResModel.value() ); + m_hp480.processBuffer( m_upBuf , m_upBufFrames ); + + m_hp481.setSampleRate( sampleRate ); + m_hp481.setFrequency( m_eqControls.m_hpFeqModel.value() ); + m_hp481.setQ( m_eqControls.m_hpResModel.value() ); + m_hp481.processBuffer( m_upBuf , m_upBufFrames ); + } + } + + if( m_eqControls.m_lowShelfActiveModel.value() ) + { + m_lowShelf.setSampleRate( sampleRate ); + m_lowShelf.setFrequency( m_eqControls.m_lowShelfFreqModel.value() ); + m_lowShelf.setQ( m_eqControls.m_lowShelfResModel .value() ); + m_lowShelf.setGain( m_eqControls.m_lowShelfGainModel.value() ); + m_lowShelf.processBuffer( m_upBuf , m_upBufFrames ); + } + + if( m_eqControls.m_para1ActiveModel.value() ) + { + m_para1.setSampleRate(sampleRate ); + m_para1.setFrequency( m_eqControls.m_para1FreqModel.value() ); + m_para1.setQ( m_eqControls.m_para1ResModel.value() ); + m_para1.setGain( m_eqControls.m_para1GainModel.value() ); + m_para1.processBuffer( m_upBuf , m_upBufFrames ); + } + + if( m_eqControls.m_para2ActiveModel.value() ) + { + m_para2.setSampleRate( sampleRate ); + m_para2.setFrequency( m_eqControls.m_para2FreqModel.value() ); + m_para2.setQ( m_eqControls.m_para2ResModel.value() ); + m_para2.setGain( m_eqControls.m_para2GainModel.value() ); + m_para2.processBuffer( m_upBuf , m_upBufFrames ); + } + + if( m_eqControls.m_para3ActiveModel.value() ) + { + m_para3.setSampleRate( sampleRate); + m_para3.setFrequency( m_eqControls.m_para3FreqModel.value() ); + m_para3.setQ( m_eqControls.m_para3ResModel.value() ); + m_para3.setGain( m_eqControls.m_para3GainModel.value() ); + m_para3.processBuffer( m_upBuf , m_upBufFrames ); + } + + if( m_eqControls.m_para4ActiveModel.value() ) + { + m_para4.setSampleRate( sampleRate ); + m_para4.setFrequency( m_eqControls.m_para4FreqModel.value() ); + m_para4.setQ( m_eqControls.m_para4ResModel.value() ); + m_para4.setGain( m_eqControls.m_para4GainModel.value() ); + m_para4.processBuffer( m_upBuf , m_upBufFrames ); + } + + if( m_eqControls.m_highShelfActiveModel.value() ) + { + m_highShelf.setSampleRate( sampleRate ); + m_highShelf.setFrequency( m_eqControls.m_highShelfFreqModel.value() ); + m_highShelf.setQ( m_eqControls.m_highShelfResModel.value() ); + m_highShelf.setGain( m_eqControls.m_highShelfGainModel.value() ); + m_highShelf.processBuffer( m_upBuf , m_upBufFrames ); + } + + if(m_eqControls.m_lpActiveModel.value() ){ + m_lp12.setSampleRate( sampleRate ); + m_lp12.setFrequency( m_eqControls.m_lpFreqModel.value() ); + m_lp12.setQ( m_eqControls.m_lpResModel.value() ); + m_lp12.processBuffer( m_upBuf , m_upBufFrames ); + + if( m_eqControls.m_lp24Model.value() || m_eqControls.m_lp48Model.value() ) + { + m_lp24.setSampleRate( sampleRate ); + m_lp24.setFrequency( m_eqControls.m_lpFreqModel.value() ); + m_lp24.setQ( m_eqControls.m_lpResModel.value() ); + m_lp24.processBuffer( m_upBuf , m_upBufFrames ); + } + + if( m_eqControls.m_lp48Model.value() ) + { + m_lp480.setSampleRate( sampleRate ); + m_lp480.setFrequency( m_eqControls.m_lpFreqModel.value() ); + m_lp480.setQ( m_eqControls.m_lpResModel.value() ); + m_lp480.processBuffer( m_upBuf , m_upBufFrames ); + + m_lp481.setSampleRate( sampleRate ); + m_lp481.setFrequency( m_eqControls.m_lpFreqModel.value() ); + m_lp481.setQ( m_eqControls.m_lpResModel.value() ); + m_lp481.processBuffer( m_upBuf , m_upBufFrames ); + } + } + + sampleFrame outPeak = { 0, 0 }; + gain( m_upBuf , m_upBufFrames, outGain, &outPeak ); + m_eqControls.m_outPeakL = m_eqControls.m_outPeakL < outPeak[0] ? outPeak[0] : m_eqControls.m_outPeakL; + m_eqControls.m_outPeakR = m_eqControls.m_outPeakR < outPeak[1] ? outPeak[0] : m_eqControls.m_outPeakR; + for( int i =0; i < m_dFilterCount; i++) + { + m_downsampleFilters[i].processBuffer(m_upBuf , m_upBufFrames ); + } + downSample( buf, frames ); + for( fpp_t f = 0; f < frames; ++f ) + { + outSum += buf[f][0]*buf[f][0] + buf[f][1]*buf[f][1]; + } + checkGate( outSum / frames ); + if(m_eqControls.m_analyzeModel.value() ) + { + m_eqControls.m_outFftBands.analyze( buf, frames ); + } + else + { + m_eqControls.m_outFftBands.clear(); + } + setBandPeaks( &m_eqControls.m_outFftBands , ( int )( sampleRate * 0.5 ) ); + m_eqControls.m_inProgress = false; + return isRunning(); +} + + + + +void EqEffect::gain( sampleFrame *buf, const fpp_t frames, float scale, sampleFrame* peak ) +{ + peak[0][0] = 0.0f; peak[0][1] = 0.0f; + for( fpp_t f = 0; f < frames; ++f ) + { + buf[f][0] *= scale; + buf[f][1] *= scale; + + if( fabs( buf[f][0] ) > peak[0][0] ) + { + peak[0][0] = fabs( buf[f][0] ); + } + if( fabs( buf[f][1] ) > peak[0][1] ) + { + peak[0][1] = fabs( buf[f][0] ); + } + + } +} + + + + + +sampleFrame m_lastUpFrame; +void EqEffect::upsample( sampleFrame *buf, const fpp_t frames ) +{ + + if( m_upBufFrames != frames * 2 ) + { + if( m_upBuf ) + { + delete m_upBuf; + } + m_upBuf = new sampleFrame[frames * 2]; + m_upBufFrames = frames * 2; + } + for( int f = 0, f2 = 0; f < frames; ++f, f2 += 2 ) + { + m_upBuf[f2][0] = linearInterpolate( m_lastUpFrame[0],buf[f][0], 0.5 ); + m_upBuf[f2][1] = linearInterpolate( m_lastUpFrame[1],buf[f][1], 0.5 ); + m_upBuf[f2+1][0] = buf[f][0]; + m_upBuf[f2+1][1] = buf[f][1]; + m_lastUpFrame[0] = buf[f][0]; + m_lastUpFrame[1] = buf[f][1]; + } +} + + +void EqEffect::downSample( sampleFrame *buf, const fpp_t frames ) +{ + for( int f = 0, f2 = 0; f < frames; ++f, f2 += 2 ) + { + buf[f][0] = m_upBuf[f2+1][0]; + buf[f][1] = m_upBuf[f2+1][1]; + } +} + + + + +float EqEffect::peakBand( float minF, float maxF, EqAnalyser *fft, int sr ) +{ + float peak = -60; + float * b = fft->m_bands; + float h = 0; + for(int x = 0; x < MAX_BANDS; x++, b++) + { + if( bandToFreq( x ,sr) >= minF && bandToFreq( x,sr ) <= maxF ) + { + h = 20*( log10( *b / fft->m_energy ) ); + peak = h > peak ? h : peak; + } + } + return (peak+100)/100; +} + +void EqEffect::setBandPeaks(EqAnalyser *fft, int samplerate ) +{ + m_eqControls.m_lowShelfPeakR = m_eqControls.m_lowShelfPeakL = + peakBand( 0, + m_eqControls.m_lowShelfFreqModel.value(), fft , samplerate ); + + m_eqControls.m_para1PeakL = m_eqControls.m_para1PeakR = + peakBand( m_eqControls.m_para1FreqModel.value() + - (m_eqControls.m_para1FreqModel.value() / m_eqControls.m_para1ResModel.value() * 0.5), + m_eqControls.m_para1FreqModel.value() + + (m_eqControls.m_para1FreqModel.value() / m_eqControls.m_para1ResModel.value() * 0.5), + fft , samplerate ); + + m_eqControls.m_para2PeakL = m_eqControls.m_para2PeakR = + peakBand( m_eqControls.m_para2FreqModel.value() + - (m_eqControls.m_para2FreqModel.value() / m_eqControls.m_para2ResModel.value() * 0.5), + m_eqControls.m_para2FreqModel.value() + + (m_eqControls.m_para2FreqModel.value() / m_eqControls.m_para2ResModel.value() * 0.5), + fft , samplerate ); + + m_eqControls.m_para3PeakL = m_eqControls.m_para3PeakR = + peakBand( m_eqControls.m_para3FreqModel.value() + - (m_eqControls.m_para3FreqModel.value() / m_eqControls.m_para3ResModel.value() * 0.5), + m_eqControls.m_para3FreqModel.value() + + (m_eqControls.m_para3FreqModel.value() / m_eqControls.m_para3ResModel.value() * 0.5), + fft , samplerate ); + + m_eqControls.m_para4PeakL = m_eqControls.m_para4PeakR = + peakBand( m_eqControls.m_para4FreqModel.value() + - (m_eqControls.m_para4FreqModel.value() / m_eqControls.m_para4ResModel.value() * 0.5), + m_eqControls.m_para4FreqModel.value() + + (m_eqControls.m_para4FreqModel.value() / m_eqControls.m_para4ResModel.value() * 0.5), + fft , samplerate ); + + m_eqControls.m_highShelfPeakL = m_eqControls.m_highShelfPeakR = + peakBand( m_eqControls.m_highShelfFreqModel.value(), + samplerate * 0.5 , fft, samplerate ); +} + + + + + +extern "C" +{ + +//needed for getting plugin out of shared lib +Plugin * PLUGIN_EXPORT lmms_plugin_main( Model* parent, void* data ) +{ + return new EqEffect( parent , static_cast( data ) ); +} + +} diff --git a/plugins/Eq/EqEffect.h b/plugins/Eq/EqEffect.h new file mode 100644 index 000000000..9a4cd9411 --- /dev/null +++ b/plugins/Eq/EqEffect.h @@ -0,0 +1,89 @@ +/* eqeffect.h - defination of EqEffect class. +* +* Copyright (c) 2014 David French +* +* This file is part of LMMS - http://lmms.io +* +* 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 (see COPYING); if not, write to the +* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +* Boston, MA 02110-1301 USA. +* +*/ + + +#ifndef EQEFFECT_H +#define EQEFFECT_H + +#include "Effect.h" +#include "EqControls.h" +#include "lmms_math.h" +#include "BasicFilters.h" +#include "EqFilter.h" + + + +class EqEffect : public Effect +{ +public: + EqEffect( Model* parent , const Descriptor::SubPluginFeatures::Key* key ); + virtual ~EqEffect(); + virtual bool processAudioBuffer( sampleFrame *buf, const fpp_t frames ); + virtual EffectControls* controls() + { + return &m_eqControls; + } + void gain( sampleFrame *buf, const fpp_t frames, float scale, sampleFrame* peak ); + +private: + EqControls m_eqControls; + + EqHp12Filter m_hp12; + EqHp12Filter m_hp24; + EqHp12Filter m_hp480; + EqHp12Filter m_hp481; + + EqLowShelfFilter m_lowShelf; + + EqPeakFilter m_para1; + EqPeakFilter m_para2; + EqPeakFilter m_para3; + EqPeakFilter m_para4; + + EqHighShelfFilter m_highShelf; + + EqLp12Filter m_lp12; + EqLp12Filter m_lp24; + EqLp12Filter m_lp480; + EqLp12Filter m_lp481; + EqLinkwitzRiley* m_downsampleFilters; + int m_dFilterCount; + sampleFrame* m_upBuf; + fpp_t m_upBufFrames; + + void upsample( sampleFrame *buf, const fpp_t frames ); + void downSample( sampleFrame *buf, const fpp_t frames ); + void analyze( sampleFrame *buf, const fpp_t frames, EqAnalyser* fft ); + float peakBand(float minF, float maxF,EqAnalyser*, int); + + inline float bandToFreq ( int index , int sampleRate ) + { + return index * sampleRate / (MAX_BANDS * 2); + } + + void setBandPeaks( EqAnalyser *fft , int); + + +}; + +#endif // EQEFFECT_H diff --git a/plugins/Eq/EqFader.h b/plugins/Eq/EqFader.h new file mode 100644 index 000000000..9ef7f80c3 --- /dev/null +++ b/plugins/Eq/EqFader.h @@ -0,0 +1,101 @@ +/* eqfader.h - defination of EqFader class. +* +* Copyright (c) 2014 David French +* +* This file is part of LMMS - http://lmms.io +* +* 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 (see COPYING); if not, write to the +* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +* Boston, MA 02110-1301 USA. +* +*/ + +#ifndef EQFADER_H +#define EQFADER_H +#include "Fader.h" +#include "EffectControls.h" +#include "MainWindow.h" +#include "qwidget.h" +#include "TextFloat.h" +#include "qlist.h" + + + +class EqFader : public Fader +{ + +public: + Q_OBJECT +public: + EqFader( FloatModel * model, const QString & name, QWidget * parent, float* lPeak, float* rPeak ) : + Fader( model, name, parent) + { + setMinimumSize( 23, 116 ); + setMaximumSize( 23, 116 ); + resize( 23, 116 ); + m_lPeak = lPeak; + m_rPeak = rPeak; + connect( Engine::mainWindow(), SIGNAL( periodicUpdate() ), this, SLOT( updateVuMeters() ) ); + m_model = model; + setPeak_L( 0 ); + setPeak_R( 0 ); + } + + + + + ~EqFader() + { + } + + +private slots: + + void updateVuMeters() + { + const float opl = getPeak_L(); + const float opr = getPeak_R(); + const float fall_off = 1.2; + if( *m_lPeak > opl ) + { + setPeak_L( *m_lPeak ); + *m_lPeak = 0; + } + else + { + setPeak_L( opl/fall_off ); + } + + if( *m_rPeak > opr ) + { + setPeak_R( *m_rPeak ); + *m_rPeak = 0; + } + else + { + setPeak_R( opr/fall_off ); + } + update(); + } + + + + +private: + float* m_lPeak; + float* m_rPeak; + FloatModel* m_model; + +}; +#endif // EQFADER_H diff --git a/plugins/Eq/EqFilter.h b/plugins/Eq/EqFilter.h new file mode 100644 index 000000000..b703edc95 --- /dev/null +++ b/plugins/Eq/EqFilter.h @@ -0,0 +1,388 @@ +/* + * eqfilter.cpp - defination of EqFilterclass. + * + * Copyright (c) 2014 David French + * + * This file is part of LMMS - http://lmms.io + * + * 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 (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#ifndef EQFILTER_H +#define EQFILTER_H + +#include "BasicFilters.h" +#include "lmms_math.h" + +/// +/// \brief The EqFilter class. +/// A wrapper for the StereoBiQuad class, giving it freq, res, and gain controls. +/// It is designed to process periods in one pass, with recalculation of coefficents +/// upon parameter changes. The intention is to use this as a bass class, children override +/// the calcCoefficents() function, providing the coefficents a1, a2, b0, b1, b2. +/// +class EqFilter : public StereoBiQuad +{ +public: + EqFilter() + { + + } + + + + + virtual inline void setSampleRate( int sampleRate ) + { + if( sampleRate != m_sampleRate ) + { + m_sampleRate = sampleRate; + calcCoefficents(); + } + } + + + + + virtual inline void setFrequency( float freq ){ + if ( freq != m_freq ) + { + m_freq = freq; + calcCoefficents(); + } + } + + + + + virtual void setQ( float res ) + { + if ( res != m_res ) + { + m_res = res; + calcCoefficents(); + } + } + + + + + virtual void setGain( float gain ) + { + if ( gain != m_gain ) + { + m_gain = gain; + calcCoefficents(); + } + } + + + + + /// + /// \brief processBuffer + /// \param buf Audio Buffer + /// \param frames Count of sampleFrames in Audio Buffer + /// + virtual void processBuffer( sampleFrame* buf, const fpp_t frames ) + { + for ( fpp_t f = 0 ; f < frames ; ++f) + { + buf[f][0] = update( buf[f][0] , 0); + buf[f][1] = update( buf[f][1] , 1); + } + } + +protected: + /// + /// \brief calcCoefficents + /// Override this in child classes to provide the coefficents, based on + /// Freq, Res and Gain + virtual void calcCoefficents(){ + setCoeffs( 0, 0, 0, 0, 0 ); + + } + + float m_sampleRate; + float m_freq; + float m_res; + float m_gain; +}; + + + + +/// +/// \brief The EqHp12Filter class +/// A 2 pole High Pass Filter +/// Coefficent calculations from http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt +class EqHp12Filter : public EqFilter +{ +public : + virtual void calcCoefficents() + { + + // calc intermediate + float w0 = F_2PI * m_freq / m_sampleRate; + float c = cosf( w0 ); + float s = sinf( w0 ); + float alpha = s / ( 2 * m_res ); + + float a0, a1, a2, b0, b1, b2; // coeffs to calculate + + //calc coefficents + b0 = ( 1 + c ) * 0.5; + b1 = ( -( 1 + c ) ); + b2 = ( 1 + c ) * 0.5; + a0 = 1 + alpha; + a1 = ( -2 * c ); + a2 = 1 - alpha; + + //normalise + b0 /= a0; + b1 /= a0; + b2 /= a0; + a1 /= a0; + a2 /= a0; + + a0 = 1; + + setCoeffs( a1, a2, b0, b1, b2 ); + + + } +}; + + + + +/// +/// \brief The EqLp12Filter class. +/// A 2 pole low pass filter +/// Coefficent calculations from http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt +/// +class EqLp12Filter : public EqFilter +{ +public : + virtual void calcCoefficents() + { + + // calc intermediate + float w0 = F_2PI * m_freq / m_sampleRate; + float c = cosf( w0 ); + float s = sinf( w0 ); + float alpha = s / ( 2 * m_res ); + + float a0, a1, a2, b0, b1, b2; // coeffs to calculate + + //calc coefficents + b0 = ( 1 - c ) * 0.5; + b1 = 1 - c; + b2 = ( 1 - c ) * 0.5; + a0 = 1 + alpha; + a1 = -2 * c; + a2 = 1 - alpha; + + //normalise + b0 /= a0; + b1 /= a0; + b2 /= a0; + a1 /= a0; + a2 /= a0; + + a0 = 1; + + setCoeffs( a1, a2, b0, b1, b2 ); + } +}; + + + +/// +/// \brief The EqPeakFilter class +/// A Peak Filter +/// Coefficent calculations from http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt +/// +class EqPeakFilter : public EqFilter +{ +public: + + + virtual void calcCoefficents() + { + // calc intermediate + float w0 = F_2PI * m_freq / m_sampleRate; + float c = cosf( w0 ); + float s = sinf( w0 ); + float A = pow( 10, m_gain * 0.025); + float alpha = s / ( 2 * m_res ); + + float a0, a1, a2, b0, b1, b2; // coeffs to calculate + + //calc coefficents + b0 = 1 + alpha*A; + b1 = -2*c; + b2 = 1 - alpha*A; + a0 = 1 + alpha/A; + a1 = -2*c; + a2 = 1 - alpha/A; + + //normalise + b0 /= a0; + b1 /= a0; + b2 /= a0; + a1 /= a0; + a2 /= a0; + a0 = 1; + + setCoeffs( a1, a2, b0, b1, b2 ); + } +}; + + + + +class EqLowShelfFilter : public EqFilter +{ +public : + virtual void calcCoefficents() + { + + // calc intermediate + float w0 = F_2PI * m_freq / m_sampleRate; + float c = cosf( w0 ); + float s = sinf( w0 ); + float A = pow( 10, m_gain * 0.025); + // float alpha = s / ( 2 * m_res ); + float beta = sqrt( A ) / m_res; + + float a0, a1, a2, b0, b1, b2; // coeffs to calculate + + //calc coefficents + b0 = A * ( ( A+1 ) - ( A-1 ) * c + beta * s ); + b1 = 2 * A * ( ( A - 1 ) - ( A + 1 ) * c) ; + b2 = A * ( ( A + 1 ) - ( A - 1 ) * c - beta * s); + a0 = ( A + 1 ) + ( A - 1 ) * c + beta * s; + a1 = -2 * ( ( A - 1 ) + ( A + 1 ) * c ); + a2 = ( A + 1 ) + ( A - 1) * c - beta * s; + + //normalise + b0 /= a0; + b1 /= a0; + b2 /= a0; + a1 /= a0; + a2 /= a0; + + a0 = 1; + + setCoeffs( a1, a2, b0, b1, b2 ); + + + } +}; + +class EqHighShelfFilter : public EqFilter +{ +public : + virtual void calcCoefficents() + { + + // calc intermediate + float w0 = F_2PI * m_freq / m_sampleRate; + float c = cosf( w0 ); + float s = sinf( w0 ); + float A = pow( 10, m_gain * 0.025 ); + float beta = sqrt( A ) / m_res; + + float a0, a1, a2, b0, b1, b2; // coeffs to calculate + + //calc coefficents + b0 = A *( ( A +1 ) + ( A - 1 ) * c + beta * s); + b1 = -2 * A * ( ( A - 1 ) + ( A + 1 ) * c ); + b2 = A * ( ( A + 1 ) + ( A - 1 ) * c - beta * s); + a0 = ( A + 1 ) - ( A - 1 ) * c + beta * s; + a1 = 2 * ( ( A - 1 ) - ( A + 1 ) * c ); + a2 = ( A + 1) - ( A - 1 ) * c - beta * s; + //normalise + b0 /= a0; + b1 /= a0; + b2 /= a0; + a1 /= a0; + a2 /= a0; + a0 = 1; + + setCoeffs( a1, a2, b0, b1, b2 ); + } +}; + + + + +class EqLinkwitzRiley : public StereoLinkwitzRiley +{ +public: + EqLinkwitzRiley() : + StereoLinkwitzRiley( 44100), + m_freq(0 ), + m_sr( 1 ) + { + } + + virtual inline void setSR( int sampleRate ) + { + if( sampleRate != m_sr ) + { + m_sr = sampleRate; + setLowpass(m_freq); + setSampleRate( sampleRate ); + } + } + + + + + virtual inline void setFrequency( float freq ){ + if ( freq != m_freq ) + { + m_freq = freq; + setLowpass(m_freq); + } + } + + + + + virtual void processBuffer( sampleFrame* buf, const fpp_t frames ) + { + for ( fpp_t f = 0 ; f < frames ; ++f) + { + buf[f][0] = update( buf[f][0] , 0); + buf[f][1] = update( buf[f][1] , 1); + } + } +protected: + + float m_freq; + int m_sr; + + +}; + + + + +#endif // EQFILTER_H diff --git a/plugins/Eq/EqParameterWidget.cpp b/plugins/Eq/EqParameterWidget.cpp new file mode 100644 index 000000000..31c74a7f0 --- /dev/null +++ b/plugins/Eq/EqParameterWidget.cpp @@ -0,0 +1,221 @@ +/* + * eqparameterwidget.cpp - defination of EqParameterWidget class. + * + * Copyright (c) 2014 David French + * + * This file is part of LMMS - http://lmms.io + * + * 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 (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#include "EqParameterWidget.h" +#include "QPainter" +#include "qwidget.h" +#include "lmms_math.h" +#include "MainWindow.h" +#include "QMouseEvent" + +EqParameterWidget::EqParameterWidget( QWidget *parent ) : + QWidget( parent ), + m_bands ( 0 ), + m_selectedBand ( 0 ) +{ + m_bands = new EqBand[8]; + resize( 250, 116 ); + // connect( Engine::mainWindow(), SIGNAL( periodicUpdate() ), this, SLOT( update() ) ); + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(update())); + timer->start(100); + float totalLength = log10( 21000 ); + m_pixelsPerUnitWidth = width( ) / totalLength ; + float totalHeight = 80; + m_pixelsPerUnitHeight = (height() - 4) / ( totalHeight ); + m_scale = 1.5; + m_pixelsPerOctave = freqToXPixel( 10000 ) - freqToXPixel( 5000 ); + +} + + + + +EqParameterWidget::~EqParameterWidget() +{ + if(m_bands) + { + delete[] m_bands; + m_bands = 0; + } +} + + + + +void EqParameterWidget::paintEvent( QPaintEvent *event ) +{ + QPainter painter( this ); + //Draw Frequecy maker lines + painter.setPen( QPen( QColor( 100, 100, 100, 200 ), 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin ) ); + for( int x = 20 ; x < 100; x += 10) + { + painter.drawLine( freqToXPixel( x ) , 0, freqToXPixel( x ) , height() ); + } + for( int x = 100 ; x < 1000; x += 100) + { + painter.drawLine( freqToXPixel( x ) , 0, freqToXPixel( x ) , height() ); + } + for( int x = 1000 ; x < 11000; x += 1000) + { + painter.drawLine( freqToXPixel( x ) , 0, freqToXPixel( x ) , height() ); + } + //draw 0dB line + painter.drawLine(0, gainToYPixel( 0 ) , width(), gainToYPixel( 0 ) ); + + for( int i = 0 ; i < bandCount() ; i++ ) + { + m_bands[i].color.setAlpha( m_bands[i].active->value() ? activeAplha() : inactiveAlpha() ); + painter.setPen( QPen( m_bands[i].color, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin ) ); + float x = freqToXPixel( m_bands[i].freq->value() ); + float y = height() * 0.5; + float gain = 1; + if( m_bands[i].gain ) + { + gain = m_bands[i].gain->value(); + } + y = gainToYPixel( gain ); + float bw = m_bands[i].freq->value() / m_bands[i].res->value(); + m_bands[i].x = x; m_bands[i].y = y; + const int radius = 7; + painter.drawEllipse( x - radius , y - radius, radius * 2 ,radius * 2 ); + QString msg = QString ( "%1" ).arg ( QString::number (i + 1) ); + painter.drawText(x - ( radius * 0.5 ), y + ( radius * 0.85 ), msg ); + painter.setPen( QPen( m_bands[i].color, 1, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin ) ); + if( i == 0 || i == bandCount() - 1 ) + { + painter.drawLine(x , y, x, y - (m_bands[i].res->value() * 4 ) ); + } + else + { + painter.drawLine(freqToXPixel(m_bands[i].freq->value()-(bw * 0.5)),y,freqToXPixel(m_bands[i].freq->value()+(bw * 0.5)),y); + } + } +} + + + + +void EqParameterWidget::mousePressEvent( QMouseEvent *event ) +{ + m_oldX = event->x(); m_oldY = event->y(); + m_selectedBand = selectNearestHandle( event->x(), event->y() ); + m_mouseAction = none; + if ( event->button() == Qt::LeftButton ) m_mouseAction = drag; + if ( event->button() == Qt::RightButton ) m_mouseAction = res; +} + + + + +void EqParameterWidget::mouseReleaseEvent( QMouseEvent *event ) +{ + m_selectedBand = 0; + m_mouseAction = none; +} + + + + +void EqParameterWidget::mouseMoveEvent( QMouseEvent *event ) +{ + int deltaX = event->x() - m_oldX; + int deltaR = event->y() - m_oldY; + m_oldX = event->x(); m_oldY = event->y(); + if(m_selectedBand && m_selectedBand->active->value() ) + { + switch ( m_mouseAction ) { + case none : + break; + case drag: + if( m_selectedBand->freq ) m_selectedBand->freq->setValue( xPixelToFreq( m_oldX ) ); + if( m_selectedBand->gain )m_selectedBand->gain->setValue( yPixelToGain( m_oldY ) ); + break; + case res: + if( m_selectedBand->res )m_selectedBand->res->incValue( deltaX * resPixelMultiplyer() ); + if( m_selectedBand->res )m_selectedBand->res->incValue( (-deltaR) * resPixelMultiplyer() ); + break; + default: + break; + } + } +} + + + + +void EqParameterWidget::mouseDoubleClickEvent( QMouseEvent *event ) +{ + EqBand* selected = selectNearestHandle( event->x() , event->y() ); + if( selected ) + { + selected->active->setValue( selected->active->value() ? 0 : 1 ); + } +} + + + + +EqBand* EqParameterWidget::selectNearestHandle( const int x, const int y ) +{ + EqBand* selectedModel = 0; + float* distanceToHandles = new float[bandCount()]; + //calc distance to each handle + for( int i = 0 ; i < bandCount() ; i++ ) + { + int xOffset = m_bands[i].x - x; + int yOffset = m_bands[i].y - y; + distanceToHandles[i] = fabs( sqrt( ( xOffset * xOffset ) + ( yOffset * yOffset ) ) ); + } + //select band + int shortestBand = 0; + for ( int i = 1 ; i < bandCount() ; i++ ) + { + if ( distanceToHandles [i] < distanceToHandles[shortestBand] ){ + shortestBand = i; + } + } + if(distanceToHandles[shortestBand] < maxDistanceFromHandle() ) + { + selectedModel = &m_bands[shortestBand]; + } + delete distanceToHandles; + return selectedModel; +} + + + + +EqBand::EqBand() : + gain ( 0 ), + res ( 0 ), + freq ( 0 ), + color ( QColor( 255, 255, 255 ) ), + x( 0 ), + y( 0 ), + name ( QString( "" ) ), + peakL( 0 ), + peakR( 0 ) +{ +} diff --git a/plugins/Eq/EqParameterWidget.h b/plugins/Eq/EqParameterWidget.h new file mode 100644 index 000000000..6cc7f1a89 --- /dev/null +++ b/plugins/Eq/EqParameterWidget.h @@ -0,0 +1,161 @@ +/* + * eqparameterwidget.cpp - defination of EqParameterWidget class. + * + * Copyright (c) 2014 David French + * + * This file is part of LMMS - http://lmms.io + * + * 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 (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#ifndef EQPARAMETERWIDGET_H +#define EQPARAMETERWIDGET_H +#include +#include "EffectControls.h" + + +class EqBand +{ +public : + EqBand(); + FloatModel* gain; + FloatModel* res; + FloatModel* freq; + BoolModel* active; + QColor color; + int x; + int y; + QString name; + float* peakL; + float* peakR; + + +}; + + + +class EqParameterWidget : public QWidget +{ + +public: + explicit EqParameterWidget( QWidget *parent = 0 ); + ~EqParameterWidget(); + const int bandCount() + { + return 8; + } + + + + const int maxDistanceFromHandle() + { + return 20; + } + + + + + EqBand* getBandModels( int i ) + { + return &m_bands[i]; + } + + + + + const int activeAplha() + { + return 200; + } + + + + + const int inactiveAlpha() + { + return 100; + } + + + + + const float resPixelMultiplyer() + { + return 100; + } + + +signals: + +public slots: + +protected: + virtual void paintEvent ( QPaintEvent * event ); + virtual void mousePressEvent(QMouseEvent * event ); + virtual void mouseReleaseEvent(QMouseEvent * event); + virtual void mouseMoveEvent(QMouseEvent * event); + virtual void mouseDoubleClickEvent(QMouseEvent * event); + +private: + EqBand *m_bands; + float m_pixelsPerUnitWidth; + float m_pixelsPerUnitHeight; + float m_pixelsPerOctave; + float m_scale; + EqBand* m_selectedBand; + + EqBand* selectNearestHandle( const int x, const int y ); + + enum MouseAction { none, drag, res } m_mouseAction; + int m_oldX, m_oldY; + int *m_xGridBands; + + + inline int freqToXPixel( float freq ) + { + return ( log10( freq ) * m_pixelsPerUnitWidth * m_scale ) - ( width() * 0.5 ); + } + + + + + inline float xPixelToFreq( int x ) + { + return pow( 10, ( x + ( width() * 0.5 ) ) / ( m_pixelsPerUnitWidth * m_scale ) ); + } + + + + + inline int gainToYPixel( float gain ) + { + return ( height() - 3) - ( gain * m_pixelsPerUnitHeight ) - ( (height() -3 ) * 0.5); + } + + + + + inline float yPixelToGain( int y ) + { + return ( ( 0.5 * height() ) - y) / m_pixelsPerUnitHeight; + } + +}; + + +#endif // EQPARAMETERWIDGET_H diff --git a/plugins/Eq/EqSpectrumView.h b/plugins/Eq/EqSpectrumView.h new file mode 100644 index 000000000..71c64f5a4 --- /dev/null +++ b/plugins/Eq/EqSpectrumView.h @@ -0,0 +1,218 @@ +/* eqspectrumview.h - defination of EqSpectrumView class. +* +* Copyright (c) 2014 David French +* +* This file is part of LMMS - http://lmms.io +* +* 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 (see COPYING); if not, write to the +* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +* Boston, MA 02110-1301 USA. +* +*/ +#ifndef EQSPECTRUMVIEW_H +#define EQSPECTRUMVIEW_H + +#include "qpainter.h" +//#include "eqeffect.h" +#include "qwidget.h" +#include "fft_helpers.h" +#include "Engine.h" + + +const int MAX_BANDS = 2048; + +class EqAnalyser +{ +public: + + fftwf_plan m_fftPlan; + fftwf_complex * m_specBuf; + float m_absSpecBuf[FFT_BUFFER_SIZE+1]; + float m_buffer[FFT_BUFFER_SIZE*2]; + int m_framesFilledUp; + float m_bands[MAX_BANDS]; + float m_energy; + int m_sr; + + + EqAnalyser() : + m_framesFilledUp ( 0 ), + m_energy ( 0 ), + m_sr ( 1 ) + { + m_inProgress=false; + m_specBuf = (fftwf_complex *) fftwf_malloc( ( FFT_BUFFER_SIZE + 1 ) * sizeof( fftwf_complex ) ); + m_fftPlan = fftwf_plan_dft_r2c_1d( FFT_BUFFER_SIZE*2, m_buffer, m_specBuf, FFTW_MEASURE ); + clear(); + } + + virtual ~EqAnalyser() + { + fftwf_destroy_plan( m_fftPlan ); + fftwf_free( m_specBuf ); + } + + + bool getInProgress() + { + return m_inProgress; + } + + + + void clear() + { + m_framesFilledUp = 0; + m_energy = 0; + memset( m_buffer, 0, sizeof( m_buffer ) ); + memset( m_bands, 0, sizeof( m_bands ) ); + } + + + + void analyze( sampleFrame *buf, const fpp_t frames ) + { + m_inProgress=true; + const int FFT_BUFFER_SIZE = 2048; + fpp_t f = 0; + if( frames > FFT_BUFFER_SIZE ) + { + m_framesFilledUp = 0; + f = frames - FFT_BUFFER_SIZE; + } + // meger channels + for( ; f < frames; ++f ) + { + m_buffer[m_framesFilledUp] = + ( buf[f][0] + buf[f][1] ) * 0.5; + ++m_framesFilledUp; + } + + if( m_framesFilledUp < FFT_BUFFER_SIZE ) + { + m_inProgress = false; + return; + } + + m_sr = Engine::mixer()->processingSampleRate(); + const int LOWEST_FREQ = 0; + const int HIGHEST_FREQ = m_sr / 2; + + fftwf_execute( m_fftPlan ); + absspec( m_specBuf, m_absSpecBuf, FFT_BUFFER_SIZE+1 ); + + compressbands( m_absSpecBuf, m_bands, FFT_BUFFER_SIZE+1, + MAX_BANDS, + ( int )( LOWEST_FREQ * ( FFT_BUFFER_SIZE + 1 ) / ( float )( m_sr / 2 ) ), + ( int )( HIGHEST_FREQ * ( FFT_BUFFER_SIZE + 1) / ( float )( m_sr / 2 ) ) ); + m_energy = maximum( m_bands, MAX_BANDS ) / maximum( m_buffer, FFT_BUFFER_SIZE ); + m_framesFilledUp = 0; + m_inProgress = false; + } +private: + bool m_inProgress; +}; + + +class EqSpectrumView : public QWidget +{ + +public: + explicit EqSpectrumView( EqAnalyser * b, QWidget * _parent = 0 ): + QWidget( _parent ), + m_sa( b ) + { + setFixedSize( 250, 116 ); + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(update())); + timer->start(2000); + setAttribute( Qt::WA_TranslucentBackground, true ); + m_skipBands = MAX_BANDS * 0.5; + float totalLength = log10( 21000); + m_pixelsPerUnitWidth = width( ) / totalLength ; + m_scale = 1.5; + color = QColor( 255, 255, 255, 255 ); + } + + + + + virtual ~EqSpectrumView() + { + } + + + + + QColor color; + EqAnalyser *m_sa; + QPainterPath pp; + virtual void paintEvent( QPaintEvent* event ) + { + const int fh = height(); + const int LOWER_Y = -60; // dB + QPainter p( this ); + p.setPen( QPen( color, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin ) ); + const float e = m_sa->m_energy; + if( e <= 0 ) + { + //dont draw anything + return; + } + if(m_sa->getInProgress() ){ + p.fillPath( pp ,QBrush( color ) ); + return; + } + pp = QPainterPath(); + float * b = m_sa->m_bands; + int h; + pp.moveTo( 0,height() ); + for( int x = 0; x < MAX_BANDS; ++x, ++b ) + { + h = (int)( fh * 2.0 / 3.0 * ( 20 * ( log10 ( *b / e ) ) - LOWER_Y ) / (-LOWER_Y ) ); + if( h < 0 ) h = 0; else if( h >= fh ) continue; + pp.lineTo( freqToXPixel(bandToFreq( x ) ), fh-h ); + } + pp.lineTo( width(), height() ); + pp.closeSubpath(); + p.fillPath( pp, QBrush( color ) ); + p.drawPath( pp ); + } + + + + + inline int bandToXPixel( float band ) + { + return ( log10( band - m_skipBands ) * m_pixelsPerUnitWidth * m_scale ); + } + + inline float bandToFreq ( int index ) + { + return index * m_sa->m_sr / (MAX_BANDS * 2 ); + } + + + inline int freqToXPixel( float freq ) + { + return ( log10( freq ) * m_pixelsPerUnitWidth * m_scale ) - ( width() * 0.5 ); + } +private: + float m_pixelsPerUnitWidth; + float m_scale; + int m_skipBands; +} ; + + +#endif // EQSPECTRUMVIEW_H diff --git a/plugins/Eq/artwork.png b/plugins/Eq/artwork.png new file mode 100644 index 000000000..33fa4960d Binary files /dev/null and b/plugins/Eq/artwork.png differ diff --git a/plugins/Eq/logo.png b/plugins/Eq/logo.png new file mode 100644 index 000000000..89e9f3680 Binary files /dev/null and b/plugins/Eq/logo.png differ