Merge pull request #979 from diizy/master

Peak Controller: improve envelope calculation
This commit is contained in:
Vesa V
2014-07-12 05:29:47 +03:00
5 changed files with 67 additions and 60 deletions

View File

@@ -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;

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -23,7 +23,6 @@
*
*/
#include <math.h>
#include <cstdio>
#include <QtXml/QDomElement>
#include <QtCore/QObject>
@@ -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
{