You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdemultimedia/arts/modules/synth/synth_compressor_impl.cc

140 lines
3.4 KiB

/*
Copyright (C) 2001 Matthias Kretz <kretz@kde.org>
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; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "artsmodulessynth.h"
#include "stdsynthmodule.h"
#include "debug.h"
#include <math.h>
#include <string.h>
#ifndef LN2
# define LN2 0.69314718
#endif
#ifndef MAX
# define MAX(a,b) (((a) > (b) ? (a) : (b)))
#endif
using namespace std;
namespace Arts {
class Synth_COMPRESSOR_impl : virtual public Synth_COMPRESSOR_skel,
virtual public StdSynthModule
{
protected:
float _attack, _release, _threshold, _ratiominus1, _output;
float _attackfactor, _releasefactor;
float _volume;
float _compfactor;
bool _autooutput;
public:
float attack() { return _attack; }
float release() { return _release; }
float threshold() { return _threshold; }
float ratio() { return _ratiominus1 + 1.0; }
float output() { return _output; }
Synth_COMPRESSOR_impl()
: _threshold( 1 )
, _ratiominus1( -0.2 )
, _output( 0 )
, _autooutput( true )
{
newCompFactor();
attack( 10 );
release( 10 );
}
void newCompFactor()
{
_compfactor = _output / pow( _threshold, _ratiominus1 );
}
void streamInit()
{
_volume = 0;
}
void calculateBlock(unsigned long samples)
{
for( unsigned long i = 0; i < samples; i++ ) {
float delta = fabs( invalue[i] ) - _volume;
if( delta > 0.0 )
_volume += _attackfactor * delta;
else
_volume += _releasefactor * delta;
if( _volume > _threshold )
// compress
// this is what it does:
// UtodB(x) = 20 * log( x )
// dBtoU(x) = pow( 10, x / 20 )
// outvalue[i] = dBtoU( ( UtodB( volume ) - UtodB( threshold ) ) * ratio + UtodB( threshold ) ) / volume * output * invalue[ i ];
// showing that it's equal to the formula below
// is left as an exercise to the reader.
outvalue[i] = pow( _volume, _ratiominus1 ) * _compfactor * invalue[ i ];
else
outvalue[i] = invalue[i] * _output;
}
}
void attack( float newAttack )
{ // in ms
_attack = newAttack;
// _attackfactor has to be <= 1, that's why we need the MAX here
_attackfactor = LN2 / MAX( _attack / 1000 * samplingRateFloat, LN2 );
attack_changed( newAttack );
}
void release( float newRelease )
{ // in ms
_release = newRelease;
// _releasefactor has to be <= 1, that's why we need the MAX here
_releasefactor = LN2 / MAX( _release / 1000 * samplingRateFloat, LN2 );
release_changed( newRelease );
}
void threshold( float newThreshold )
{ // in V not in dB
_threshold = newThreshold;
newCompFactor();
threshold_changed( newThreshold );
}
void ratio( float newRatio )
{
_ratiominus1 = newRatio - 1;
newCompFactor();
ratio_changed( newRatio );
}
void output( float newOutput )
{ // in V not in dB
_output = newOutput;
newCompFactor();
output_changed( newOutput );
}
};
REGISTER_IMPLEMENTATION(Synth_COMPRESSOR_impl);
}