1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-07-20 14:47:49 +02:00
2010-01-24 09:19:39 +00:00

189 lines
6.5 KiB
C++

/***************************************************/
/*! \class Mandolin
\brief STK mandolin instrument model class.
This class inherits from PluckTwo and uses
"commuted synthesis" techniques to model a
mandolin instrument.
This is a digital waveguide model, making its
use possibly subject to patents held by
Stanford University, Yamaha, and others.
Commuted Synthesis, in particular, is covered
by patents, granted, pending, and/or
applied-for. All are assigned to the Board of
Trustees, Stanford University. For
information, contact the Office of Technology
Licensing, Stanford University.
Control Change Numbers:
- Body Size = 2
- Pluck Position = 4
- String Sustain = 11
- String Detuning = 1
- Microphone Position = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
*/
/***************************************************/
#include "Mandolin.h"
#include "SKINI.msg"
using namespace Nyq;
Mandolin :: Mandolin(StkFloat lowestFrequency)
: PluckTwo(lowestFrequency)
{
// Concatenate the STK rawwave path to the rawwave files
soundfile_[0] = new FileWvIn( (Stk::rawwavePath() + "mand1.raw").c_str(), true );
soundfile_[1] = new FileWvIn( (Stk::rawwavePath() + "mand2.raw").c_str(), true );
soundfile_[2] = new FileWvIn( (Stk::rawwavePath() + "mand3.raw").c_str(), true );
soundfile_[3] = new FileWvIn( (Stk::rawwavePath() + "mand4.raw").c_str(), true );
soundfile_[4] = new FileWvIn( (Stk::rawwavePath() + "mand5.raw").c_str(), true );
soundfile_[5] = new FileWvIn( (Stk::rawwavePath() + "mand6.raw").c_str(), true );
soundfile_[6] = new FileWvIn( (Stk::rawwavePath() + "mand7.raw").c_str(), true );
soundfile_[7] = new FileWvIn( (Stk::rawwavePath() + "mand8.raw").c_str(), true );
soundfile_[8] = new FileWvIn( (Stk::rawwavePath() + "mand9.raw").c_str(), true );
soundfile_[9] = new FileWvIn( (Stk::rawwavePath() + "mand10.raw").c_str(), true );
soundfile_[10] = new FileWvIn( (Stk::rawwavePath() + "mand11.raw").c_str(), true );
soundfile_[11] = new FileWvIn( (Stk::rawwavePath() + "mand12.raw").c_str(), true );
mic_ = 0;
dampTime_ = 0;
waveDone_ = soundfile_[mic_]->isFinished();
}
Mandolin :: ~Mandolin()
{
for ( int i=0; i<12; i++ )
delete soundfile_[i];
}
void Mandolin :: pluck(StkFloat amplitude)
{
// This function gets interesting, because pluck
// may be longer than string length, so we just
// reset the soundfile and add in the pluck in
// the tick method.
soundfile_[mic_]->reset();
waveDone_ = false;
pluckAmplitude_ = amplitude;
if ( amplitude < 0.0 ) {
errorString_ << "Mandolin::pluck: amplitude parameter less than zero ... setting to 0.0!";
handleError( StkError::WARNING );
pluckAmplitude_ = 0.0;
}
else if ( amplitude > 1.0 ) {
errorString_ << "Mandolin::pluck: amplitude parameter greater than one ... setting to 1.0!";
handleError( StkError::WARNING );
pluckAmplitude_ = 1.0;
}
// Set the pick position, which puts zeroes at position * length.
combDelay_.setDelay( 0.5 * pluckPosition_ * lastLength_ );
dampTime_ = (long) lastLength_; // See tick method below.
}
void Mandolin :: pluck(StkFloat amplitude, StkFloat position)
{
// Pluck position puts zeroes at position * length.
pluckPosition_ = position;
if ( position < 0.0 ) {
std::cerr << "Mandolin::pluck: position parameter less than zero ... setting to 0.0!";
handleError( StkError::WARNING );
pluckPosition_ = 0.0;
}
else if ( position > 1.0 ) {
errorString_ << "Mandolin::pluck: amplitude parameter greater than one ... setting to 1.0!";
handleError( StkError::WARNING );
pluckPosition_ = 1.0;
}
this->pluck( amplitude );
}
void Mandolin :: noteOn(StkFloat frequency, StkFloat amplitude)
{
this->setFrequency( frequency );
this->pluck( amplitude );
#if defined(_STK_DEBUG_)
errorString_ << "Mandolin::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << ".";
handleError( StkError::DEBUG_WARNING );
#endif
}
void Mandolin :: setBodySize(StkFloat size)
{
// Scale the commuted body response by its sample rate (22050).
StkFloat rate = size * 22050.0 / Stk::sampleRate();
for ( int i=0; i<12; i++ )
soundfile_[i]->setRate( rate );
}
StkFloat Mandolin :: computeSample()
{
StkFloat temp = 0.0;
if ( !waveDone_ ) {
// Scale the pluck excitation with comb
// filtering for the duration of the file.
temp = soundfile_[mic_]->tick() * pluckAmplitude_;
temp = temp - combDelay_.tick(temp);
waveDone_ = soundfile_[mic_]->isFinished();
}
// Damping hack to help avoid overflow on re-plucking.
if ( dampTime_ >=0 ) {
dampTime_ -= 1;
// Calculate 1st delay filtered reflection plus pluck excitation.
lastOutput_ = delayLine_.tick( filter_.tick( temp + (delayLine_.lastOut() * 0.7) ) );
// Calculate 2nd delay just like the 1st.
lastOutput_ += delayLine2_.tick( filter2_.tick( temp + (delayLine2_.lastOut() * 0.7) ) );
}
else { // No damping hack after 1 period.
// Calculate 1st delay filtered reflection plus pluck excitation.
lastOutput_ = delayLine_.tick( filter_.tick( temp + (delayLine_.lastOut() * loopGain_) ) );
// Calculate 2nd delay just like the 1st.
lastOutput_ += delayLine2_.tick( filter2_.tick( temp + (delayLine2_.lastOut() * loopGain_) ) );
}
lastOutput_ *= 0.3;
return lastOutput_;
}
void Mandolin :: controlChange(int number, StkFloat value)
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
norm = 0.0;
errorString_ << "Mandolin::controlChange: control value less than zero ... setting to zero!";
handleError( StkError::WARNING );
}
else if ( norm > 1.0 ) {
norm = 1.0;
errorString_ << "Mandolin::controlChange: control value greater than 128.0 ... setting to 128.0!";
handleError( StkError::WARNING );
}
if (number == __SK_BodySize_) // 2
this->setBodySize( norm * 2.0 );
else if (number == __SK_PickPosition_) // 4
this->setPluckPosition( norm );
else if (number == __SK_StringDamping_) // 11
this->setBaseLoopGain( 0.97 + (norm * 0.03));
else if (number == __SK_StringDetune_) // 1
this->setDetune( 1.0 - (norm * 0.1) );
else if (number == __SK_AfterTouch_Cont_) // 128
mic_ = (int) (norm * 11.0);
else {
errorString_ << "Mandolin::controlChange: undefined control number (" << number << ")!";
handleError( StkError::WARNING );
}
#if defined(_STK_DEBUG_)
errorString_ << "Mandolin::controlChange: number = " << number << ", value = " << value << ".";
handleError( StkError::DEBUG_WARNING );
#endif
}