spectrum analysis implemented

This commit is contained in:
dave
2014-12-11 00:08:42 +00:00
parent 1595c2728e
commit 9c9e9db164
11 changed files with 237 additions and 64 deletions

View File

@@ -82,6 +82,12 @@ public:
{
m_displayConversion = b;
}
inline void setHintText( const QString & _txt_before,
const QString & _txt_after )
{
setDescription( _txt_before );
setUnit( _txt_after );
}
private:
virtual void contextMenuEvent( QContextMenuEvent * _me );

View File

@@ -1,3 +1,5 @@
INCLUDE(BuildPlugin)
BUILD_PLUGIN(eq eqeffect.cpp eqcontrols.cpp eqcontrolsdialog.cpp eqfilter.h eqparameterwidget.cpp eqfader.h MOCFILES eqcontrols.h eqparameterwidget.h eqfader.h EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png")
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")

View File

@@ -35,12 +35,12 @@ EqControls::EqControls( EqEffect *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 , -20, 20, 0.001, this, tr( "Low shelf gain" ) ),
m_para1GainModel( 0.0 , -20, 20, 0.001, this, tr( "Peak 1 gain" ) ),
m_para2GainModel( 0.0 , -20, 20, 0.001, this, tr( "Peak 2 gain" ) ),
m_para3GainModel( 0.0 , -20, 20, 0.001, this, tr( "Peak 3 gain" ) ),
m_para4GainModel( 0.0 , -20, 20, 0.001, this, tr( "Peak 4 gain" ) ),
m_highShelfGainModel( 0.0 , -20, 20, 0.001, this, tr( "High Shelf 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" ) ),

View File

@@ -33,9 +33,9 @@ class EqEffect;
class EqControls : public EffectControls
{
Q_OBJECT
Q_OBJECT
public:
EqControls( EqEffect* effect );
explicit EqControls( EqEffect* effect );
virtual ~EqControls()
{
}
@@ -51,7 +51,6 @@ public:
}
virtual EffectControlDialog* createView()
{
printf("create dialog\n");
return new EqControlsDialog( this );
}
@@ -66,6 +65,9 @@ public:
float m_para4PeakL, m_para4PeakR;
float m_highShelfPeakL, m_highShelfPeakR;
FftBands m_inFftBands;
FftBands m_outFftBands;

View File

@@ -33,6 +33,7 @@
#include "QWidget"
#include "MainWindow.h"
#include "LedCheckbox.h"
//#include "eqspectrumview.h"
@@ -48,9 +49,14 @@ EqControlsDialog::EqControlsDialog(EqControls *controls) :
setPalette( pal );
setFixedSize( 350, 275 );
m_inSpec = new EqSpectrumView( &controls->m_inFftBands, this);
m_inSpec->move( 50, 5 );
m_inSpec->color = QColor( 200, 200, 100, 100 );
m_outSpec = new EqSpectrumView( &controls->m_outFftBands, this);
m_outSpec->move( 50, 5 );
m_outSpec->color = QColor(100, 200, 200, 100);
m_parameterWidget = new EqParameterWidget( this );
m_parameterWidget->move( 50, 5 );
// m_inSpec = new EqSpectrumView( controls->m_effect, this);
setBand( 0, &controls->m_hpActiveModel, &controls->m_hpFeqModel, &controls->m_hpResModel, 0, QColor(173, 115, 57), tr( "HP" ) ,0,0);
setBand( 1, &controls->m_lowShelfActiveModel, &controls->m_lowShelfFreqModel, &controls->m_lowShelfResModel, &controls->m_lowShelfGainModel, QColor(255, 0, 0), tr( "Low Shelf" ), &controls->m_lowShelfPeakL , &controls->m_lowShelfPeakR );
@@ -66,6 +72,7 @@ EqControlsDialog::EqControlsDialog(EqControls *controls) :
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
@@ -78,6 +85,8 @@ EqControlsDialog::EqControlsDialog(EqControls *controls) :
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++)
@@ -86,11 +95,13 @@ EqControlsDialog::EqControlsDialog(EqControls *controls) :
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 );
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 );
m_activeBox->move( cw * i + fo + 3, 260 );

View File

@@ -32,7 +32,7 @@
#include "eqparameterwidget.h"
#include "MainWindow.h"
#include "qpushbutton.h"
//#include "eqspectrumview.h"
#include "eqspectrumview.h"
class EqControls;
@@ -69,7 +69,8 @@ private:
LedCheckBox* m_analyzeBox;
EqParameterWidget* m_parameterWidget;
// EqSpectrumView* m_inSpec;
EqSpectrumView* m_inSpec;
EqSpectrumView* m_outSpec;
virtual void mouseDoubleClickEvent(QMouseEvent *event);

View File

@@ -34,7 +34,7 @@
//re write to store data from each filter(models,name, storeage name ) in a class, stored in array
//then just loop ever array for each section
const int MAX_BANDS = 249;
extern "C"
{
@@ -58,16 +58,13 @@ Plugin::Descriptor PLUGIN_EXPORT eq_plugin_descriptor =
EqEffect::EqEffect(Model *parent, const Plugin::Descriptor::SubPluginFeatures::Key *key) :
Effect( &eq_plugin_descriptor, parent, key ),
m_eqControls( this )
{
m_dFilterCount = 4;
m_dFilterCount = 10;
m_downsampleFilters = new EqLp12Filter[m_dFilterCount];
for( int i = 0; i < m_dFilterCount; i++)
{
m_downsampleFilters[i].setFrequency(20000);
m_downsampleFilters[i].setQ(0.66);
m_downsampleFilters[i].setFrequency(22000);
m_downsampleFilters[i].setQ(0.85);
m_downsampleFilters[i].setGain(0);
m_downsampleFilters[i].setSampleRate(Engine::mixer()->processingSampleRate() * 2 );
}
@@ -99,6 +96,7 @@ bool EqEffect::processAudioBuffer(sampleFrame *buf, const fpp_t frames)
sample_t dryS[2];
sampleFrame m_inPeak;
analyze( buf, frames, &m_eqControls.m_inFftBands) ;
//TODO UPSAMPLE
upsample( buf, frames );
@@ -236,6 +234,8 @@ bool EqEffect::processAudioBuffer(sampleFrame *buf, const fpp_t frames)
outSum += buf[f][0]*buf[f][0] + buf[f][1]*buf[f][1];
}
checkGate( outSum / frames );
analyze( buf, frames, &m_eqControls.m_outFftBands) ;
setBandPeaks( &m_eqControls.m_outFftBands , (int)(sampleRate * 0.5));
return isRunning();
}
@@ -298,6 +298,94 @@ void EqEffect::downSample(sampleFrame *buf, const fpp_t frames)
}
}
void EqEffect::analyze(sampleFrame *buf, const fpp_t frames, FftBands* fft)
{
const int FFT_BUFFER_SIZE = 2048;
fpp_t f = 0;
if( frames > FFT_BUFFER_SIZE )
{
fft->m_framesFilledUp = 0;
f = frames - FFT_BUFFER_SIZE;
}
// meger channels
for( ; f < frames; ++f )
{
fft->m_buffer[fft->m_framesFilledUp] =
( buf[f][0] + buf[f][1] ) * 0.5;
++fft->m_framesFilledUp;
}
if( fft->m_framesFilledUp < FFT_BUFFER_SIZE )
{
return;
}
fft->m_sr = Engine::mixer()->processingSampleRate();
const int LOWEST_FREQ = 0;
const int HIGHEST_FREQ = fft->m_sr / 2;
fftwf_execute( fft->m_fftPlan );
absspec( fft->m_specBuf, fft->m_absSpecBuf, FFT_BUFFER_SIZE+1 );
compressbands( fft->m_absSpecBuf, fft->m_bands, FFT_BUFFER_SIZE+1,
MAX_BANDS,
(int)(LOWEST_FREQ*(FFT_BUFFER_SIZE+1)/(float)(fft->m_sr /2)),
(int)(HIGHEST_FREQ*(FFT_BUFFER_SIZE+1)/(float)(fft->m_sr /2)));
fft->m_energy = maximum( fft->m_bands, MAX_BANDS ) / maximum( fft->m_buffer, FFT_BUFFER_SIZE );
fft->m_framesFilledUp = 0;
}
float EqEffect::peakBand(float minF, float maxF, FftBands *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(FftBands *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 );
}

View File

@@ -31,49 +31,60 @@
#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 );
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;
EqControls m_eqControls;
EqHp12Filter m_hp12;
EqHp12Filter m_hp24;
EqHp12Filter m_hp480;
EqHp12Filter m_hp481;
EqHp12Filter m_hp12;
EqHp12Filter m_hp24;
EqHp12Filter m_hp480;
EqHp12Filter m_hp481;
EqLowShelfFilter m_lowShelf;
EqLowShelfFilter m_lowShelf;
EqPeakFilter m_para1;
EqPeakFilter m_para2;
EqPeakFilter m_para3;
EqPeakFilter m_para4;
EqPeakFilter m_para1;
EqPeakFilter m_para2;
EqPeakFilter m_para3;
EqPeakFilter m_para4;
EqHighShelfFilter m_highShelf;
EqHighShelfFilter m_highShelf;
EqLp12Filter m_lp12;
EqLp12Filter m_lp24;
EqLp12Filter m_lp480;
EqLp12Filter m_lp481;
EqLp12Filter m_lp12;
EqLp12Filter m_lp24;
EqLp12Filter m_lp480;
EqLp12Filter m_lp481;
EqLp12Filter* m_downsampleFilters;
int m_dFilterCount;
sampleFrame* m_upBuf;
fpp_t m_upBufFrames;
// const static int MAX_BANDS = 249;
// const static int MAX_BANDS = 249;
void upsample( sampleFrame *buf, const fpp_t frames );
void downSample( sampleFrame *buf, const fpp_t frames );
// float m_bands[MAX_BANDS];
// float m_energy;
void analyze( sampleFrame *buf, const fpp_t frames, FftBands* fft );
float peakBand(float minF, float maxF,FftBands*, int);
inline float bandToFreq ( int index , int sampleRate )
{
return index * sampleRate / (MAX_BANDS * 2);
}
void setBandPeaks( FftBands *fft , int);
// float m_bands[MAX_BANDS];
// float m_energy;
};

View File

@@ -40,7 +40,7 @@ EqParameterWidget::EqParameterWidget( QWidget *parent ) :
connect( Engine::mainWindow(), SIGNAL( periodicUpdate() ), this, SLOT( update() ) );
float totalLength = log10( 21000 );
m_pixelsPerUnitWidth = width( ) / totalLength ;
float totalHeight = 40;
float totalHeight = 80;
m_pixelsPerUnitHeight = (height() - 4) / ( totalHeight );
m_scale = 1.5;
m_pixelsPerOctave = freqToXPixel( 10000 ) - freqToXPixel( 5000 );
@@ -63,7 +63,7 @@ void EqParameterWidget::paintEvent( QPaintEvent *event )
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, 3, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin ) );
painter.setPen( QPen( m_bands[i].color, 10, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin ) );
float x = freqToXPixel( m_bands[i].freq->value() );
float y = height() * 0.5;
float gain = 1;
@@ -75,7 +75,7 @@ void EqParameterWidget::paintEvent( QPaintEvent *event )
float bw = m_bands[i].freq->value() / m_bands[i].res->value();
m_bands[i].x = x; m_bands[i].y = y;
painter.drawPoint( x, y );
painter.setPen( QPen( m_bands[i].color, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin ) );
painter.setPen( QPen( m_bands[i].color, 3, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin ) );
if(i == 0 || i == bandCount() - 1 ){
painter.drawLine(x, y, x, y - (m_bands[i].res->value() * 4 ) );
}

View File

@@ -2,38 +2,70 @@
#define EQSPECTRUMVIEW_H
#include "qpainter.h"
#include "eqeffect.h"
//#include "eqeffect.h"
#include "qwidget.h"
#include "fft_helpers.h"
class EqParams
const int MAX_BANDS = 512;
class FftBands
{
public:
const static int MAX_BANDS = 249;
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;
FftBands() :
m_framesFilledUp( 0 ),
m_energy( 0 )
{
memset( m_buffer, 0, sizeof( m_buffer ) );
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 );
}
};
class EqSpectrumView : public QWidget
{
public:
EqSpectrumView( EqParams* s, QWidget * _parent = 0) :
explicit EqSpectrumView( FftBands * b, QWidget * _parent = 0) :
QWidget( _parent ),
m_sa( s )
m_sa( b )
{
setFixedSize( 240, 116 );
setFixedSize( 250, 116 );
connect( Engine::mainWindow(), SIGNAL( periodicUpdate() ), this, SLOT( update() ) );
setAttribute( Qt::WA_OpaquePaintEvent, true );
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()
{
}
EqParams *m_sa;
QColor color;
FftBands *m_sa;
int m_lastY;
virtual void paintEvent( QPaintEvent* event )
{
const int MAX_BANDS = 249;
int m_lastY = height();
QPainter p( this );
p.setPen( QPen( color, 1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin ) );
const float e = m_sa->m_energy;
if( e <= 0 )
{
@@ -51,7 +83,8 @@ EqParams *m_sa;
{
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;
p.drawPoint( x, fh-h );
p.drawLine(freqToXPixel(bandToFreq(x -1 ) ),m_lastY, freqToXPixel(bandToFreq(x ) ), fh-h );
m_lastY = fh-h;
}
}
else
@@ -67,12 +100,29 @@ EqParams *m_sa;
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;
//EqParams *m_sa;
// QImage m_backgroundPlain;
// QImage m_background;
} ;

View File

@@ -107,6 +107,7 @@ Fader::Fader( FloatModel * _model, const QString & _name, QWidget * _parent ) :
setMaximumSize( 23, 116);
resize( 23, 116 );
setModel( _model );
setHintText( "Volume:","%");
}
@@ -141,6 +142,7 @@ Fader::Fader( FloatModel * model, const QString & name, QWidget * parent, QPixma
setMaximumSize( m_back->width(), m_back->height() );
resize( m_back->width(), m_back->height() );
setModel( model );
setHintText( "Volume:","%");
}
@@ -324,7 +326,7 @@ void Fader::updateTextFloat()
}
else
{
s_textFloat->setText( QString("Volume: %1 %").arg( m_displayConversion ? m_model->value() * 100 : m_model->value() ) );
s_textFloat->setText( m_description + " " + QString("%1 ").arg( m_displayConversion ? m_model->value() * 100 : m_model->value() ) + " " + m_unit );
}
s_textFloat->moveGlobal( this, QPoint( width() - ( *m_knob ).width() - 5, knobPosY() - 46 ) );
}