From aad0e7630b6c4b041ef6030e5a8f0d985916994b Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Tue, 29 Jul 2008 08:51:03 +0000 Subject: [PATCH] moved FFT-helper functions from Spectrum Analyzer plugin to core to make it also usable by other plugins git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@1407 0778d3d1-df1d-0410-868b-ea421aaaa00d --- ChangeLog | 10 + include/fft_helpers.h | 88 ++++++ lmmsconfig.h.in | 1 + .../spectrum_analyzer/spectrum_analyzer.cpp | 251 ++---------------- plugins/spectrum_analyzer/spectrum_analyzer.h | 8 +- src/core/fft_helpers.cpp | 247 +++++++++++++++++ 6 files changed, 365 insertions(+), 240 deletions(-) create mode 100644 include/fft_helpers.h create mode 100644 src/core/fft_helpers.cpp diff --git a/ChangeLog b/ChangeLog index cc6e8b2d1..6910a8d21 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2008-07-29 Tobias Doerffel + + * plugins/spectrum_analyzer/spectrum_analyzer.cpp: + * plugins/spectrum_analyzer/spectrum_analyzer.h: + * include/fft_helpers.h: + * src/core/fft_helpers.cpp: + * lmmsconfig.h.in: + moved FFT-helper functions from Spectrum Analyzer plugin to core to + make it also usable by other plugins + 2008-07-28 Tobias Doerffel * plugins/ladspa_effect/ladspa_controls.cpp: diff --git a/include/fft_helpers.h b/include/fft_helpers.h new file mode 100644 index 000000000..cc5d8b9d2 --- /dev/null +++ b/include/fft_helpers.h @@ -0,0 +1,88 @@ +/* + * fft_helpers.h - some functions around FFT analysis + * + * Copyright (c) 2008 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#ifndef _FFT_HELPERS_H +#define _FFT_HELPERS_H + +#include "lmmsconfig.h" + +#ifdef LMMS_HAVE_FFTW3F + +#include + +const int FFT_BUFFER_SIZE = 2048; + +enum WINDOWS +{ + KAISER=1, + RECTANGLE, + HANNING, + HAMMING +}; + +/* returns biggest value from abs_spectrum[spec_size] array + * + * returns -1 on error + */ +float maximum( float * _abs_spectrum, unsigned int _spec_size ); + +/* apply hanning or hamming window to channel + * + * returns -1 on error + */ +int hanming( float * _timebuffer, int _length, WINDOWS _type ); + +/* compute absolute values of complex_buffer, save to absspec_buffer + * take care that - compl_len is not bigger than complex_buffer! + * - absspec buffer is big enough! + * + * returns 0 on success, else -1 + */ +int absspec( fftwf_complex * _complex_buffer, float * _absspec_buffer, + int _compl_length ); + +/* build fewer subbands from many absolute spectrum values + * take care that - compressedbands[] array num_new elements long + * - num_old > num_new + * + * returns 0 on success, else -1 + */ +int compressbands( float * _absspec_buffer, float * _compressedband, + int _num_old, int _num_new, int _bottom, int _top ); + + +int calc13octaveband31( float * _absspec_buffer, float * _subbands, + int _num_spec, float _max_frequency ); + +/* compute power of finite time sequence + * take care num_values is length of timesignal[] + * + * returns power on success, else -1 + */ +float signalpower(float *timesignal, int num_values); + +#endif + +#endif diff --git a/lmmsconfig.h.in b/lmmsconfig.h.in index 181b100e0..bf7485a7a 100644 --- a/lmmsconfig.h.in +++ b/lmmsconfig.h.in @@ -3,6 +3,7 @@ #cmakedefine LMMS_BUILD_APPLE #cmakedefine LMMS_HAVE_ALSA +#cmakedefine LMMS_HAVE_FFTW3F #cmakedefine LMMS_HAVE_JACK #cmakedefine LMMS_HAVE_OGGVORBIS #cmakedefine LMMS_HAVE_OSS diff --git a/plugins/spectrum_analyzer/spectrum_analyzer.cpp b/plugins/spectrum_analyzer/spectrum_analyzer.cpp index 929a79a7f..f283b09f4 100644 --- a/plugins/spectrum_analyzer/spectrum_analyzer.cpp +++ b/plugins/spectrum_analyzer/spectrum_analyzer.cpp @@ -58,9 +58,9 @@ spectrumAnalyzer::spectrumAnalyzer( model * _parent, m_framesFilledUp( 0 ), m_energy( 0 ) { - m_specBuf = (fftwf_complex *) fftwf_malloc( ( BUFFER_SIZE + 1 ) * + m_specBuf = (fftwf_complex *) fftwf_malloc( ( FFT_BUFFER_SIZE + 1 ) * sizeof( fftwf_complex ) ); - m_fftPlan = fftwf_plan_dft_r2c_1d( BUFFER_SIZE*2, m_buffer, + m_fftPlan = fftwf_plan_dft_r2c_1d( FFT_BUFFER_SIZE*2, m_buffer, m_specBuf, FFTW_MEASURE ); } @@ -75,228 +75,6 @@ spectrumAnalyzer::~spectrumAnalyzer() -enum WINDOWS -{ - KAISER=1, - RECTANGLE, - HANNING, - HAMMING -}; - - -/* returns biggest value from abs_spectrum[spec_size] array - - returns -1 on error -*/ -float maximum(float *abs_spectrum, unsigned int spec_size) -{ - float maxi=0; - unsigned int i; - - if ( abs_spectrum==NULL ) - return -1; - - if (spec_size<=0) - return -1; - - for ( i=0; imaxi ) - maxi=abs_spectrum[i]; - } - - return maxi; -} - - -/* apply hanning or hamming window to channel - - returns -1 on error */ -int hanming(float *timebuffer, int length, int type) -{ - int i; - float alpha; - - if ( (timebuffer==NULL)||(length<=0) ) - return -1; - - switch (type) - { - case HAMMING: alpha=0.54; break; - case HANNING: - default: alpha=0.5; break; - } - - for ( i=0; i num_new - - returns 0 on success, else -1 */ -int compressbands(float *absspec_buffer, float *compressedband, int num_old, int num_new, int bottom, int top) -{ - float ratio; - int i, usefromold; - float j; - float j_min, j_max; - - if ( (absspec_buffer==NULL)||(compressedband==NULL) ) - return -1; - - if ( num_old=num_old ) - top=num_old-1; - - usefromold=num_old-(num_old-top)-bottom; - - ratio=(float)usefromold/(float)num_new; - - // foreach new subband - for ( i=0; i BUFFER_SIZE ) + if( _frames > FFT_BUFFER_SIZE ) { m_framesFilledUp = 0; - f = _frames - BUFFER_SIZE; + f = _frames - FFT_BUFFER_SIZE; } const int cm = m_saControls.m_channelMode.value(); @@ -341,32 +119,35 @@ bool spectrumAnalyzer::processAudioBuffer( sampleFrame * _buf, break; } - if( m_framesFilledUp < BUFFER_SIZE ) + if( m_framesFilledUp < FFT_BUFFER_SIZE ) { return( isRunning() ); } -// hanming( m_buffer, BUFFER_SIZE, HAMMING ); +// hanming( m_buffer, FFT_BUFFER_SIZE, HAMMING ); const sample_rate_t sr = engine::getMixer()->processingSampleRate(); const int LOWEST_FREQ = 0; const int HIGHEST_FREQ = sr / 2; fftwf_execute( m_fftPlan ); - absspec( m_specBuf, m_absSpecBuf, BUFFER_SIZE+1 ); + absspec( m_specBuf, m_absSpecBuf, FFT_BUFFER_SIZE+1 ); if( m_saControls.m_linearSpec.value() ) { - compressbands( m_absSpecBuf, m_bands, BUFFER_SIZE+1, + compressbands( m_absSpecBuf, m_bands, FFT_BUFFER_SIZE+1, MAX_BANDS, - (int)(LOWEST_FREQ*(BUFFER_SIZE+1)/(float)(sr/2)), - (int)(HIGHEST_FREQ*(BUFFER_SIZE+1)/(float)(sr/2))); - m_energy = maximum( m_bands, MAX_BANDS ) / maximum( m_buffer, BUFFER_SIZE ); + (int)(LOWEST_FREQ*(FFT_BUFFER_SIZE+1)/(float)(sr/2)), + (int)(HIGHEST_FREQ*(FFT_BUFFER_SIZE+1)/(float)(sr/2))); + m_energy = maximum( m_bands, MAX_BANDS ) / + maximum( m_buffer, FFT_BUFFER_SIZE ); } else { - calc13octaveband31( m_absSpecBuf, m_bands, BUFFER_SIZE+1, sr/2.0); - m_energy = signalpower( m_buffer, BUFFER_SIZE ) / maximum( m_buffer, BUFFER_SIZE ); + calc13octaveband31( m_absSpecBuf, m_bands, + FFT_BUFFER_SIZE+1, sr/2.0 ); + m_energy = signalpower( m_buffer, FFT_BUFFER_SIZE ) / + maximum( m_buffer, FFT_BUFFER_SIZE ); } diff --git a/plugins/spectrum_analyzer/spectrum_analyzer.h b/plugins/spectrum_analyzer/spectrum_analyzer.h index 526383f58..6a81a742d 100644 --- a/plugins/spectrum_analyzer/spectrum_analyzer.h +++ b/plugins/spectrum_analyzer/spectrum_analyzer.h @@ -26,14 +26,12 @@ #ifndef _SPECTRUM_ANALYZER_H #define _SPECTRUM_ANALYZER_H -#include - #include "effect.h" +#include "fft_helpers.h" #include "spectrumanalyzer_controls.h" const int MAX_BANDS = 249; -const int BUFFER_SIZE = 2048; class spectrumAnalyzer : public effect @@ -64,8 +62,8 @@ private: fftwf_plan m_fftPlan; fftwf_complex * m_specBuf; - float m_absSpecBuf[BUFFER_SIZE+1]; - float m_buffer[BUFFER_SIZE*2]; + float m_absSpecBuf[FFT_BUFFER_SIZE+1]; + float m_buffer[FFT_BUFFER_SIZE*2]; int m_framesFilledUp; float m_bands[MAX_BANDS]; diff --git a/src/core/fft_helpers.cpp b/src/core/fft_helpers.cpp new file mode 100644 index 000000000..eb80025e0 --- /dev/null +++ b/src/core/fft_helpers.cpp @@ -0,0 +1,247 @@ +/* + * fft_helpers.cpp - some functions around FFT analysis + * + * Copyright (c) 2008 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#include "fft_helpers.h" + +#ifdef LMMS_HAVE_FFTW3F + +#include + + +/* returns biggest value from abs_spectrum[spec_size] array + + returns -1 on error +*/ +float maximum(float *abs_spectrum, unsigned int spec_size) +{ + float maxi=0; + unsigned int i; + + if ( abs_spectrum==NULL ) + return -1; + + if (spec_size<=0) + return -1; + + for ( i=0; imaxi ) + maxi=abs_spectrum[i]; + } + + return maxi; +} + + +/* apply hanning or hamming window to channel + + returns -1 on error */ +int hanming(float *timebuffer, int length, WINDOWS type) +{ + int i; + float alpha; + + if ( (timebuffer==NULL)||(length<=0) ) + return -1; + + switch (type) + { + case HAMMING: alpha=0.54; break; + case HANNING: + default: alpha=0.5; break; + } + + for ( i=0; i num_new + + returns 0 on success, else -1 */ +int compressbands(float *absspec_buffer, float *compressedband, int num_old, int num_new, int bottom, int top) +{ + float ratio; + int i, usefromold; + float j; + float j_min, j_max; + + if ( (absspec_buffer==NULL)||(compressedband==NULL) ) + return -1; + + if ( num_old=num_old ) + top=num_old-1; + + usefromold=num_old-(num_old-top)-bottom; + + ratio=(float)usefromold/(float)num_new; + + // foreach new subband + for ( i=0; i