diff --git a/include/PeakController.h b/include/PeakController.h index a235bcca5..d53211d95 100644 --- a/include/PeakController.h +++ b/include/PeakController.h @@ -72,6 +72,7 @@ protected: friend class PeakControllerDialog; private: + float m_currentSample; //backward compatibility for <= 0.4.15 static int m_getCount; static int m_loadCount; diff --git a/include/lmms_math.h b/include/lmms_math.h index 0ec8ccc49..67b4f10e9 100644 --- a/include/lmms_math.h +++ b/include/lmms_math.h @@ -200,4 +200,19 @@ static inline float dbvToAmp( float dbv ) } + +//! returns 1.0f if val >= 0.0f, -1.0 else +static inline float sign( float val ) +{ + return val >= 0.0f ? 1.0f : -1.0f; +} + + +//! if val >= 0.0f, returns sqrtf(val), else: -sqrtf(-val) +static inline float sqrt_neg( float val ) +{ + return sqrtf( fabs( val ) ) * sign( val ); +} + + #endif diff --git a/plugins/peak_controller_effect/peak_controller_effect.cpp b/plugins/peak_controller_effect/peak_controller_effect.cpp index 2689db00c..1dc36ea7a 100644 --- a/plugins/peak_controller_effect/peak_controller_effect.cpp +++ b/plugins/peak_controller_effect/peak_controller_effect.cpp @@ -28,6 +28,7 @@ #include "song.h" #include "PeakController.h" #include "peak_controller_effect.h" +#include "lmms_math.h" #include "embed.cpp" @@ -63,9 +64,6 @@ PeakControllerEffect::PeakControllerEffect( m_effectId( rand() ), m_peakControls( this ), m_lastSample( 0 ), - m_previousSample( 0 ), - m_lastRMS( -1 ), - m_lastRMSavail(false), m_autoController( NULL ) { m_autoController = new PeakController( engine::getSong(), this ); @@ -86,22 +84,6 @@ PeakControllerEffect::~PeakControllerEffect() } } -namespace helpers -{ - - //! returns 1.0f if val > 0.0f, -1.0 else - inline float sign( float val ) - { - return -1.0f + 2.0f * ( val > 0.0f ); - } - - //! if val >= 0.0f, returns sqrtf(val), else: -sqrtf(-val) - inline float sqrt_neg( float val ) - { - return sqrtf( fabs( val ) ) * helpers::sign( val ); - } - -} bool PeakControllerEffect::processAudioBuffer( sampleFrame * _buf, const fpp_t _frames ) @@ -132,8 +114,8 @@ bool PeakControllerEffect::processAudioBuffer( sampleFrame * _buf, { // the value is absolute because of squaring, // so we need to correct it - sum += _buf[i][0] * _buf[i][0] * helpers::sign( _buf[i][0] ) - + _buf[i][1] * _buf[i][1] * helpers::sign( _buf[i][1] ); + sum += _buf[i][0] * _buf[i][0] * sign( _buf[i][0] ) + + _buf[i][1] * _buf[i][1] * sign( _buf[i][1] ); } } @@ -147,35 +129,9 @@ bool PeakControllerEffect::processAudioBuffer( sampleFrame * _buf, } } - float curRMS = helpers::sqrt_neg( sum / _frames ); - const float origRMS = curRMS; - - if( !m_lastRMSavail ) - { - m_lastRMSavail = true; - m_lastRMS = curRMS; - } - const float v = ( curRMS >= m_lastRMS ) ? - c.m_attackModel.value() : - c.m_decayModel.value(); - const float a = helpers::sqrt_neg( helpers::sqrt_neg( v ) ); - curRMS = (1-a)*curRMS + a*m_lastRMS; - + float curRMS = sqrt_neg( sum / _frames ); const float amount = c.m_amountModel.value() * c.m_amountMultModel.value(); - m_previousSample = m_lastSample; - m_lastSample = c.m_baseModel.value() + amount*curRMS; - m_lastRMS = curRMS; - - // on greater buffer sizes our LP is updated less frequently, therfore - // replay a certain number of passes so the LP state is as if it was - // updated N times with buffer-size 1/N - const int timeOversamp = (4*_frames) / DEFAULT_BUFFER_SIZE-1; - for( int i = 0; i < timeOversamp; ++i ) - { - m_lastRMS = (1-a)*origRMS + a*m_lastRMS; - } - - //checkGate( out_sum / _frames ); + m_lastSample = c.m_baseModel.value() + amount * curRMS; return isRunning(); } diff --git a/plugins/peak_controller_effect/peak_controller_effect.h b/plugins/peak_controller_effect/peak_controller_effect.h index ad05fb645..142ffb523 100644 --- a/plugins/peak_controller_effect/peak_controller_effect.h +++ b/plugins/peak_controller_effect/peak_controller_effect.h @@ -48,15 +48,20 @@ public: return m_lastSample; } - float previousSample() - { - return m_previousSample; - } - PeakController * controller() { return m_autoController; } + + FloatModel * attackModel() + { + return &( m_peakControls.m_attackModel ); + } + + FloatModel * decayModel() + { + return &( m_peakControls.m_decayModel ); + } int m_effectId; @@ -64,9 +69,6 @@ private: PeakControllerEffectControls m_peakControls; float m_lastSample; - float m_previousSample; - float m_lastRMS; - bool m_lastRMSavail; PeakController * m_autoController; diff --git a/src/core/PeakController.cpp b/src/core/PeakController.cpp index e5f239d7d..5913cd8dc 100644 --- a/src/core/PeakController.cpp +++ b/src/core/PeakController.cpp @@ -23,7 +23,6 @@ * */ -#include #include #include #include @@ -39,6 +38,9 @@ #include "ControllerDialog.h" #include "plugins/peak_controller_effect/peak_controller_effect.h" #include "PresetPreviewPlayHandle.h" +#include "lmms_math.h" +#include "interpolation.h" + PeakControllerEffectVector PeakController::s_effects; int PeakController::m_getCount; @@ -49,7 +51,8 @@ bool PeakController::m_buggedFile; PeakController::PeakController( Model * _parent, PeakControllerEffect * _peak_effect ) : Controller( Controller::PeakController, _parent, tr( "Peak Controller" ) ), - m_peakEffect( _peak_effect ) + m_peakEffect( _peak_effect ), + m_currentSample( 0.0f ) { setSampleExact( true ); if( m_peakEffect ) @@ -79,7 +82,37 @@ void PeakController::updateValueBuffer() { if( m_peakEffect ) { - m_valueBuffer.interpolate( m_peakEffect->previousSample(), m_peakEffect->lastSample() ); + float targetSample = m_peakEffect->lastSample(); + if( m_currentSample != targetSample ) + { + const f_cnt_t frames = engine::mixer()->framesPerPeriod(); + float * values = m_valueBuffer.values(); + + const float ratio = ( 44100.0 / 256.0 ) / engine::mixer()->processingSampleRate(); + const float v = m_currentSample >= targetSample + ? m_peakEffect->decayModel()->value() + : m_peakEffect->attackModel()->value(); + const float diff = ( targetSample - m_currentSample ) * ratio; + const float a = ( 1.0f - sqrt_neg( sqrt_neg( v ) ) ) * diff; + const bool att = m_currentSample < targetSample; + + for( f_cnt_t f = 0; f < frames; ++f ) + { + if( att ) // going up... + { + m_currentSample = qMin( targetSample, m_currentSample + a ); // qmin prevents overshoot + } + else + { + m_currentSample = qMax( targetSample, m_currentSample + a ); // qmax prevents overshoot + } + values[f] = m_currentSample; + } + } + else + { + m_valueBuffer.fill( m_currentSample ); + } } else {