Files
stk/src/Modal.cpp
Gary Scavone fc877b87bf Version 4.4.4
2013-09-29 23:22:28 +02:00

170 lines
4.1 KiB
C++

/***************************************************/
/*! \class Modal
\brief STK resonance model abstract base class.
This class contains an excitation wavetable,
an envelope, an oscillator, and N resonances
(non-sweeping BiQuad filters), where N is set
during instantiation.
by Perry R. Cook and Gary P. Scavone, 1995-2012.
*/
/***************************************************/
#include "Modal.h"
#include <cstdlib>
namespace stk {
Modal :: Modal( unsigned int modes )
: nModes_(modes)
{
if ( nModes_ == 0 ) {
oStream_ << "Modal: 'modes' argument to constructor is zero!";
handleError( StkError::FUNCTION_ARGUMENT );
}
// We don't make the excitation wave here yet, because we don't know
// what it's going to be.
ratios_.resize( nModes_ );
radii_.resize( nModes_ );
filters_ = (BiQuad **) calloc( nModes_, sizeof(BiQuad *) );
for (unsigned int i=0; i<nModes_; i++ ) {
filters_[i] = new BiQuad;
filters_[i]->setEqualGainZeroes();
}
// Set some default values.
vibrato_.setFrequency( 6.0 );
vibratoGain_ = 0.0;
directGain_ = 0.0;
masterGain_ = 1.0;
baseFrequency_ = 440.0;
this->clear();
stickHardness_ = 0.5;
strikePosition_ = 0.561;
}
Modal :: ~Modal( void )
{
for ( unsigned int i=0; i<nModes_; i++ ) {
delete filters_[i];
}
free( filters_ );
}
void Modal :: clear( void )
{
onepole_.clear();
for ( unsigned int i=0; i<nModes_; i++ )
filters_[i]->clear();
}
void Modal :: setFrequency( StkFloat frequency )
{
#if defined(_STK_DEBUG_)
if ( frequency <= 0.0 ) {
oStream_ << "Modal::setFrequency: argument is less than or equal to zero!";
handleError( StkError::WARNING ); return;
}
#endif
baseFrequency_ = frequency;
for ( unsigned int i=0; i<nModes_; i++ )
this->setRatioAndRadius( i, ratios_[i], radii_[i] );
}
void Modal :: setRatioAndRadius( unsigned int modeIndex, StkFloat ratio, StkFloat radius )
{
if ( modeIndex >= nModes_ ) {
oStream_ << "Modal::setRatioAndRadius: modeIndex parameter is greater than number of modes!";
handleError( StkError::WARNING ); return;
}
StkFloat nyquist = Stk::sampleRate() / 2.0;
StkFloat temp;
if ( ratio * baseFrequency_ < nyquist ) {
ratios_[modeIndex] = ratio;
}
else {
temp = ratio;
while (temp * baseFrequency_ > nyquist) temp *= 0.5;
ratios_[modeIndex] = temp;
#if defined(_STK_DEBUG_)
oStream_ << "Modal::setRatioAndRadius: aliasing would occur here ... correcting.";
handleError( StkError::DEBUG_PRINT );
#endif
}
radii_[modeIndex] = radius;
if (ratio < 0)
temp = -ratio;
else
temp = ratio * baseFrequency_;
filters_[modeIndex]->setResonance(temp, radius);
}
void Modal :: setModeGain( unsigned int modeIndex, StkFloat gain )
{
if ( modeIndex >= nModes_ ) {
oStream_ << "Modal::setModeGain: modeIndex parameter is greater than number of modes!";
handleError( StkError::WARNING ); return;
}
filters_[modeIndex]->setGain( gain );
}
void Modal :: strike( StkFloat amplitude )
{
if ( amplitude < 0.0 || amplitude > 1.0 ) {
oStream_ << "Modal::strike: amplitude is out of range!";
handleError( StkError::WARNING );
}
envelope_.setRate( 1.0 );
envelope_.setTarget( amplitude );
onepole_.setPole( 1.0 - amplitude );
envelope_.tick();
wave_->reset();
StkFloat temp;
for ( unsigned int i=0; i<nModes_; i++ ) {
if (ratios_[i] < 0)
temp = -ratios_[i];
else
temp = ratios_[i] * baseFrequency_;
filters_[i]->setResonance(temp, radii_[i]);
}
}
void Modal :: noteOn( StkFloat frequency, StkFloat amplitude )
{
this->strike( amplitude );
this->setFrequency( frequency );
}
void Modal :: noteOff( StkFloat amplitude )
{
// This calls damp, but inverts the meaning of amplitude (high
// amplitude means fast damping).
this->damp( 1.0 - (amplitude * 0.03) );
}
void Modal :: damp( StkFloat amplitude )
{
StkFloat temp;
for ( unsigned int i=0; i<nModes_; i++ ) {
if ( ratios_[i] < 0 )
temp = -ratios_[i];
else
temp = ratios_[i] * baseFrequency_;
filters_[i]->setResonance( temp, radii_[i]*amplitude );
}
}
} // stk namespace