diff --git a/include/RmsHelper.h b/include/RmsHelper.h new file mode 100644 index 0000000000..784a5fd3c7 --- /dev/null +++ b/include/RmsHelper.h @@ -0,0 +1,94 @@ +/* + * RmsHelper.h - helper class for calculating RMS + * + * Copyright (c) 2014 Vesa Kivimäki + * Copyright (c) 2008 Tobias Doerffel + * + * 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 RMS_HELPER_H +#define RMS_HELPER_H + +#include "lmms_math.h" + +class RmsHelper +{ +public: + RmsHelper( int size ) : + m_buffer( NULL ) + { + setSize( size ); + } + virtual ~RmsHelper() + { + if( m_buffer ) delete m_buffer; + } + + inline void setSize( int size ) + { + if( m_buffer ) + { + if( m_size < size ) + { + delete m_buffer; + m_buffer = new float[ size ]; + m_size = size; + reset(); + } + else + { + m_size = size; + reset(); + } + } + else + { + m_buffer = new float[ size ]; + m_size = size; + reset(); + } + } + + inline void reset() + { + m_sizef = 1.0f / (float) m_size; + m_pos = 0; + m_sum = 0.0f; + memset( m_buffer, 0, m_size * sizeof( float ) ); + } + + inline float update( const float in ) + { + m_sum -= m_buffer[ m_pos ]; + m_sum += m_buffer[ m_pos ] = in * in; + ++m_pos %= m_size; + return sqrtf( m_sum * m_sizef ); + } + +private: + float * m_buffer; + float m_sum; + unsigned int m_pos; + unsigned int m_size; + float m_sizef; +}; + + +#endif diff --git a/plugins/dynamics_processor/dynamics_processor.cpp b/plugins/dynamics_processor/dynamics_processor.cpp index 24e421deb3..cd18e0f13e 100644 --- a/plugins/dynamics_processor/dynamics_processor.cpp +++ b/plugins/dynamics_processor/dynamics_processor.cpp @@ -58,7 +58,10 @@ dynProcEffect::dynProcEffect( Model * _parent, m_dpControls( this ) { m_currentPeak[0] = m_currentPeak[1] = DYN_NOISE_FLOOR; - m_needsUpdate = true; + m_rms[0] = new RmsHelper( 64 * engine::mixer()->processingSampleRate() / 44100 ); + m_rms[1] = new RmsHelper( 64 * engine::mixer()->processingSampleRate() / 44100 ); + calcAttack(); + calcRelease(); } @@ -66,6 +69,7 @@ dynProcEffect::dynProcEffect( Model * _parent, dynProcEffect::~dynProcEffect() { + delete[] m_rms; } @@ -110,15 +114,25 @@ bool dynProcEffect::processAudioBuffer( sampleFrame * _buf, // debug code // qDebug( "peaks %f %f", m_currentPeak[0], m_currentPeak[1] ); - if( m_dpControls.m_attackModel.isValueChanged() || m_needsUpdate ) + if( m_needsUpdate ) { + m_rms[0]->setSize( 64 * engine::mixer()->processingSampleRate() / 44100 ); + m_rms[1]->setSize( 64 * engine::mixer()->processingSampleRate() / 44100 ); calcAttack(); - } - if( m_dpControls.m_releaseModel.isValueChanged() || m_needsUpdate ) - { calcRelease(); + m_needsUpdate = false; + } + else + { + if( m_dpControls.m_attackModel.isValueChanged() ) + { + calcAttack(); + } + if( m_dpControls.m_releaseModel.isValueChanged() ) + { + calcRelease(); + } } - m_needsUpdate = false; for( fpp_t f = 0; f < _frames; ++f ) { @@ -131,14 +145,15 @@ bool dynProcEffect::processAudioBuffer( sampleFrame * _buf, // update peak values for ( i=0; i <= 1; i++ ) { - if( qAbs( s[i] ) > m_currentPeak[i] ) + const double t = m_rms[i]->update( s[i] ); + if( t > m_currentPeak[i] ) { - m_currentPeak[i] = qMin( m_currentPeak[i] * m_attCoeff, qAbs( s[i] ) ); + m_currentPeak[i] = qMin( m_currentPeak[i] * m_attCoeff, t ); } else - if( qAbs( s[i] ) < m_currentPeak[i] ) + if( t < m_currentPeak[i] ) { - m_currentPeak[i] = qMax( m_currentPeak[i] * m_relCoeff, qAbs( s[i] ) ); + m_currentPeak[i] = qMax( m_currentPeak[i] * m_relCoeff, t ); } m_currentPeak[i] = qBound( DYN_NOISE_FLOOR, m_currentPeak[i], 10.0f ); diff --git a/plugins/dynamics_processor/dynamics_processor.h b/plugins/dynamics_processor/dynamics_processor.h index 004146eb27..cf9d585866 100644 --- a/plugins/dynamics_processor/dynamics_processor.h +++ b/plugins/dynamics_processor/dynamics_processor.h @@ -29,7 +29,7 @@ #include "Effect.h" #include "dynamics_processor_controls.h" - +#include "RmsHelper.h" class dynProcEffect : public Effect @@ -59,6 +59,8 @@ private: double m_relCoeff; bool m_needsUpdate; + + RmsHelper * m_rms [2]; friend class dynProcControls;