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.
140 lines
3.4 KiB
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);
|
|
}
|