Version 4.4.0

This commit is contained in:
Gary Scavone
2013-09-29 23:11:39 +02:00
committed by Stephen Sinclair
parent d199342e86
commit eccd8c9981
287 changed files with 11712 additions and 7676 deletions

View File

@@ -2,33 +2,32 @@
/*! \class ADSR
\brief STK ADSR envelope class.
This Envelope subclass implements a
traditional ADSR (Attack, Decay,
Sustain, Release) envelope. It
responds to simple keyOn and keyOff
messages, keeping track of its state.
The \e state = ADSR::DONE after the
envelope value reaches 0.0 in the
ADSR::RELEASE state.
This class implements a traditional ADSR (Attack, Decay, Sustain,
Release) envelope. It responds to simple keyOn and keyOff
messages, keeping track of its state. The \e state = ADSR::DONE
after the envelope value reaches 0.0 in the ADSR::RELEASE state.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "ADSR.h"
ADSR :: ADSR() : Envelope()
namespace stk {
ADSR :: ADSR( void )
{
target_ = 0.0;
value_ = 0.0;
attackRate_ = 0.001;
decayRate_ = 0.001;
releaseRate_ = 0.005;
sustainLevel_ = 0.5;
releaseRate_ = 0.01;
state_ = ATTACK;
Stk::addSampleRateAlert( this );
}
ADSR :: ~ADSR()
ADSR :: ~ADSR( void )
{
}
@@ -44,20 +43,18 @@ void ADSR :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
void ADSR :: keyOn()
{
target_ = 1.0;
rate_ = attackRate_;
state_ = ATTACK;
}
void ADSR :: keyOff()
{
target_ = 0.0;
rate_ = releaseRate_;
state_ = RELEASE;
}
void ADSR :: setAttackRate(StkFloat rate)
void ADSR :: setAttackRate( StkFloat rate )
{
if (rate < 0.0) {
if ( rate < 0.0 ) {
errorString_ << "ADSR::setAttackRate: negative rates not allowed ... correcting!";
handleError( StkError::WARNING );
attackRate_ = -rate;
@@ -65,9 +62,9 @@ void ADSR :: setAttackRate(StkFloat rate)
else attackRate_ = rate;
}
void ADSR :: setDecayRate(StkFloat rate)
void ADSR :: setDecayRate( StkFloat rate )
{
if (rate < 0.0) {
if ( rate < 0.0 ) {
errorString_ << "ADSR::setDecayRate: negative rates not allowed ... correcting!";
handleError( StkError::WARNING );
decayRate_ = -rate;
@@ -75,9 +72,9 @@ void ADSR :: setDecayRate(StkFloat rate)
else decayRate_ = rate;
}
void ADSR :: setSustainLevel(StkFloat level)
void ADSR :: setSustainLevel( StkFloat level )
{
if (level < 0.0 ) {
if ( level < 0.0 ) {
errorString_ << "ADSR::setSustainLevel: level out of range ... correcting!";
handleError( StkError::WARNING );
sustainLevel_ = 0.0;
@@ -85,9 +82,9 @@ void ADSR :: setSustainLevel(StkFloat level)
else sustainLevel_ = level;
}
void ADSR :: setReleaseRate(StkFloat rate)
void ADSR :: setReleaseRate( StkFloat rate )
{
if (rate < 0.0) {
if ( rate < 0.0 ) {
errorString_ << "ADSR::setReleaseRate: negative rates not allowed ... correcting!";
handleError( StkError::WARNING );
releaseRate_ = -rate;
@@ -95,9 +92,9 @@ void ADSR :: setReleaseRate(StkFloat rate)
else releaseRate_ = rate;
}
void ADSR :: setAttackTime(StkFloat time)
void ADSR :: setAttackTime( StkFloat time )
{
if (time < 0.0) {
if ( time < 0.0 ) {
errorString_ << "ADSR::setAttackTime: negative times not allowed ... correcting!";
handleError( StkError::WARNING );
attackRate_ = 1.0 / ( -time * Stk::sampleRate() );
@@ -105,9 +102,9 @@ void ADSR :: setAttackTime(StkFloat time)
else attackRate_ = 1.0 / ( time * Stk::sampleRate() );
}
void ADSR :: setDecayTime(StkFloat time)
void ADSR :: setDecayTime( StkFloat time )
{
if (time < 0.0) {
if ( time < 0.0 ) {
errorString_ << "ADSR::setDecayTime: negative times not allowed ... correcting!";
handleError( StkError::WARNING );
decayRate_ = 1.0 / ( -time * Stk::sampleRate() );
@@ -115,9 +112,9 @@ void ADSR :: setDecayTime(StkFloat time)
else decayRate_ = 1.0 / ( time * Stk::sampleRate() );
}
void ADSR :: setReleaseTime(StkFloat time)
void ADSR :: setReleaseTime( StkFloat time )
{
if (time < 0.0) {
if ( time < 0.0 ) {
errorString_ << "ADSR::setReleaseTime: negative times not allowed ... correcting!";
handleError( StkError::WARNING );
releaseRate_ = sustainLevel_ / ( -time * Stk::sampleRate() );
@@ -125,74 +122,34 @@ void ADSR :: setReleaseTime(StkFloat time)
else releaseRate_ = sustainLevel_ / ( time * Stk::sampleRate() );
}
void ADSR :: setAllTimes(StkFloat aTime, StkFloat dTime, StkFloat sLevel, StkFloat rTime)
void ADSR :: setAllTimes( StkFloat aTime, StkFloat dTime, StkFloat sLevel, StkFloat rTime )
{
this->setAttackTime(aTime);
this->setDecayTime(dTime);
this->setSustainLevel(sLevel);
this->setReleaseTime(rTime);
this->setAttackTime( aTime );
this->setDecayTime( dTime );
this->setSustainLevel( sLevel );
this->setReleaseTime( rTime );
}
void ADSR :: setTarget(StkFloat target)
void ADSR :: setTarget( StkFloat target )
{
target_ = target;
if (value_ < target_) {
if ( value_ < target_ ) {
state_ = ATTACK;
this->setSustainLevel(target_);
rate_ = attackRate_;
this->setSustainLevel( target_ );
}
if (value_ > target_) {
this->setSustainLevel(target_);
if ( value_ > target_ ) {
this->setSustainLevel( target_ );
state_ = DECAY;
rate_ = decayRate_;
}
}
void ADSR :: setValue(StkFloat value)
void ADSR :: setValue( StkFloat value )
{
state_ = SUSTAIN;
target_ = value;
value_ = value;
this->setSustainLevel(value);
rate_ = (StkFloat) 0.0;
this->setSustainLevel( value );
lastFrame_[0] = value;
}
int ADSR :: getState(void) const
{
return state_;
}
StkFloat ADSR :: computeSample()
{
switch (state_) {
case ATTACK:
value_ += rate_;
if (value_ >= target_) {
value_ = target_;
rate_ = decayRate_;
target_ = sustainLevel_;
state_ = DECAY;
}
break;
case DECAY:
value_ -= decayRate_;
if (value_ <= sustainLevel_) {
value_ = sustainLevel_;
rate_ = (StkFloat) 0.0;
state_ = SUSTAIN;
}
break;
case RELEASE:
value_ -= releaseRate_;
if (value_ <= 0.0) {
value_ = (StkFloat) 0.0;
state_ = DONE;
}
}
lastOutput_ = value_;
return value_;
}
} // stk namespace

View File

@@ -6,7 +6,7 @@
which asymptotically approaches a target value.
The algorithm used is of the form:
x[n] = a x[n-1] + (1-a) target,
y[n] = a y[n-1] + (1-a) target,
where a = exp(-T/tau), T is the sample period, and
tau is a time constant. The user can set the time
@@ -19,20 +19,26 @@
to \e keyOn and \e keyOff messages by ramping to
1.0 on keyOn and to 0.0 on keyOff.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Asymp.h"
#include <cmath>
Asymp :: Asymp(void) : Envelope()
namespace stk {
Asymp :: Asymp( void )
{
value_ = 0.0;
target_ = 0.0;
state_ = 0;
factor_ = exp( -1.0 / ( 0.3 * Stk::sampleRate() ) );
constant_ = 0.0;
Stk::addSampleRateAlert( this );
}
Asymp :: ~Asymp(void)
Asymp :: ~Asymp( void )
{
}
@@ -44,33 +50,31 @@ void Asymp :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
}
}
void Asymp :: keyOn(void)
void Asymp :: keyOn( void )
{
Envelope::keyOn();
constant_ = ( 1.0 - factor_ ) * target_;
this->setTarget( 1.0 );
}
void Asymp :: keyOff(void)
void Asymp :: keyOff( void )
{
Envelope::keyOff();
constant_ = ( 1.0 - factor_ ) * target_;
this->setTarget( 0.0 );
}
void Asymp :: setTau(StkFloat tau)
void Asymp :: setTau( StkFloat tau )
{
if (tau <= 0.0) {
if ( tau <= 0.0 ) {
errorString_ << "Asymp::setTau: negative or zero tau not allowed ... ignoring!";
handleError( StkError::WARNING );
return;
}
factor_ = std::exp( -1.0 / ( tau * Stk::sampleRate() ) );
factor_ = std::exp( -1.0 / ( tau * Stk::sampleRate() ) );
constant_ = ( 1.0 - factor_ ) * target_;
}
void Asymp :: setTime(StkFloat time)
void Asymp :: setTime( StkFloat time )
{
if (time <= 0.0) {
if ( time <= 0.0 ) {
errorString_ << "Asymp::setTime: negative or zero times not allowed ... ignoring!";
handleError( StkError::WARNING );
return;
@@ -81,34 +85,19 @@ void Asymp :: setTime(StkFloat time)
constant_ = ( 1.0 - factor_ ) * target_;
}
void Asymp :: setTarget(StkFloat target)
void Asymp :: setTarget( StkFloat target )
{
Envelope::setTarget( target );
target_ = target;
if ( value_ != target_ ) state_ = 1;
constant_ = ( 1.0 - factor_ ) * target_;
}
StkFloat Asymp :: computeSample(void)
void Asymp :: setValue( StkFloat value )
{
if (state_) {
value_ = factor_ * value_ + constant_;
// Check threshold.
if ( target_ > value_ ) {
if ( target_ - value_ <= TARGET_THRESHOLD ) {
value_ = target_;
state_ = 0;
}
}
else {
if ( value_ - target_ <= TARGET_THRESHOLD ) {
value_ = target_;
state_ = 0;
}
}
}
lastOutput_ = value_;
return value_;
state_ = 0;
target_ = value;
value_ = value;
}
} // stk namespace

View File

@@ -25,7 +25,7 @@
- Tibetan Bowl = 3
by Georg Essl, 1999 - 2004.
Modified for Stk 4.0 by Gary Scavone.
Modified for STK 4.0 by Gary Scavone.
*/
/***************************************************/
@@ -33,7 +33,9 @@
#include "SKINI.msg"
#include <cmath>
BandedWG :: BandedWG()
namespace stk {
BandedWG :: BandedWG( void )
{
doPluck_ = true;
@@ -55,22 +57,22 @@ BandedWG :: BandedWG()
strikeAmp_ = 0.0;
}
BandedWG :: ~BandedWG()
BandedWG :: ~BandedWG( void )
{
}
void BandedWG :: clear()
void BandedWG :: clear( void )
{
for (int i=0; i<nModes_; i++) {
for ( int i=0; i<nModes_; i++ ) {
delay_[i].clear();
bandpass_[i].clear();
}
}
void BandedWG :: setPreset(int preset)
void BandedWG :: setPreset( int preset )
{
int i;
switch (preset){
switch ( preset ) {
case 1: // Tuned Bar
presetModes_ = 4;
@@ -167,7 +169,7 @@ void BandedWG :: setPreset(int preset)
setFrequency( frequency_ );
}
void BandedWG :: setFrequency(StkFloat frequency)
void BandedWG :: setFrequency( StkFloat frequency )
{
frequency_ = frequency;
if ( frequency <= 0.0 ) {
@@ -208,25 +210,25 @@ void BandedWG :: setFrequency(StkFloat frequency)
//strikePosition_ = (int)(strikePosition_*(length/modes_[0])/olen);
}
void BandedWG :: setStrikePosition(StkFloat position)
void BandedWG :: setStrikePosition( StkFloat position )
{
strikePosition_ = (int)(delay_[0].getDelay() * position / 2.0);
}
void BandedWG :: startBowing(StkFloat amplitude, StkFloat rate)
void BandedWG :: startBowing( StkFloat amplitude, StkFloat rate )
{
adsr_.setRate(rate);
adsr_.setAttackRate(rate);
adsr_.keyOn();
maxVelocity_ = 0.03 + (0.1 * amplitude);
}
void BandedWG :: stopBowing(StkFloat rate)
void BandedWG :: stopBowing( StkFloat rate )
{
adsr_.setRate(rate);
adsr_.setReleaseRate(rate);
adsr_.keyOff();
}
void BandedWG :: pluck(StkFloat amplitude)
void BandedWG :: pluck( StkFloat amplitude )
{
int j;
StkFloat min_len = delay_[nModes_-1].getDelay();
@@ -237,7 +239,7 @@ void BandedWG :: pluck(StkFloat amplitude)
// strikeAmp_ += amplitude;
}
void BandedWG :: noteOn(StkFloat frequency, StkFloat amplitude)
void BandedWG :: noteOn( StkFloat frequency, StkFloat amplitude )
{
this->setFrequency(frequency);
@@ -252,7 +254,7 @@ void BandedWG :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
void BandedWG :: noteOff(StkFloat amplitude)
void BandedWG :: noteOff( StkFloat amplitude )
{
if ( !doPluck_ )
this->stopBowing((1.0 - amplitude) * 0.005);
@@ -263,7 +265,7 @@ void BandedWG :: noteOff(StkFloat amplitude)
#endif
}
StkFloat BandedWG :: computeSample()
StkFloat BandedWG :: tick( unsigned int )
{
int k;
@@ -274,12 +276,12 @@ StkFloat BandedWG :: computeSample()
// strikeAmp_ = 0.0;
}
else {
if (integrationConstant_ == 0.0)
if ( integrationConstant_ == 0.0 )
velocityInput_ = 0.0;
else
velocityInput_ = integrationConstant_ * velocityInput_;
for (k=0; k<nModes_; k++)
for ( k=0; k<nModes_; k++ )
velocityInput_ += baseGain_ * delay_[k].lastOut();
if ( trackVelocity_ ) {
@@ -296,18 +298,18 @@ StkFloat BandedWG :: computeSample()
}
StkFloat data = 0.0;
for (k=0; k<nModes_; k++) {
for ( k=0; k<nModes_; k++ ) {
bandpass_[k].tick(input + gains_[k] * delay_[k].lastOut());
delay_[k].tick(bandpass_[k].lastOut());
data += bandpass_[k].lastOut();
}
//lastOutput = data * nModes_;
lastOutput_ = data * 4;
return lastOutput_;
//lastFrame_[0] = data * nModes_;
lastFrame_[0] = data * 4;
return lastFrame_[0];
}
void BandedWG :: controlChange(int number, StkFloat value)
void BandedWG :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -375,4 +377,4 @@ void BandedWG :: controlChange(int number, StkFloat value)
#endif
}
} // stk namespace

View File

@@ -28,43 +28,45 @@
type who should worry about this (making
money) worry away.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "BeeThree.h"
BeeThree :: BeeThree()
namespace stk {
BeeThree :: BeeThree( void )
: FM()
{
// Concatenate the STK rawwave path to the rawwave files
for ( unsigned int i=0; i<3; i++ )
waves_[i] = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
waves_[3] = new WaveLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
waves_[i] = new FileLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
waves_[3] = new FileLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
this->setRatio(0, 0.999);
this->setRatio(1, 1.997);
this->setRatio(2, 3.006);
this->setRatio(3, 6.009);
this->setRatio( 0, 0.999 );
this->setRatio( 1, 1.997 );
this->setRatio( 2, 3.006 );
this->setRatio( 3, 6.009 );
gains_[0] = fmGains_[95];
gains_[1] = fmGains_[95];
gains_[2] = fmGains_[99];
gains_[3] = fmGains_[95];
adsr_[0]->setAllTimes( 0.005, 0.003, 1.0, 0.01);
adsr_[1]->setAllTimes( 0.005, 0.003, 1.0, 0.01);
adsr_[2]->setAllTimes( 0.005, 0.003, 1.0, 0.01);
adsr_[3]->setAllTimes( 0.005, 0.001, 0.4, 0.03);
adsr_[0]->setAllTimes( 0.005, 0.003, 1.0, 0.01 );
adsr_[1]->setAllTimes( 0.005, 0.003, 1.0, 0.01 );
adsr_[2]->setAllTimes( 0.005, 0.003, 1.0, 0.01 );
adsr_[3]->setAllTimes( 0.005, 0.001, 0.4, 0.03 );
twozero_.setGain( 0.1 );
}
BeeThree :: ~BeeThree()
BeeThree :: ~BeeThree( void )
{
}
void BeeThree :: noteOn(StkFloat frequency, StkFloat amplitude)
void BeeThree :: noteOn( StkFloat frequency, StkFloat amplitude )
{
gains_[0] = amplitude * fmGains_[95];
gains_[1] = amplitude * fmGains_[95];
@@ -79,28 +81,4 @@ void BeeThree :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
StkFloat BeeThree :: computeSample()
{
register StkFloat temp;
if (modDepth_ > 0.0) {
temp = 1.0 + (modDepth_ * vibrato_.tick() * 0.1);
waves_[0]->setFrequency(baseFrequency_ * temp * ratios_[0]);
waves_[1]->setFrequency(baseFrequency_ * temp * ratios_[1]);
waves_[2]->setFrequency(baseFrequency_ * temp * ratios_[2]);
waves_[3]->setFrequency(baseFrequency_ * temp * ratios_[3]);
}
waves_[3]->addPhaseOffset( twozero_.lastOut() );
temp = control1_ * 2.0 * gains_[3] * adsr_[3]->tick() * waves_[3]->tick();
twozero_.tick(temp);
temp += control2_ * 2.0 * gains_[2] * adsr_[2]->tick() * waves_[2]->tick();
temp += gains_[1] * adsr_[1]->tick() * waves_[1]->tick();
temp += gains_[0] * adsr_[0]->tick() * waves_[0]->tick();
lastOutput_ = temp * 0.125;
return lastOutput_;
}
} // stk namespace

View File

@@ -2,26 +2,28 @@
/*! \class BiQuad
\brief STK biquad (two-pole, two-zero) filter class.
This protected Filter subclass implements a
two-pole, two-zero digital filter. A method
is provided for creating a resonance in the
frequency response while maintaining a constant
filter gain.
This class implements a two-pole, two-zero digital filter.
Methods are provided for creating a resonance or notch in the
frequency response while maintaining a constant filter gain.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "BiQuad.h"
#include <cmath>
namespace stk {
BiQuad :: BiQuad() : Filter()
{
std::vector<StkFloat> b(3, 0.0);
std::vector<StkFloat> a(3, 0.0);
b[0] = 1.0;
a[0] = 1.0;
Filter::setCoefficients( b, a );
b_.resize( 3, 0.0 );
a_.resize( 3, 0.0 );
b_[0] = 1.0;
a_[0] = 1.0;
inputs_.resize( 3, 1, 0.0 );
outputs_.resize( 3, 1, 0.0 );
Stk::addSampleRateAlert( this );
}
@@ -30,6 +32,17 @@ BiQuad :: ~BiQuad()
Stk::removeSampleRateAlert( this );
}
void BiQuad :: setCoefficients( StkFloat b0, StkFloat b1, StkFloat b2, StkFloat a1, StkFloat a2, bool clearState )
{
b_[0] = b0;
b_[1] = b1;
b_[2] = b2;
a_[1] = a1;
a_[2] = a2;
if ( clearState ) this->clear();
}
void BiQuad :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
{
if ( !ignoreSampleRateChange_ ) {
@@ -38,40 +51,10 @@ void BiQuad :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
}
}
void BiQuad :: clear(void)
{
Filter::clear();
}
void BiQuad :: setB0(StkFloat b0)
{
b_[0] = b0;
}
void BiQuad :: setB1(StkFloat b1)
{
b_[1] = b1;
}
void BiQuad :: setB2(StkFloat b2)
{
b_[2] = b2;
}
void BiQuad :: setA1(StkFloat a1)
{
a_[1] = a1;
}
void BiQuad :: setA2(StkFloat a2)
{
a_[2] = a2;
}
void BiQuad :: setResonance(StkFloat frequency, StkFloat radius, bool normalize)
{
a_[2] = radius * radius;
a_[1] = -2.0 * radius * cos(TWO_PI * frequency / Stk::sampleRate());
a_[1] = -2.0 * radius * cos( TWO_PI * frequency / Stk::sampleRate() );
if ( normalize ) {
// Use zeros at +- 1 and normalize the filter peak gain.
@@ -85,7 +68,7 @@ void BiQuad :: setNotch(StkFloat frequency, StkFloat radius)
{
// This method does not attempt to normalize the filter gain.
b_[2] = radius * radius;
b_[1] = (StkFloat) -2.0 * radius * cos(TWO_PI * (double) frequency / Stk::sampleRate());
b_[1] = (StkFloat) -2.0 * radius * cos( TWO_PI * (double) frequency / Stk::sampleRate() );
}
void BiQuad :: setEqualGainZeroes()
@@ -95,17 +78,4 @@ void BiQuad :: setEqualGainZeroes()
b_[2] = -1.0;
}
void BiQuad :: setGain(StkFloat gain)
{
Filter::setGain(gain);
}
StkFloat BiQuad :: getGain(void) const
{
return Filter::getGain();
}
StkFloat BiQuad :: lastOut(void) const
{
return Filter::lastOut();
}
} // stk namespace

View File

@@ -22,8 +22,8 @@
/***************************************************/
#include "Blit.h"
#include <cmath>
#include <limits>
namespace stk {
Blit:: Blit( StkFloat frequency )
{
@@ -39,7 +39,7 @@ Blit :: ~Blit()
void Blit :: reset()
{
phase_ = 0.0;
lastOutput_ = 0;
lastFrame_[0] = 0.0;
}
void Blit :: setFrequency( StkFloat frequency )
@@ -75,31 +75,4 @@ void Blit :: updateHarmonics( void )
#endif
}
StkFloat Blit :: computeSample( void )
{
// The code below implements the SincM algorithm of Stilson and
// Smith with an additional scale factor of P / M applied to
// normalize the output.
// A fully optimized version of this code would replace the two sin
// calls with a pair of fast sin oscillators, for which stable fast
// two-multiply algorithms are well known. In the spirit of STK,
// which favors clarity over performance, the optimization has not
// been made here.
// Avoid a divide by zero at the sinc peak, which has a limiting
// value of 1.0.
StkFloat denominator = sin( phase_ );
if ( denominator <= std::numeric_limits<StkFloat>::epsilon() ) {
lastOutput_ = 1.0;
} else {
lastOutput_ = sin( m_ * phase_ );
lastOutput_ /= m_ * denominator;
}
phase_ += rate_;
if ( phase_ >= PI ) phase_ -= PI;
return lastOutput_;
}
} // stk namespace

View File

@@ -20,8 +20,8 @@
/***************************************************/
#include "BlitSaw.h"
#include <cmath>
#include <limits>
namespace stk {
BlitSaw:: BlitSaw( StkFloat frequency )
{
@@ -38,7 +38,7 @@ void BlitSaw :: reset()
{
phase_ = 0.0f;
state_ = 0.0;
lastOutput_ = 0;
lastFrame_[0] = 0.0;
}
void BlitSaw :: setFrequency( StkFloat frequency )
@@ -88,38 +88,4 @@ void BlitSaw :: updateHarmonics( void )
#endif
}
StkFloat BlitSaw :: computeSample( void )
{
// The code below implements the BLIT algorithm of Stilson and
// Smith, followed by a summation and filtering operation to produce
// a sawtooth waveform. After experimenting with various approaches
// to calculate the average value of the BLIT over one period, I
// found that an estimate of C2_ = 1.0 / period (in samples) worked
// most consistently. A "leaky integrator" is then applied to the
// difference of the BLIT output and C2_. (GPS - 1 October 2005)
// A fully optimized version of this code would replace the two sin
// calls with a pair of fast sin oscillators, for which stable fast
// two-multiply algorithms are well known. In the spirit of STK,
// which favors clarity over performance, the optimization has
// not been made here.
// Avoid a divide by zero, or use of a denormalized divisor
// at the sinc peak, which has a limiting value of m_ / p_.
StkFloat denominator = sin( phase_ );
if ( fabs(denominator) <= std::numeric_limits<StkFloat>::epsilon() )
lastOutput_ = a_;
else {
lastOutput_ = sin( m_ * phase_ );
lastOutput_ /= p_ * denominator;
}
lastOutput_ += state_ - C2_;
state_ = lastOutput_ * 0.995;
phase_ += rate_;
if ( phase_ >= PI ) phase_ -= PI;
return lastOutput_;
}
} // stk namespace

View File

@@ -25,14 +25,14 @@
Blit waveforms. This class is not guaranteed to be well behaved
in the presence of significant aliasing.
Based on initial code of Robin Davies, 2005.
Modified algorithm code by Gary Scavone, 2005 - 2006.
Based on initial code of Robin Davies, 2005
Modified algorithm code by Gary Scavone, 2005 - 2009.
*/
/***************************************************/
#include "BlitSquare.h"
#include <cmath>
#include <limits>
namespace stk {
BlitSquare:: BlitSquare( StkFloat frequency )
{
@@ -48,7 +48,7 @@ BlitSquare :: ~BlitSquare()
void BlitSquare :: reset()
{
phase_ = 0.0;
lastOutput_ = 0;
lastFrame_[0] = 0.0;
dcbState_ = 0.0;
lastBlitOutput_ = 0;
}
@@ -92,40 +92,4 @@ void BlitSquare :: updateHarmonics( void )
#endif
}
StkFloat BlitSquare :: computeSample( void )
{
StkFloat temp = lastBlitOutput_;
// A fully optimized version of this would replace the two sin calls
// with a pair of fast sin oscillators, for which stable fast
// two-multiply algorithms are well known. In the spirit of STK,
// which favors clarity over performance, the optimization has
// not been made here.
// Avoid a divide by zero, or use of a denomralized divisor
// at the sinc peak, which has a limiting value of 1.0.
StkFloat denominator = sin( phase_ );
if ( fabs( denominator ) < std::numeric_limits<StkFloat>::epsilon() ) {
// Inexact comparison safely distinguishes betwen *close to zero*, and *close to PI*.
if ( phase_ < 0.1f || phase_ > TWO_PI - 0.1f )
lastBlitOutput_ = a_;
else
lastBlitOutput_ = -a_;
}
else {
lastBlitOutput_ = sin( m_ * phase_ );
lastBlitOutput_ /= p_ * denominator;
}
lastBlitOutput_ += temp;
// Now apply DC blocker.
lastOutput_ = lastBlitOutput_ - dcbState_ + 0.999 * lastOutput_;
dcbState_ = lastBlitOutput_;
phase_ += rate_;
if ( phase_ >= TWO_PI ) phase_ -= TWO_PI;
return lastOutput_;
}
} // stk namespace

View File

@@ -12,16 +12,18 @@
- Vibrato Gain = 1
- Volume = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "BlowBotl.h"
#include "SKINI.msg"
namespace stk {
#define __BOTTLE_RADIUS_ 0.999
BlowBotl :: BlowBotl()
BlowBotl :: BlowBotl( void )
{
dcBlock_.setBlockZero();
@@ -35,16 +37,16 @@ BlowBotl :: BlowBotl()
maxPressure_ = (StkFloat) 0.0;
}
BlowBotl :: ~BlowBotl()
BlowBotl :: ~BlowBotl( void )
{
}
void BlowBotl :: clear()
void BlowBotl :: clear( void )
{
resonator_.clear();
}
void BlowBotl :: setFrequency(StkFloat frequency)
void BlowBotl :: setFrequency( StkFloat frequency )
{
StkFloat freakency = frequency;
if ( frequency <= 0.0 ) {
@@ -56,20 +58,20 @@ void BlowBotl :: setFrequency(StkFloat frequency)
resonator_.setResonance( freakency, __BOTTLE_RADIUS_, true );
}
void BlowBotl :: startBlowing(StkFloat amplitude, StkFloat rate)
void BlowBotl :: startBlowing( StkFloat amplitude, StkFloat rate )
{
adsr_.setAttackRate(rate);
maxPressure_ = amplitude;
adsr_.keyOn();
}
void BlowBotl :: stopBlowing(StkFloat rate)
void BlowBotl :: stopBlowing( StkFloat rate )
{
adsr_.setReleaseRate(rate);
adsr_.keyOff();
}
void BlowBotl :: noteOn(StkFloat frequency, StkFloat amplitude)
void BlowBotl :: noteOn( StkFloat frequency, StkFloat amplitude )
{
this->setFrequency(frequency);
startBlowing( 1.1 + (amplitude * 0.20), amplitude * 0.02);
@@ -81,7 +83,7 @@ void BlowBotl :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
void BlowBotl :: noteOff(StkFloat amplitude)
void BlowBotl :: noteOff( StkFloat amplitude )
{
this->stopBlowing(amplitude * 0.02);
@@ -91,29 +93,7 @@ void BlowBotl :: noteOff(StkFloat amplitude)
#endif
}
StkFloat BlowBotl :: computeSample()
{
StkFloat breathPressure;
StkFloat randPressure;
StkFloat pressureDiff;
// Calculate the breath pressure (envelope + vibrato)
breathPressure = maxPressure_ * adsr_.tick();
breathPressure += vibratoGain_ * vibrato_.tick();
pressureDiff = breathPressure - resonator_.lastOut();
randPressure = noiseGain_ * noise_.tick();
randPressure *= breathPressure;
randPressure *= (1.0 + pressureDiff);
resonator_.tick( breathPressure + randPressure - ( jetTable_.tick( pressureDiff ) * pressureDiff ) );
lastOutput_ = 0.2 * outputGain_ * dcBlock_.tick( pressureDiff );
return lastOutput_;
}
void BlowBotl :: controlChange(int number, StkFloat value)
void BlowBotl :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -145,3 +125,5 @@ void BlowBotl :: controlChange(int number, StkFloat value)
handleError( StkError::DEBUG_WARNING );
#endif
}
} // stk namespace

View File

@@ -29,17 +29,19 @@
- Register State = 1
- Breath Pressure = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "BlowHole.h"
#include "SKINI.msg"
#include <math.h>
#include <cmath>
BlowHole :: BlowHole(StkFloat lowestFrequency)
namespace stk {
BlowHole :: BlowHole( StkFloat lowestFrequency )
{
length_ = (unsigned long) (Stk::sampleRate() / lowestFrequency + 1);
length_ = (unsigned long) ( Stk::sampleRate() / lowestFrequency + 1 );
// delays[0] is the delay line between the reed and the register vent.
delays_[0].setDelay( 5.0 * Stk::sampleRate() / 22050.0 );
// delays[1] is the delay line between the register vent and the tonehole.
@@ -83,11 +85,11 @@ BlowHole :: BlowHole(StkFloat lowestFrequency)
vibratoGain_ = 0.01;
}
BlowHole :: ~BlowHole()
BlowHole :: ~BlowHole( void )
{
}
void BlowHole :: clear()
void BlowHole :: clear( void )
{
delays_[0].clear();
delays_[1].clear();
@@ -97,7 +99,7 @@ void BlowHole :: clear()
vent_.tick( 0.0 );
}
void BlowHole :: setFrequency(StkFloat frequency)
void BlowHole :: setFrequency( StkFloat frequency )
{
StkFloat freakency = frequency;
if ( frequency <= 0.0 ) {
@@ -114,7 +116,7 @@ void BlowHole :: setFrequency(StkFloat frequency)
delays_[1].setDelay(delay);
}
void BlowHole :: setVent(StkFloat newValue)
void BlowHole :: setVent( StkFloat newValue )
{
// This method allows setting of the register vent "open-ness" at
// any point between "Open" (newValue = 1) and "Closed"
@@ -132,7 +134,7 @@ void BlowHole :: setVent(StkFloat newValue)
vent_.setGain( gain );
}
void BlowHole :: setTonehole(StkFloat newValue)
void BlowHole :: setTonehole( StkFloat newValue )
{
// This method allows setting of the tonehole "open-ness" at
// any point between "Open" (newValue = 1) and "Closed"
@@ -150,19 +152,19 @@ void BlowHole :: setTonehole(StkFloat newValue)
tonehole_.setB0( new_coeff );
}
void BlowHole :: startBlowing(StkFloat amplitude, StkFloat rate)
void BlowHole :: startBlowing( StkFloat amplitude, StkFloat rate )
{
envelope_.setRate( rate );
envelope_.setTarget( amplitude );
}
void BlowHole :: stopBlowing(StkFloat rate)
void BlowHole :: stopBlowing( StkFloat rate )
{
envelope_.setRate( rate );
envelope_.setTarget( 0.0 );
}
void BlowHole :: noteOn(StkFloat frequency, StkFloat amplitude)
void BlowHole :: noteOn( StkFloat frequency, StkFloat amplitude )
{
this->setFrequency( frequency );
this->startBlowing( 0.55 + (amplitude * 0.30), amplitude * 0.005 );
@@ -174,7 +176,7 @@ void BlowHole :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
void BlowHole :: noteOff(StkFloat amplitude)
void BlowHole :: noteOff( StkFloat amplitude )
{
this->stopBlowing( amplitude * 0.01 );
@@ -184,42 +186,7 @@ void BlowHole :: noteOff(StkFloat amplitude)
#endif
}
StkFloat BlowHole :: computeSample()
{
StkFloat pressureDiff;
StkFloat breathPressure;
StkFloat temp;
// Calculate the breath pressure (envelope + noise + vibrato)
breathPressure = envelope_.tick();
breathPressure += breathPressure * noiseGain_ * noise_.tick();
breathPressure += breathPressure * vibratoGain_ * vibrato_.tick();
// Calculate the differential pressure = reflected - mouthpiece pressures
pressureDiff = delays_[0].lastOut() - breathPressure;
// Do two-port junction scattering for register vent
StkFloat pa = breathPressure + pressureDiff * reedTable_.tick( pressureDiff );
StkFloat pb = delays_[1].lastOut();
vent_.tick( pa+pb );
lastOutput_ = delays_[0].tick( vent_.lastOut()+pb );
lastOutput_ *= outputGain_;
// Do three-port junction scattering (under tonehole)
pa += vent_.lastOut();
pb = delays_[2].lastOut();
StkFloat pth = tonehole_.lastOut();
temp = scatter_ * (pa + pb - 2 * pth);
delays_[2].tick( filter_.tick(pa + temp) * -0.95 );
delays_[1].tick( pb + temp );
tonehole_.tick( pa + pb - pth + temp );
return lastOutput_;
}
void BlowHole :: controlChange(int number, StkFloat value)
void BlowHole :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -253,3 +220,5 @@ void BlowHole :: controlChange(int number, StkFloat value)
handleError( StkError::DEBUG_WARNING );
#endif
}
} // stk namespace

View File

@@ -1,51 +0,0 @@
/***************************************************/
/*! \class BowTable
\brief STK bowed string table class.
This class implements a simple bowed string
non-linear function, as described by Smith (1986).
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
*/
/***************************************************/
#include "BowTable.h"
#include <math.h>
BowTable :: BowTable()
{
offset_ = (StkFloat) 0.0;
slope_ = (StkFloat) 0.1;
}
BowTable :: ~BowTable()
{
}
void BowTable :: setOffset(StkFloat offset)
{
offset_ = offset;
}
void BowTable :: setSlope(StkFloat slope)
{
slope_ = slope;
}
StkFloat BowTable :: computeSample(StkFloat input)
{
// The input represents differential string vs. bow velocity.
StkFloat sample;
sample = input + offset_; // add bias to input
sample *= slope_; // then scale it
lastOutput_ = (StkFloat) fabs( (double) sample ) + (StkFloat) 0.75;
lastOutput_ = (StkFloat) pow( lastOutput_, (StkFloat) -4.0 );
// Set minimum friction to 0.0
// if (lastOutput < 0.0 ) lastOutput = 0.0;
// Set maximum friction to 1.0.
if (lastOutput_ > 1.0 ) lastOutput_ = (StkFloat) 1.0;
return lastOutput_;
}

View File

@@ -17,14 +17,16 @@
- Vibrato Gain = 1
- Volume = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Bowed.h"
#include "SKINI.msg"
Bowed :: Bowed(StkFloat lowestFrequency)
namespace stk {
Bowed :: Bowed( StkFloat lowestFrequency )
{
unsigned long length;
length = (long) ( Stk::sampleRate() / lowestFrequency + 1 );
@@ -54,17 +56,17 @@ Bowed :: Bowed(StkFloat lowestFrequency)
this->setFrequency( 220.0 );
}
Bowed :: ~Bowed()
Bowed :: ~Bowed( void )
{
}
void Bowed :: clear()
void Bowed :: clear( void )
{
neckDelay_.clear();
bridgeDelay_.clear();
}
void Bowed :: setFrequency(StkFloat frequency)
void Bowed :: setFrequency( StkFloat frequency )
{
StkFloat freakency = frequency;
if ( frequency <= 0.0 ) {
@@ -80,20 +82,20 @@ void Bowed :: setFrequency(StkFloat frequency)
neckDelay_.setDelay( baseDelay_ * (1.0 - betaRatio_) ); // bow to nut (finger) length
}
void Bowed :: startBowing(StkFloat amplitude, StkFloat rate)
void Bowed :: startBowing( StkFloat amplitude, StkFloat rate )
{
adsr_.setRate( rate );
adsr_.setAttackRate( rate );
adsr_.keyOn();
maxVelocity_ = 0.03 + ( 0.2 * amplitude );
}
void Bowed :: stopBowing(StkFloat rate)
void Bowed :: stopBowing( StkFloat rate )
{
adsr_.setRate( rate );
adsr_.setReleaseRate( rate );
adsr_.keyOff();
}
void Bowed :: noteOn(StkFloat frequency, StkFloat amplitude)
void Bowed :: noteOn( StkFloat frequency, StkFloat amplitude )
{
this->startBowing( amplitude, amplitude * 0.001 );
this->setFrequency( frequency );
@@ -104,7 +106,7 @@ void Bowed :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
void Bowed :: noteOff(StkFloat amplitude)
void Bowed :: noteOff( StkFloat amplitude )
{
this->stopBowing( (1.0 - amplitude) * 0.005 );
@@ -114,41 +116,12 @@ void Bowed :: noteOff(StkFloat amplitude)
#endif
}
void Bowed :: setVibrato(StkFloat gain)
void Bowed :: setVibrato( StkFloat gain )
{
vibratoGain_ = gain;
}
StkFloat Bowed :: computeSample()
{
StkFloat bowVelocity;
StkFloat bridgeRefl;
StkFloat nutRefl;
StkFloat newVel;
StkFloat velDiff;
StkFloat stringVel;
bowVelocity = maxVelocity_ * adsr_.tick();
bridgeRefl = -stringFilter_.tick( bridgeDelay_.lastOut() );
nutRefl = -neckDelay_.lastOut();
stringVel = bridgeRefl + nutRefl; // Sum is String Velocity
velDiff = bowVelocity - stringVel; // Differential Velocity
newVel = velDiff * bowTable_.tick( velDiff ); // Non-Linear Bow Function
neckDelay_.tick(bridgeRefl + newVel); // Do string propagations
bridgeDelay_.tick(nutRefl + newVel);
if ( vibratoGain_ > 0.0 ) {
neckDelay_.setDelay( (baseDelay_ * (1.0 - betaRatio_) ) +
(baseDelay_ * vibratoGain_ * vibrato_.tick()) );
}
lastOutput_ = bodyFilter_.tick( bridgeDelay_.lastOut() );
return lastOutput_;
}
void Bowed :: controlChange(int number, StkFloat value)
void Bowed :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -185,3 +158,5 @@ void Bowed :: controlChange(int number, StkFloat value)
handleError( StkError::DEBUG_WARNING );
#endif
}
} // stk namespace

View File

@@ -16,7 +16,7 @@
- Vibrato Gain = 1
- Volume = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
@@ -24,16 +24,18 @@
#include "SKINI.msg"
#include <cmath>
Brass :: Brass(StkFloat lowestFrequency)
namespace stk {
Brass :: Brass( StkFloat lowestFrequency )
{
length_ = (unsigned long) (Stk::sampleRate() / lowestFrequency + 1);
length_ = (unsigned long) ( Stk::sampleRate() / lowestFrequency + 1 );
delayLine_.setMaximumDelay( length_ );
delayLine_.setDelay( 0.5 * length_ );
lipFilter_.setGain( 0.03 );
dcBlock_.setBlockZero();
adsr_.setAllTimes( 0.005, 0.001, 1.0, 0.010);
adsr_.setAllTimes( 0.005, 0.001, 1.0, 0.010 );
vibrato_.setFrequency( 6.137 );
vibratoGain_ = 0.0;
@@ -46,18 +48,18 @@ Brass :: Brass(StkFloat lowestFrequency)
this->setFrequency( 220.0 );
}
Brass :: ~Brass()
Brass :: ~Brass( void )
{
}
void Brass :: clear()
void Brass :: clear( void )
{
delayLine_.clear();
lipFilter_.clear();
dcBlock_.clear();
}
void Brass :: setFrequency(StkFloat frequency)
void Brass :: setFrequency( StkFloat frequency )
{
StkFloat freakency = frequency;
if ( frequency <= 0.0 ) {
@@ -74,7 +76,7 @@ void Brass :: setFrequency(StkFloat frequency)
lipFilter_.setResonance( freakency, 0.997 );
}
void Brass :: setLip(StkFloat frequency)
void Brass :: setLip( StkFloat frequency )
{
StkFloat freakency = frequency;
if ( frequency <= 0.0 ) {
@@ -86,20 +88,20 @@ void Brass :: setLip(StkFloat frequency)
lipFilter_.setResonance( freakency, 0.997 );
}
void Brass :: startBlowing(StkFloat amplitude, StkFloat rate)
void Brass :: startBlowing( StkFloat amplitude, StkFloat rate )
{
adsr_.setAttackRate( rate );
maxPressure_ = amplitude;
adsr_.keyOn();
}
void Brass :: stopBlowing(StkFloat rate)
void Brass :: stopBlowing( StkFloat rate )
{
adsr_.setReleaseRate( rate );
adsr_.keyOff();
}
void Brass :: noteOn(StkFloat frequency, StkFloat amplitude)
void Brass :: noteOn( StkFloat frequency, StkFloat amplitude )
{
this->setFrequency( frequency );
this->startBlowing( amplitude, amplitude * 0.001 );
@@ -110,7 +112,7 @@ void Brass :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
void Brass :: noteOff(StkFloat amplitude)
void Brass :: noteOff( StkFloat amplitude )
{
this->stopBlowing( amplitude * 0.005 );
@@ -120,26 +122,7 @@ void Brass :: noteOff(StkFloat amplitude)
#endif
}
StkFloat Brass :: computeSample()
{
StkFloat breathPressure = maxPressure_ * adsr_.tick();
breathPressure += vibratoGain_ * vibrato_.tick();
StkFloat mouthPressure = 0.3 * breathPressure;
StkFloat borePressure = 0.85 * delayLine_.lastOut();
StkFloat deltaPressure = mouthPressure - borePressure; // Differential pressure.
deltaPressure = lipFilter_.tick( deltaPressure ); // Force - > position.
deltaPressure *= deltaPressure; // Basic position to area mapping.
if ( deltaPressure > 1.0 ) deltaPressure = 1.0; // Non-linear saturation.
// The following input scattering assumes the mouthPressure = area.
lastOutput_ = deltaPressure * mouthPressure + ( 1.0 - deltaPressure) * borePressure;
lastOutput_ = delayLine_.tick( dcBlock_.tick( lastOutput_ ) );
return lastOutput_;
}
void Brass :: controlChange(int number, StkFloat value)
void Brass :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -175,3 +158,5 @@ void Brass :: controlChange(int number, StkFloat value)
handleError( StkError::DEBUG_WARNING );
#endif
}
} // stk namespace

View File

@@ -2,60 +2,45 @@
/*! \class Chorus
\brief STK chorus effect class.
This class implements a chorus effect.
This class implements a chorus effect. It takes a monophonic
input signal and produces a stereo output signal.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Chorus.h"
#include <iostream>
Chorus :: Chorus(StkFloat baseDelay)
namespace stk {
Chorus :: Chorus( StkFloat baseDelay )
{
lastFrame_.resize( 1, 2, 0.0 ); // resize lastFrame_ for stereo output
delayLine_[0].setMaximumDelay( (unsigned long) (baseDelay * 1.414) + 2);
delayLine_[0].setDelay( baseDelay );
delayLine_[1].setMaximumDelay( (unsigned long) (baseDelay * 1.414) + 2);
delayLine_[1].setDelay( baseDelay );
baseLength_ = baseDelay;
mods_[0].setFrequency(0.2);
mods_[1].setFrequency(0.222222);
mods_[0].setFrequency( 0.2 );
mods_[1].setFrequency( 0.222222 );
modDepth_ = 0.05;
effectMix_ = 0.5;
this->clear();
}
Chorus :: ~Chorus()
{
}
void Chorus :: clear()
void Chorus :: clear( void )
{
delayLine_[0].clear();
delayLine_[1].clear();
lastOutput_[0] = 0.0;
lastOutput_[1] = 0.0;
lastFrame_[0] = 0.0;
lastFrame_[1] = 0.0;
}
void Chorus :: setModDepth(StkFloat depth)
void Chorus :: setModFrequency( StkFloat frequency )
{
modDepth_ = depth;
mods_[0].setFrequency( frequency );
mods_[1].setFrequency( frequency * 1.1111 );
}
void Chorus :: setModFrequency(StkFloat frequency)
{
mods_[0].setFrequency(frequency);
mods_[1].setFrequency(frequency * 1.1111);
}
StkFloat Chorus :: computeSample(StkFloat input)
{
delayLine_[0].setDelay( baseLength_ * 0.707 * (1.0 + modDepth_ * mods_[0].tick()) );
delayLine_[1].setDelay( baseLength_ * 0.5 * (1.0 - modDepth_ * mods_[1].tick()) );
lastOutput_[0] = input * (1.0 - effectMix_);
lastOutput_[0] += effectMix_ * delayLine_[0].tick(input);
lastOutput_[1] = input * (1.0 - effectMix_);
lastOutput_[1] += effectMix_ * delayLine_[1].tick(input);
return Effect::lastOut();
}
} // stk namespace

View File

@@ -18,14 +18,16 @@
- Vibrato Gain = 1
- Breath Pressure = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Clarinet.h"
#include "SKINI.msg"
Clarinet :: Clarinet(StkFloat lowestFrequency)
namespace stk {
Clarinet :: Clarinet( StkFloat lowestFrequency )
{
length_ = (long) (Stk::sampleRate() / lowestFrequency + 1);
delayLine_.setMaximumDelay( length_ );
@@ -39,17 +41,17 @@ Clarinet :: Clarinet(StkFloat lowestFrequency)
vibratoGain_ = (StkFloat) 0.1;
}
Clarinet :: ~Clarinet()
Clarinet :: ~Clarinet( void )
{
}
void Clarinet :: clear()
void Clarinet :: clear( void )
{
delayLine_.clear();
filter_.tick( 0.0 );
}
void Clarinet :: setFrequency(StkFloat frequency)
void Clarinet :: setFrequency( StkFloat frequency )
{
StkFloat freakency = frequency;
if ( frequency <= 0.0 ) {
@@ -65,19 +67,19 @@ void Clarinet :: setFrequency(StkFloat frequency)
delayLine_.setDelay(delay);
}
void Clarinet :: startBlowing(StkFloat amplitude, StkFloat rate)
void Clarinet :: startBlowing( StkFloat amplitude, StkFloat rate )
{
envelope_.setRate(rate);
envelope_.setTarget(amplitude);
}
void Clarinet :: stopBlowing(StkFloat rate)
void Clarinet :: stopBlowing( StkFloat rate )
{
envelope_.setRate(rate);
envelope_.setTarget((StkFloat) 0.0);
}
void Clarinet :: noteOn(StkFloat frequency, StkFloat amplitude)
void Clarinet :: noteOn( StkFloat frequency, StkFloat amplitude )
{
this->setFrequency(frequency);
this->startBlowing((StkFloat) 0.55 + (amplitude * (StkFloat) 0.30), amplitude * (StkFloat) 0.005);
@@ -89,7 +91,7 @@ void Clarinet :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
void Clarinet :: noteOff(StkFloat amplitude)
void Clarinet :: noteOff( StkFloat amplitude )
{
this->stopBlowing( amplitude * 0.01 );
@@ -99,32 +101,7 @@ void Clarinet :: noteOff(StkFloat amplitude)
#endif
}
StkFloat Clarinet :: computeSample()
{
StkFloat pressureDiff;
StkFloat breathPressure;
// Calculate the breath pressure (envelope + noise + vibrato)
breathPressure = envelope_.tick();
breathPressure += breathPressure * noiseGain_ * noise_.tick();
breathPressure += breathPressure * vibratoGain_ * vibrato_.tick();
// Perform commuted loss filtering.
pressureDiff = -0.95 * filter_.tick(delayLine_.lastOut());
// Calculate pressure difference of reflected and mouthpiece pressures.
pressureDiff = pressureDiff - breathPressure;
// Perform non-linear scattering using pressure difference in reed function.
lastOutput_ = delayLine_.tick(breathPressure + pressureDiff * reedTable_.tick(pressureDiff));
// Apply output gain.
lastOutput_ *= outputGain_;
return lastOutput_;
}
void Clarinet :: controlChange(int number, StkFloat value)
void Clarinet :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -158,3 +135,5 @@ void Clarinet :: controlChange(int number, StkFloat value)
handleError( StkError::DEBUG_WARNING );
#endif
}
} // stk namespace

View File

@@ -2,36 +2,23 @@
/*! \class Delay
\brief STK non-interpolating delay line class.
This protected Filter subclass implements
a non-interpolating digital delay-line.
A fixed maximum length of 4095 and a delay
of zero is set using the default constructor.
Alternatively, the delay and maximum length
can be set during instantiation with an
overloaded constructor.
This class implements a non-interpolating digital delay-line. If
the delay and maximum length are not specified during
instantiation, a fixed maximum length of 4095 and a delay of zero
is set.
A non-interpolating delay line is typically
used in fixed delay-length applications, such
as for reverberation.
A non-interpolating delay line is typically used in fixed
delay-length applications, such as for reverberation.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Delay.h"
Delay :: Delay() : Filter()
{
// Default maximum delay length set to 4095.
inputs_.resize( 4096 );
this->clear();
namespace stk {
inPoint_ = 0;
outPoint_ = 0;
delay_ = 0;
}
Delay :: Delay(unsigned long delay, unsigned long maxDelay)
Delay :: Delay( unsigned long delay, unsigned long maxDelay )
{
// Writing before reading allows delays from 0 to length-1.
// If we want to allow a delay of maxDelay, we need a
@@ -46,10 +33,8 @@ Delay :: Delay(unsigned long delay, unsigned long maxDelay)
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( maxDelay > inputs_.size()-1 ) {
inputs_.resize( maxDelay+1 );
this->clear();
}
if ( ( maxDelay + 1 ) > inputs_.size() )
inputs_.resize( maxDelay + 1, 1, 0.0 );
inPoint_ = 0;
this->setDelay( delay );
@@ -59,14 +44,7 @@ Delay :: ~Delay()
{
}
void Delay :: clear(void)
{
for (unsigned int i=0; i<inputs_.size(); i++)
inputs_[i] = 0.0;
outputs_[0] = 0.0;
}
void Delay :: setMaximumDelay(unsigned long delay)
void Delay :: setMaximumDelay( unsigned long delay )
{
if ( delay < inputs_.size() ) return;
@@ -75,7 +53,7 @@ void Delay :: setMaximumDelay(unsigned long delay)
handleError( StkError::WARNING );
return;
}
else if (delay < delay_ ) {
else if ( delay < delay_ ) {
errorString_ << "Delay::setMaximumDelay: argument (" << delay << ") less than current delay setting (" << delay_ << ")!\n";
handleError( StkError::WARNING );
return;
@@ -84,7 +62,7 @@ void Delay :: setMaximumDelay(unsigned long delay)
inputs_.resize( delay + 1 );
}
void Delay :: setDelay(unsigned long delay)
void Delay :: setDelay( unsigned long delay )
{
if ( delay > inputs_.size() - 1 ) { // The value is too big.
errorString_ << "Delay::setDelay: argument (" << delay << ") too big ... setting to maximum!\n";
@@ -109,26 +87,21 @@ void Delay :: setDelay(unsigned long delay)
}
}
unsigned long Delay :: getDelay(void) const
{
return (unsigned long) delay_;
}
StkFloat Delay :: energy(void) const
StkFloat Delay :: energy( void ) const
{
unsigned long i;
register StkFloat e = 0;
if (inPoint_ >= outPoint_) {
for (i=outPoint_; i<inPoint_; i++) {
if ( inPoint_ >= outPoint_ ) {
for ( i=outPoint_; i<inPoint_; i++ ) {
register StkFloat t = inputs_[i];
e += t*t;
}
} else {
for (i=outPoint_; i<inputs_.size(); i++) {
for ( i=outPoint_; i<inputs_.size(); i++ ) {
register StkFloat t = inputs_[i];
e += t*t;
}
for (i=0; i<inPoint_; i++) {
for ( i=0; i<inPoint_; i++ ) {
register StkFloat t = inputs_[i];
e += t*t;
}
@@ -136,60 +109,13 @@ StkFloat Delay :: energy(void) const
return e;
}
StkFloat Delay :: contentsAt(unsigned long tapDelay)
StkFloat Delay :: contentsAt( unsigned long tapDelay )
{
unsigned long i = tapDelay;
if (i < 1) {
errorString_ << "Delay::contentsAt: argument (" << tapDelay << ") too small!";
handleError( StkError::WARNING );
return 0.0;
}
else if (i > delay_) {
errorString_ << "Delay::contentsAt: argument (" << tapDelay << ") too big!";
handleError( StkError::WARNING );
return 0.0;
}
long tap = inPoint_ - i;
if (tap < 0) // Check for wraparound.
long tap = inPoint_ - tapDelay - 1;
while ( tap < 0 ) // Check for wraparound.
tap += inputs_.size();
return inputs_[tap];
}
StkFloat Delay :: lastOut(void) const
{
return Filter::lastOut();
}
StkFloat Delay :: nextOut(void)
{
return inputs_[outPoint_];
}
StkFloat Delay :: computeSample( StkFloat input )
{
inputs_[inPoint_++] = input;
// Check for end condition
if (inPoint_ == inputs_.size())
inPoint_ = 0;
// Read out next value
outputs_[0] = inputs_[outPoint_++];
if (outPoint_ == inputs_.size())
outPoint_ = 0;
return outputs_[0];
}
StkFloat Delay :: tick( StkFloat input )
{
return computeSample( input );
}
StkFrames& Delay :: tick( StkFrames& frames, unsigned int channel )
{
return Filter::tick( frames, channel );
}
} // stk namespace

View File

@@ -2,11 +2,10 @@
/*! \class DelayA
\brief STK allpass interpolating delay line class.
This Delay subclass implements a fractional-length digital
delay-line using a first-order allpass filter. A fixed maximum
length of 4095 and a delay of 0.5 is set using the default
constructor. Alternatively, the delay and maximum length can be
set during instantiation with an overloaded constructor.
This class implements a fractional-length digital delay-line using
a first-order allpass filter. If the delay and maximum length are
not specified during instantiation, a fixed maximum length of 4095
and a delay of zero is set.
An allpass filter has unity magnitude gain but variable phase
delay properties, making it useful in achieving fractional delays
@@ -15,23 +14,18 @@
minimum delay possible in this implementation is limited to a
value of 0.5.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "DelayA.h"
DelayA :: DelayA() : Delay()
{
this->setDelay( 0.5 );
apInput_ = 0.0;
doNextOut_ = true;
}
namespace stk {
DelayA :: DelayA(StkFloat delay, unsigned long maxDelay)
DelayA :: DelayA( StkFloat delay, unsigned long maxDelay )
{
if ( delay < 0.0 || maxDelay < 1 ) {
errorString_ << "DelayA::DelayA: delay must be >= 0.0, maxDelay must be > 0!";
if ( delay < 0.5 || maxDelay < 1 ) {
errorString_ << "DelayA::DelayA: delay must be >= 0.5, maxDelay must be > 0!";
handleError( StkError::FUNCTION_ARGUMENT );
}
@@ -41,13 +35,11 @@ DelayA :: DelayA(StkFloat delay, unsigned long maxDelay)
}
// Writing before reading allows delays from 0 to length-1.
if ( maxDelay > inputs_.size()-1 ) {
inputs_.resize( maxDelay+1 );
this->clear();
}
if ( maxDelay + 1 > inputs_.size() )
inputs_.resize( maxDelay + 1, 1, 0.0 );
inPoint_ = 0;
this->setDelay(delay);
this->setDelay( delay );
apInput_ = 0.0;
doNextOut_ = true;
}
@@ -58,16 +50,36 @@ DelayA :: ~DelayA()
void DelayA :: clear()
{
Delay::clear();
for ( unsigned int i=0; i<inputs_.size(); i++ )
inputs_[i] = 0.0;
lastFrame_[0] = 0.0;
apInput_ = 0.0;
}
void DelayA :: setDelay(StkFloat delay)
void DelayA :: setMaximumDelay( unsigned long delay )
{
if ( delay < inputs_.size() ) return;
if ( delay < 0 ) {
errorString_ << "DelayA::setMaximumDelay: argument (" << delay << ") less than zero!\n";
handleError( StkError::WARNING );
return;
}
else if ( delay < delay_ ) {
errorString_ << "DelayA::setMaximumDelay: argument (" << delay << ") less than current delay setting (" << delay_ << ")!\n";
handleError( StkError::WARNING );
return;
}
inputs_.resize( delay + 1 );
}
void DelayA :: setDelay( StkFloat delay )
{
StkFloat outPointer;
unsigned long length = inputs_.size();
if ( delay > inputs_.size() - 1 ) { // The value is too big.
if ( delay + 1 > length ) { // The value is too big.
errorString_ << "DelayA::setDelay: argument (" << delay << ") too big ... setting to maximum!";
handleError( StkError::WARNING );
@@ -75,7 +87,7 @@ void DelayA :: setDelay(StkFloat delay)
outPointer = inPoint_ + 1.0;
delay_ = length - 1;
}
else if (delay < 0.5) {
else if ( delay < 0.5 ) {
errorString_ << "DelayA::setDelay: argument (" << delay << ") less than 0.5 not possible!";
handleError( StkError::WARNING );
@@ -87,14 +99,14 @@ void DelayA :: setDelay(StkFloat delay)
delay_ = delay;
}
if (outPointer < 0)
while ( outPointer < 0 )
outPointer += length; // modulo maximum length
outPoint_ = (long) outPointer; // integer part
if ( outPoint_ == length ) outPoint_ = 0;
alpha_ = 1.0 + outPoint_ - outPointer; // fractional part
if (alpha_ < 0.5) {
if ( alpha_ < 0.5 ) {
// The optimal range for alpha is about 0.5 - 1.5 in order to
// achieve the flattest phase delay response.
outPoint_ += 1;
@@ -106,38 +118,13 @@ void DelayA :: setDelay(StkFloat delay)
((StkFloat) 1.0 + alpha_); // coefficient for all pass
}
StkFloat DelayA :: getDelay(void) const
StkFloat DelayA :: contentsAt( unsigned long tapDelay )
{
return delay_;
long tap = inPoint_ - tapDelay - 1;
while ( tap < 0 ) // Check for wraparound.
tap += inputs_.size();
return inputs_[tap];
}
StkFloat DelayA :: nextOut(void)
{
if ( doNextOut_ ) {
// Do allpass interpolation delay.
nextOutput_ = -coeff_ * outputs_[0];
nextOutput_ += apInput_ + (coeff_ * inputs_[outPoint_]);
doNextOut_ = false;
}
return nextOutput_;
}
StkFloat DelayA :: computeSample( StkFloat input )
{
inputs_[inPoint_++] = input;
// Increment input pointer modulo length.
if (inPoint_ == inputs_.size())
inPoint_ = 0;
outputs_[0] = nextOut();
doNextOut_ = true;
// Save the allpass input and increment modulo length.
apInput_ = inputs_[outPoint_++];
if (outPoint_ == inputs_.size())
outPoint_ = 0;
return outputs_[0];
}
} // stk namespace

View File

@@ -2,34 +2,26 @@
/*! \class DelayL
\brief STK linear interpolating delay line class.
This Delay subclass implements a fractional-
length digital delay-line using first-order
linear interpolation. A fixed maximum length
of 4095 and a delay of zero is set using the
default constructor. Alternatively, the
delay and maximum length can be set during
instantiation with an overloaded constructor.
This class implements a fractional-length digital delay-line using
first-order linear interpolation. If the delay and maximum length
are not specified during instantiation, a fixed maximum length of
4095 and a delay of zero is set.
Linear interpolation is an efficient technique
for achieving fractional delay lengths, though
it does introduce high-frequency signal
attenuation to varying degrees depending on the
fractional delay setting. The use of higher
order Lagrange interpolators can typically
improve (minimize) this attenuation characteristic.
Linear interpolation is an efficient technique for achieving
fractional delay lengths, though it does introduce high-frequency
signal attenuation to varying degrees depending on the fractional
delay setting. The use of higher order Lagrange interpolators can
typically improve (minimize) this attenuation characteristic.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "DelayL.h"
DelayL :: DelayL() : Delay()
{
doNextOut_ = true;
}
namespace stk {
DelayL :: DelayL(StkFloat delay, unsigned long maxDelay)
DelayL :: DelayL( StkFloat delay, unsigned long maxDelay )
{
if ( delay < 0.0 || maxDelay < 1 ) {
errorString_ << "DelayL::DelayL: delay must be >= 0.0, maxDelay must be > 0!";
@@ -42,13 +34,11 @@ DelayL :: DelayL(StkFloat delay, unsigned long maxDelay)
}
// Writing before reading allows delays from 0 to length-1.
if ( maxDelay > inputs_.size()-1 ) {
inputs_.resize( maxDelay+1 );
this->clear();
}
if ( maxDelay + 1 > inputs_.size() )
inputs_.resize( maxDelay + 1, 1, 0.0 );
inPoint_ = 0;
this->setDelay(delay);
this->setDelay( delay );
doNextOut_ = true;
}
@@ -56,11 +46,29 @@ DelayL :: ~DelayL()
{
}
void DelayL :: setDelay(StkFloat delay)
void DelayL :: setMaximumDelay( unsigned long delay )
{
if ( delay < inputs_.size() ) return;
if ( delay < 0 ) {
errorString_ << "DelayL::setMaximumDelay: argument (" << delay << ") less than zero!\n";
handleError( StkError::WARNING );
return;
}
else if ( delay < delay_ ) {
errorString_ << "DelayL::setMaximumDelay: argument (" << delay << ") less than current delay setting (" << delay_ << ")!\n";
handleError( StkError::WARNING );
return;
}
inputs_.resize( delay + 1 );
}
void DelayL :: setDelay( StkFloat delay )
{
StkFloat outPointer;
if ( delay > inputs_.size() - 1 ) { // The value is too big.
if ( delay + 1 > inputs_.size() ) { // The value is too big.
errorString_ << "DelayL::setDelay: argument (" << delay << ") too big ... setting to maximum!";
handleError( StkError::WARNING );
@@ -89,42 +97,13 @@ void DelayL :: setDelay(StkFloat delay)
omAlpha_ = (StkFloat) 1.0 - alpha_;
}
StkFloat DelayL :: getDelay(void) const
StkFloat DelayL :: contentsAt( unsigned long tapDelay )
{
return delay_;
}
StkFloat DelayL :: nextOut(void)
{
if ( doNextOut_ ) {
// First 1/2 of interpolation
nextOutput_ = inputs_[outPoint_] * omAlpha_;
// Second 1/2 of interpolation
if (outPoint_+1 < inputs_.size())
nextOutput_ += inputs_[outPoint_+1] * alpha_;
else
nextOutput_ += inputs_[0] * alpha_;
doNextOut_ = false;
}
return nextOutput_;
}
StkFloat DelayL :: computeSample( StkFloat input )
{
inputs_[inPoint_++] = input;
// Increment input pointer modulo length.
if (inPoint_ == inputs_.size())
inPoint_ = 0;
outputs_[0] = nextOut();
doNextOut_ = true;
// Increment output pointer modulo length.
if (++outPoint_ == inputs_.size())
outPoint_ = 0;
return outputs_[0];
long tap = inPoint_ - tapDelay - 1;
while ( tap < 0 ) // Check for wraparound.
tap += inputs_.size();
return inputs_[tap];
}
} // stk namespace

View File

@@ -11,13 +11,15 @@
of simultaneous voices) via a #define in the
Drummer.h.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Drummer.h"
#include <cmath>
namespace stk {
// Not really General MIDI yet.
unsigned char genMIDIMap[128] =
{ 0,0,0,0,0,0,0,0, // 0-7
@@ -53,7 +55,7 @@ char waveNames[DRUM_NUMWAVES][16] =
"tambourn.raw"
};
Drummer :: Drummer() : Instrmnt()
Drummer :: Drummer( void ) : Instrmnt()
{
// This counts the number of sounding voices.
nSounding_ = 0;
@@ -61,11 +63,11 @@ Drummer :: Drummer() : Instrmnt()
soundNumber_ = std::vector<int> (DRUM_POLYPHONY, -1);
}
Drummer :: ~Drummer()
Drummer :: ~Drummer( void )
{
}
void Drummer :: noteOn(StkFloat instrument, StkFloat amplitude)
void Drummer :: noteOn( StkFloat instrument, StkFloat amplitude )
{
#if defined(_STK_DEBUG_)
errorString_ << "Drummer::NoteOn: instrument = " << instrument << ", amplitude = " << amplitude << '.';
@@ -110,7 +112,7 @@ void Drummer :: noteOn(StkFloat instrument, StkFloat amplitude)
if ( soundOrder_[iWave] < 0 ) break;
nSounding_ += 1;
}
else {
else { // interrupt oldest voice
for ( iWave=0; iWave<DRUM_POLYPHONY; iWave++ )
if ( soundOrder_[iWave] == 0 ) break;
// Re-order the list.
@@ -121,6 +123,7 @@ void Drummer :: noteOn(StkFloat instrument, StkFloat amplitude)
}
soundOrder_[iWave] = nSounding_ - 1;
soundNumber_[iWave] = noteNumber;
std::cout << "iWave = " << iWave << ", nSounding = " << nSounding_ << ", soundOrder[] = " << soundOrder_[iWave] << std::endl;
// Concatenate the STK rawwave path to the rawwave file
waves_[iWave].openFile( (Stk::rawwavePath() + waveNames[ genMIDIMap[ noteNumber ] ]).c_str(), true );
@@ -131,7 +134,7 @@ void Drummer :: noteOn(StkFloat instrument, StkFloat amplitude)
}
#if defined(_STK_DEBUG_)
errorString_ << "Drummer::noteOn: number sounding = " << nSounding_ << '\n';
errorString_ << "Drummer::noteOn: number sounding = " << nSounding_ << ", notes: ";
for ( int i=0; i<nSounding_; i++ ) errorString_ << soundNumber_[i] << " ";
errorString_ << '\n';
handleError( StkError::DEBUG_WARNING );
@@ -145,26 +148,4 @@ void Drummer :: noteOff( StkFloat amplitude )
while ( i < nSounding_ ) filters_[i++].setGain( amplitude * 0.01 );
}
StkFloat Drummer :: computeSample()
{
lastOutput_ = 0.0;
if ( nSounding_ == 0 ) return lastOutput_;
for ( int i=0; i<DRUM_POLYPHONY; i++ ) {
if ( soundOrder_[i] >= 0 ) {
if ( waves_[i].isFinished() ) {
// Re-order the list.
for ( int j=0; j<DRUM_POLYPHONY; j++ ) {
if ( soundOrder_[j] > soundOrder_[i] )
soundOrder_[j] -= 1;
}
soundOrder_[i] = -1;
nSounding_--;
}
else
lastOutput_ += filters_[i].tick( waves_[i].tick() );
}
}
return lastOutput_;
}
} // stk namespace

View File

@@ -4,13 +4,15 @@
This class implements an echo effect.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Echo.h"
#include <iostream>
namespace stk {
Echo :: Echo( unsigned long maximumDelay ) : Effect()
{
this->setMaximumDelay( maximumDelay );
@@ -19,15 +21,10 @@ Echo :: Echo( unsigned long maximumDelay ) : Effect()
this->clear();
}
Echo :: ~Echo()
{
}
void Echo :: clear()
void Echo :: clear( void )
{
delayLine_.clear();
lastOutput_[0] = 0.0;
lastOutput_[1] = 0.0;
lastFrame_[0] = 0.0;
}
void Echo :: setMaximumDelay( unsigned long delay )
@@ -54,10 +51,4 @@ void Echo :: setDelay( unsigned long delay )
delayLine_.setDelay( size );
}
StkFloat Echo :: computeSample(StkFloat input)
{
lastOutput_[0] = effectMix_ * delayLine_.tick(input);
lastOutput_[0] += input * (1.0 - effectMix_);
lastOutput_[1] = lastOutput_[0];
return lastOutput_[0];
}
} // stk namespace

View File

@@ -1,96 +0,0 @@
/***************************************************/
/*! \class Effect
\brief STK abstract effects parent class.
This class provides common functionality for
STK effects subclasses.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
*/
/***************************************************/
#include "Effect.h"
#include <math.h>
Effect :: Effect()
{
}
Effect :: ~Effect()
{
}
void Effect :: setEffectMix(StkFloat mix)
{
if ( mix < 0.0 ) {
errorString_ << "Effect::setEffectMix: mix parameter is less than zero ... setting to zero!";
handleError( StkError::WARNING );
effectMix_ = 0.0;
}
else if ( mix > 1.0 ) {
errorString_ << "Effect::setEffectMix: mix parameter is greater than 1.0 ... setting to one!";
handleError( StkError::WARNING );
effectMix_ = 1.0;
}
else
effectMix_ = mix;
}
StkFloat Effect :: lastOut() const
{
return (lastOutput_[0] + lastOutput_[1]) * 0.5;
}
StkFloat Effect :: lastOutLeft() const
{
return lastOutput_[0];
}
StkFloat Effect :: lastOutRight() const
{
return lastOutput_[1];
}
StkFloat Effect :: tick( StkFloat input )
{
return computeSample( input );
}
StkFrames& Effect :: tick( StkFrames& frames, unsigned int channel )
{
if ( channel >= frames.channels() ) {
errorString_ << "Effect::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( frames.channels() == 1 ) {
for ( unsigned int i=0; i<frames.frames(); i++ )
frames[i] = computeSample( frames[i] );
}
else if ( frames.interleaved() ) {
unsigned int hop = frames.channels();
unsigned int index = channel;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
frames[index] = computeSample( frames[index] );
index += hop;
}
}
else {
unsigned int iStart = channel * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++, iStart++ )
frames[iStart] = computeSample( frames[iStart] );
}
return frames;
}
bool Effect :: isPrime(int number)
{
if (number == 2) return true;
if (number & 1) {
for (int i=3; i<(int)sqrt((double)number)+1; i+=2)
if ( (number % i) == 0) return false;
return true; // prime
}
else return false; // even
}

View File

@@ -1,21 +1,21 @@
/***************************************************/
/*! \class Envelope
\brief STK envelope base class.
\brief STK linear line envelope class.
This class implements a simple envelope
generator which is capable of ramping to
a target value by a specified \e rate.
It also responds to simple \e keyOn and
\e keyOff messages, ramping to 1.0 on
keyOn and to 0.0 on keyOff.
This class implements a simple linear line envelope generator
which is capable of ramping to an arbitrary target value by a
specified \e rate. It also responds to simple \e keyOn and \e
keyOff messages, ramping to 1.0 on keyOn and to 0.0 on keyOff.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Envelope.h"
Envelope :: Envelope(void) : Generator()
namespace stk {
Envelope :: Envelope( void ) : Generator()
{
target_ = 0.0;
value_ = 0.0;
@@ -24,16 +24,7 @@ Envelope :: Envelope(void) : Generator()
Stk::addSampleRateAlert( this );
}
Envelope :: Envelope ( const Envelope& e )
{
target_ = 0.0;
value_ = 0.0;
rate_ = 0.001;
state_ = 0;
Stk::addSampleRateAlert( this );
}
Envelope :: ~Envelope(void)
Envelope :: ~Envelope( void )
{
Stk::removeSampleRateAlert( this );
}
@@ -56,77 +47,4 @@ void Envelope :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
rate_ = oldRate * rate_ / newRate;
}
void Envelope :: keyOn(void)
{
target_ = 1.0;
if (value_ != target_) state_ = 1;
}
void Envelope :: keyOff(void)
{
target_ = 0.0;
if (value_ != target_) state_ = 1;
}
void Envelope :: setRate(StkFloat rate)
{
if (rate < 0.0) {
errorString_ << "Envelope::setRate: negative rates not allowed ... correcting!";
handleError( StkError::WARNING );
rate_ = -rate;
}
else
rate_ = rate;
}
void Envelope :: setTime(StkFloat time)
{
if (time < 0.0) {
errorString_ << "Envelope::setTime: negative times not allowed ... correcting!";
handleError( StkError::WARNING );
rate_ = 1.0 / (-time * Stk::sampleRate());
}
else
rate_ = 1.0 / (time * Stk::sampleRate());
}
void Envelope :: setTarget(StkFloat target)
{
target_ = target;
if (value_ != target_) state_ = 1;
}
void Envelope :: setValue(StkFloat value)
{
state_ = 0;
target_ = value;
value_ = value;
}
int Envelope :: getState(void) const
{
return state_;
}
StkFloat Envelope :: computeSample(void )
{
if (state_) {
if (target_ > value_) {
value_ += rate_;
if (value_ >= target_) {
value_ = target_;
state_ = 0;
}
}
else {
value_ -= rate_;
if (value_ <= target_) {
value_ = target_;
state_ = 0;
}
}
}
lastOutput_ = value_;
return value_;
}
} // stk namespace

View File

@@ -19,13 +19,15 @@
type who should worry about this (making
money) worry away.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "FM.h"
#include "SKINI.msg"
namespace stk {
FM :: FM( unsigned int operators )
: nOperators_(operators)
{
@@ -73,7 +75,7 @@ FM :: FM( unsigned int operators )
}
}
FM :: ~FM()
FM :: ~FM( void )
{
for (unsigned int i=0; i<nOperators_; i++ ) {
delete waves_[i];
@@ -81,21 +83,21 @@ FM :: ~FM()
}
}
void FM :: loadWaves(const char **filenames )
void FM :: loadWaves( const char **filenames )
{
for (unsigned int i=0; i<nOperators_; i++ )
waves_[i] = new WaveLoop( filenames[i], true );
waves_[i] = new FileLoop( filenames[i], true );
}
void FM :: setFrequency(StkFloat frequency)
void FM :: setFrequency( StkFloat frequency )
{
baseFrequency_ = frequency;
for (unsigned int i=0; i<nOperators_; i++ )
for ( unsigned int i=0; i<nOperators_; i++ )
waves_[i]->setFrequency( baseFrequency_ * ratios_[i] );
}
void FM :: setRatio(unsigned int waveIndex, StkFloat ratio)
void FM :: setRatio( unsigned int waveIndex, StkFloat ratio )
{
if ( waveIndex < 0 ) {
errorString_ << "FM::setRatio: waveIndex parameter is less than zero!";
@@ -115,7 +117,7 @@ void FM :: setRatio(unsigned int waveIndex, StkFloat ratio)
waves_[waveIndex]->setFrequency( ratio );
}
void FM :: setGain(unsigned int waveIndex, StkFloat gain)
void FM :: setGain( unsigned int waveIndex, StkFloat gain )
{
if ( waveIndex < 0 ) {
errorString_ << "FM::setGain: waveIndex parameter is less than zero!";
@@ -131,39 +133,19 @@ void FM :: setGain(unsigned int waveIndex, StkFloat gain)
gains_[waveIndex] = gain;
}
void FM :: setModulationSpeed(StkFloat mSpeed)
void FM :: keyOn( void )
{
vibrato_.setFrequency( mSpeed );
}
void FM :: setModulationDepth(StkFloat mDepth)
{
modDepth_ = mDepth;
}
void FM :: setControl1(StkFloat cVal)
{
control1_ = cVal * 2.0;
}
void FM :: setControl2(StkFloat cVal)
{
control2_ = cVal * 2.0;
}
void FM :: keyOn()
{
for (unsigned int i=0; i<nOperators_; i++ )
for ( unsigned int i=0; i<nOperators_; i++ )
adsr_[i]->keyOn();
}
void FM :: keyOff()
void FM :: keyOff( void )
{
for (unsigned int i=0; i<nOperators_; i++ )
for ( unsigned int i=0; i<nOperators_; i++ )
adsr_[i]->keyOff();
}
void FM :: noteOff(StkFloat amplitude)
void FM :: noteOff( StkFloat amplitude )
{
this->keyOff();
@@ -173,7 +155,7 @@ void FM :: noteOff(StkFloat amplitude)
#endif
}
void FM :: controlChange(int number, StkFloat value)
void FM :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -212,3 +194,4 @@ void FM :: controlChange(int number, StkFloat value)
#endif
}
} // stk namespace

View File

@@ -26,7 +26,7 @@
type who should worry about this (making
money) worry away.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
@@ -34,13 +34,15 @@
#include "SKINI.msg"
#include "Phonemes.h"
FMVoices :: FMVoices()
namespace stk {
FMVoices :: FMVoices( void )
: FM()
{
// Concatenate the STK rawwave path to the rawwave files
for ( unsigned int i=0; i<3; i++ )
waves_[i] = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
waves_[3] = new WaveLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
waves_[i] = new FileLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
waves_[3] = new FileLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
this->setRatio(0, 2.00);
this->setRatio(1, 4.00);
@@ -67,11 +69,11 @@ FMVoices :: FMVoices()
this->setFrequency( 110.0 );
}
FMVoices :: ~FMVoices()
FMVoices :: ~FMVoices( void )
{
}
void FMVoices :: setFrequency(StkFloat frequency)
void FMVoices :: setFrequency( StkFloat frequency )
{
StkFloat temp, temp2 = 0.0;
int tempi = 0;
@@ -109,7 +111,7 @@ void FMVoices :: setFrequency(StkFloat frequency)
gains_[2] = 1.0;
}
void FMVoices :: noteOn(StkFloat frequency, StkFloat amplitude)
void FMVoices :: noteOn( StkFloat frequency, StkFloat amplitude )
{
this->setFrequency( frequency );
tilt_[0] = amplitude;
@@ -123,32 +125,7 @@ void FMVoices :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
StkFloat FMVoices :: computeSample()
{
register StkFloat temp, temp2;
temp = gains_[3] * adsr_[3]->tick() * waves_[3]->tick();
temp2 = vibrato_.tick() * modDepth_ * 0.1;
waves_[0]->setFrequency(baseFrequency_ * (1.0 + temp2) * ratios_[0]);
waves_[1]->setFrequency(baseFrequency_ * (1.0 + temp2) * ratios_[1]);
waves_[2]->setFrequency(baseFrequency_ * (1.0 + temp2) * ratios_[2]);
waves_[3]->setFrequency(baseFrequency_ * (1.0 + temp2) * ratios_[3]);
waves_[0]->addPhaseOffset(temp * mods_[0]);
waves_[1]->addPhaseOffset(temp * mods_[1]);
waves_[2]->addPhaseOffset(temp * mods_[2]);
waves_[3]->addPhaseOffset( twozero_.lastOut() );
twozero_.tick( temp );
temp = gains_[0] * tilt_[0] * adsr_[0]->tick() * waves_[0]->tick();
temp += gains_[1] * tilt_[1] * adsr_[1]->tick() * waves_[1]->tick();
temp += gains_[2] * tilt_[2] * adsr_[2]->tick() * waves_[2]->tick();
lastOutput_ = temp * 0.33;
return lastOutput_;
}
void FMVoices :: controlChange(int number, StkFloat value)
void FMVoices :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -188,3 +165,5 @@ void FMVoices :: controlChange(int number, StkFloat value)
handleError( StkError::DEBUG_WARNING );
#endif
}
} // stk namespace

View File

@@ -1,31 +1,33 @@
/***************************************************/
/*! \class WaveLoop
\brief STK waveform oscillator class.
/*! \class FileLoop
\brief STK file looping / oscillator class.
This class inherits from FileWvIn and provides audio file looping
functionality. Any audio file that can be loaded by FileRead can
be looped using this class.
This class provides audio file looping functionality. Any audio
file that can be loaded by FileRead can be looped using this
class.
WaveLoop supports multi-channel data. It is important to
distinguish the tick() methods, which return samples produced by
averaging across sample frames, from the tickFrame() methods,
which return references or pointers to multi-channel sample
frames.
FileLoop supports multi-channel data. It is important to
distinguish the tick() method that computes a single frame (and
returns only the specified sample of a multi-channel frame) from
the overloaded one that takes an StkFrames object for
multi-channel and/or multi-frame data.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "WaveLoop.h"
#include "FileLoop.h"
#include <cmath>
WaveLoop :: WaveLoop( unsigned long chunkThreshold, unsigned long chunkSize )
namespace stk {
FileLoop :: FileLoop( unsigned long chunkThreshold, unsigned long chunkSize )
: FileWvIn( chunkThreshold, chunkSize ), phaseOffset_(0.0)
{
Stk::addSampleRateAlert( this );
}
WaveLoop :: WaveLoop( std::string fileName, bool raw, bool doNormalize,
FileLoop :: FileLoop( std::string fileName, bool raw, bool doNormalize,
unsigned long chunkThreshold, unsigned long chunkSize )
: FileWvIn( chunkThreshold, chunkSize ), phaseOffset_(0.0)
{
@@ -33,18 +35,12 @@ WaveLoop :: WaveLoop( std::string fileName, bool raw, bool doNormalize,
Stk::addSampleRateAlert( this );
}
WaveLoop :: ~WaveLoop()
FileLoop :: ~FileLoop( void )
{
Stk::removeSampleRateAlert( this );
}
void WaveLoop :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
{
if ( !ignoreSampleRateChange_ )
this->setRate( oldRate * rate_ / newRate );
}
void WaveLoop :: openFile( std::string fileName, bool raw, bool doNormalize )
void FileLoop :: openFile( std::string fileName, bool raw, bool doNormalize )
{
// Call close() in case another file is already open.
this->closeFile();
@@ -56,7 +52,7 @@ void WaveLoop :: openFile( std::string fileName, bool raw, bool doNormalize )
if ( file_.fileSize() > chunkThreshold_ ) {
chunking_ = true;
chunkPointer_ = 0;
data_.resize( chunkSize_, file_.channels() );
data_.resize( chunkSize_ + 1, file_.channels() );
if ( doNormalize ) normalizing_ = true;
else normalizing_ = false;
}
@@ -79,7 +75,7 @@ void WaveLoop :: openFile( std::string fileName, bool raw, bool doNormalize )
}
// Resize our lastOutputs container.
lastOutputs_.resize( 1, file_.channels() );
lastFrame_.resize( 1, file_.channels() );
// Set default rate based on file sampling rate.
this->setRate( data_.dataRate() / Stk::sampleRate() );
@@ -89,7 +85,7 @@ void WaveLoop :: openFile( std::string fileName, bool raw, bool doNormalize )
this->reset();
}
void WaveLoop :: setRate( StkFloat rate )
void FileLoop :: setRate( StkFloat rate )
{
rate_ = rate;
@@ -97,13 +93,7 @@ void WaveLoop :: setRate( StkFloat rate )
else interpolate_ = false;
}
void WaveLoop :: setFrequency( StkFloat frequency )
{
// This is a looping frequency.
this->setRate( file_.fileSize() * frequency / Stk::sampleRate() );
}
void WaveLoop :: addTime( StkFloat time )
void FileLoop :: addTime( StkFloat time )
{
// Add an absolute time in samples.
time_ += time;
@@ -115,7 +105,7 @@ void WaveLoop :: addTime( StkFloat time )
time_ -= fileSize;
}
void WaveLoop :: addPhase( StkFloat angle )
void FileLoop :: addPhase( StkFloat angle )
{
// Add a time in cycles (one cycle = fileSize).
StkFloat fileSize = file_.fileSize();
@@ -127,35 +117,40 @@ void WaveLoop :: addPhase( StkFloat angle )
time_ -= fileSize;
}
void WaveLoop :: addPhaseOffset( StkFloat angle )
void FileLoop :: addPhaseOffset( StkFloat angle )
{
// Add a phase offset in cycles, where 1.0 = fileSize.
phaseOffset_ = file_.fileSize() * angle;
}
void WaveLoop :: computeFrame( void )
StkFloat FileLoop :: tick( unsigned int channel )
{
#if defined(_STK_DEBUG_)
if ( channel >= data_.channels() ) {
errorString_ << "FileLoop::tick(): channel argument and soundfile data are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
// Check limits of time address ... if necessary, recalculate modulo
// fileSize.
StkFloat fileSize = file_.fileSize();
while ( time_ < 0.0 )
time_ += fileSize;
while ( time_ >= fileSize )
time_ -= fileSize;
StkFloat tyme;
StkFloat tyme = time_;
if ( phaseOffset_ ) {
tyme = time_ + phaseOffset_;
tyme += phaseOffset_;
while ( tyme < 0.0 )
tyme += fileSize;
while ( tyme >= fileSize )
tyme -= fileSize;
}
else {
tyme = time_;
}
if (chunking_) {
if ( chunking_ ) {
// Check the time address vs. our current buffer limits.
if ( ( time_ < (StkFloat) chunkPointer_ ) ||
@@ -184,14 +179,46 @@ void WaveLoop :: computeFrame( void )
}
if ( interpolate_ ) {
for ( unsigned int i=0; i<lastOutputs_.size(); i++ )
lastOutputs_[i] = data_.interpolate( tyme, i );
for ( unsigned int i=0; i<lastFrame_.size(); i++ )
lastFrame_[i] = data_.interpolate( tyme, i );
}
else {
for ( unsigned int i=0; i<lastOutputs_.size(); i++ )
lastOutputs_[i] = data_( (size_t) tyme, i );
for ( unsigned int i=0; i<lastFrame_.size(); i++ )
lastFrame_[i] = data_( (size_t) tyme, i );
}
// Increment time, which can be negative.
time_ += rate_;
return lastFrame_[channel];
}
StkFrames& FileLoop :: tick( StkFrames& frames )
{
if ( !file_.isOpen() ) {
#if defined(_STK_DEBUG_)
errorString_ << "FileLoop::tick(): no file data is loaded!";
handleError( StkError::WARNING );
#endif
return frames;
}
unsigned int nChannels = lastFrame_.channels();
#if defined(_STK_DEBUG_)
if ( nChannels != frames.channels() ) {
errorString_ << "FileLoop::tick(): StkFrames argument is incompatible with file data!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
unsigned int j, counter = 0;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
this->tick();
for ( j=0; j<nChannels; j++ )
frames[counter++] = lastFrame_[j];
}
return frames;
}
} // stk namespace

View File

@@ -32,8 +32,11 @@
#include "FileRead.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <cmath>
namespace stk {
FileRead :: FileRead()
: fd_(0)
{
@@ -730,3 +733,4 @@ void FileRead :: read( StkFrames& buffer, unsigned long startFrame, bool doNorma
handleError( StkError::FILE_ERROR);
}
} // stk namespace

View File

@@ -17,13 +17,16 @@
type, the data type will automatically be modified. Compressed
data types are not supported.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "FileWrite.h"
#include <string.h>
#include <cmath>
namespace stk {
const FileWrite::FILE_TYPE FileWrite :: FILE_RAW = 1;
const FileWrite::FILE_TYPE FileWrite :: FILE_WAV = 2;
const FileWrite::FILE_TYPE FileWrite :: FILE_SND = 3;
@@ -699,3 +702,5 @@ void FileWrite :: write( StkFrames& buffer )
errorString_ << "FileWrite::write(): error writing data to file!";
handleError( StkError::FILE_ERROR );
}
} // stk namespace

View File

@@ -4,14 +4,15 @@
This class inherits from WvIn. It provides a "tick-level"
interface to the FileRead class. It also provides variable-rate
"playback" functionality. Audio file support is provided by the
FileRead class. Linear interpolation is used for fractional "read
rates".
playback functionality. Audio file support is provided by the
FileRead class. Linear interpolation is used for fractional read
rates.
FileWvIn supports multi-channel data. It is important to distinguish
the tick() methods, which return samples produced by averaging
across sample frames, from the tickFrame() methods, which return
references to multi-channel sample frames.
FileWvIn supports multi-channel data. It is important to
distinguish the tick() method that computes a single frame (and
returns only the specified sample of a multi-channel frame) from
the overloaded one that takes an StkFrames object for
multi-channel and/or multi-frame data.
FileWvIn will either load the entire content of an audio file into
local memory or incrementally read file data from disk in chunks.
@@ -20,19 +21,21 @@
chunkThreshold (in sample frames) will be read incrementally in
chunks of \e chunkSize each (also in sample frames).
When the end of a file is reached, subsequent calls to the tick()
functions return zero-valued data.
When the file end is reached, subsequent calls to the tick()
functions return zeros and isFinished() returns \e true.
See the FileRead class for a description of the supported audio
file formats.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "FileWvIn.h"
#include <cmath>
namespace stk {
FileWvIn :: FileWvIn( unsigned long chunkThreshold, unsigned long chunkSize )
: finished_(true), interpolate_(false), time_(0.0),
chunkThreshold_(chunkThreshold), chunkSize_(chunkSize)
@@ -65,6 +68,7 @@ void FileWvIn :: closeFile( void )
{
if ( file_.isOpen() ) file_.close();
finished_ = true;
lastFrame_.resize( 0, 0 );
}
void FileWvIn :: openFile( std::string fileName, bool raw, bool doNormalize )
@@ -91,8 +95,8 @@ void FileWvIn :: openFile( std::string fileName, bool raw, bool doNormalize )
// Load all or part of the data.
file_.read( data_, 0, doNormalize );
// Resize our lastOutputs container.
lastOutputs_.resize( 1, file_.channels() );
// Resize our lastFrame container.
lastFrame_.resize( 1, file_.channels() );
// Set default rate based on file sampling rate.
this->setRate( data_.dataRate() / Stk::sampleRate() );
@@ -105,8 +109,7 @@ void FileWvIn :: openFile( std::string fileName, bool raw, bool doNormalize )
void FileWvIn :: reset(void)
{
time_ = (StkFloat) 0.0;
for ( unsigned int i=0; i<lastOutputs_.size(); i++ )
lastOutputs_[i] = 0.0;
for ( unsigned int i=0; i<lastFrame_.size(); i++ ) lastFrame_[i] = 0.0;
finished_ = false;
}
@@ -129,11 +132,11 @@ void FileWvIn :: normalize( StkFloat peak )
max = (StkFloat) fabs((double) data_[i]);
}
if (max > 0.0) {
if ( max > 0.0 ) {
max = 1.0 / max;
max *= peak;
for ( i=0; i<data_.size(); i++ )
data_[i] *= max;
data_[i] *= max;
}
}
@@ -162,27 +165,26 @@ void FileWvIn :: addTime( StkFloat time )
if ( time_ < 0.0 ) time_ = 0.0;
if ( time_ > file_.fileSize() - 1.0 ) {
time_ = file_.fileSize() - 1.0;
for ( unsigned int i=0; i<lastOutputs_.size(); i++ )
lastOutputs_[i] = 0.0;
for ( unsigned int i=0; i<lastFrame_.size(); i++ ) lastFrame_[i] = 0.0;
finished_ = true;
}
}
StkFloat FileWvIn :: lastOut( void ) const
StkFloat FileWvIn :: tick( unsigned int channel )
{
if ( finished_ ) return 0.0;
return WvIn :: lastOut();
}
#if defined(_STK_DEBUG_)
if ( channel >= data_.channels() ) {
errorString_ << "FileWvIn::tick(): channel argument and soundfile data are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
void FileWvIn :: computeFrame( void )
{
if ( finished_ ) return;
if ( finished_ ) return 0.0;
if ( time_ < 0.0 || time_ > (StkFloat) ( file_.fileSize() - 1.0 ) ) {
for ( unsigned int i=0; i<lastOutputs_.size(); i++ )
lastOutputs_[i] = 0.0;
for ( unsigned int i=0; i<lastFrame_.size(); i++ ) lastFrame_[i] = 0.0;
finished_ = true;
return;
return 0.0;
}
StkFloat tyme = time_;
@@ -211,15 +213,46 @@ void FileWvIn :: computeFrame( void )
}
if ( interpolate_ ) {
for ( unsigned int i=0; i<lastOutputs_.size(); i++ )
lastOutputs_[i] = data_.interpolate( tyme, i );
for ( unsigned int i=0; i<lastFrame_.size(); i++ )
lastFrame_[i] = data_.interpolate( tyme, i );
}
else {
for ( unsigned int i=0; i<lastOutputs_.size(); i++ )
lastOutputs_[i] = data_( (size_t) tyme, i );
for ( unsigned int i=0; i<lastFrame_.size(); i++ )
lastFrame_[i] = data_( (size_t) tyme, i );
}
// Increment time, which can be negative.
time_ += rate_;
return lastFrame_[channel];
}
StkFrames& FileWvIn :: tick( StkFrames& frames )
{
if ( !file_.isOpen() ) {
#if defined(_STK_DEBUG_)
errorString_ << "FileWvIn::tick(): no file data is loaded!";
handleError( StkError::DEBUG_WARNING );
#endif
return frames;
}
unsigned int nChannels = lastFrame_.channels();
#if defined(_STK_DEBUG_)
if ( nChannels != frames.channels() ) {
errorString_ << "FileWvIn::tick(): StkFrames argument is incompatible with file data!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
unsigned int j, counter = 0;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
this->tick();
for ( j=0; j<nChannels; j++ )
frames[counter++] = lastFrame_[j];
}
return frames;
}
} // stk namespace

View File

@@ -7,9 +7,9 @@
FileWvOut writes samples to an audio file and supports
multi-channel data. It is important to distinguish the tick()
methods, which output single samples to all channels in a sample
frame, from the tickFrame() methods, which take a pointer or
reference to multi-channel sample frame data.
method that outputs a single sample to all channels in a sample
frame from the overloaded one that takes a reference to an
StkFrames object for multi-channel and/or multi-frame data.
See the FileWrite class for a description of the supported audio
file formats.
@@ -17,12 +17,14 @@
Currently, FileWvOut is non-interpolating and the output rate is
always Stk::sampleRate().
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "FileWvOut.h"
namespace stk {
FileWvOut :: FileWvOut( unsigned int bufferFrames )
:bufferFrames_( bufferFrames )
{
@@ -88,13 +90,15 @@ void FileWvOut :: incrementFrame( void )
}
}
void FileWvOut :: computeSample( const StkFloat sample )
void FileWvOut :: tick( const StkFloat sample )
{
#if defined(_STK_DEBUG_)
if ( !file_.isOpen() ) {
errorString_ << "FileWvOut::computeSample(): no file open!";
errorString_ << "FileWvOut::tick(): no file open!";
handleError( StkError::WARNING );
return;
}
#endif
unsigned int nChannels = data_.channels();
StkFloat input = sample;
@@ -105,48 +109,32 @@ void FileWvOut :: computeSample( const StkFloat sample )
this->incrementFrame();
}
void FileWvOut :: computeFrames( const StkFrames& frames )
void FileWvOut :: tick( const StkFrames& frames )
{
#if defined(_STK_DEBUG_)
if ( !file_.isOpen() ) {
errorString_ << "FileWvOut::computeFrames(): no file open!";
errorString_ << "FileWvOut::tick(): no file open!";
handleError( StkError::WARNING );
return;
}
if ( data_.channels() != frames.channels() ) {
errorString_ << "FileWvOut::computeFrames(): incompatible channel value in StkFrames argument!";
errorString_ << "FileWvOut::tick(): incompatible channel value in StkFrames argument!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
unsigned int iFrames = 0;
unsigned int j, nChannels = data_.channels();
if ( nChannels == 1 || frames.interleaved() ) {
for ( unsigned int i=0; i<frames.frames(); i++ ) {
unsigned int iFrames = 0;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
for ( j=0; j<nChannels; j++ ) {
data_[iData_] = frames[iFrames++];
clipTest( data_[iData_++] );
}
this->incrementFrame();
for ( j=0; j<nChannels; j++ ) {
data_[iData_] = frames[iFrames++];
clipTest( data_[iData_++] );
}
}
else { // non-interleaved frames
unsigned long hop = frames.frames();
unsigned int index;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
index = i;
for ( j=0; j<nChannels; j++ ) {
data_[iData_] = frames[index];
clipTest( data_[iData_++] );
index += hop;
}
this->incrementFrame();
}
this->incrementFrame();
}
}
} // stk namespace

View File

@@ -1,234 +0,0 @@
/***************************************************/
/*! \class Filter
\brief STK filter class.
This class implements a generic structure that
can be used to create a wide range of filters.
It can function independently or be subclassed
to provide more specific controls based on a
particular filter type.
In particular, this class implements the standard
difference equation:
a[0]*y[n] = b[0]*x[n] + ... + b[nb]*x[n-nb] -
a[1]*y[n-1] - ... - a[na]*y[n-na]
If a[0] is not equal to 1, the filter coefficients
are normalized by a[0].
The \e gain parameter is applied at the filter
input and does not affect the coefficient values.
The default gain value is 1.0. This structure
results in one extra multiply per computed sample,
but allows easy control of the overall filter gain.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
*/
/***************************************************/
#include "Filter.h"
#include <stdio.h>
Filter :: Filter()
{
// The default constructor should setup for pass-through.
gain_ = 1.0;
b_.push_back( 1.0 );
a_.push_back( 1.0 );
inputs_.push_back( 0.0 );
outputs_.push_back( 0.0 );
}
Filter :: Filter( std::vector<StkFloat> &bCoefficients, std::vector<StkFloat> &aCoefficients )
{
// Check the arguments.
if ( bCoefficients.size() == 0 || aCoefficients.size() == 0 ) {
errorString_ << "Filter: a and b coefficient vectors must both have size > 0!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( aCoefficients[0] == 0.0 ) {
errorString_ << "Filter: a[0] coefficient cannot == 0!";
handleError( StkError::FUNCTION_ARGUMENT );
}
gain_ = 1.0;
b_ = bCoefficients;
a_ = aCoefficients;
inputs_ = std::vector<StkFloat> ( b_.size() );
outputs_ = std::vector<StkFloat> ( a_.size() );
this->clear();
}
Filter :: ~Filter()
{
}
void Filter :: clear(void)
{
unsigned int i;
for (i=0; i<inputs_.size(); i++)
inputs_[i] = 0.0;
for (i=0; i<outputs_.size(); i++)
outputs_[i] = 0.0;
}
void Filter :: setCoefficients( std::vector<StkFloat> &bCoefficients, std::vector<StkFloat> &aCoefficients, bool clearState )
{
// Check the arguments.
if ( bCoefficients.size() == 0 || aCoefficients.size() == 0 ) {
errorString_ << "Filter::setCoefficients: a and b coefficient vectors must both have size > 0!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( aCoefficients[0] == 0.0 ) {
errorString_ << "Filter::setCoefficients: a[0] coefficient cannot == 0!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( b_.size() != bCoefficients.size() ) {
b_ = bCoefficients;
inputs_.clear();
inputs_ = std::vector<StkFloat> ( b_.size() );
}
else {
for ( unsigned int i=0; i<b_.size(); i++ ) b_[i] = bCoefficients[i];
}
if ( a_.size() != aCoefficients.size() ) {
a_ = aCoefficients;
outputs_.clear();
outputs_ = std::vector<StkFloat> ( a_.size() );
}
else {
for ( unsigned int i=0; i<a_.size(); i++ ) a_[i] = aCoefficients[i];
}
if ( clearState ) this->clear();
// Scale coefficients by a[0] if necessary
if ( a_[0] != 1.0 ) {
unsigned int i;
for ( i=0; i<b_.size(); i++ ) b_[i] /= a_[0];
for ( i=1; i<a_.size(); i++ ) a_[i] /= a_[0];
}
}
void Filter :: setNumerator( std::vector<StkFloat> &bCoefficients, bool clearState )
{
// Check the argument.
if ( bCoefficients.size() == 0 ) {
errorString_ << "Filter::setNumerator: coefficient vector must have size > 0!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( b_.size() != bCoefficients.size() ) {
b_ = bCoefficients;
inputs_.clear();
inputs_ = std::vector<StkFloat> ( b_.size() );
}
else {
for ( unsigned int i=0; i<b_.size(); i++ ) b_[i] = bCoefficients[i];
}
if ( clearState ) this->clear();
}
void Filter :: setDenominator( std::vector<StkFloat> &aCoefficients, bool clearState )
{
// Check the argument.
if ( aCoefficients.size() == 0 ) {
errorString_ << "Filter::setDenominator: coefficient vector must have size > 0!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( aCoefficients[0] == 0.0 ) {
errorString_ << "Filter::setDenominator: a[0] coefficient cannot == 0!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( a_.size() != aCoefficients.size() ) {
a_ = aCoefficients;
outputs_.clear();
outputs_ = std::vector<StkFloat> ( a_.size() );
}
else {
for ( unsigned int i=0; i<a_.size(); i++ ) a_[i] = aCoefficients[i];
}
if ( clearState ) this->clear();
// Scale coefficients by a[0] if necessary
if ( a_[0] != 1.0 ) {
unsigned int i;
for ( i=0; i<b_.size(); i++ ) b_[i] /= a_[0];
for ( i=1; i<a_.size(); i++ ) a_[i] /= a_[0];
}
}
void Filter :: setGain(StkFloat gain)
{
gain_ = gain;
}
StkFloat Filter :: getGain(void) const
{
return gain_;
}
StkFloat Filter :: lastOut(void) const
{
return outputs_[0];
}
StkFloat Filter :: tick( StkFloat input )
{
unsigned int i;
outputs_[0] = 0.0;
inputs_[0] = gain_ * input;
for (i=b_.size()-1; i>0; i--) {
outputs_[0] += b_[i] * inputs_[i];
inputs_[i] = inputs_[i-1];
}
outputs_[0] += b_[0] * inputs_[0];
for (i=a_.size()-1; i>0; i--) {
outputs_[0] += -a_[i] * outputs_[i];
outputs_[i] = outputs_[i-1];
}
return outputs_[0];
}
StkFrames& Filter :: tick( StkFrames& frames, unsigned int channel )
{
if ( channel >= frames.channels() ) {
errorString_ << "Filter::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( frames.channels() == 1 ) {
for ( unsigned int i=0; i<frames.frames(); i++ )
frames[i] = tick( frames[i] );
}
else if ( frames.interleaved() ) {
unsigned int hop = frames.channels();
unsigned int index = channel;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
frames[index] = tick( frames[index] );
index += hop;
}
}
else {
unsigned int iStart = channel * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++, iStart++ )
frames[iStart] = tick( frames[iStart] );
}
return frames;
}

73
src/Fir.cpp Normal file
View File

@@ -0,0 +1,73 @@
/***************************************************/
/*! \class Fir
\brief STK general finite impulse response filter class.
This class provides a generic digital filter structure that can be
used to implement FIR filters. For filters with feedback terms,
the Iir class should be used.
In particular, this class implements the standard difference
equation:
y[n] = b[0]*x[n] + ... + b[nb]*x[n-nb]
The \e gain parameter is applied at the filter input and does not
affect the coefficient values. The default gain value is 1.0.
This structure results in one extra multiply per computed sample,
but allows easy control of the overall filter gain.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Fir.h"
namespace stk {
Fir :: Fir()
{
// The default constructor should setup for pass-through.
b_.push_back( 1.0 );
inputs_.resize( 1, 1, 0.0 );
}
Fir :: Fir( std::vector<StkFloat> &coefficients )
{
// Check the arguments.
if ( coefficients.size() == 0 ) {
errorString_ << "Fir: coefficient vector must have size > 0!";
handleError( StkError::FUNCTION_ARGUMENT );
}
gain_ = 1.0;
b_ = coefficients;
inputs_.resize( b_.size(), 1, 0.0 );
this->clear();
}
Fir :: ~Fir()
{
}
void Fir :: setCoefficients( std::vector<StkFloat> &coefficients, bool clearState )
{
// Check the argument.
if ( coefficients.size() == 0 ) {
errorString_ << "Fir::setCoefficients: coefficient vector must have size > 0!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( b_.size() != coefficients.size() ) {
b_ = coefficients;
inputs_.resize( b_.size(), 1, 0.0 );
}
else {
for ( unsigned int i=0; i<b_.size(); i++ ) b_[i] = coefficients[i];
}
if ( clearState ) this->clear();
}
} // stk namespace

View File

@@ -18,16 +18,18 @@
- Vibrato Gain = 1
- Breath Pressure = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Flute.h"
#include "SKINI.msg"
Flute :: Flute(StkFloat lowestFrequency)
namespace stk {
Flute :: Flute( StkFloat lowestFrequency )
{
length_ = (unsigned long) (Stk::sampleRate() / lowestFrequency + 1);
length_ = (unsigned long) ( Stk::sampleRate() / lowestFrequency + 1 );
boreDelay_.setMaximumDelay( length_ );
boreDelay_.setDelay( 100.0 );
@@ -54,11 +56,11 @@ Flute :: Flute(StkFloat lowestFrequency)
lastFrequency_ = 220.0;
}
Flute :: ~Flute()
Flute :: ~Flute( void )
{
}
void Flute :: clear()
void Flute :: clear( void )
{
jetDelay_.clear();
boreDelay_.clear();
@@ -66,7 +68,7 @@ void Flute :: clear()
dcBlock_.clear();
}
void Flute :: setFrequency(StkFloat frequency)
void Flute :: setFrequency( StkFloat frequency )
{
lastFrequency_ = frequency;
if ( frequency <= 0.0 ) {
@@ -87,20 +89,20 @@ void Flute :: setFrequency(StkFloat frequency)
jetDelay_.setDelay(delay * jetRatio_);
}
void Flute :: startBlowing(StkFloat amplitude, StkFloat rate)
void Flute :: startBlowing( StkFloat amplitude, StkFloat rate )
{
adsr_.setAttackRate( rate );
maxPressure_ = amplitude / (StkFloat) 0.8;
adsr_.keyOn();
}
void Flute :: stopBlowing(StkFloat rate)
void Flute :: stopBlowing( StkFloat rate )
{
adsr_.setReleaseRate( rate );
adsr_.keyOff();
}
void Flute :: noteOn(StkFloat frequency, StkFloat amplitude)
void Flute :: noteOn( StkFloat frequency, StkFloat amplitude )
{
this->setFrequency( frequency );
this->startBlowing( 1.1 + (amplitude * 0.20), amplitude * 0.02 );
@@ -112,7 +114,7 @@ void Flute :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
void Flute :: noteOff(StkFloat amplitude)
void Flute :: noteOff( StkFloat amplitude )
{
this->stopBlowing( amplitude * 0.02 );
@@ -122,12 +124,12 @@ void Flute :: noteOff(StkFloat amplitude)
#endif
}
void Flute :: setJetReflection(StkFloat coefficient)
void Flute :: setJetReflection( StkFloat coefficient )
{
jetReflection_ = coefficient;
}
void Flute :: setEndReflection(StkFloat coefficient)
void Flute :: setEndReflection( StkFloat coefficient )
{
endReflection_ = coefficient;
}
@@ -140,28 +142,7 @@ void Flute :: setJetDelay( StkFloat aRatio )
jetDelay_.setDelay(temp * aRatio); // Scaled by ratio.
}
StkFloat Flute :: computeSample()
{
StkFloat pressureDiff;
StkFloat breathPressure;
// Calculate the breath pressure (envelope + noise + vibrato)
breathPressure = maxPressure_ * adsr_.tick();
breathPressure += breathPressure * ( noiseGain_ * noise_.tick() + vibratoGain_ * vibrato_.tick() );
StkFloat temp = filter_.tick( boreDelay_.lastOut() );
temp = dcBlock_.tick( temp ); // Block DC on reflection.
pressureDiff = breathPressure - (jetReflection_ * temp);
pressureDiff = jetDelay_.tick( pressureDiff );
pressureDiff = jetTable_.tick( pressureDiff ) + (endReflection_ * temp);
lastOutput_ = (StkFloat) 0.3 * boreDelay_.tick( pressureDiff );
lastOutput_ *= outputGain_;
return lastOutput_;
}
void Flute :: controlChange(int number, StkFloat value)
void Flute :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -195,3 +176,5 @@ void Flute :: controlChange(int number, StkFloat value)
handleError( StkError::DEBUG_WARNING );
#endif
}
} // stk namespace

View File

@@ -2,63 +2,83 @@
/*! \class FormSwep
\brief STK sweepable formant filter class.
This public BiQuad filter subclass implements
a formant (resonance) which can be "swept"
over time from one frequency setting to another.
It provides methods for controlling the sweep
rate and target frequency.
This class implements a formant (resonance) which can be "swept"
over time from one frequency setting to another. It provides
methods for controlling the sweep rate and target frequency.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "FormSwep.h"
#include <cmath>
FormSwep :: FormSwep() : BiQuad()
namespace stk {
FormSwep :: FormSwep( void )
{
frequency_ = (StkFloat) 0.0;
radius_ = (StkFloat) 0.0;
targetGain_ = (StkFloat) 1.0;
targetFrequency_ = (StkFloat) 0.0;
targetRadius_ = (StkFloat) 0.0;
deltaGain_ = (StkFloat) 0.0;
deltaFrequency_ = (StkFloat) 0.0;
deltaRadius_ = (StkFloat) 0.0;
sweepState_ = (StkFloat) 0.0;
sweepRate_ = (StkFloat) 0.002;
frequency_ = 0.0;
radius_ = 0.0;
targetGain_ = 1.0;
targetFrequency_ = 0.0;
targetRadius_ = 0.0;
deltaGain_ = 0.0;
deltaFrequency_ = 0.0;
deltaRadius_ = 0.0;
sweepState_ = 0.0;
sweepRate_ = 0.002;
dirty_ = false;
this->clear();
b_.resize( 3, 0.0 );
a_.resize( 3, 0.0 );
a_[0] = 1.0;
inputs_.resize( 3, 1, 0.0 );
outputs_.resize( 3, 1, 0.0 );
Stk::addSampleRateAlert( this );
}
FormSwep :: ~FormSwep()
{
Stk::removeSampleRateAlert( this );
}
void FormSwep :: setResonance(StkFloat frequency, StkFloat radius)
void FormSwep :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
{
if ( !ignoreSampleRateChange_ ) {
errorString_ << "FormSwep::sampleRateChanged: you may need to recompute filter coefficients!";
handleError( StkError::WARNING );
}
}
void FormSwep :: setResonance( StkFloat frequency, StkFloat radius )
{
dirty_ = false;
radius_ = radius;
frequency_ = frequency;
BiQuad::setResonance( frequency_, radius_, true );
a_[2] = radius * radius;
a_[1] = -2.0 * radius * cos( TWO_PI * frequency / Stk::sampleRate() );
// Use zeros at +- 1 and normalize the filter peak gain.
b_[0] = 0.5 - 0.5 * a_[2];
b_[1] = 0.0;
b_[2] = -b_[0];
}
void FormSwep :: setStates(StkFloat frequency, StkFloat radius, StkFloat gain)
void FormSwep :: setStates( StkFloat frequency, StkFloat radius, StkFloat gain )
{
dirty_ = false;
if ( frequency_ != frequency || radius_ != radius )
BiQuad::setResonance( frequency, radius, true );
this->setResonance( frequency, radius );
frequency_ = frequency;
radius_ = radius;
gain_ = gain;
targetFrequency_ = frequency;
targetRadius_ = radius;
targetGain_ = gain;
}
void FormSwep :: setTargets(StkFloat frequency, StkFloat radius, StkFloat gain)
void FormSwep :: setTargets( StkFloat frequency, StkFloat radius, StkFloat gain )
{
dirty_ = true;
startFrequency_ = frequency_;
@@ -70,42 +90,21 @@ void FormSwep :: setTargets(StkFloat frequency, StkFloat radius, StkFloat gain)
deltaFrequency_ = frequency - frequency_;
deltaRadius_ = radius - radius_;
deltaGain_ = gain - gain_;
sweepState_ = (StkFloat) 0.0;
sweepState_ = 0.0;
}
void FormSwep :: setSweepRate(StkFloat rate)
void FormSwep :: setSweepRate( StkFloat rate )
{
sweepRate_ = rate;
if ( sweepRate_ > 1.0 ) sweepRate_ = 1.0;
if ( sweepRate_ < 0.0 ) sweepRate_ = 0.0;
}
void FormSwep :: setSweepTime(StkFloat time)
void FormSwep :: setSweepTime( StkFloat time )
{
sweepRate_ = 1.0 / ( time * Stk::sampleRate() );
if ( sweepRate_ > 1.0 ) sweepRate_ = 1.0;
if ( sweepRate_ < 0.0 ) sweepRate_ = 0.0;
}
StkFloat FormSwep :: computeSample( StkFloat input )
{
if (dirty_) {
sweepState_ += sweepRate_;
if ( sweepState_ >= 1.0 ) {
sweepState_ = 1.0;
dirty_ = false;
radius_ = targetRadius_;
frequency_ = targetFrequency_;
gain_ = targetGain_;
}
else {
radius_ = startRadius_ + (deltaRadius_ * sweepState_);
frequency_ = startFrequency_ + (deltaFrequency_ * sweepState_);
gain_ = startGain_ + (deltaGain_ * sweepState_);
}
BiQuad::setResonance( frequency_, radius_, true );
}
return BiQuad::computeSample( input );
}
} // stk namespace

View File

@@ -1,55 +0,0 @@
/***************************************************/
/*! \class Function
\brief STK abstract function parent class.
This class provides common functionality for STK classes which
implement tables or other types of input to output function
mappings.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
*/
/***************************************************/
#include "Function.h"
Function :: Function() : Stk()
{
lastOutput_ = (StkFloat) 0.0;
}
Function :: ~Function()
{
}
StkFloat Function :: tick( StkFloat input )
{
return computeSample( input );
}
StkFrames& Function :: tick( StkFrames& frames, unsigned int channel )
{
if ( channel >= frames.channels() ) {
errorString_ << "Function::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( frames.channels() == 1 ) {
for ( unsigned int i=0; i<frames.frames(); i++ )
frames[i] = computeSample( frames[i] );
}
else if ( frames.interleaved() ) {
unsigned int hop = frames.channels();
unsigned int index = channel;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
frames[index] = computeSample( frames[index] );
index += hop;
}
}
else {
unsigned int iStart = channel * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++, iStart++ )
frames[iStart] = computeSample( frames[iStart] );
}
return frames;
}

View File

@@ -1,54 +0,0 @@
/***************************************************/
/*! \class Generator
\brief STK abstract unit generator parent class.
This class provides common functionality for
STK unit generator sample-source subclasses.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
*/
/***************************************************/
#include "Generator.h"
Generator :: Generator() : Stk()
{
lastOutput_ = 0.0;
}
Generator :: ~Generator()
{
}
StkFloat Generator :: tick( void )
{
return computeSample();
}
StkFrames& Generator :: tick( StkFrames& frames, unsigned int channel )
{
if ( channel >= frames.channels() ) {
errorString_ << "Generator::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( frames.channels() == 1 ) {
for ( unsigned int i=0; i<frames.frames(); i++ )
frames[i] = computeSample();
}
else if ( frames.interleaved() ) {
unsigned int hop = frames.channels();
unsigned int index = channel;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
frames[index] = computeSample();
index += hop;
}
}
else {
unsigned int iStart = channel * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++, iStart++ )
frames[iStart] = computeSample();
}
return frames;
}

View File

@@ -3,15 +3,15 @@
\brief STK granular synthesis class.
This class implements a real-time granular synthesis algorithm
that operates on an input soundfile. Currently, only monophonic
files are supported. Various functions are provided to allow
control over voice and grain parameters.
that operates on an input soundfile. Multi-channel files are
supported. Various functions are provided to allow control over
voice and grain parameters.
The functionality of this class is based on the program MacPod by
Chris Rolfe and Damian Keller, though there are likely to be a
number of differences in the actual implementation.
by Gary Scavone, 2005.
by Gary Scavone, 2005 - 2009.
*/
/***************************************************/
@@ -19,6 +19,8 @@
#include "FileRead.h"
#include <cmath>
namespace stk {
Granulate :: Granulate( void )
{
this->setGrainParameters(); // use default values
@@ -38,7 +40,7 @@ Granulate :: Granulate( unsigned int nVoices, std::string fileName, bool typeRaw
this->setVoices( nVoices );
}
Granulate :: ~Granulate()
Granulate :: ~Granulate( void )
{
}
@@ -85,13 +87,9 @@ void Granulate :: openFile( std::string fileName, bool typeRaw )
{
// Attempt to load the soundfile data.
FileRead file( fileName, typeRaw );
if ( file.channels() != 1 ) {
errorString_ << "Granulate::openFile: this class currently only supports monophonic soundfiles.";
handleError( StkError::FUNCTION_ARGUMENT );
}
data_.resize( file.fileSize(), file.channels() );
file.read( data_ );
lastFrame_.resize( 1, file.channels(), 0.0 );
this->reset();
@@ -102,7 +100,7 @@ void Granulate :: openFile( std::string fileName, bool typeRaw )
}
void Granulate :: reset()
void Granulate :: reset( void )
{
gPointer_ = 0;
@@ -115,7 +113,8 @@ void Granulate :: reset()
grains_[i].state = GRAIN_STOPPED;
}
lastOutput_ = 0.0;
for ( unsigned int i=0; i<lastFrame_.channels(); i++ )
lastFrame_[i] = 0.0;
}
void Granulate :: setVoices( unsigned int nVoices )
@@ -200,13 +199,22 @@ void Granulate :: calculateGrain( Granulate::Grain& grain )
grain.startPointer = grain.pointer;
}
StkFloat Granulate :: computeSample( void )
StkFloat Granulate :: tick( unsigned int channel )
{
lastOutput_ = 0.0;
if ( data_.size() == 0 ) return lastOutput_;
#if defined(_STK_DEBUG_)
if ( channel >= data_.channels() ) {
errorString_ << "Granulate::tick(): channel argument and soundfile data are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
unsigned int i, j, nChannels = lastFrame_.channels();
for ( j=0; j<nChannels; j++ ) lastFrame_[j] = 0.0;
if ( data_.size() == 0 ) return 0.0;
StkFloat sample;
for ( unsigned int i=0; i<grains_.size(); i++ ) {
for ( i=0; i<grains_.size(); i++ ) {
if ( grains_[i].counter == 0 ) { // Update the grain state.
@@ -251,16 +259,20 @@ StkFloat Granulate :: computeSample( void )
// Accumulate the grain outputs.
if ( grains_[i].state > 0 ) {
sample = data_[ grains_[i].pointer++ ];
for ( j=0; j<nChannels; j++ ) {
sample = data_[ nChannels * grains_[i].pointer + j ];
if ( grains_[i].state == GRAIN_FADEIN || grains_[i].state == GRAIN_FADEOUT ) {
sample *= grains_[i].eScaler;
grains_[i].eScaler += grains_[i].eRate;
if ( grains_[i].state == GRAIN_FADEIN || grains_[i].state == GRAIN_FADEOUT ) {
sample *= grains_[i].eScaler;
grains_[i].eScaler += grains_[i].eRate;
}
lastFrame_[j] += sample;
}
lastOutput_ += sample;
// Check pointer limits.
// Increment and check pointer limits.
grains_[i].pointer++;
if ( grains_[i].pointer >= data_.frames() )
grains_[i].pointer = 0;
}
@@ -276,6 +288,7 @@ StkFloat Granulate :: computeSample( void )
stretchCounter_ = 0;
}
return lastOutput_ * gain_;
return lastFrame_[channel];
}
} // stk namespace

View File

@@ -22,19 +22,21 @@
type who should worry about this (making
money) worry away.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "HevyMetl.h"
HevyMetl :: HevyMetl()
namespace stk {
HevyMetl :: HevyMetl( void )
: FM()
{
// Concatenate the STK rawwave path to the rawwave files
for ( unsigned int i=0; i<3; i++ )
waves_[i] = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
waves_[3] = new WaveLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
waves_[i] = new FileLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
waves_[3] = new FileLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
this->setRatio(0, 1.0 * 1.000);
this->setRatio(1, 4.0 * 0.999);
@@ -56,11 +58,11 @@ HevyMetl :: HevyMetl()
modDepth_ = 0.0;
}
HevyMetl :: ~HevyMetl()
HevyMetl :: ~HevyMetl( void )
{
}
void HevyMetl :: noteOn(StkFloat frequency, StkFloat amplitude)
void HevyMetl :: noteOn( StkFloat frequency, StkFloat amplitude )
{
gains_[0] = amplitude * fmGains_[92];
gains_[1] = amplitude * fmGains_[76];
@@ -75,29 +77,4 @@ void HevyMetl :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
StkFloat HevyMetl :: computeSample()
{
register StkFloat temp;
temp = vibrato_.tick() * modDepth_ * 0.2;
waves_[0]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[0]);
waves_[1]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[1]);
waves_[2]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[2]);
waves_[3]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[3]);
temp = gains_[2] * adsr_[2]->tick() * waves_[2]->tick();
waves_[1]->addPhaseOffset( temp );
waves_[3]->addPhaseOffset( twozero_.lastOut() );
temp = (1.0 - (control2_ * 0.5)) * gains_[3] * adsr_[3]->tick() * waves_[3]->tick();
twozero_.tick(temp);
temp += control2_ * 0.5 * gains_[1] * adsr_[1]->tick() * waves_[1]->tick();
temp = temp * control1_;
waves_[0]->addPhaseOffset( temp );
temp = gains_[0] * adsr_[0]->tick() * waves_[0]->tick();
lastOutput_ = temp * 0.5;
return lastOutput_;
}
} // stk namespace

125
src/Iir.cpp Normal file
View File

@@ -0,0 +1,125 @@
/***************************************************/
/*! \class Iir
\brief STK general infinite impulse response filter class.
This class provides a generic digital filter structure that can be
used to implement IIR filters. For filters containing only
feedforward terms, the Fir class is slightly more efficient.
In particular, this class implements the standard difference
equation:
a[0]*y[n] = b[0]*x[n] + ... + b[nb]*x[n-nb] -
a[1]*y[n-1] - ... - a[na]*y[n-na]
If a[0] is not equal to 1, the filter coeffcients are normalized
by a[0].
The \e gain parameter is applied at the filter input and does not
affect the coefficient values. The default gain value is 1.0.
This structure results in one extra multiply per computed sample,
but allows easy control of the overall filter gain.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Iir.h"
namespace stk {
Iir :: Iir()
{
// The default constructor should setup for pass-through.
b_.push_back( 1.0 );
a_.push_back( 1.0 );
inputs_.resize( 1, 1, 0.0 );
outputs_.resize( 1, 1, 0.0 );
}
Iir :: Iir( std::vector<StkFloat> &bCoefficients, std::vector<StkFloat> &aCoefficients )
{
// Check the arguments.
if ( bCoefficients.size() == 0 || aCoefficients.size() == 0 ) {
errorString_ << "Iir: a and b coefficient vectors must both have size > 0!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( aCoefficients[0] == 0.0 ) {
errorString_ << "Iir: a[0] coefficient cannot == 0!";
handleError( StkError::FUNCTION_ARGUMENT );
}
gain_ = 1.0;
b_ = bCoefficients;
a_ = aCoefficients;
inputs_.resize( b_.size(), 1, 0.0 );
outputs_.resize( a_.size(), 1, 0.0 );
this->clear();
}
Iir :: ~Iir()
{
}
void Iir :: setCoefficients( std::vector<StkFloat> &bCoefficients, std::vector<StkFloat> &aCoefficients, bool clearState )
{
this->setNumerator( bCoefficients, false );
this->setDenominator( aCoefficients, false );
if ( clearState ) this->clear();
}
void Iir :: setNumerator( std::vector<StkFloat> &bCoefficients, bool clearState )
{
// Check the argument.
if ( bCoefficients.size() == 0 ) {
errorString_ << "Iir::setNumerator: coefficient vector must have size > 0!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( b_.size() != bCoefficients.size() ) {
b_ = bCoefficients;
inputs_.resize( b_.size(), 1, 0.0 );
}
else {
for ( unsigned int i=0; i<b_.size(); i++ ) b_[i] = bCoefficients[i];
}
if ( clearState ) this->clear();
}
void Iir :: setDenominator( std::vector<StkFloat> &aCoefficients, bool clearState )
{
// Check the argument.
if ( aCoefficients.size() == 0 ) {
errorString_ << "Iir::setDenominator: coefficient vector must have size > 0!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( aCoefficients[0] == 0.0 ) {
errorString_ << "Iir::setDenominator: a[0] coefficient cannot == 0!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( a_.size() != aCoefficients.size() ) {
a_ = aCoefficients;
outputs_.resize( a_.size(), 1, 0.0 );
}
else {
for ( unsigned int i=0; i<a_.size(); i++ ) a_[i] = aCoefficients[i];
}
if ( clearState ) this->clear();
// Scale coefficients by a[0] if necessary
if ( a_[0] != 1.0 ) {
unsigned int i;
for ( i=0; i<b_.size(); i++ ) b_[i] /= a_[0];
for ( i=1; i<a_.size(); i++ ) a_[i] /= a_[0];
}
}
} // stk namespace

View File

@@ -8,10 +8,10 @@
supported.
InetWvIn supports multi-channel data. It is important to
distinguish the tick() methods, which return samples produced by
averaging across sample frames, from the tickFrame() methods,
which return references or pointers to multi-channel sample
frames.
distinguish the tick() method that computes a single frame (and
returns only the specified sample of a multi-channel frame) from
the overloaded one that takes an StkFrames object for
multi-channel and/or multi-frame data.
This class implements a socket server. When using the TCP
protocol, the server "listens" for a single remote connection
@@ -20,12 +20,14 @@
data type for the incoming stream is signed 16-bit integers,
though any of the defined StkFormats are permissible.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "InetWvIn.h"
namespace stk {
extern "C" THREAD_RETURN THREAD_TYPE inputThread( void * ptr )
{
ThreadInfo *info = (ThreadInfo *)ptr;
@@ -90,7 +92,7 @@ void InetWvIn :: listen( int port, unsigned int nChannels,
}
data_.resize( bufferFrames_, nChannels );
lastOutputs_.resize( 1, nChannels, 0.0 );
lastFrame_.resize( 1, nChannels, 0.0 );
bufferCounter_ = 0;
writePoint_ = 0;
@@ -254,22 +256,65 @@ bool InetWvIn :: isConnected( void )
return connected_;
}
void InetWvIn :: computeFrame( void )
StkFloat InetWvIn :: tick( unsigned int channel )
{
// If no connection and we've output all samples in the queue, return.
if ( !connected_ && bytesFilled_ == 0 && bufferCounter_ == 0 ) return;
// If no connection and we've output all samples in the queue, return 0.0.
if ( !connected_ && bytesFilled_ == 0 && bufferCounter_ == 0 ) {
#if defined(_STK_DEBUG_)
errorString_ << "InetWvIn::tick(): a valid socket connection does not exist!";
handleError( StkError::DEBUG_WARNING );
#endif
return 0.0;
}
#if defined(_STK_DEBUG_)
if ( channel >= data_.channels() ) {
errorString_ << "InetWvIn::tick(): channel argument is incompatible with data stream!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
if ( bufferCounter_ == 0 )
bufferCounter_ = readData();
unsigned int nChannels = lastOutputs_.channels();
long temp = (bufferFrames_ - bufferCounter_) * nChannels;
unsigned int nChannels = lastFrame_.channels();
long index = ( bufferFrames_ - bufferCounter_ ) * nChannels;
for ( unsigned int i=0; i<nChannels; i++ )
lastOutputs_[i] = data_[temp++];
lastFrame_[i] = data_[index++];
bufferCounter_--;
if ( bufferCounter_ < 0 )
bufferCounter_ = 0;
return;
return lastFrame_[channel];
}
StkFrames& InetWvIn :: tick( StkFrames& frames )
{
#if defined(_STK_DEBUG_)
if ( data_.channels() != frames.channels() ) {
errorString_ << "InetWvIn::tick(): StkFrames argument is incompatible with streamed channels!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
// If no connection and we've output all samples in the queue, return.
if ( !connected_ && bytesFilled_ == 0 && bufferCounter_ == 0 ) {
#if defined(_STK_DEBUG_)
errorString_ << "InetWvIn::tick(): a valid socket connection does not exist!";
handleError( StkError::DEBUG_WARNING );
#endif
return frames;
}
unsigned int j, counter = 0;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
this->tick();
for ( j=0; j<lastFrame_.channels(); j++ )
frames[counter++] = lastFrame_[j];
}
return frames;
}
} // stk namespace

View File

@@ -7,16 +7,17 @@
order, if necessary, before being transmitted.
InetWvOut supports multi-channel data. It is important to
distinguish the tick() methods, which output single samples to all
channels in a sample frame, from the tickFrame() method, which
takes a reference to multi-channel sample frame data.
distinguish the tick() method that outputs a single sample to all
channels in a sample frame from the overloaded one that takes a
reference to an StkFrames object for multi-channel and/or
multi-frame data.
This class connects to a socket server, the port and IP address of
which must be specified as constructor arguments. The default
data type is signed 16-bit integers but any of the defined
StkFormats are permissible.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
@@ -24,6 +25,8 @@
#include "TcpClient.h"
#include "UdpSocket.h"
namespace stk {
InetWvOut :: InetWvOut( unsigned long packetFrames )
: buffer_(0), soket_(0), bufferFrames_(packetFrames), bufferBytes_(0)
{
@@ -175,9 +178,15 @@ void InetWvOut :: incrementFrame( void )
}
}
void InetWvOut :: computeSample( const StkFloat sample )
void InetWvOut :: tick( const StkFloat sample )
{
if ( !soket_ || !soket_->isValid( soket_->id() ) ) return;
if ( !soket_ || !soket_->isValid( soket_->id() ) ) {
#if defined(_STK_DEBUG_)
errorString_ << "InetWvOut::tick(): a valid socket connection does not exist!";
handleError( StkError::DEBUG_WARNING );
#endif
return;
}
unsigned int nChannels = data_.channels();
StkFloat input = sample;
@@ -188,43 +197,34 @@ void InetWvOut :: computeSample( const StkFloat sample )
this->incrementFrame();
}
void InetWvOut :: computeFrames( const StkFrames& frames )
void InetWvOut :: tick( const StkFrames& frames )
{
if ( !soket_ || !soket_->isValid( soket_->id() ) ) return;
if ( !soket_ || !soket_->isValid( soket_->id() ) ) {
#if defined(_STK_DEBUG_)
errorString_ << "InetWvOut::tick(): a valid socket connection does not exist!";
handleError( StkError::DEBUG_WARNING );
#endif
return;
}
#if defined(_STK_DEBUG_)
if ( data_.channels() != frames.channels() ) {
errorString_ << "InetWvOut::computeFrames(): incompatible channel value in StkFrames argument!";
errorString_ << "InetWvOut::tick(): incompatible channel value in StkFrames argument!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
unsigned int j, nChannels = data_.channels();
if ( nChannels == 1 || frames.interleaved() ) {
unsigned int iFrames = 0;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
unsigned int iFrames = 0;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
for ( j=0; j<nChannels; j++ ) {
data_[iData_] = frames[iFrames++];
clipTest( data_[iData_++] );
}
this->incrementFrame();
for ( j=0; j<nChannels; j++ ) {
data_[iData_] = frames[iFrames++];
clipTest( data_[iData_++] );
}
}
else { // non-interleaved frames
unsigned long hop = frames.frames();
unsigned int index;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
index = i;
for ( j=0; j<nChannels; j++ ) {
data_[iData_] = frames[index];
clipTest( data_[iData_++] );
index += hop;
}
this->incrementFrame();
}
this->incrementFrame();
}
}
} // stk namespace

View File

@@ -1,81 +0,0 @@
/***************************************************/
/*! \class Instrmnt
\brief STK instrument abstract base class.
This class provides a common interface for
all STK instruments.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
*/
/***************************************************/
#include "Instrmnt.h"
Instrmnt :: Instrmnt()
{
}
Instrmnt :: ~Instrmnt()
{
}
void Instrmnt :: setFrequency(StkFloat frequency)
{
errorString_ << "Instrmnt::setFrequency: virtual setFrequency function call!";
handleError( StkError::WARNING );
}
StkFloat Instrmnt :: lastOut() const
{
return lastOutput_;
}
// Support for stereo output:
StkFloat Instrmnt :: lastOutLeft(void) const
{
return 0.5 * lastOutput_;
}
StkFloat Instrmnt :: lastOutRight(void) const
{
return 0.5 * lastOutput_;
}
StkFloat Instrmnt :: tick( void )
{
return computeSample();
}
StkFrames& Instrmnt :: tick( StkFrames& frames, unsigned int channel )
{
if ( channel >= frames.channels() ) {
errorString_ << "Instrmnt::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( frames.channels() == 1 ) {
for ( unsigned int i=0; i<frames.frames(); i++ )
frames[i] = tick();
}
else if ( frames.interleaved() ) {
unsigned int hop = frames.channels();
unsigned int index = channel;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
frames[index] = tick();
index += hop;
}
}
else {
unsigned int iStart = channel * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++, iStart++ )
frames[iStart] = tick();
}
return frames;
}
void Instrmnt :: controlChange(int number, StkFloat value)
{
errorString_ << "Instrmnt::controlChange: virtual function call!";
handleError( StkError::WARNING );
}

View File

@@ -2,38 +2,41 @@
/*! \class JCRev
\brief John Chowning's reverberator class.
This class is derived from the CLM JCRev
function, which is based on the use of
networks of simple allpass and comb delay
filters. This class implements three series
allpass units, followed by four parallel comb
filters, and two decorrelation delay lines in
parallel at the output.
This class takes a monophonic input signal and produces a stereo
output signal. It is derived from the CLM JCRev function, which
is based on the use of networks of simple allpass and comb delay
filters. This class implements three series allpass units,
followed by four parallel comb filters, and two decorrelation
delay lines in parallel at the output.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "JCRev.h"
#include <math.h>
#include <cmath>
JCRev :: JCRev(StkFloat T60)
namespace stk {
JCRev :: JCRev( StkFloat T60 )
{
lastFrame_.resize( 1, 2, 0.0 ); // resize lastFrame_ for stereo output
// Delay lengths for 44100 Hz sample rate.
int lengths[9] = {1777, 1847, 1993, 2137, 389, 127, 43, 211, 179};
double scaler = Stk::sampleRate() / 44100.0;
int delay, i;
if ( scaler != 1.0 ) {
for (i=0; i<9; i++) {
delay = (int) floor(scaler * lengths[i]);
for ( i=0; i<9; i++ ) {
delay = (int) floor( scaler * lengths[i] );
if ( (delay & 1) == 0) delay++;
while ( !this->isPrime(delay) ) delay += 2;
lengths[i] = delay;
}
}
for (i=0; i<3; i++) {
for ( i=0; i<3; i++ ) {
allpassDelays_[i].setMaximumDelay( lengths[i+4] );
allpassDelays_[i].setDelay( lengths[i+4] );
}
@@ -53,10 +56,6 @@ JCRev :: JCRev(StkFloat T60)
this->clear();
}
JCRev :: ~JCRev()
{
}
void JCRev :: clear()
{
allpassDelays_[0].clear();
@@ -68,8 +67,8 @@ void JCRev :: clear()
combDelays_[3].clear();
outRightDelay_.clear();
outLeftDelay_.clear();
lastOutput_[0] = 0.0;
lastOutput_[1] = 0.0;
lastFrame_[0] = 0.0;
lastFrame_[1] = 0.0;
}
void JCRev :: setT60( StkFloat T60 )
@@ -78,46 +77,44 @@ void JCRev :: setT60( StkFloat T60 )
combCoefficient_[i] = pow(10.0, (-3.0 * combDelays_[i].getDelay() / (T60 * Stk::sampleRate())));
}
StkFloat JCRev :: computeSample(StkFloat input)
StkFrames& JCRev :: tick( StkFrames& frames, unsigned int channel )
{
StkFloat temp, temp0, temp1, temp2, temp3, temp4, temp5, temp6;
StkFloat filtout;
#if defined(_STK_DEBUG_)
if ( channel >= frames.channels() - 1 ) {
errorString_ << "JCRev::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
temp = allpassDelays_[0].lastOut();
temp0 = allpassCoefficient_ * temp;
temp0 += input;
allpassDelays_[0].tick(temp0);
temp0 = -(allpassCoefficient_ * temp0) + temp;
temp = allpassDelays_[1].lastOut();
temp1 = allpassCoefficient_ * temp;
temp1 += temp0;
allpassDelays_[1].tick(temp1);
temp1 = -(allpassCoefficient_ * temp1) + temp;
temp = allpassDelays_[2].lastOut();
temp2 = allpassCoefficient_ * temp;
temp2 += temp1;
allpassDelays_[2].tick(temp2);
temp2 = -(allpassCoefficient_ * temp2) + temp;
temp3 = temp2 + (combCoefficient_[0] * combDelays_[0].lastOut());
temp4 = temp2 + (combCoefficient_[1] * combDelays_[1].lastOut());
temp5 = temp2 + (combCoefficient_[2] * combDelays_[2].lastOut());
temp6 = temp2 + (combCoefficient_[3] * combDelays_[3].lastOut());
StkFloat *samples = &frames[channel];
unsigned int hop = frames.channels();
for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
*samples = tick( *samples );
*samples++;
*samples = lastFrame_[1];
}
combDelays_[0].tick(temp3);
combDelays_[1].tick(temp4);
combDelays_[2].tick(temp5);
combDelays_[3].tick(temp6);
filtout = temp3 + temp4 + temp5 + temp6;
lastOutput_[0] = effectMix_ * (outLeftDelay_.tick(filtout));
lastOutput_[1] = effectMix_ * (outRightDelay_.tick(filtout));
temp = (1.0 - effectMix_) * input;
lastOutput_[0] += temp;
lastOutput_[1] += temp;
return Effect::lastOut();
return frames;
}
StkFrames& JCRev :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
{
#if defined(_STK_DEBUG_)
if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() - 1 ) {
errorString_ << "JCRev::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
StkFloat *iSamples = &iFrames[iChannel];
StkFloat *oSamples = &oFrames[oChannel];
unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
*oSamples++ = tick( *iSamples );
*oSamples = lastFrame_[1];
}
return iFrames;
}
} // stk namespace

View File

@@ -1,39 +0,0 @@
/***************************************************/
/*! \class JetTable
\brief STK jet table class.
This class implements a flue jet non-linear
function, computed by a polynomial calculation.
Contrary to the name, this is not a "table".
Consult Fletcher and Rossing, Karjalainen,
Cook, and others for more information.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
*/
/***************************************************/
#include "JetTable.h"
JetTable :: JetTable() : Function()
{
}
JetTable :: ~JetTable()
{
}
StkFloat JetTable :: computeSample( StkFloat input )
{
// Perform "table lookup" using a polynomial
// calculation (x^3 - x), which approximates
// the jet sigmoid behavior.
lastOutput_ = input * (input * input - (StkFloat) 1.0);
// Saturate at +/- 1.0.
if (lastOutput_ > 1.0)
lastOutput_ = (StkFloat) 1.0;
if (lastOutput_ < -1.0)
lastOutput_ = (StkFloat) -1.0;
return lastOutput_;
}

View File

@@ -7,11 +7,12 @@ RM = /bin/rm
OBJECT_PATH = @object_path@
vpath %.o $(OBJECT_PATH)
OBJECTS = Stk.o Generator.o Noise.o SubNoise.o Blit.o BlitSaw.o BlitSquare.o \
Envelope.o ADSR.o Asymp.o Modulate.o SingWave.o SineWave.o Granulate.o \
FileRead.o FileWrite.o WvIn.o FileWvIn.o WaveLoop.o WvOut.o FileWvOut.o \
Filter.o OneZero.o OnePole.o PoleZero.o TwoZero.o TwoPole.o \
OBJECTS = Stk.o Generator.o Noise.o Blit.o BlitSaw.o BlitSquare.o Granulate.o \
Envelope.o ADSR.o Asymp.o Modulate.o SineWave.o FileLoop.o SingWave.o \
FileRead.o FileWrite.o WvIn.o FileWvIn.o WvOut.o FileWvOut.o \
Filter.o Fir.o Iir.o OneZero.o OnePole.o PoleZero.o TwoZero.o TwoPole.o \
BiQuad.o FormSwep.o Delay.o DelayL.o DelayA.o \
\
Effect.o PRCRev.o JCRev.o NRev.o \
Chorus.o Echo.o PitShift.o \
Function.o ReedTable.o JetTable.o BowTable.o \
@@ -25,7 +26,6 @@ OBJECTS = Stk.o Generator.o Noise.o SubNoise.o Blit.o BlitSaw.o BlitSquare.o \
\
Messager.o Skini.o MidiFileIn.o
INCLUDE = @include@
ifeq ($(strip $(INCLUDE)),)
vpath %.h ../include
@@ -36,20 +36,19 @@ else
endif
CC = @CXX@
DEFS = @byte_order@
DEFS += @debug@
CFLAGS = @cflags@
CFLAGS += @warn@ $(INCLUDE) -Iinclude
DEFS = @CPPFLAGS@
DEFS += @byte_order@
CFLAGS = @CXXFLAGS@
CFLAGS += $(INCLUDE) -Iinclude
REALTIME = @realtime@
ifeq ($(REALTIME),yes)
OBJECTS += RtMidi.o RtAudio.o RtWvOut.o RtWvIn.o InetWvOut.o InetWvIn.o Thread.o Mutex.o Socket.o TcpClient.o TcpServer.o UdpSocket.o @objects@
DEFS += @audio_apis@
endif
RAWWAVES = @rawwaves@
ifeq ($(strip $(RAWWAVES)), )
RAWWAVES = ../rawwaves/
RAWWAVES = ../../rawwaves/
endif
DEFS += -DRAWWAVE_PATH=\"$(RAWWAVES)\"
@@ -70,3 +69,4 @@ $(OBJECTS) : Stk.h
clean :
-rm $(OBJECT_PATH)/*.o
-rm $(LIBRARY)
-rm -fR *.dSYM

View File

@@ -23,15 +23,17 @@
- String Detuning = 1
- Microphone Position = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Mandolin.h"
#include "SKINI.msg"
Mandolin :: Mandolin(StkFloat lowestFrequency)
: PluckTwo(lowestFrequency)
namespace stk {
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 );
@@ -52,7 +54,7 @@ Mandolin :: Mandolin(StkFloat lowestFrequency)
waveDone_ = soundfile_[mic_]->isFinished();
}
Mandolin :: ~Mandolin()
Mandolin :: ~Mandolin( void )
{
for ( int i=0; i<12; i++ )
delete soundfile_[i];
@@ -83,7 +85,7 @@ void Mandolin :: pluck( StkFloat amplitude )
dampTime_ = (long) lastLength_; // See tick method below.
}
void Mandolin :: pluck(StkFloat amplitude, StkFloat position)
void Mandolin :: pluck( StkFloat amplitude, StkFloat position )
{
// Pluck position puts zeroes at position * length.
pluckPosition_ = position;
@@ -101,7 +103,7 @@ void Mandolin :: pluck(StkFloat amplitude, StkFloat position)
this->pluck( amplitude );
}
void Mandolin :: noteOn(StkFloat frequency, StkFloat amplitude)
void Mandolin :: noteOn( StkFloat frequency, StkFloat amplitude )
{
this->setFrequency( frequency );
this->pluck( amplitude );
@@ -112,7 +114,7 @@ void Mandolin :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
void Mandolin :: setBodySize(StkFloat size)
void Mandolin :: setBodySize( StkFloat size )
{
// Scale the commuted body response by its sample rate (22050).
StkFloat rate = size * 22050.0 / Stk::sampleRate();
@@ -120,37 +122,7 @@ void Mandolin :: setBodySize(StkFloat size)
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)
void Mandolin :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -184,3 +156,5 @@ void Mandolin :: controlChange(int number, StkFloat value)
handleError( StkError::DEBUG_WARNING );
#endif
}
} // stk namespace

View File

@@ -27,7 +27,9 @@
#include "Mesh2D.h"
#include "SKINI.msg"
Mesh2D :: Mesh2D(short nX, short nY)
namespace stk {
Mesh2D :: Mesh2D( short nX, short nY )
{
this->setNX(nX);
this->setNY(nY);
@@ -52,11 +54,11 @@ Mesh2D :: Mesh2D(short nX, short nY)
yInput_ = 0;
}
Mesh2D :: ~Mesh2D()
Mesh2D :: ~Mesh2D( void )
{
}
void Mesh2D :: clear()
void Mesh2D :: clear( void )
{
this->clearMesh();
@@ -70,7 +72,7 @@ void Mesh2D :: clear()
counter_=0;
}
void Mesh2D :: clearMesh()
void Mesh2D :: clearMesh( void )
{
int x, y;
for (x=0; x<NXMAX-1; x++) {
@@ -94,7 +96,7 @@ void Mesh2D :: clearMesh()
}
}
StkFloat Mesh2D :: energy()
StkFloat Mesh2D :: energy( void )
{
// Return total energy contained in wave variables Note that some
// energy is also contained in any filter delay elements.
@@ -134,7 +136,7 @@ StkFloat Mesh2D :: energy()
return(e);
}
void Mesh2D :: setNX(short lenX)
void Mesh2D :: setNX( short lenX )
{
NX_ = lenX;
if ( lenX < 2 ) {
@@ -149,7 +151,7 @@ void Mesh2D :: setNX(short lenX)
}
}
void Mesh2D :: setNY(short lenY)
void Mesh2D :: setNY( short lenY )
{
NY_ = lenY;
if ( lenY < 2 ) {
@@ -164,7 +166,7 @@ void Mesh2D :: setNY(short lenY)
}
}
void Mesh2D :: setDecay(StkFloat decayFactor)
void Mesh2D :: setDecay( StkFloat decayFactor )
{
StkFloat gain = decayFactor;
if ( decayFactor < 0.0 ) {
@@ -186,7 +188,7 @@ void Mesh2D :: setDecay(StkFloat decayFactor)
filterX_[i].setGain( gain );
}
void Mesh2D :: setInputPosition(StkFloat xFactor, StkFloat yFactor)
void Mesh2D :: setInputPosition( StkFloat xFactor, StkFloat yFactor )
{
if ( xFactor < 0.0 ) {
errorString_ << "Mesh2D::setInputPosition xFactor value is less than 0.0!";
@@ -215,7 +217,7 @@ void Mesh2D :: setInputPosition(StkFloat xFactor, StkFloat yFactor)
yInput_ = (short) (yFactor * (NY_ - 1));
}
void Mesh2D :: noteOn(StkFloat frequency, StkFloat amplitude)
void Mesh2D :: noteOn( StkFloat frequency, StkFloat amplitude )
{
// Input at corner.
if ( counter_ & 1 ) {
@@ -233,7 +235,7 @@ void Mesh2D :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
void Mesh2D :: noteOff(StkFloat amplitude)
void Mesh2D :: noteOff( StkFloat amplitude )
{
#if defined(_STK_DEBUG_)
errorString_ << "Mesh2D::NoteOff: amplitude = " << amplitude << ".";
@@ -246,28 +248,28 @@ StkFloat Mesh2D :: inputTick( StkFloat input )
if ( counter_ & 1 ) {
vxp1_[xInput_][yInput_] += input;
vyp1_[xInput_][yInput_] += input;
lastOutput_ = tick1();
lastFrame_[0] = tick1();
}
else {
vxp_[xInput_][yInput_] += input;
vyp_[xInput_][yInput_] += input;
lastOutput_ = tick0();
lastFrame_[0] = tick0();
}
counter_++;
return lastOutput_;
return lastFrame_[0];
}
StkFloat Mesh2D :: computeSample()
StkFloat Mesh2D :: tick( unsigned int )
{
lastOutput_ = ((counter_ & 1) ? this->tick1() : this->tick0());
lastFrame_[0] = ((counter_ & 1) ? this->tick1() : this->tick0());
counter_++;
return lastOutput_;
return lastFrame_[0];
}
const StkFloat VSCALE = 0.5;
StkFloat Mesh2D :: tick0()
StkFloat Mesh2D :: tick0( void )
{
int x, y;
StkFloat outsamp = 0;
@@ -315,7 +317,7 @@ StkFloat Mesh2D :: tick0()
return outsamp;
}
StkFloat Mesh2D :: tick1()
StkFloat Mesh2D :: tick1( void )
{
int x, y;
StkFloat outsamp = 0;
@@ -362,7 +364,7 @@ StkFloat Mesh2D :: tick1()
return outsamp;
}
void Mesh2D :: controlChange(int number, StkFloat value)
void Mesh2D :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -394,3 +396,5 @@ void Mesh2D :: controlChange(int number, StkFloat value)
handleError( StkError::DEBUG_WARNING );
#endif
}
} // stk namespace

View File

@@ -28,14 +28,24 @@
This class is primarily for use in STK example programs but it is
generic enough to work in many other contexts.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Messager.h"
#include <iostream>
#include <algorithm>
#include "SKINI.msg"
namespace stk {
#if defined(__STK_REALTIME__)
extern "C" THREAD_RETURN THREAD_TYPE stdinHandler(void * ptr);
extern "C" THREAD_RETURN THREAD_TYPE socketHandler(void * ptr);
#endif // __STK_REALTIME__
static const int STK_FILE = 0x1;
static const int STK_MIDI = 0x2;
static const int STK_STDIN = 0x4;
@@ -152,6 +162,8 @@ bool Messager :: startStdInput()
return true;
}
//} // stk namespace
THREAD_RETURN THREAD_TYPE stdinHandler(void *ptr)
{
Messager::MessagerData *data = (Messager::MessagerData *) ptr;
@@ -208,6 +220,8 @@ void midiHandler( double timeStamp, std::vector<unsigned char> *bytes, void *ptr
data->mutex.unlock();
}
//namespace stk {
bool Messager :: startMidiInput( int port )
{
if ( data_.sources == STK_FILE ) {
@@ -290,6 +304,8 @@ bool Messager :: startSocketInput( int port )
return true;
}
//} // stk namespace
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
#include <sys/time.h>
#include <errno.h>
@@ -412,4 +428,7 @@ THREAD_RETURN THREAD_TYPE socketHandler(void *ptr)
return NULL;
}
} // stk namespace
#endif

View File

@@ -11,13 +11,16 @@
Tempo changes are internally tracked by the class and reflected in
the values returned by the function getTickSeconds().
by Gary P. Scavone, 2003.
by Gary P. Scavone, 2003 - 2009.
*/
/**********************************************************************/
#include "MidiFileIn.h"
#include <string.h>
#include <iostream>
namespace stk {
MidiFileIn :: MidiFileIn( std::string fileName )
{
// Attempt to open the file.
@@ -360,3 +363,5 @@ bool MidiFileIn :: readVariableLength( unsigned long *value )
return true;
}
} // stk namespace

View File

@@ -1,19 +1,21 @@
/***************************************************/
/*! \class Modal
\brief STK resonance model instrument.
\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 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Modal.h"
Modal :: Modal(unsigned int modes)
namespace stk {
Modal :: Modal( unsigned int modes )
: nModes_(modes)
{
if ( nModes_ == 0 ) {
@@ -45,29 +47,29 @@ Modal :: Modal(unsigned int modes)
strikePosition_ = 0.561;
}
Modal :: ~Modal()
Modal :: ~Modal( void )
{
for (unsigned int i=0; i<nModes_; i++ ) {
for ( unsigned int i=0; i<nModes_; i++ ) {
delete filters_[i];
}
free(filters_);
free( filters_ );
}
void Modal :: clear()
void Modal :: clear( void )
{
onepole_.clear();
for (unsigned int i=0; i<nModes_; i++ )
for ( unsigned int i=0; i<nModes_; i++ )
filters_[i]->clear();
}
void Modal :: setFrequency(StkFloat frequency)
void Modal :: setFrequency( StkFloat frequency )
{
baseFrequency_ = frequency;
for (unsigned int i=0; i<nModes_; i++ )
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)
void Modal :: setRatioAndRadius( unsigned int modeIndex, StkFloat ratio, StkFloat radius )
{
if ( modeIndex >= nModes_ ) {
errorString_ << "Modal::setRatioAndRadius: modeIndex parameter is greater than number of modes!";
@@ -99,17 +101,7 @@ void Modal :: setRatioAndRadius(unsigned int modeIndex, StkFloat ratio, StkFloat
filters_[modeIndex]->setResonance(temp, radius);
}
void Modal :: setMasterGain(StkFloat aGain)
{
masterGain_ = aGain;
}
void Modal :: setDirectGain(StkFloat aGain)
{
directGain_ = aGain;
}
void Modal :: setModeGain(unsigned int modeIndex, StkFloat gain)
void Modal :: setModeGain( unsigned int modeIndex, StkFloat gain )
{
if ( modeIndex >= nModes_ ) {
errorString_ << "Modal::setModeGain: modeIndex parameter is greater than number of modes!";
@@ -117,10 +109,10 @@ void Modal :: setModeGain(unsigned int modeIndex, StkFloat gain)
return;
}
filters_[modeIndex]->setGain(gain);
filters_[modeIndex]->setGain( gain );
}
void Modal :: strike(StkFloat amplitude)
void Modal :: strike( StkFloat amplitude )
{
StkFloat gain = amplitude;
if ( amplitude < 0.0 ) {
@@ -141,7 +133,7 @@ void Modal :: strike(StkFloat amplitude)
wave_->reset();
StkFloat temp;
for (unsigned int i=0; i<nModes_; i++) {
for ( unsigned int i=0; i<nModes_; i++ ) {
if (ratios_[i] < 0)
temp = -ratios_[i];
else
@@ -150,7 +142,7 @@ void Modal :: strike(StkFloat amplitude)
}
}
void Modal :: noteOn(StkFloat frequency, StkFloat amplitude)
void Modal :: noteOn( StkFloat frequency, StkFloat amplitude )
{
this->strike(amplitude);
this->setFrequency(frequency);
@@ -161,7 +153,7 @@ void Modal :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
void Modal :: noteOff(StkFloat amplitude)
void Modal :: noteOff( StkFloat amplitude )
{
// This calls damp, but inverts the meaning of amplitude (high
// amplitude means fast damping).
@@ -173,35 +165,16 @@ void Modal :: noteOff(StkFloat amplitude)
#endif
}
void Modal :: damp(StkFloat amplitude)
void Modal :: damp( StkFloat amplitude )
{
StkFloat temp;
for (unsigned int i=0; i<nModes_; i++) {
if (ratios_[i] < 0)
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);
filters_[i]->setResonance( temp, radii_[i]*amplitude );
}
}
StkFloat Modal :: computeSample()
{
StkFloat temp = masterGain_ * onepole_.tick( wave_->tick() * envelope_.tick() );
StkFloat temp2 = 0.0;
for (unsigned int i=0; i<nModes_; i++)
temp2 += filters_[i]->tick(temp);
temp2 -= temp2 * directGain_;
temp2 += directGain_ * temp;
if (vibratoGain_ != 0.0) {
// Calculate AM and apply to master out
temp = 1.0 + (vibrato_.tick() * vibratoGain_);
temp2 = temp * temp2;
}
lastOutput_ = temp2;
return lastOutput_;
}
} // stk namespace

View File

@@ -24,7 +24,7 @@
- Two Fixed = 7
- Clump = 8
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
@@ -32,7 +32,9 @@
#include "SKINI.msg"
#include <cmath>
ModalBar :: ModalBar()
namespace stk {
ModalBar :: ModalBar( void )
: Modal()
{
// Concatenate the STK rawwave path to the rawwave file
@@ -43,12 +45,12 @@ ModalBar :: ModalBar()
this->setPreset( 0 );
}
ModalBar :: ~ModalBar()
ModalBar :: ~ModalBar( void )
{
delete wave_;
}
void ModalBar :: setStickHardness(StkFloat hardness)
void ModalBar :: setStickHardness( StkFloat hardness )
{
stickHardness_ = hardness;
if ( hardness < 0.0 ) {
@@ -66,7 +68,7 @@ void ModalBar :: setStickHardness(StkFloat hardness)
masterGain_ = 0.1 + (1.8 * stickHardness_);
}
void ModalBar :: setStrikePosition(StkFloat position)
void ModalBar :: setStrikePosition( StkFloat position )
{
strikePosition_ = position;
if ( position < 0.0 ) {
@@ -92,7 +94,7 @@ void ModalBar :: setStrikePosition(StkFloat position)
this->setModeGain(2, 0.11 * temp);
}
void ModalBar :: setPreset(int preset)
void ModalBar :: setPreset( int preset )
{
// Presets:
// First line: relative modal frequencies (negative number is
@@ -156,7 +158,7 @@ void ModalBar :: setPreset(int preset)
vibratoGain_ = 0.0;
}
void ModalBar :: controlChange(int number, StkFloat value)
void ModalBar :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -194,3 +196,5 @@ void ModalBar :: controlChange(int number, StkFloat value)
handleError( StkError::DEBUG_WARNING );
#endif
}
} // stk namespace

View File

@@ -6,54 +6,44 @@
modulations to give a nice, natural human
modulation function.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Modulate.h"
Modulate :: Modulate()
namespace stk {
Modulate :: Modulate( void )
{
vibrato_.setFrequency( 6.0 );
vibratoGain_ = 0.04;
noise_.setRate( 330 );
randomGain_ = 0.05;
noiseRate_ = (unsigned int) ( 330.0 * Stk::sampleRate() / 22050.0 );
noiseCounter_ = noiseRate_;
randomGain_ = 0.05;
filter_.setPole( 0.999 );
filter_.setGain( randomGain_ );
Stk::addSampleRateAlert( this );
}
Modulate :: ~Modulate()
Modulate :: ~Modulate( void )
{
Stk::removeSampleRateAlert( this );
}
void Modulate :: reset()
void Modulate :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
{
lastOutput_ = (StkFloat) 0.0;
if ( !ignoreSampleRateChange_ )
noiseRate_ = (unsigned int ) ( newRate * noiseRate_ / oldRate );
}
void Modulate :: setVibratoRate(StkFloat rate)
{
vibrato_.setFrequency( rate );
}
void Modulate :: setVibratoGain(StkFloat gain)
{
vibratoGain_ = gain;
}
void Modulate :: setRandomGain(StkFloat gain)
void Modulate :: setRandomGain( StkFloat gain )
{
randomGain_ = gain;
filter_.setGain( randomGain_ );
}
StkFloat Modulate :: computeSample()
{
// Compute periodic and random modulations.
lastOutput_ = vibratoGain_ * vibrato_.tick();
lastOutput_ += filter_.tick( noise_.tick() );
return lastOutput_;
}
} // stk namespace

View File

@@ -14,19 +14,21 @@
- Vibrato Gain = 1
- Gain = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Moog.h"
#include "SKINI.msg"
Moog :: Moog()
namespace stk {
Moog :: Moog( void )
{
// Concatenate the STK rawwave path to the rawwave file
attacks_.push_back( new FileWvIn( (Stk::rawwavePath() + "mandpluk.raw").c_str(), true ) );
loops_.push_back ( new WaveLoop( (Stk::rawwavePath() + "impuls20.raw").c_str(), true ) );
loops_.push_back ( new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true ) ); // vibrato
loops_.push_back ( new FileLoop( (Stk::rawwavePath() + "impuls20.raw").c_str(), true ) );
loops_.push_back ( new FileLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true ) ); // vibrato
loops_[1]->setFrequency( 6.122 );
filters_[0].setTargets( 0.0, 0.7 );
@@ -38,11 +40,11 @@ Moog :: Moog()
modDepth_ = 0.0;
}
Moog :: ~Moog()
Moog :: ~Moog( void )
{
}
void Moog :: setFrequency(StkFloat frequency)
void Moog :: setFrequency( StkFloat frequency )
{
baseFrequency_ = frequency;
if ( frequency <= 0.0 ) {
@@ -56,7 +58,7 @@ void Moog :: setFrequency(StkFloat frequency)
loops_[0]->setFrequency( baseFrequency_ );
}
void Moog :: noteOn(StkFloat frequency, StkFloat amplitude)
void Moog :: noteOn( StkFloat frequency, StkFloat amplitude )
{
StkFloat temp;
@@ -82,35 +84,7 @@ void Moog :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
void Moog :: setModulationSpeed(StkFloat mSpeed)
{
loops_[1]->setFrequency( mSpeed );
}
void Moog :: setModulationDepth(StkFloat mDepth)
{
modDepth_ = mDepth * 0.5;
}
StkFloat Moog :: computeSample()
{
StkFloat temp;
if ( modDepth_ != 0.0 ) {
temp = loops_[1]->tick() * modDepth_;
loops_[0]->setFrequency( baseFrequency_ * (1.0 + temp) );
}
temp = attackGain_ * attacks_[0]->tick();
temp += loopGain_ * loops_[0]->tick();
temp = filter_.tick( temp );
temp *= adsr_.tick();
temp = filters_[0].tick( temp );
lastOutput_ = filters_[1].tick( temp );
return lastOutput_ * 3.0;
}
void Moog :: controlChange(int number, StkFloat value)
void Moog :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -144,3 +118,5 @@ void Moog :: controlChange(int number, StkFloat value)
handleError( StkError::DEBUG_WARNING );
#endif
}
} // stk namespace

View File

@@ -7,12 +7,14 @@
systems, the pthread library is used. Under
Windows, critical sections are used.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Mutex.h"
namespace stk {
Mutex :: Mutex()
{
@@ -98,3 +100,5 @@ void Mutex :: signal()
#endif
}
} // stk namespace

View File

@@ -2,43 +2,45 @@
/*! \class NRev
\brief CCRMA's NRev reverberator class.
This class is derived from the CLM NRev
function, which is based on the use of
networks of simple allpass and comb delay
filters. This particular arrangement consists
of 6 comb filters in parallel, followed by 3
allpass filters, a lowpass filter, and another
allpass in series, followed by two allpass
filters in parallel with corresponding right
and left outputs.
This class takes a monophonic input signal and produces a stereo
output signal. It is derived from the CLM NRev function, which is
based on the use of networks of simple allpass and comb delay
filters. This particular arrangement consists of 6 comb filters
in parallel, followed by 3 allpass filters, a lowpass filter, and
another allpass in series, followed by two allpass filters in
parallel with corresponding right and left outputs.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "NRev.h"
#include <math.h>
#include <cmath>
NRev :: NRev(StkFloat T60)
namespace stk {
NRev :: NRev( StkFloat T60 )
{
lastFrame_.resize( 1, 2, 0.0 ); // resize lastFrame_ for stereo output
int lengths[15] = {1433, 1601, 1867, 2053, 2251, 2399, 347, 113, 37, 59, 53, 43, 37, 29, 19};
double scaler = Stk::sampleRate() / 25641.0;
int delay, i;
for (i=0; i<15; i++) {
for ( i=0; i<15; i++ ) {
delay = (int) floor(scaler * lengths[i]);
if ( (delay & 1) == 0) delay++;
while ( !this->isPrime(delay) ) delay += 2;
lengths[i] = delay;
}
for (i=0; i<6; i++) {
for ( i=0; i<6; i++ ) {
combDelays_[i].setMaximumDelay( lengths[i] );
combDelays_[i].setDelay( lengths[i] );
combCoefficient_[i] = pow(10.0, (-3 * lengths[i] / (T60 * Stk::sampleRate())));
}
for (i=0; i<8; i++) {
for ( i=0; i<8; i++ ) {
allpassDelays_[i].setMaximumDelay( lengths[i+6] );
allpassDelays_[i].setDelay( lengths[i+6] );
}
@@ -49,17 +51,13 @@ NRev :: NRev(StkFloat T60)
this->clear();
}
NRev :: ~NRev()
{
}
void NRev :: clear()
{
int i;
for (i=0; i<6; i++) combDelays_[i].clear();
for (i=0; i<8; i++) allpassDelays_[i].clear();
lastOutput_[0] = 0.0;
lastOutput_[1] = 0.0;
lastFrame_[0] = 0.0;
lastFrame_[1] = 0.0;
lowpassState_ = 0.0;
}
@@ -69,47 +67,44 @@ void NRev :: setT60( StkFloat T60 )
combCoefficient_[i] = pow(10.0, (-3.0 * combDelays_[i].getDelay() / (T60 * Stk::sampleRate())));
}
StkFloat NRev :: computeSample(StkFloat input)
StkFrames& NRev :: tick( StkFrames& frames, unsigned int channel )
{
StkFloat temp, temp0, temp1, temp2, temp3;
int i;
temp0 = 0.0;
for (i=0; i<6; i++) {
temp = input + (combCoefficient_[i] * combDelays_[i].lastOut());
temp0 += combDelays_[i].tick(temp);
#if defined(_STK_DEBUG_)
if ( channel >= frames.channels() - 1 ) {
errorString_ << "NRev::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
for (i=0; i<3; i++) {
temp = allpassDelays_[i].lastOut();
temp1 = allpassCoefficient_ * temp;
temp1 += temp0;
allpassDelays_[i].tick(temp1);
temp0 = -(allpassCoefficient_ * temp1) + temp;
#endif
StkFloat *samples = &frames[channel];
unsigned int hop = frames.channels();
for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
*samples = tick( *samples );
samples++;
*samples = lastFrame_[1];
}
// One-pole lowpass filter.
lowpassState_ = 0.7*lowpassState_ + 0.3*temp0;
temp = allpassDelays_[3].lastOut();
temp1 = allpassCoefficient_ * temp;
temp1 += lowpassState_;
allpassDelays_[3].tick(temp1);
temp1 = -(allpassCoefficient_ * temp1) + temp;
temp = allpassDelays_[4].lastOut();
temp2 = allpassCoefficient_ * temp;
temp2 += temp1;
allpassDelays_[4].tick(temp2);
lastOutput_[0] = effectMix_*(-(allpassCoefficient_ * temp2) + temp);
temp = allpassDelays_[5].lastOut();
temp3 = allpassCoefficient_ * temp;
temp3 += temp1;
allpassDelays_[5].tick(temp3);
lastOutput_[1] = effectMix_*(-(allpassCoefficient_ * temp3) + temp);
temp = (1.0 - effectMix_) * input;
lastOutput_[0] += temp;
lastOutput_[1] += temp;
return Effect::lastOut();
return frames;
}
StkFrames& NRev :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
{
#if defined(_STK_DEBUG_)
if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() - 1 ) {
errorString_ << "NRev::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
StkFloat *iSamples = &iFrames[iChannel];
StkFloat *oSamples = &oFrames[oChannel];
unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
*oSamples++ = tick( *iSamples );
*oSamples = lastFrame_[1];
}
return iFrames;
}
} // stk namespace

View File

@@ -6,44 +6,29 @@
C rand() function. The quality of the rand()
function varies from one OS to another.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Noise.h"
#include <stdlib.h>
#include <time.h>
Noise :: Noise() : Generator()
{
// Seed the random number generator with system time.
this->setSeed( 0 );
lastOutput_ = (StkFloat) 0.0;
}
namespace stk {
Noise :: Noise( unsigned int seed ) : Generator()
Noise :: Noise( unsigned int seed )
{
// Seed the random number generator
this->setSeed( seed );
lastOutput_ = (StkFloat) 0.0;
}
Noise :: ~Noise()
{
}
void Noise :: setSeed( unsigned int seed )
{
if ( seed == 0 )
srand( (unsigned int) time(NULL) );
srand( (unsigned int) time( NULL ) );
else
srand( seed );
}
StkFloat Noise :: computeSample()
{
lastOutput_ = (StkFloat) (2.0 * rand() / (RAND_MAX + 1.0) );
lastOutput_ -= 1.0;
return lastOutput_;
}
} // stk namespace

View File

@@ -2,64 +2,36 @@
/*! \class OnePole
\brief STK one-pole filter class.
This protected Filter subclass implements
a one-pole digital filter. A method is
provided for setting the pole position along
the real axis of the z-plane while maintaining
a constant peak filter gain.
This class implements a one-pole digital filter. A method is
provided for setting the pole position along the real axis of the
z-plane while maintaining a constant peak filter gain.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "OnePole.h"
OnePole :: OnePole() : Filter()
namespace stk {
OnePole :: OnePole( StkFloat thePole )
{
std::vector<StkFloat> b(1, 0.1);
std::vector<StkFloat> a(2, 1.0);
a[1] = -0.9;
Filter::setCoefficients( b, a );
}
b_.resize( 1 );
a_.resize( 2 );
inputs_.resize( 1, 1, 0.0 );
outputs_.resize( 2, 1, 0.0 );
OnePole :: OnePole(StkFloat thePole) : Filter()
{
std::vector<StkFloat> b(1);
std::vector<StkFloat> a(2, 1.0);
a[1] = -thePole;
// Normalize coefficients for peak unity gain.
if (thePole > 0.0)
b[0] = (StkFloat) (1.0 - thePole);
else
b[0] = (StkFloat) (1.0 + thePole);
Filter::setCoefficients( b, a );
this->setPole( thePole );
}
OnePole :: ~OnePole()
{
}
void OnePole :: clear(void)
{
Filter::clear();
}
void OnePole :: setB0(StkFloat b0)
{
b_[0] = b0;
}
void OnePole :: setA1(StkFloat a1)
{
a_[1] = a1;
}
void OnePole :: setPole(StkFloat thePole)
void OnePole :: setPole( StkFloat thePole )
{
// Normalize coefficients for peak unity gain.
if (thePole > 0.0)
if ( thePole > 0.0 )
b_[0] = (StkFloat) (1.0 - thePole);
else
b_[0] = (StkFloat) (1.0 + thePole);
@@ -67,31 +39,12 @@ void OnePole :: setPole(StkFloat thePole)
a_[1] = -thePole;
}
void OnePole :: setGain(StkFloat gain)
void OnePole :: setCoefficients( StkFloat b0, StkFloat a1, bool clearState )
{
Filter::setGain(gain);
b_[0] = b0;
a_[1] = a1;
if ( clearState ) this->clear();
}
StkFloat OnePole :: getGain(void) const
{
return Filter::getGain();
}
StkFloat OnePole :: lastOut(void) const
{
return Filter::lastOut();
}
StkFloat OnePole :: tick( StkFloat input )
{
inputs_[0] = gain_ * input;
outputs_[0] = b_[0] * inputs_[0] - a_[1] * outputs_[1];
outputs_[1] = outputs_[0];
return outputs_[0];
}
StkFrames& OnePole :: tick( StkFrames& frames, unsigned int channel )
{
return Filter::tick( frames, channel );
}
} // stk namespace

View File

@@ -2,63 +2,34 @@
/*! \class OneZero
\brief STK one-zero filter class.
This protected Filter subclass implements
a one-zero digital filter. A method is
provided for setting the zero position
along the real axis of the z-plane while
maintaining a constant filter gain.
This class implements a one-zero digital filter. A method is
provided for setting the zero position along the real axis of the
z-plane while maintaining a constant filter gain.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "OneZero.h"
OneZero :: OneZero() : Filter()
namespace stk {
OneZero :: OneZero( StkFloat theZero )
{
std::vector<StkFloat> b(2, 0.5);
std::vector<StkFloat> a(1, 1.0);
Filter::setCoefficients( b, a );
b_.resize( 2 );
inputs_.resize( 2, 1, 0.0 );
this->setZero( theZero );
}
OneZero :: OneZero(StkFloat theZero) : Filter()
{
std::vector<StkFloat> b(2);
std::vector<StkFloat> a(1, 1.0);
// Normalize coefficients for unity gain.
if (theZero > 0.0)
b[0] = 1.0 / ((StkFloat) 1.0 + theZero);
else
b[0] = 1.0 / ((StkFloat) 1.0 - theZero);
b[1] = -theZero * b[0];
Filter::setCoefficients( b, a );
}
OneZero :: ~OneZero(void)
OneZero :: ~OneZero( void )
{
}
void OneZero :: clear(void)
{
Filter::clear();
}
void OneZero :: setB0(StkFloat b0)
{
b_[0] = b0;
}
void OneZero :: setB1(StkFloat b1)
{
b_[1] = b1;
}
void OneZero :: setZero(StkFloat theZero)
void OneZero :: setZero( StkFloat theZero )
{
// Normalize coefficients for unity gain.
if (theZero > 0.0)
if ( theZero > 0.0 )
b_[0] = 1.0 / ((StkFloat) 1.0 + theZero);
else
b_[0] = 1.0 / ((StkFloat) 1.0 - theZero);
@@ -66,31 +37,12 @@ void OneZero :: setZero(StkFloat theZero)
b_[1] = -theZero * b_[0];
}
void OneZero :: setGain(StkFloat gain)
void OneZero :: setCoefficients( StkFloat b0, StkFloat b1, bool clearState )
{
Filter::setGain(gain);
b_[0] = b0;
b_[1] = b1;
if ( clearState ) this->clear();
}
StkFloat OneZero :: getGain(void) const
{
return Filter::getGain();
}
StkFloat OneZero :: lastOut(void) const
{
return Filter::lastOut();
}
StkFloat OneZero :: tick( StkFloat input )
{
inputs_[0] = gain_ * input;
outputs_[0] = b_[1] * inputs_[1] + b_[0] * inputs_[0];
inputs_[1] = inputs_[0];
return outputs_[0];
}
StkFrames& OneZero :: tick( StkFrames& frames, unsigned int channel )
{
return Filter::tick( frames, channel );
}
} // stk namespace

View File

@@ -10,15 +10,19 @@
two series allpass units and two parallel comb
filters.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "PRCRev.h"
#include <math.h>
#include <cmath>
PRCRev :: PRCRev(StkFloat T60)
namespace stk {
PRCRev :: PRCRev( StkFloat T60 )
{
lastFrame_.resize( 1, 2, 0.0 ); // resize lastFrame_ for stereo output
// Delay lengths for 44100 Hz sample rate.
int lengths[4]= {353, 1097, 1777, 2137};
double scaler = Stk::sampleRate() / 44100.0;
@@ -34,7 +38,7 @@ PRCRev :: PRCRev(StkFloat T60)
}
}
for (i=0; i<2; i++) {
for ( i=0; i<2; i++ ) {
allpassDelays_[i].setMaximumDelay( lengths[i] );
allpassDelays_[i].setDelay( lengths[i] );
@@ -48,18 +52,14 @@ PRCRev :: PRCRev(StkFloat T60)
this->clear();
}
PRCRev :: ~PRCRev()
{
}
void PRCRev :: clear()
void PRCRev :: clear( void )
{
allpassDelays_[0].clear();
allpassDelays_[1].clear();
combDelays_[0].clear();
combDelays_[1].clear();
lastOutput_[0] = 0.0;
lastOutput_[1] = 0.0;
lastFrame_[0] = 0.0;
lastFrame_[1] = 0.0;
}
void PRCRev :: setT60( StkFloat T60 )
@@ -68,31 +68,44 @@ void PRCRev :: setT60( StkFloat T60 )
combCoefficient_[1] = pow(10.0, (-3.0 * combDelays_[1].getDelay() / (T60 * Stk::sampleRate())));
}
StkFloat PRCRev :: computeSample(StkFloat input)
StkFrames& PRCRev :: tick( StkFrames& frames, unsigned int channel )
{
StkFloat temp, temp0, temp1, temp2, temp3;
#if defined(_STK_DEBUG_)
if ( channel >= frames.channels() - 1 ) {
errorString_ << "PRCRev::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
temp = allpassDelays_[0].lastOut();
temp0 = allpassCoefficient_ * temp;
temp0 += input;
allpassDelays_[0].tick(temp0);
temp0 = -(allpassCoefficient_ * temp0) + temp;
temp = allpassDelays_[1].lastOut();
temp1 = allpassCoefficient_ * temp;
temp1 += temp0;
allpassDelays_[1].tick(temp1);
temp1 = -(allpassCoefficient_ * temp1) + temp;
temp2 = temp1 + (combCoefficient_[0] * combDelays_[0].lastOut());
temp3 = temp1 + (combCoefficient_[1] * combDelays_[1].lastOut());
StkFloat *samples = &frames[channel];
unsigned int hop = frames.channels();
for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
*samples = tick( *samples );
*samples++;
*samples = lastFrame_[1];
}
lastOutput_[0] = effectMix_ * (combDelays_[0].tick(temp2));
lastOutput_[1] = effectMix_ * (combDelays_[1].tick(temp3));
temp = (1.0 - effectMix_) * input;
lastOutput_[0] += temp;
lastOutput_[1] += temp;
return Effect::lastOut();
return frames;
}
StkFrames& PRCRev :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
{
#if defined(_STK_DEBUG_)
if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() - 1 ) {
errorString_ << "PRCRev::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
StkFloat *iSamples = &iFrames[iChannel];
StkFloat *oSamples = &oFrames[oChannel];
unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
*oSamples++ = tick( *iSamples );
*oSamples = lastFrame_[1];
}
return iFrames;
}
} // stk namespace

View File

@@ -22,19 +22,21 @@
type who should worry about this (making
money) worry away.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "PercFlut.h"
PercFlut :: PercFlut()
namespace stk {
PercFlut :: PercFlut( void )
: FM()
{
// Concatenate the STK rawwave path to the rawwave files
for ( unsigned int i=0; i<3; i++ )
waves_[i] = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
waves_[3] = new WaveLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
waves_[i] = new FileLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
waves_[3] = new FileLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
this->setRatio(0, 1.50 * 1.000);
this->setRatio(1, 3.00 * 0.995);
@@ -54,16 +56,16 @@ PercFlut :: PercFlut()
modDepth_ = 0.005;
}
PercFlut :: ~PercFlut()
PercFlut :: ~PercFlut( void )
{
}
void PercFlut :: setFrequency(StkFloat frequency)
void PercFlut :: setFrequency( StkFloat frequency )
{
baseFrequency_ = frequency;
}
void PercFlut :: noteOn(StkFloat frequency, StkFloat amplitude)
void PercFlut :: noteOn( StkFloat frequency, StkFloat amplitude )
{
gains_[0] = amplitude * fmGains_[99] * 0.5;
gains_[1] = amplitude * fmGains_[71] * 0.5;
@@ -78,29 +80,4 @@ void PercFlut :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
StkFloat PercFlut :: computeSample()
{
register StkFloat temp;
temp = vibrato_.tick() * modDepth_ * 0.2;
waves_[0]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[0]);
waves_[1]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[1]);
waves_[2]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[2]);
waves_[3]->setFrequency(baseFrequency_ * (1.0 + temp) * ratios_[3]);
waves_[3]->addPhaseOffset( twozero_.lastOut() );
temp = gains_[3] * adsr_[3]->tick() * waves_[3]->tick();
twozero_.tick(temp);
waves_[2]->addPhaseOffset( temp );
temp = (1.0 - (control2_ * 0.5)) * gains_[2] * adsr_[2]->tick() * waves_[2]->tick();
temp += control2_ * 0.5 * gains_[1] * adsr_[1]->tick() * waves_[1]->tick();
temp = temp * control1_;
waves_[0]->addPhaseOffset(temp);
temp = gains_[0] * adsr_[0]->tick() * waves_[0]->tick();
lastOutput_ = temp * 0.5;
return lastOutput_;
}
} // stk namespace

View File

@@ -6,13 +6,15 @@
set of 32 static phoneme formant parameters
and provide access to those values.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Phonemes.h"
#include <iostream>
namespace stk {
const char Phonemes :: phonemeNames[32][4] =
{"eee", "ihh", "ehh", "aaa",
"ahh", "aww", "ohh", "uhh",
@@ -292,3 +294,5 @@ StkFloat Phonemes :: formantGain( unsigned int index, unsigned int partial )
}
return phonemeParameters[index][partial][2];
}
} // stk namespace

View File

@@ -5,19 +5,19 @@
This class implements a simple pitch shifter
using delay lines.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "PitShift.h"
#include <cmath>
const int maxDelay = 5024;
namespace stk {
PitShift :: PitShift()
PitShift :: PitShift( void )
{
delayLength = maxDelay - 24;
halfLength = delayLength / 2;
delayLength_ = maxDelay - 24;
halfLength_ = delayLength_ / 2;
delay_[0] = 12;
delay_[1] = maxDelay / 2;
@@ -29,60 +29,60 @@ PitShift :: PitShift()
rate_ = 1.0;
}
PitShift :: ~PitShift()
{
}
void PitShift :: clear()
{
delayLine_[0].clear();
delayLine_[1].clear();
lastOutput_[0] = 0.0;
lastOutput_[1] = 0.0;
lastFrame_[0] = 0.0;
}
void PitShift :: setShift(StkFloat shift)
void PitShift :: setShift( StkFloat shift )
{
if (shift < 1.0) {
if ( shift < 1.0 ) {
rate_ = 1.0 - shift;
}
else if (shift > 1.0) {
else if ( shift > 1.0 ) {
rate_ = 1.0 - shift;
}
else {
rate_ = 0.0;
delay_[0] = halfLength+12;
delay_[0] = halfLength_ + 12;
}
}
StkFloat PitShift :: computeSample(StkFloat input)
StkFrames& PitShift :: tick( StkFrames& frames, unsigned int channel )
{
// Calculate the two delay length values, keeping them within the
// range 12 to maxDelay-12.
delay_[0] += rate_;
while (delay_[0] > maxDelay-12) delay_[0] -= delayLength;
while (delay_[0] < 12) delay_[0] += delayLength;
#if defined(_STK_DEBUG_)
if ( channel >= frames.channels() ) {
errorString_ << "PitShift::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
delay_[1] = delay_[0] + halfLength;
while (delay_[1] > maxDelay-12) delay_[1] -= delayLength;
while (delay_[1] < 12) delay_[1] += delayLength;
StkFloat *samples = &frames[channel];
unsigned int hop = frames.channels();
for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
*samples = tick( *samples );
// Set the new delay line lengths.
delayLine_[0].setDelay((long)delay_[0]);
delayLine_[1].setDelay((long)delay_[1]);
// Calculate a triangular envelope.
env_[1] = fabs( (delay_[0] - halfLength + 12) * (1.0 / (halfLength+12) ) );
env_[0] = 1.0 - env_[1];
// Delay input and apply envelope.
lastOutput_[0] = env_[0] * delayLine_[0].tick(input);
lastOutput_[0] += env_[1] * delayLine_[1].tick(input);
// Compute effect mix and output.
lastOutput_[0] *= effectMix_;
lastOutput_[0] += (1.0 - effectMix_) * input;
lastOutput_[1] = lastOutput_[0];
return lastOutput_[0];
return frames;
}
StkFrames& PitShift :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
{
#if defined(_STK_DEBUG_)
if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
errorString_ << "PitShift::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
StkFloat *iSamples = &iFrames[iChannel];
StkFloat *oSamples = &oFrames[oChannel];
unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop )
*oSamples = tick( *iSamples );
return iFrames;
}
} // stk namespace

View File

@@ -14,15 +14,17 @@
use possibly subject to patents held by
Stanford University, Yamaha, and others.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "PluckTwo.h"
PluckTwo :: PluckTwo(StkFloat lowestFrequency)
namespace stk {
PluckTwo :: PluckTwo( StkFloat lowestFrequency )
{
length_ = (unsigned long) (Stk::sampleRate() / lowestFrequency + 1);
length_ = (unsigned long) ( Stk::sampleRate() / lowestFrequency + 1 );
lastLength_ = length_ * 0.5;
delayLine_.setMaximumDelay( length_ );
delayLine_.setDelay( lastLength_ );
@@ -37,14 +39,13 @@ PluckTwo :: PluckTwo(StkFloat lowestFrequency)
pluckPosition_ = 0.4;
detuning_ = 0.995;
lastFrequency_ = lowestFrequency * 2.0;
}
PluckTwo :: ~PluckTwo()
PluckTwo :: ~PluckTwo( void )
{
}
void PluckTwo :: clear()
void PluckTwo :: clear( void )
{
delayLine_.clear();
delayLine2_.clear();
@@ -53,7 +54,7 @@ void PluckTwo :: clear()
filter2_.clear();
}
void PluckTwo :: setFrequency(StkFloat frequency)
void PluckTwo :: setFrequency( StkFloat frequency )
{
lastFrequency_ = frequency;
if ( lastFrequency_ <= 0.0 ) {
@@ -78,7 +79,7 @@ void PluckTwo :: setFrequency(StkFloat frequency)
if ( loopGain_ > 1.0 ) loopGain_ = 0.99999;
}
void PluckTwo :: setDetune(StkFloat detune)
void PluckTwo :: setDetune( StkFloat detune )
{
detuning_ = detune;
if ( detuning_ <= 0.0 ) {
@@ -90,13 +91,13 @@ void PluckTwo :: setDetune(StkFloat detune)
delayLine2_.setDelay( (lastLength_ * detuning_) - 0.5);
}
void PluckTwo :: setFreqAndDetune(StkFloat frequency, StkFloat detune)
void PluckTwo :: setFreqAndDetune( StkFloat frequency, StkFloat detune )
{
detuning_ = detune;
this->setFrequency( frequency );
}
void PluckTwo :: setPluckPosition(StkFloat position)
void PluckTwo :: setPluckPosition( StkFloat position )
{
pluckPosition_ = position;
if ( position < 0.0 ) {
@@ -111,14 +112,14 @@ void PluckTwo :: setPluckPosition(StkFloat position)
}
}
void PluckTwo :: setBaseLoopGain(StkFloat aGain)
void PluckTwo :: setBaseLoopGain( StkFloat aGain )
{
baseLoopGain_ = aGain;
loopGain_ = baseLoopGain_ + (lastFrequency_ * 0.000005);
if ( loopGain_ > 0.99999 ) loopGain_ = 0.99999;
}
void PluckTwo :: noteOff(StkFloat amplitude)
void PluckTwo :: noteOff( StkFloat amplitude )
{
loopGain_ = (1.0 - amplitude) * 0.5;
@@ -128,3 +129,4 @@ void PluckTwo :: noteOff(StkFloat amplitude)
#endif
}
} // stk namespace

View File

@@ -13,26 +13,28 @@
Stanford, bearing the names of Karplus and/or
Strong.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Plucked.h"
namespace stk {
Plucked :: Plucked( StkFloat lowestFrequency )
{
length_ = (unsigned long) (Stk::sampleRate() / lowestFrequency + 1);
length_ = (unsigned long) ( Stk::sampleRate() / lowestFrequency + 1 );
loopGain_ = 0.999;
delayLine_.setMaximumDelay( length_ );
delayLine_.setDelay( 0.5 * length_ );
this->clear();
}
Plucked :: ~Plucked()
Plucked :: ~Plucked( void )
{
}
void Plucked :: clear()
void Plucked :: clear( void )
{
delayLine_.clear();
loopFilter_.clear();
@@ -92,7 +94,7 @@ void Plucked :: noteOn( StkFloat frequency, StkFloat amplitude )
#endif
}
void Plucked :: noteOff(StkFloat amplitude)
void Plucked :: noteOff( StkFloat amplitude )
{
loopGain_ = 1.0 - amplitude;
if ( loopGain_ < 0.0 ) {
@@ -112,10 +114,4 @@ void Plucked :: noteOff(StkFloat amplitude)
#endif
}
StkFloat Plucked :: computeSample()
{
// Here's the whole inner loop of the instrument!!
lastOutput_ = delayLine_.tick( loopFilter_.tick( delayLine_.lastOut() * loopGain_ ) );
lastOutput_ *= 3.0;
return lastOutput_;
}
} // stk namespace

View File

@@ -2,53 +2,44 @@
/*! \class PoleZero
\brief STK one-pole, one-zero filter class.
This protected Filter subclass implements
a one-pole, one-zero digital filter. A
method is provided for creating an allpass
filter with a given coefficient. Another
method is provided to create a DC blocking filter.
This class implements a one-pole, one-zero digital filter. A
method is provided for creating an allpass filter with a given
coefficient. Another method is provided to create a DC blocking
filter.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "PoleZero.h"
PoleZero :: PoleZero() : Filter()
namespace stk {
PoleZero :: PoleZero()
{
// Default setting for pass-through.
std::vector<StkFloat> b(2, 0.0);
std::vector<StkFloat> a(2, 0.0);
b[0] = 1.0;
a[0] = 1.0;
Filter::setCoefficients( b, a );
b_.resize( 2, 0.0 );
a_.resize( 2, 0.0 );
b_[0] = 1.0;
a_[0] = 1.0;
inputs_.resize( 2, 1, 0.0 );
outputs_.resize( 2, 1, 0.0 );
}
PoleZero :: ~PoleZero()
{
}
void PoleZero :: clear(void)
{
Filter::clear();
}
void PoleZero :: setB0(StkFloat b0)
void PoleZero :: setCoefficients( StkFloat b0, StkFloat b1, StkFloat a1, bool clearState )
{
b_[0] = b0;
}
void PoleZero :: setB1(StkFloat b1)
{
b_[1] = b1;
}
void PoleZero :: setA1(StkFloat a1)
{
a_[1] = a1;
if ( clearState ) this->clear();
}
void PoleZero :: setAllpass(StkFloat coefficient)
void PoleZero :: setAllpass( StkFloat coefficient )
{
b_[0] = coefficient;
b_[1] = 1.0;
@@ -56,7 +47,7 @@ void PoleZero :: setAllpass(StkFloat coefficient)
a_[1] = coefficient;
}
void PoleZero :: setBlockZero(StkFloat thePole)
void PoleZero :: setBlockZero( StkFloat thePole )
{
b_[0] = 1.0;
b_[1] = -1.0;
@@ -64,32 +55,4 @@ void PoleZero :: setBlockZero(StkFloat thePole)
a_[1] = -thePole;
}
void PoleZero :: setGain(StkFloat gain)
{
Filter::setGain(gain);
}
StkFloat PoleZero :: getGain(void) const
{
return Filter::getGain();
}
StkFloat PoleZero :: lastOut(void) const
{
return Filter::lastOut();
}
StkFloat PoleZero :: tick( StkFloat input )
{
inputs_[0] = gain_ * input;
outputs_[0] = b_[0] * inputs_[0] + b_[1] * inputs_[1] - a_[1] * outputs_[1];
inputs_[1] = inputs_[0];
outputs_[1] = outputs_[0];
return outputs_[0];
}
StkFrames& PoleZero :: tick( StkFrames& frames, unsigned int channel )
{
return Filter::tick( frames, channel );
}
} // stk namespace

View File

@@ -1,57 +0,0 @@
/***************************************************/
/*! \class ReedTable
\brief STK reed table class.
This class implements a simple one breakpoint,
non-linear reed function, as described by
Smith (1986). This function is based on a
memoryless non-linear spring model of the reed
(the reed mass is ignored) which saturates when
the reed collides with the mouthpiece facing.
See McIntyre, Schumacher, & Woodhouse (1983),
Smith (1986), Hirschman, Cook, Scavone, and
others for more information.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
*/
/***************************************************/
#include "ReedTable.h"
ReedTable :: ReedTable()
{
offset_ = (StkFloat) 0.6; // Offset is a bias, related to reed rest position.
slope_ = (StkFloat) -0.8; // Slope corresponds loosely to reed stiffness.
}
ReedTable :: ~ReedTable()
{
}
void ReedTable :: setOffset(StkFloat offset)
{
offset_ = offset;
}
void ReedTable :: setSlope(StkFloat slope)
{
slope_ = slope;
}
StkFloat ReedTable :: computeSample(StkFloat input)
{
// The input is differential pressure across the reed.
lastOutput_ = offset_ + (slope_ * input);
// If output is > 1, the reed has slammed shut and the
// reflection function value saturates at 1.0.
if (lastOutput_ > 1.0) lastOutput_ = (StkFloat) 1.0;
// This is nearly impossible in a physical system, but
// a reflection function value of -1.0 corresponds to
// an open end (and no discontinuity in bore profile).
if (lastOutput_ < -1.0) lastOutput_ = (StkFloat) -1.0;
return lastOutput_;
}

View File

@@ -13,14 +13,16 @@
- Zero Radii = 1
- Envelope Gain = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Resonate.h"
#include "SKINI.msg"
Resonate :: Resonate()
namespace stk {
Resonate :: Resonate( void )
{
poleFrequency_ = 4000.0;
poleRadius_ = 0.95;
@@ -30,21 +32,11 @@ Resonate :: Resonate()
zeroRadius_ = 0.0;
}
Resonate :: ~Resonate()
Resonate :: ~Resonate( void )
{
}
void Resonate :: keyOn()
{
adsr_.keyOn();
}
void Resonate :: keyOff()
{
adsr_.keyOff();
}
void Resonate :: noteOn(StkFloat frequency, StkFloat amplitude)
void Resonate :: noteOn( StkFloat frequency, StkFloat amplitude )
{
adsr_.setTarget( amplitude );
this->keyOn();
@@ -55,7 +47,7 @@ void Resonate :: noteOn(StkFloat frequency, StkFloat amplitude)
handleError( StkError::DEBUG_WARNING );
#endif
}
void Resonate :: noteOff(StkFloat amplitude)
void Resonate :: noteOff( StkFloat amplitude )
{
this->keyOff();
@@ -88,7 +80,7 @@ void Resonate :: setResonance( StkFloat frequency, StkFloat radius )
filter_.setResonance( poleFrequency_, poleRadius_, true );
}
void Resonate :: setNotch(StkFloat frequency, StkFloat radius)
void Resonate :: setNotch( StkFloat frequency, StkFloat radius )
{
zeroFrequency_ = frequency;
if ( frequency < 0.0 ) {
@@ -107,19 +99,7 @@ void Resonate :: setNotch(StkFloat frequency, StkFloat radius)
filter_.setNotch( zeroFrequency_, zeroRadius_ );
}
void Resonate :: setEqualGainZeroes()
{
filter_.setEqualGainZeroes();
}
StkFloat Resonate :: computeSample()
{
lastOutput_ = filter_.tick( noise_.tick() );
lastOutput_ *= adsr_.tick();
return lastOutput_;
}
void Resonate :: controlChange(int number, StkFloat value)
void Resonate :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -153,3 +133,5 @@ void Resonate :: controlChange(int number, StkFloat value)
handleError( StkError::DEBUG_WARNING );
#endif
}
} // stk namespace

View File

@@ -26,19 +26,21 @@
type who should worry about this (making
money) worry away.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Rhodey.h"
Rhodey :: Rhodey()
namespace stk {
Rhodey :: Rhodey( void )
: FM()
{
// Concatenate the STK rawwave path to the rawwave files
for ( unsigned int i=0; i<3; i++ )
waves_[i] = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
waves_[3] = new WaveLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
waves_[i] = new FileLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
waves_[3] = new FileLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
this->setRatio(0, 1.0);
this->setRatio(1, 0.5);
@@ -58,11 +60,11 @@ Rhodey :: Rhodey()
twozero_.setGain( 1.0 );
}
Rhodey :: ~Rhodey()
Rhodey :: ~Rhodey( void )
{
}
void Rhodey :: setFrequency(StkFloat frequency)
void Rhodey :: setFrequency( StkFloat frequency )
{
baseFrequency_ = frequency * 2.0;
@@ -70,7 +72,7 @@ void Rhodey :: setFrequency(StkFloat frequency)
waves_[i]->setFrequency( baseFrequency_ * ratios_[i] );
}
void Rhodey :: noteOn(StkFloat frequency, StkFloat amplitude)
void Rhodey :: noteOn( StkFloat frequency, StkFloat amplitude )
{
gains_[0] = amplitude * fmGains_[99];
gains_[1] = amplitude * fmGains_[90];
@@ -85,26 +87,4 @@ void Rhodey :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
StkFloat Rhodey :: computeSample()
{
StkFloat temp, temp2;
temp = gains_[1] * adsr_[1]->tick() * waves_[1]->tick();
temp = temp * control1_;
waves_[0]->addPhaseOffset( temp );
waves_[3]->addPhaseOffset( twozero_.lastOut() );
temp = gains_[3] * adsr_[3]->tick() * waves_[3]->tick();
twozero_.tick(temp);
waves_[2]->addPhaseOffset( temp );
temp = ( 1.0 - (control2_ * 0.5)) * gains_[0] * adsr_[0]->tick() * waves_[0]->tick();
temp += control2_ * 0.5 * gains_[2] * adsr_[2]->tick() * waves_[2]->tick();
// Calculate amplitude modulation and apply it to output.
temp2 = vibrato_.tick() * modDepth_;
temp = temp * (1.0 + temp2);
lastOutput_ = temp * 0.5;
return lastOutput_;
}
} // stk namespace

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@
RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/
RtMidi: realtime MIDI i/o C++ classes
Copyright (c) 2003-2007 Gary P. Scavone
Copyright (c) 2003-2009 Gary P. Scavone
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
@@ -35,7 +35,7 @@
*/
/**********************************************************************/
// RtMidi: Version 1.0.7
// RtMidi: Version 1.0.9
#include "RtMidi.h"
#include <sstream>
@@ -69,9 +69,9 @@ void RtMidi :: error( RtError::Type type )
// Common RtMidiIn Definitions
//*********************************************************************//
RtMidiIn :: RtMidiIn() : RtMidi()
RtMidiIn :: RtMidiIn( const std::string clientName ) : RtMidi()
{
this->initialize();
this->initialize( clientName );
}
void RtMidiIn :: setCallback( RtMidiCallback callback, void *userData )
@@ -144,9 +144,9 @@ double RtMidiIn :: getMessage( std::vector<unsigned char> *message )
// Common RtMidiOut Definitions
//*********************************************************************//
RtMidiOut :: RtMidiOut() : RtMidi()
RtMidiOut :: RtMidiOut( const std::string clientName ) : RtMidi()
{
this->initialize();
this->initialize( clientName );
}
@@ -155,7 +155,7 @@ RtMidiOut :: RtMidiOut() : RtMidi()
//*********************************************************************//
// API information found at:
// - http://developer. apple .com/audio/pdf/coreaudio.pdf
// - http://developer.apple.com/audio/pdf/coreaudio.pdf
#if defined(__MACOSX_CORE__)
@@ -187,20 +187,24 @@ void midiInputCallback( const MIDIPacketList *list, void *procRef, void *srcRef
RtMidiIn::RtMidiInData *data = static_cast<RtMidiIn::RtMidiInData *> (procRef);
CoreMidiData *apiData = static_cast<CoreMidiData *> (data->apiData);
bool continueSysex = false;
unsigned char status;
unsigned short nBytes, iByte, size;
unsigned long long time;
RtMidiIn::MidiMessage message;
bool& continueSysex = data->continueSysex;
RtMidiIn::MidiMessage& message = data->message;
const MIDIPacket *packet = &list->packet[0];
for ( unsigned int i=0; i<list->numPackets; ++i ) {
// My interpretation of the CoreMIDI documentation: all message
// types, except sysex, are complete within a packet and there may
// be several of them in a single packet. Sysex messages can be
// broken across multiple packets but are bundled alone within a
// packet. I'm assuming that sysex messages, if segmented, must
// be complete within the same MIDIPacketList.
// broken across multiple packets and PacketLists but are bundled
// alone within each packet (these packets do not contain other
// message types). If sysex messages are split across multiple
// MIDIPacketLists, they must be handled by multiple calls to this
// function.
nBytes = packet->length;
if ( nBytes == 0 ) continue;
@@ -220,12 +224,13 @@ void midiInputCallback( const MIDIPacketList *list, void *procRef, void *srcRef
iByte = 0;
if ( continueSysex ) {
// We have a continuing, segmented sysex message.
if ( !(data->ignoreFlags & 0x01) ) {
if ( !( data->ignoreFlags & 0x01 ) ) {
// If we're not ignoring sysex messages, copy the entire packet.
for ( unsigned int j=0; j<nBytes; j++ )
message.bytes.push_back( packet->data[j] );
}
if ( packet->data[nBytes] == 0xF7 ) continueSysex = false;
continueSysex = packet->data[nBytes-1] != 0xF7;
if ( !continueSysex ) {
// If not a continuing sysex message, invoke the user callback function or queue the message.
if ( data->usingCallback && message.bytes.size() > 0 ) {
@@ -259,7 +264,7 @@ void midiInputCallback( const MIDIPacketList *list, void *procRef, void *srcRef
iByte = nBytes;
}
else size = nBytes - iByte;
if ( packet->data[nBytes] == 0xF7 ) continueSysex = false;
continueSysex = packet->data[nBytes-1] != 0xF7;
}
else if ( status < 0xF3 ) {
if ( status == 0xF1 && (data->ignoreFlags & 0x02) ) {
@@ -311,11 +316,11 @@ void midiInputCallback( const MIDIPacketList *list, void *procRef, void *srcRef
}
}
void RtMidiIn :: initialize( void )
void RtMidiIn :: initialize( const std::string& clientName )
{
// Set up our client.
MIDIClientRef client;
OSStatus result = MIDIClientCreate( CFSTR("RtMidi Input Client"), NULL, NULL, &client );
OSStatus result = MIDIClientCreate( CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII ), NULL, NULL, &client );
if ( result != noErr ) {
errorString_ = "RtMidiIn::initialize: error creating OS-X MIDI client object.";
error( RtError::DRIVER_ERROR );
@@ -329,7 +334,7 @@ void RtMidiIn :: initialize( void )
inputData_.apiData = (void *) data;
}
void RtMidiIn :: openPort( unsigned int portNumber )
void RtMidiIn :: openPort( unsigned int portNumber, const std::string portName )
{
if ( connected_ ) {
errorString_ = "RtMidiIn::openPort: a valid connection already exists!";
@@ -352,7 +357,9 @@ void RtMidiIn :: openPort( unsigned int portNumber )
MIDIPortRef port;
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
OSStatus result = MIDIInputPortCreate( data->client, CFSTR("RtMidi MIDI Input Port"), midiInputCallback, (void *)&inputData_, &port );
OSStatus result = MIDIInputPortCreate( data->client,
CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
midiInputCallback, (void *)&inputData_, &port );
if ( result != noErr ) {
MIDIClientDispose( data->client );
errorString_ = "RtMidiIn::openPort: error creating OS-X MIDI input port.";
@@ -427,6 +434,130 @@ unsigned int RtMidiIn :: getPortCount()
return MIDIGetNumberOfSources();
}
// This function was submitted by Douglas Casey Tucker and apparently
// derived largely from PortMidi.
CFStringRef EndpointName( MIDIEndpointRef endpoint, bool isExternal )
{
CFMutableStringRef result = CFStringCreateMutable( NULL, 0 );
CFStringRef str;
// Begin with the endpoint's name.
str = NULL;
MIDIObjectGetStringProperty( endpoint, kMIDIPropertyName, &str );
if ( str != NULL ) {
CFStringAppend( result, str );
CFRelease( str );
}
MIDIEntityRef entity = NULL;
MIDIEndpointGetEntity( endpoint, &entity );
if ( entity == NULL )
// probably virtual
return result;
if ( CFStringGetLength( result ) == 0 ) {
// endpoint name has zero length -- try the entity
str = NULL;
MIDIObjectGetStringProperty( entity, kMIDIPropertyName, &str );
if ( str != NULL ) {
CFStringAppend( result, str );
CFRelease( str );
}
}
// now consider the device's name
MIDIDeviceRef device = NULL;
MIDIEntityGetDevice( entity, &device );
if ( device == NULL )
return result;
str = NULL;
MIDIObjectGetStringProperty( device, kMIDIPropertyName, &str );
if ( CFStringGetLength( result ) == 0 ) {
CFRelease( result );
return str;
}
if ( str != NULL ) {
// if an external device has only one entity, throw away
// the endpoint name and just use the device name
if ( isExternal && MIDIDeviceGetNumberOfEntities( device ) < 2 ) {
CFRelease( result );
return str;
} else {
if ( CFStringGetLength( str ) == 0 ) {
CFRelease( str );
return result;
}
// does the entity name already start with the device name?
// (some drivers do this though they shouldn't)
// if so, do not prepend
if ( CFStringCompareWithOptions( result, /* endpoint name */
str /* device name */,
CFRangeMake(0, CFStringGetLength( str ) ), 0 ) != kCFCompareEqualTo ) {
// prepend the device name to the entity name
if ( CFStringGetLength( result ) > 0 )
CFStringInsert( result, 0, CFSTR(" ") );
CFStringInsert( result, 0, str );
}
CFRelease( str );
}
}
return result;
}
// This function was submitted by Douglas Casey Tucker and apparently
// derived largely from PortMidi.
static CFStringRef ConnectedEndpointName( MIDIEndpointRef endpoint )
{
CFMutableStringRef result = CFStringCreateMutable( NULL, 0 );
CFStringRef str;
OSStatus err;
int i;
// Does the endpoint have connections?
CFDataRef connections = NULL;
int nConnected = 0;
bool anyStrings = false;
err = MIDIObjectGetDataProperty( endpoint, kMIDIPropertyConnectionUniqueID, &connections );
if ( connections != NULL ) {
// It has connections, follow them
// Concatenate the names of all connected devices
nConnected = CFDataGetLength( connections ) / sizeof(MIDIUniqueID);
if ( nConnected ) {
const SInt32 *pid = (const SInt32 *)(CFDataGetBytePtr(connections));
for ( i=0; i<nConnected; ++i, ++pid ) {
MIDIUniqueID id = EndianS32_BtoN( *pid );
MIDIObjectRef connObject;
MIDIObjectType connObjectType;
err = MIDIObjectFindByUniqueID( id, &connObject, &connObjectType );
if ( err == noErr ) {
if ( connObjectType == kMIDIObjectType_ExternalSource ||
connObjectType == kMIDIObjectType_ExternalDestination ) {
// Connected to an external device's endpoint (10.3 and later).
str = EndpointName( (MIDIEndpointRef)(connObject), true );
} else {
// Connected to an external device (10.2) (or something else, catch-
str = NULL;
MIDIObjectGetStringProperty( connObject, kMIDIPropertyName, &str );
}
if ( str != NULL ) {
if ( anyStrings )
CFStringAppend( result, CFSTR(", ") );
else anyStrings = true;
CFStringAppend( result, str );
CFRelease( str );
}
}
}
}
CFRelease( connections );
}
if ( anyStrings )
return result;
// Here, either the endpoint had no connections, or we failed to obtain names
return EndpointName( endpoint, false );
}
std::string RtMidiIn :: getPortName( unsigned int portNumber )
{
CFStringRef nameRef;
@@ -441,7 +572,10 @@ std::string RtMidiIn :: getPortName( unsigned int portNumber )
}
portRef = MIDIGetSource( portNumber );
MIDIObjectGetStringProperty( portRef, kMIDIPropertyName, &nameRef );
nameRef = ConnectedEndpointName(portRef);
//MIDIObjectGetStringProperty( portRef, kMIDIPropertyName, &nameRef );
// modified by D. Casey Tucker 2009-03-10
CFStringGetCString( nameRef, name, sizeof(name), 0);
CFRelease( nameRef );
std::string stringName = name;
@@ -472,18 +606,19 @@ std::string RtMidiOut :: getPortName( unsigned int portNumber )
}
portRef = MIDIGetDestination( portNumber );
MIDIObjectGetStringProperty( portRef, kMIDIPropertyName, &nameRef );
nameRef = ConnectedEndpointName(portRef);
//MIDIObjectGetStringProperty( portRef, kMIDIPropertyName, &nameRef );
CFStringGetCString( nameRef, name, sizeof(name), 0);
CFRelease( nameRef );
std::string stringName = name;
return stringName;
}
void RtMidiOut :: initialize( void )
void RtMidiOut :: initialize( const std::string& clientName )
{
// Set up our client.
MIDIClientRef client;
OSStatus result = MIDIClientCreate( CFSTR("RtMidi Output Client"), NULL, NULL, &client );
OSStatus result = MIDIClientCreate( CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII ), NULL, NULL, &client );
if ( result != noErr ) {
errorString_ = "RtMidiOut::initialize: error creating OS-X MIDI client object.";
error( RtError::DRIVER_ERROR );
@@ -496,7 +631,7 @@ void RtMidiOut :: initialize( void )
apiData_ = (void *) data;
}
void RtMidiOut :: openPort( unsigned int portNumber )
void RtMidiOut :: openPort( unsigned int portNumber, const std::string portName )
{
if ( connected_ ) {
errorString_ = "RtMidiOut::openPort: a valid connection already exists!";
@@ -519,7 +654,9 @@ void RtMidiOut :: openPort( unsigned int portNumber )
MIDIPortRef port;
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
OSStatus result = MIDIOutputPortCreate( data->client, CFSTR("RtMidi Virtual MIDI Output Port"), &port );
OSStatus result = MIDIOutputPortCreate( data->client,
CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
&port );
if ( result != noErr ) {
MIDIClientDispose( data->client );
errorString_ = "RtMidiOut::openPort: error creating OS-X MIDI output port.";
@@ -588,33 +725,59 @@ RtMidiOut :: ~RtMidiOut()
void RtMidiOut :: sendMessage( std::vector<unsigned char> *message )
{
// The CoreMidi documentation indicates a maximum PackList size of
// 64K, so we may need to break long sysex messages into pieces and
// send via separate lists.
unsigned int nBytes = message->size();
// Pad the buffer for extra (unknown) structure data.
Byte buffer[nBytes+32];
MIDIPacketList *pktlist = (MIDIPacketList *) buffer;
MIDIPacket *curPacket = MIDIPacketListInit( pktlist );
MIDITimeStamp timeStamp = 0;
curPacket = MIDIPacketListAdd( pktlist, sizeof(buffer), curPacket, timeStamp, nBytes, &message->at(0) );
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
// Send to any destinations that may have connected to us.
OSStatus result;
if ( data->endpoint ) {
result = MIDIReceived( data->endpoint, pktlist );
if ( result != noErr ) {
errorString_ = "RtMidiOut::sendMessage: error sending MIDI to virtual destinations.";
error( RtError::WARNING );
}
if ( nBytes == 0 ) {
errorString_ = "RtMidiOut::sendMessage: no data in message argument!";
error( RtError::WARNING );
return;
}
// And send to an explicit destination port if we're connected.
if ( connected_ ) {
result = MIDISend( data->port, data->destinationId, pktlist );
if ( result != noErr ) {
errorString_ = "RtMidiOut::sendMessage: error sending MIDI message to port.";
error( RtError::WARNING );
if ( nBytes > 3 && ( message->at(0) != 0xF0 ) ) {
errorString_ = "RtMidiOut::sendMessage: message format problem ... not sysex but > 3 bytes?";
error( RtError::WARNING );
return;
}
unsigned int packetBytes, bytesLeft = nBytes;
unsigned int messageIndex = 0;
MIDITimeStamp timeStamp = 0;
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
while ( bytesLeft > 0 ) {
packetBytes = ( bytesLeft > 32736 ) ? 32736 : bytesLeft;
Byte buffer[packetBytes + 32]; // extra memory for other structure variables
MIDIPacketList *packetList = (MIDIPacketList *) buffer;
MIDIPacket *curPacket = MIDIPacketListInit( packetList );
curPacket = MIDIPacketListAdd( packetList, packetBytes+32, curPacket, timeStamp, packetBytes, (const Byte *) &message->at( messageIndex ) );
if ( !curPacket ) {
errorString_ = "RtMidiOut::sendMessage: could not allocate packet list";
error( RtError::DRIVER_ERROR );
}
messageIndex += packetBytes;
bytesLeft -= packetBytes;
// Send to any destinations that may have connected to us.
OSStatus result;
if ( data->endpoint ) {
result = MIDIReceived( data->endpoint, packetList );
if ( result != noErr ) {
errorString_ = "RtMidiOut::sendMessage: error sending MIDI to virtual destinations.";
error( RtError::WARNING );
}
}
// And send to an explicit destination port if we're connected.
if ( connected_ ) {
result = MIDISend( data->port, data->destinationId, packetList );
if ( result != noErr ) {
errorString_ = "RtMidiOut::sendMessage: error sending MIDI message to port.";
error( RtError::WARNING );
}
}
}
}
@@ -637,6 +800,10 @@ void RtMidiOut :: sendMessage( std::vector<unsigned char> *message )
// Thanks to Pedro Lopez-Cabanillas for help with the ALSA sequencer
// time stamps and other assorted fixes!!!
// If you don't need timestamping for incoming MIDI events, define the
// preprocessor definition AVOID_TIMESTAMPING to save resources
// associated with the ALSA sequencer queues.
#include <pthread.h>
#include <sys/time.h>
@@ -713,7 +880,9 @@ extern "C" void *alsaMidiHandler( void *ptr )
// This is a bit weird, but we now have to decode an ALSA MIDI
// event (back) into MIDI bytes. We'll ignore non-MIDI types.
message.bytes.clear();
if ( !continueSysex )
message.bytes.clear();
switch ( ev->type ) {
case SND_SEQ_EVENT_PORT_SUBSCRIBED:
@@ -723,8 +892,14 @@ extern "C" void *alsaMidiHandler( void *ptr )
break;
case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
#if defined(__RTMIDI_DEBUG__)
std::cerr << "RtMidiIn::alsaMidiHandler: port connection has closed!\n";
data->doInput = false;
std::cout << "sender = " << (int) ev->data.connect.sender.client << ":"
<< (int) ev->data.connect.sender.port
<< ", dest = " << (int) ev->data.connect.dest.client << ":"
<< (int) ev->data.connect.dest.port
<< std::endl;
#endif
break;
case SND_SEQ_EVENT_QFRAME: // MIDI time code
@@ -768,7 +943,7 @@ extern "C" void *alsaMidiHandler( void *ptr )
else
message.bytes.insert( message.bytes.end(), buffer, &buffer[nBytes] );
continueSysex = ( ev->type == SND_SEQ_EVENT_SYSEX && message.bytes.back() != 0xF7 );
continueSysex = ( ( ev->type == SND_SEQ_EVENT_SYSEX ) && ( message.bytes.back() != 0xF7 ) );
if ( continueSysex )
break;
@@ -794,7 +969,7 @@ extern "C" void *alsaMidiHandler( void *ptr )
snd_seq_free_event(ev);
if ( message.bytes.size() == 0 ) continue;
if ( data->usingCallback ) {
if ( data->usingCallback && !continueSysex ) {
RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
callback( message.timeStamp, &message.bytes, data->userData );
}
@@ -813,10 +988,10 @@ extern "C" void *alsaMidiHandler( void *ptr )
return 0;
}
void RtMidiIn :: initialize( void )
void RtMidiIn :: initialize( const std::string& clientName )
{
// Set up the ALSA sequencer client.
snd_seq_t *seq;
snd_seq_t *seq;
int result = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK);
if ( result < 0 ) {
errorString_ = "RtMidiIn::initialize: error creating ALSA sequencer input client object.";
@@ -824,7 +999,7 @@ void RtMidiIn :: initialize( void )
}
// Set client name.
snd_seq_set_client_name(seq, "RtMidi Input Client");
snd_seq_set_client_name( seq, clientName.c_str() );
// Save our api-specific connection information.
AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
@@ -834,6 +1009,7 @@ void RtMidiIn :: initialize( void )
inputData_.apiData = (void *) data;
// Create the input queue
#ifndef AVOID_TIMESTAMPING
data->queue_id = snd_seq_alloc_named_queue(seq, "RtMidi Queue");
// Set arbitrary tempo (mm=100) and resolution (240)
snd_seq_queue_tempo_t *qtempo;
@@ -842,6 +1018,7 @@ void RtMidiIn :: initialize( void )
snd_seq_queue_tempo_set_ppq(qtempo, 240);
snd_seq_set_queue_tempo(data->seq, data->queue_id, qtempo);
snd_seq_drain_output(data->seq);
#endif
}
// This function is used to count or get the pinfo structure for a given port number.
@@ -860,7 +1037,10 @@ unsigned int portInfo( snd_seq_t *seq, snd_seq_port_info_t *pinfo, unsigned int
snd_seq_port_info_set_client( pinfo, client );
snd_seq_port_info_set_port( pinfo, -1 );
while ( snd_seq_query_next_port( seq, pinfo ) >= 0 ) {
if ( !PORT_TYPE( pinfo, type ) ) continue;
unsigned int atyp = snd_seq_port_info_get_type( pinfo );
if ( ( atyp & SND_SEQ_PORT_TYPE_MIDI_GENERIC ) == 0 ) continue;
unsigned int caps = snd_seq_port_info_get_capability( pinfo );
if ( ( caps & type ) != type ) continue;
if ( count == portNumber ) return 1;
count++;
}
@@ -871,7 +1051,7 @@ unsigned int portInfo( snd_seq_t *seq, snd_seq_port_info_t *pinfo, unsigned int
return 0;
}
void RtMidiIn :: openPort( unsigned int portNumber )
void RtMidiIn :: openPort( unsigned int portNumber, const std::string portName )
{
if ( connected_ ) {
errorString_ = "RtMidiIn::openPort: a valid connection already exists!";
@@ -910,10 +1090,12 @@ void RtMidiIn :: openPort( unsigned int portNumber )
SND_SEQ_PORT_TYPE_MIDI_GENERIC |
SND_SEQ_PORT_TYPE_APPLICATION );
snd_seq_port_info_set_midi_channels(pinfo, 16);
#ifndef AVOID_TIMESTAMPING
snd_seq_port_info_set_timestamping(pinfo, 1);
snd_seq_port_info_set_timestamp_real(pinfo, 1);
snd_seq_port_info_set_timestamp_queue(pinfo, data->queue_id);
snd_seq_port_info_set_name(pinfo, "RtMidi Input");
#endif
snd_seq_port_info_set_name(pinfo, portName.c_str() );
data->vport = snd_seq_create_port(data->seq, pinfo);
if ( data->vport < 0 ) {
@@ -935,8 +1117,10 @@ void RtMidiIn :: openPort( unsigned int portNumber )
if ( inputData_.doInput == false ) {
// Start the input queue
#ifndef AVOID_TIMESTAMPING
snd_seq_start_queue( data->seq, data->queue_id, NULL );
snd_seq_drain_output( data->seq );
#endif
// Start our MIDI input thread.
pthread_attr_t attr;
pthread_attr_init(&attr);
@@ -971,9 +1155,11 @@ void RtMidiIn :: openVirtualPort( std::string portName )
SND_SEQ_PORT_TYPE_MIDI_GENERIC |
SND_SEQ_PORT_TYPE_APPLICATION );
snd_seq_port_info_set_midi_channels(pinfo, 16);
#ifndef AVOID_TIMESTAMPING
snd_seq_port_info_set_timestamping(pinfo, 1);
snd_seq_port_info_set_timestamp_real(pinfo, 1);
snd_seq_port_info_set_timestamp_queue(pinfo, data->queue_id);
#endif
snd_seq_port_info_set_name(pinfo, portName.c_str());
data->vport = snd_seq_create_port(data->seq, pinfo);
@@ -985,8 +1171,10 @@ void RtMidiIn :: openVirtualPort( std::string portName )
if ( inputData_.doInput == false ) {
// Start the input queue
#ifndef AVOID_TIMESTAMPING
snd_seq_start_queue( data->seq, data->queue_id, NULL );
snd_seq_drain_output( data->seq );
#endif
// Start our MIDI input thread.
pthread_attr_t attr;
pthread_attr_init(&attr);
@@ -1013,8 +1201,10 @@ void RtMidiIn :: closePort( void )
snd_seq_unsubscribe_port( data->seq, data->subscription );
snd_seq_port_subscribe_free( data->subscription );
// Stop the input queue
#ifndef AVOID_TIMESTAMPING
snd_seq_stop_queue( data->seq, data->queue_id, NULL );
snd_seq_drain_output( data->seq );
#endif
connected_ = false;
}
}
@@ -1033,8 +1223,10 @@ RtMidiIn :: ~RtMidiIn()
// Cleanup.
if ( data->vport >= 0 ) snd_seq_delete_port( data->seq, data->vport );
#ifndef AVOID_TIMESTAMPING
snd_seq_free_queue( data->seq, data->queue_id );
snd_seq_close( data->seq );
#endif
delete data;
}
@@ -1049,12 +1241,20 @@ unsigned int RtMidiIn :: getPortCount()
std::string RtMidiIn :: getPortName( unsigned int portNumber )
{
snd_seq_port_info_t *pinfo;
snd_seq_port_info_alloca( &pinfo );
snd_seq_client_info_t *cinfo;
snd_seq_port_info_t *pinfo;
snd_seq_client_info_alloca( &cinfo );
snd_seq_port_info_alloca( &pinfo );
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) ) {
std::string stringName = std::string( snd_seq_port_info_get_name( pinfo ) );
int cnum = snd_seq_port_info_get_client( pinfo );
snd_seq_get_any_client_info( data->seq, cnum, cinfo );
std::ostringstream os;
os << snd_seq_client_info_get_name( cinfo );
os << ":";
os << snd_seq_port_info_get_port( pinfo );
std::string stringName = os.str();
return stringName;
}
@@ -1080,12 +1280,20 @@ unsigned int RtMidiOut :: getPortCount()
std::string RtMidiOut :: getPortName( unsigned int portNumber )
{
snd_seq_port_info_t *pinfo;
snd_seq_port_info_alloca( &pinfo );
snd_seq_client_info_t *cinfo;
snd_seq_port_info_t *pinfo;
snd_seq_client_info_alloca( &cinfo );
snd_seq_port_info_alloca( &pinfo );
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) ) {
std::string stringName = std::string( snd_seq_port_info_get_name( pinfo ) );
int cnum = snd_seq_port_info_get_client(pinfo);
snd_seq_get_any_client_info( data->seq, cnum, cinfo );
std::ostringstream os;
os << snd_seq_client_info_get_name(cinfo);
os << ":";
os << snd_seq_port_info_get_port(pinfo);
std::string stringName = os.str();
return stringName;
}
@@ -1095,18 +1303,18 @@ std::string RtMidiOut :: getPortName( unsigned int portNumber )
return 0;
}
void RtMidiOut :: initialize( void )
void RtMidiOut :: initialize( const std::string& clientName )
{
// Set up the ALSA sequencer client.
snd_seq_t *seq;
int result = snd_seq_open(&seq, "default", SND_SEQ_OPEN_OUTPUT, 0);
snd_seq_t *seq;
int result = snd_seq_open( &seq, "default", SND_SEQ_OPEN_OUTPUT, SND_SEQ_NONBLOCK );
if ( result < 0 ) {
errorString_ = "RtMidiOut::initialize: error creating ALSA sequencer client object.";
error( RtError::DRIVER_ERROR );
}
// Set client name.
snd_seq_set_client_name(seq, "RtMidi Output Client");
snd_seq_set_client_name( seq, clientName.c_str() );
// Save our api-specific connection information.
AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
@@ -1131,7 +1339,7 @@ void RtMidiOut :: initialize( void )
apiData_ = (void *) data;
}
void RtMidiOut :: openPort( unsigned int portNumber )
void RtMidiOut :: openPort( unsigned int portNumber, const std::string portName )
{
if ( connected_ ) {
errorString_ = "RtMidiOut::openPort: a valid connection already exists!";
@@ -1161,7 +1369,7 @@ void RtMidiOut :: openPort( unsigned int portNumber )
sender.client = snd_seq_client_id( data->seq );
if ( data->vport < 0 ) {
data->vport = snd_seq_create_simple_port( data->seq, "RtMidi Output",
data->vport = snd_seq_create_simple_port( data->seq, portName.c_str(),
SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
SND_SEQ_PORT_TYPE_MIDI_GENERIC );
if ( data->vport < 0 ) {
@@ -1423,7 +1631,7 @@ extern "C" void *irixMidiHandler( void *ptr )
return 0;
}
void RtMidiIn :: initialize( void )
void RtMidiIn :: initialize( const std::string& /*clientName*/ )
{
// Initialize the Irix MIDI system. At the moment, we will not
// worry about a return value of zero (ports) because there is a
@@ -1436,7 +1644,7 @@ void RtMidiIn :: initialize( void )
inputData_.apiData = (void *) data;
}
void RtMidiIn :: openPort( unsigned int portNumber )
void RtMidiIn :: openPort( unsigned int portNumber, const std::string /*portName*/ )
{
if ( connected_ ) {
errorString_ = "RtMidiIn::openPort: a valid connection already exists!";
@@ -1564,7 +1772,7 @@ std::string RtMidiOut :: getPortName( unsigned int portNumber )
return stringName;
}
void RtMidiOut :: initialize( void )
void RtMidiOut :: initialize( const std::string& /*clientName*/ )
{
// Initialize the Irix MIDI system. At the moment, we will not
// worry about a return value of zero (ports) because there is a
@@ -1576,7 +1784,7 @@ void RtMidiOut :: initialize( void )
apiData_ = (void *) data;
}
void RtMidiOut :: openPort( unsigned int portNumber )
void RtMidiOut :: openPort( unsigned int portNumber, const std::string /*portName*/ )
{
if ( connected_ ) {
errorString_ = "RtMidiOut::openPort: a valid connection already exists!";
@@ -1754,21 +1962,31 @@ static void CALLBACK midiInputCallback( HMIDIOUT hmin,
unsigned char *ptr = (unsigned char *) &midiMessage;
for ( int i=0; i<nBytes; i++ ) apiData->message.bytes.push_back( *ptr++ );
}
else if ( !(data->ignoreFlags & 0x01) ) {
// Sysex message and we're not ignoring it
MIDIHDR *sysex = ( MIDIHDR *) midiMessage;
for ( int i=0; i<(int)sysex->dwBytesRecorded; i++ )
apiData->message.bytes.push_back( sysex->lpData[i] );
else { // Sysex message ( MIM_LONGDATA )
MIDIHDR *sysex = ( MIDIHDR *) midiMessage;
if ( !( data->ignoreFlags & 0x01 ) ) {
// Sysex message and we're not ignoring it
for ( int i=0; i<(int)sysex->dwBytesRecorded; i++ )
apiData->message.bytes.push_back( sysex->lpData[i] );
}
// When the callback has to be unaffected (application closes),
// it seems WinMM calls it with an empty sysex to de-queue the buffer
// If the buffer is requeued afer that message, the PC suddenly reboots
// after one or two minutes (JB).
// The WinMM API requires that the sysex buffer be requeued after
// input of each sysex message. Even if we are ignoring sysex
// messages, we still need to requeue the buffer in case the user
// decides to not ignore sysex messages in the future. However,
// it seems that WinMM calls this function with an empty sysex
// buffer when an application closes and in this case, we should
// avoid requeueing it, else the computer suddenly reboots after
// one or two minutes.
if ( apiData->sysexBuffer->dwBytesRecorded > 0 ) {
//if ( sysex->dwBytesRecorded > 0 ) {
MMRESULT result = midiInAddBuffer( apiData->inHandle, apiData->sysexBuffer, sizeof(MIDIHDR) );
if ( result != MMSYSERR_NOERROR )
std::cerr << "\nRtMidiIn::midiInputCallback: error sending sysex to Midi device!!\n\n";
if ( data->ignoreFlags & 0x01 ) return;
}
else return;
}
if ( data->usingCallback ) {
@@ -1783,13 +2001,11 @@ static void CALLBACK midiInputCallback( HMIDIOUT hmin,
std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
}
// Clear the vector for the next input message. Note that doing
// this here allows our code to work for sysex messages which are
// segmented across multiple buffers.
// Clear the vector for the next input message.
apiData->message.bytes.clear();
}
void RtMidiIn :: initialize( void )
void RtMidiIn :: initialize( const std::string& /*clientName*/ )
{
// We'll issue a warning here if no devices are available but not
// throw an error since the user can plugin something later.
@@ -1806,7 +2022,7 @@ void RtMidiIn :: initialize( void )
data->message.bytes.clear(); // needs to be empty for first input message
}
void RtMidiIn :: openPort( unsigned int portNumber )
void RtMidiIn :: openPort( unsigned int portNumber, const std::string /*portName*/ )
{
if ( connected_ ) {
errorString_ = "RtMidiIn::openPort: a valid connection already exists!";
@@ -1840,8 +2056,8 @@ void RtMidiIn :: openPort( unsigned int portNumber )
// Allocate and init the sysex buffer.
data->sysexBuffer = (MIDIHDR*) new char[ sizeof(MIDIHDR) ];
data->sysexBuffer->lpData = new char[1024];
data->sysexBuffer->dwBufferLength = 1024;
data->sysexBuffer->lpData = new char[ RT_SYSEX_BUFFER_SIZE ];
data->sysexBuffer->dwBufferLength = RT_SYSEX_BUFFER_SIZE;
data->sysexBuffer->dwFlags = 0;
result = midiInPrepareHeader( data->inHandle, data->sysexBuffer, sizeof(MIDIHDR) );
@@ -1970,7 +2186,7 @@ std::string RtMidiOut :: getPortName( unsigned int portNumber )
return stringName;
}
void RtMidiOut :: initialize( void )
void RtMidiOut :: initialize( const std::string& /*clientName*/ )
{
// We'll issue a warning here if no devices are available but not
// throw an error since the user can plug something in later.
@@ -1985,7 +2201,7 @@ void RtMidiOut :: initialize( void )
apiData_ = (void *) data;
}
void RtMidiOut :: openPort( unsigned int portNumber )
void RtMidiOut :: openPort( unsigned int portNumber, const std::string /*portName*/ )
{
if ( connected_ ) {
errorString_ = "RtMidiOut::openPort: a valid connection already exists!";

View File

@@ -10,15 +10,19 @@
RtWvIn supports multi-channel data in both interleaved and
non-interleaved formats. It is important to distinguish the
tick() methods, which return samples produced by averaging across
sample frames, from the tickFrame() methods, which return
references or pointers to multi-channel sample frames.
tick() method that computes a single frame (and returns only the
specified sample of a multi-channel frame) from the overloaded one
that takes an StkFrames object for multi-channel and/or
multi-frame data.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "RtWvIn.h"
#include <string.h>
namespace stk {
// This function is automatically called by RtAudio to supply input audio data.
int read( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
@@ -56,7 +60,9 @@ void RtWvIn :: fillBuffer( void *buffer, unsigned int nFrames )
nSamples -= counter;
}
mutex_.lock();
framesFilled_ += nFrames;
mutex_.unlock();
if ( framesFilled_ > data_.frames() ) {
framesFilled_ = data_.frames();
errorString_ << "RtWvIn: audio buffer overrun!";
@@ -69,7 +75,10 @@ RtWvIn :: RtWvIn( unsigned int nChannels, StkFloat sampleRate, int device, int b
{
// We'll let RtAudio deal with channel and sample rate limitations.
RtAudio::StreamParameters parameters;
parameters.deviceId = device;
if ( device == 0 )
parameters.deviceId = adc_.getDefaultInputDevice();
else
parameters.deviceId = device - 1;
parameters.nChannels = nChannels;
unsigned int size = bufferFrames;
RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
@@ -82,7 +91,7 @@ RtWvIn :: RtWvIn( unsigned int nChannels, StkFloat sampleRate, int device, int b
}
data_.resize( size * nBuffers, nChannels );
lastOutputs_.resize( 1, nChannels );
lastFrame_.resize( 1, nChannels );
}
RtWvIn :: ~RtWvIn()
@@ -104,22 +113,82 @@ void RtWvIn :: stop()
if ( !stopped_ ) {
adc_.stopStream();
stopped_ = true;
for ( unsigned int i=0; i<lastFrame_.size(); i++ ) lastFrame_[i] = 0.0;
}
}
void RtWvIn :: computeFrame( void )
StkFloat RtWvIn :: tick( unsigned int channel )
{
#if defined(_STK_DEBUG_)
if ( channel >= data_.channels() ) {
errorString_ << "RtWvIn::tick(): channel argument is incompatible with streamed channels!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
if ( stopped_ ) this->start();
// Block until at least one frame is available.
while ( framesFilled_ == 0 )
Stk::sleep( 1 );
while ( framesFilled_ == 0 ) Stk::sleep( 1 );
for ( unsigned int i=0; i<lastOutputs_.size(); i++ )
lastOutputs_[i] = data_( readIndex_, i );
unsigned long index = readIndex_ * lastFrame_.channels();
for ( unsigned int i=0; i<lastFrame_.size(); i++ )
lastFrame_[i] = data_[index++];
mutex_.lock();
framesFilled_--;
mutex_.unlock();
readIndex_++;
if ( readIndex_ >= data_.frames() )
readIndex_ = 0;
return lastFrame_[channel];
}
StkFrames& RtWvIn :: tick( StkFrames& frames )
{
unsigned int nChannels = lastFrame_.channels();
#if defined(_STK_DEBUG_)
if ( nChannels != frames.channels() ) {
errorString_ << "RtWvIn::tick(): StkFrames argument is incompatible with adc channels!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
if ( stopped_ ) this->start();
// See how much space we have and fill as much as we can ... if we
// still have space left in the frames object, then wait and repeat.
unsigned int nFrames, bytes, framesRead = 0;
while ( framesRead < frames.frames() ) {
// Block until we have some input data.
while ( framesFilled_ == 0 ) Stk::sleep( 1 );
// Copy data in one chunk up to the end of the data buffer.
nFrames = framesFilled_;
if ( readIndex_ + nFrames > data_.frames() )
nFrames = data_.frames() - readIndex_;
if ( nFrames > frames.frames() - framesRead )
nFrames = frames.frames() - framesRead;
bytes = nFrames * nChannels * sizeof( StkFloat );
StkFloat *samples = &data_[readIndex_ * nChannels];
memcpy( &frames[framesRead * nChannels], samples, bytes );
readIndex_ += nFrames;
if ( readIndex_ == data_.frames() ) readIndex_ = 0;
framesRead += nFrames;
mutex_.lock();
framesFilled_ -= nFrames;
mutex_.unlock();
}
unsigned long index = (frames.frames() - 1) * nChannels;
for ( unsigned int i=0; i<lastFrame_.size(); i++ )
lastFrame_[i] = frames[index++];
return frames;
}
} // stk namespace

View File

@@ -8,17 +8,20 @@
into which data is written. This class should not be used when
low-latency is desired.
RtWvOut supports multi-channel data in both interleaved and
non-interleaved formats. It is important to distinguish the
tick() methods, which output single samples to all channels in a
sample frame, from the tickFrame() method, which take a pointer or
reference to multi-channel sample frame data.
RtWvOut supports multi-channel data in interleaved format. It is
important to distinguish the tick() method that outputs a single
sample to all channels in a sample frame from the overloaded one
that takes a reference to an StkFrames object for multi-channel
and/or multi-frame data.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "RtWvOut.h"
#include <string.h>
namespace stk {
// Streaming status states.
enum { RUNNING, EMPTYING, FINISHED };
@@ -73,7 +76,9 @@ int RtWvOut :: readBuffer( void *buffer, unsigned int frameCount )
nFrames -= counter;
}
mutex_.lock();
framesFilled_ -= frameCount;
mutex_.unlock();
if ( framesFilled_ < 0 ) {
framesFilled_ = 0;
// writeIndex_ = readIndex_;
@@ -90,7 +95,10 @@ RtWvOut :: RtWvOut( unsigned int nChannels, StkFloat sampleRate, int device, int
{
// We'll let RtAudio deal with channel and sample rate limitations.
RtAudio::StreamParameters parameters;
parameters.deviceId = device;
if ( device == 0 )
parameters.deviceId = dac_.getDefaultOutputDevice();
else
parameters.deviceId = device - 1;
parameters.nChannels = nChannels;
unsigned int size = bufferFrames;
RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
@@ -104,12 +112,13 @@ RtWvOut :: RtWvOut( unsigned int nChannels, StkFloat sampleRate, int device, int
}
data_.resize( size * nBuffers, nChannels );
unsigned int offset = (unsigned int ) (data_.frames() / 2.0);
writeIndex_ = offset; // start writing half-way into buffer
framesFilled_ = offset;
// Start writing half-way into buffer.
writeIndex_ = (unsigned int ) (data_.frames() / 2.0);
framesFilled_ = writeIndex_;
}
RtWvOut :: ~RtWvOut()
RtWvOut :: ~RtWvOut( void )
{
// Change status flag to signal callback to clear the buffer and close.
status_ = EMPTYING;
@@ -117,7 +126,7 @@ RtWvOut :: ~RtWvOut()
dac_.closeStream();
}
void RtWvOut :: start()
void RtWvOut :: start( void )
{
if ( stopped_ ) {
dac_.startStream();
@@ -125,7 +134,7 @@ void RtWvOut :: start()
}
}
void RtWvOut :: stop()
void RtWvOut :: stop( void )
{
if ( !stopped_ ) {
dac_.stopStream();
@@ -133,7 +142,7 @@ void RtWvOut :: stop()
}
}
void RtWvOut :: computeSample( const StkFloat sample )
void RtWvOut :: tick( const StkFloat sample )
{
if ( stopped_ ) this->start();
@@ -147,65 +156,57 @@ void RtWvOut :: computeSample( const StkFloat sample )
for ( unsigned int j=0; j<nChannels; j++ )
data_[index++] = input;
mutex_.lock();
framesFilled_++;
mutex_.unlock();
frameCounter_++;
writeIndex_++;
if ( writeIndex_ == data_.frames() )
writeIndex_ = 0;
}
void RtWvOut :: computeFrames( const StkFrames& frames )
void RtWvOut :: tick( StkFrames& frames )
{
#if defined(_STK_DEBUG_)
if ( data_.channels() != frames.channels() ) {
errorString_ << "RtWvOut::computeFrames(): incompatible channel value in StkFrames argument!";
errorString_ << "RtWvOut::tick(): incompatible channel value in StkFrames argument!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
if ( stopped_ ) this->start();
// Block until we have room for the frames of output data.
while ( data_.frames() - framesFilled_ < frames.frames() ) Stk::sleep( 1 );
// See how much space we have and fill as much as we can ... if we
// still have samples left in the frames object, then wait and
// repeat.
unsigned int framesEmpty, nFrames, bytes, framesWritten = 0;
unsigned int nChannels = data_.channels();
while ( framesWritten < frames.frames() ) {
unsigned int j, nChannels = data_.channels();
if ( nChannels == 1 || frames.interleaved() ) {
// Block until we have some room for output data.
while ( framesFilled_ == (long) data_.frames() ) Stk::sleep( 1 );
framesEmpty = data_.frames() - framesFilled_;
unsigned int index, iFrames = 0;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
// Copy data in one chunk up to the end of the data buffer.
nFrames = framesEmpty;
if ( writeIndex_ + nFrames > data_.frames() )
nFrames = data_.frames() - writeIndex_;
if ( nFrames > frames.frames() - framesWritten )
nFrames = frames.frames() - framesWritten;
bytes = nFrames * nChannels * sizeof( StkFloat );
StkFloat *samples = &data_[writeIndex_ * nChannels];
memcpy( samples, &frames[framesWritten * nChannels], bytes );
for ( unsigned int i=0; i<nFrames * nChannels; i++ ) clipTest( *samples++ );
index = writeIndex_ * nChannels;
for ( j=0; j<nChannels; j++ )
data_[index] = frames[iFrames++];
clipTest( data_[index++] );
writeIndex_ += nFrames;
if ( writeIndex_ == data_.frames() ) writeIndex_ = 0;
framesFilled_++;
frameCounter_++;
writeIndex_++;
if ( writeIndex_ == data_.frames() )
writeIndex_ = 0;
}
}
else { // non-interleaved frames
unsigned long hop = frames.frames();
unsigned int index, iFrame;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
iFrame = i;
index = writeIndex_ * nChannels;
for ( j=0; j<nChannels; j++ ) {
data_[index] = frames[iFrame];
clipTest( data_[index++] );
iFrame += hop;
}
framesFilled_++;
frameCounter_++;
writeIndex_++;
if ( writeIndex_ == data_.frames() )
writeIndex_ = 0;
}
framesWritten += nFrames;
mutex_.lock();
framesFilled_ += nFrames;
mutex_.unlock();
frameCounter_ += nFrames;
}
}
} // stk namespace

View File

@@ -3,15 +3,17 @@
\brief STK sampling synthesis abstract base class.
This instrument provides an ADSR envelope, a one-pole filter, and
structures for an arbitrary number of attack and loop waves.
structures for an arbitrary number of attack and looped files.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Sampler.h"
Sampler :: Sampler()
namespace stk {
Sampler :: Sampler( void )
{
// We don't make the waves here yet, because
// we don't know what they will be.
@@ -20,14 +22,14 @@ Sampler :: Sampler()
loopGain_ = 0.25;
}
Sampler :: ~Sampler()
Sampler :: ~Sampler( void )
{
unsigned int i;
for ( i=0; i<attacks_.size(); i++ ) delete attacks_[i];
for ( i=0; i<loops_.size(); i++ ) delete loops_[i];
}
void Sampler :: keyOn()
void Sampler :: keyOn( void )
{
// Reset all attack waves.
for ( unsigned int i=0; i<attacks_.size(); i++ )
@@ -38,12 +40,12 @@ void Sampler :: keyOn()
}
void Sampler :: keyOff()
void Sampler :: keyOff( void )
{
adsr_.keyOff();
}
void Sampler :: noteOff(StkFloat amplitude)
void Sampler :: noteOff( StkFloat amplitude )
{
this->keyOff();
@@ -52,3 +54,5 @@ void Sampler :: noteOff(StkFloat amplitude)
handleError( StkError::DEBUG_WARNING );
#endif
}
} // stk namespace

View File

@@ -31,14 +31,16 @@
- Vibrato Gain = 1
- Breath Pressure = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Saxofony.h"
#include "SKINI.msg"
Saxofony :: Saxofony(StkFloat lowestFrequency)
namespace stk {
Saxofony :: Saxofony( StkFloat lowestFrequency )
{
length_ = (unsigned long) (Stk::sampleRate() / lowestFrequency + 1);
// Initialize blowing position to 0.2 of length / 2.
@@ -58,18 +60,18 @@ Saxofony :: Saxofony(StkFloat lowestFrequency)
vibratoGain_ = 0.1;
}
Saxofony :: ~Saxofony()
Saxofony :: ~Saxofony( void )
{
}
void Saxofony :: clear()
void Saxofony :: clear( void )
{
delays_[0].clear();
delays_[1].clear();
filter_.clear();
}
void Saxofony :: setFrequency(StkFloat frequency)
void Saxofony :: setFrequency( StkFloat frequency )
{
StkFloat freakency = frequency;
if ( frequency <= 0.0 ) {
@@ -86,7 +88,7 @@ void Saxofony :: setFrequency(StkFloat frequency)
delays_[1].setDelay( position_ * delay );
}
void Saxofony :: setBlowPosition(StkFloat position)
void Saxofony :: setBlowPosition( StkFloat position )
{
if ( position_ == position ) return;
@@ -101,19 +103,19 @@ void Saxofony :: setBlowPosition(StkFloat position)
delays_[1].setDelay( position_ * totalDelay );
}
void Saxofony :: startBlowing(StkFloat amplitude, StkFloat rate)
void Saxofony :: startBlowing( StkFloat amplitude, StkFloat rate )
{
envelope_.setRate( rate );
envelope_.setTarget( amplitude );
}
void Saxofony :: stopBlowing(StkFloat rate)
void Saxofony :: stopBlowing( StkFloat rate )
{
envelope_.setRate( rate );
envelope_.setTarget( 0.0 );
}
void Saxofony :: noteOn(StkFloat frequency, StkFloat amplitude)
void Saxofony :: noteOn( StkFloat frequency, StkFloat amplitude )
{
this->setFrequency( frequency );
this->startBlowing( 0.55 + (amplitude * 0.30), amplitude * 0.005 );
@@ -125,7 +127,7 @@ void Saxofony :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
void Saxofony :: noteOff(StkFloat amplitude)
void Saxofony :: noteOff( StkFloat amplitude )
{
this->stopBlowing( amplitude * 0.01 );
@@ -135,28 +137,7 @@ void Saxofony :: noteOff(StkFloat amplitude)
#endif
}
StkFloat Saxofony :: computeSample()
{
StkFloat pressureDiff;
StkFloat breathPressure;
StkFloat temp;
// Calculate the breath pressure (envelope + noise + vibrato)
breathPressure = envelope_.tick();
breathPressure += breathPressure * noiseGain_ * noise_.tick();
breathPressure += breathPressure * vibratoGain_ * vibrato_.tick();
temp = -0.95 * filter_.tick( delays_[0].lastOut() );
lastOutput_ = temp - delays_[1].lastOut();
pressureDiff = breathPressure - lastOutput_;
delays_[1].tick( temp );
delays_[0].tick( breathPressure - (pressureDiff * reedTable_.tick(pressureDiff)) - temp );
lastOutput_ *= outputGain_;
return lastOutput_;
}
void Saxofony :: controlChange(int number, StkFloat value)
void Saxofony :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -194,3 +175,5 @@ void Saxofony :: controlChange(int number, StkFloat value)
handleError( StkError::DEBUG_WARNING );
#endif
}
} // stk namespace

View File

@@ -48,26 +48,30 @@
- Little Rocks = 21
- Tuned Bamboo Chimes = 22
by Perry R. Cook, 1996 - 2004.
by Perry R. Cook, 1996 - 2009.
*/
/***************************************************/
#include "Stk.h"
#include "Shakers.h"
#include "SKINI.msg"
#include <string.h>
#include <cmath>
int my_random(int max) // Return Random Int Between 0 and max
namespace stk {
int my_random( int max ) // Return Random Int Between 0 and max
{
int temp = (int) ((float)max * rand() / (RAND_MAX + 1.0) );
return temp;
}
StkFloat float_random(StkFloat max) // Return random float between 0.0 and max
StkFloat float_random( StkFloat max ) // Return random float between 0.0 and max
{
StkFloat temp = (StkFloat) (max * rand() / (RAND_MAX + 1.0) );
return temp;
}
StkFloat noise_tick() // Return random StkFloat float between -1.0 and 1.0
StkFloat noise_tick( void ) // Return random StkFloat float between -1.0 and 1.0
{
StkFloat temp = (StkFloat) (2.0 * rand() / (RAND_MAX + 1.0) );
temp -= 1.0;
@@ -274,10 +278,7 @@ const StkFloat LITLROCKS_RES = 0.843;
// Finally ... the class code!
#include "Shakers.h"
#include "SKINI.msg"
Shakers :: Shakers()
Shakers :: Shakers( void )
{
int i;
@@ -316,7 +317,7 @@ Shakers :: Shakers()
this->setupNum(instType_);
}
Shakers :: ~Shakers()
Shakers :: ~Shakers( void )
{
}
@@ -331,7 +332,7 @@ char instrs[NUM_INSTR][10] = {
"BigRocks", "LitlRoks", "TBamboo"
};
int Shakers :: setupName(char* instr)
int Shakers :: setupName( char* instr )
{
int which = 0;
@@ -348,22 +349,22 @@ int Shakers :: setupName(char* instr)
return this->setupNum(which);
}
void Shakers :: setFinalZs(StkFloat z0, StkFloat z1, StkFloat z2)
void Shakers :: setFinalZs( StkFloat z0, StkFloat z1, StkFloat z2 )
{
finalZCoeffs_[0] = z0;
finalZCoeffs_[1] = z1;
finalZCoeffs_[2] = z2;
}
void Shakers :: setDecays(StkFloat sndDecay_, StkFloat sysDecay_)
void Shakers :: setDecays( StkFloat sndDecay, StkFloat sysDecay )
{
soundDecay_ = sndDecay_;
systemDecay_ = sysDecay_;
soundDecay_ = sndDecay;
systemDecay_ = sysDecay;
}
int Shakers :: setFreqAndReson(int which, StkFloat freq, StkFloat reson)
int Shakers :: setFreqAndReson( int which, StkFloat freq, StkFloat reson )
{
if (which < MAX_FREQS) {
if ( which < MAX_FREQS ) {
resons_[which] = reson;
center_freqs_[which] = freq;
t_center_freqs_[which] = freq;
@@ -374,7 +375,7 @@ int Shakers :: setFreqAndReson(int which, StkFloat freq, StkFloat reson)
else return 0;
}
int Shakers :: setupNum(int inst)
int Shakers :: setupNum( int inst )
{
int i, rv = 0;
StkFloat temp;
@@ -793,7 +794,7 @@ int Shakers :: setupNum(int inst)
return rv;
}
void Shakers :: noteOn(StkFloat frequency, StkFloat amplitude)
void Shakers :: noteOn( StkFloat frequency, StkFloat amplitude )
{
// Yep ... pretty kludgey, but it works!
int noteNum = (int) ((12*log(frequency/220.0)/log(2.0)) + 57.01) % 32;
@@ -808,7 +809,7 @@ void Shakers :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
void Shakers :: noteOff(StkFloat amplitude)
void Shakers :: noteOff( StkFloat amplitude )
{
shakeEnergy_ = 0.0;
if (instType_==10 || instType_==3) ratchetPos_ = 0;
@@ -816,7 +817,7 @@ void Shakers :: noteOff(StkFloat amplitude)
const StkFloat MIN_ENERGY = 0.3;
StkFloat Shakers :: computeSample()
StkFloat Shakers :: tick( unsigned int )
{
StkFloat data;
StkFloat temp_rand;
@@ -824,15 +825,15 @@ StkFloat Shakers :: computeSample()
if (instType_ == 4) {
if (shakeEnergy_ > MIN_ENERGY) {
lastOutput_ = wuter_tick();
lastOutput_ *= 0.0001;
lastFrame_[0] = wuter_tick();
lastFrame_[0] *= 0.0001;
}
else {
lastOutput_ = 0.0;
lastFrame_[0] = 0.0;
}
}
else if (instType_ == 22) {
lastOutput_ = tbamb_tick();
lastFrame_[0] = tbamb_tick();
}
else if (instType_ == 10 || instType_ == 3) {
if (ratchetPos_ > 0) {
@@ -842,10 +843,10 @@ StkFloat Shakers :: computeSample()
ratchetPos_ -= 1;
}
totalEnergy_ = ratchet_;
lastOutput_ = ratchet_tick();
lastOutput_ *= 0.0001;
lastFrame_[0] = ratchet_tick();
lastFrame_[0] *= 0.0001;
}
else lastOutput_ = 0.0;
else lastFrame_[0] = 0.0;
}
else { // generic_tick()
if (shakeEnergy_ > MIN_ENERGY) {
@@ -879,15 +880,15 @@ StkFloat Shakers :: computeSample()
data += finalZCoeffs_[2] * finalZ_[2]; // Extra zero(s) for shape
if (data > 10000.0) data = 10000.0;
if (data < -10000.0) data = -10000.0;
lastOutput_ = data * 0.0001;
lastFrame_[0] = data * 0.0001;
}
else lastOutput_ = 0.0;
else lastFrame_[0] = 0.0;
}
return lastOutput_;
return lastFrame_[0];
}
void Shakers :: controlChange(int number, StkFloat value)
void Shakers :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -997,7 +998,7 @@ void Shakers :: controlChange(int number, StkFloat value)
// KLUDGE-O-MATIC-O-RAMA
StkFloat Shakers :: wuter_tick() {
StkFloat Shakers :: wuter_tick( void ) {
StkFloat data;
int j;
shakeEnergy_ *= systemDecay_; // Exponential system decay
@@ -1068,7 +1069,7 @@ StkFloat Shakers :: wuter_tick() {
return data;
}
StkFloat Shakers :: ratchet_tick() {
StkFloat Shakers :: ratchet_tick( void ) {
StkFloat data;
if (my_random(1024) < nObjects_) {
sndLevel_ += 512 * ratchet_ * totalEnergy_;
@@ -1094,7 +1095,7 @@ StkFloat Shakers :: ratchet_tick() {
return data;
}
StkFloat Shakers :: tbamb_tick() {
StkFloat Shakers :: tbamb_tick( void ) {
StkFloat data, temp;
static int which = 0;
int i;
@@ -1129,3 +1130,5 @@ StkFloat Shakers :: tbamb_tick() {
else data = 0.0;
return data;
}
} // stk namespace

View File

@@ -13,17 +13,19 @@
- Envelope Rate = 11
- Gain = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Simple.h"
#include "SKINI.msg"
Simple :: Simple()
namespace stk {
Simple :: Simple( void )
{
// Concatenate the STK rawwave path to the rawwave file
loop_ = new WaveLoop( (Stk::rawwavePath() + "impuls10.raw").c_str(), true );
loop_ = new FileLoop( (Stk::rawwavePath() + "impuls10.raw").c_str(), true );
filter_.setPole( 0.5 );
baseFrequency_ = 440.0;
@@ -31,22 +33,22 @@ Simple :: Simple()
loopGain_ = 0.5;
}
Simple :: ~Simple()
Simple :: ~Simple( void )
{
delete loop_;
}
void Simple :: keyOn()
void Simple :: keyOn( void )
{
adsr_.keyOn();
}
void Simple :: keyOff()
void Simple :: keyOff( void )
{
adsr_.keyOff();
}
void Simple :: noteOn(StkFloat frequency, StkFloat amplitude)
void Simple :: noteOn( StkFloat frequency, StkFloat amplitude )
{
this->keyOn();
this->setFrequency( frequency );
@@ -57,7 +59,7 @@ void Simple :: noteOn(StkFloat frequency, StkFloat amplitude)
handleError( StkError::DEBUG_WARNING );
#endif
}
void Simple :: noteOff(StkFloat amplitude)
void Simple :: noteOff( StkFloat amplitude )
{
this->keyOff();
@@ -67,23 +69,13 @@ void Simple :: noteOff(StkFloat amplitude)
#endif
}
void Simple :: setFrequency(StkFloat frequency)
void Simple :: setFrequency( StkFloat frequency )
{
biquad_.setResonance( frequency, 0.98, true );
loop_->setFrequency( frequency );
}
StkFloat Simple :: computeSample()
{
lastOutput_ = loopGain_ * loop_->tick();
biquad_.tick( noise_.tick() );
lastOutput_ += (1.0 - loopGain_) * biquad_.lastOut();
lastOutput_ = filter_.tick( lastOutput_ );
lastOutput_ *= adsr_.tick();
return lastOutput_;
}
void Simple :: controlChange(int number, StkFloat value)
void Simple :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -119,3 +111,5 @@ void Simple :: controlChange(int number, StkFloat value)
handleError( StkError::DEBUG_WARNING );
#endif
}
} // stk namespace

View File

@@ -9,13 +9,15 @@
The "table" length, set in SineWave.h, is 2048 samples by default.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "SineWave.h"
#include <cmath>
namespace stk {
StkFrames SineWave :: table_;
SineWave :: SineWave( void )
@@ -42,10 +44,10 @@ void SineWave :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
this->setRate( oldRate * rate_ / newRate );
}
void SineWave :: reset(void)
void SineWave :: reset( void )
{
time_ = 0.0;
lastOutput_ = 0;
lastFrame_[0] = 0;
}
void SineWave :: setFrequency( StkFloat frequency )
@@ -58,55 +60,19 @@ void SineWave :: addTime( StkFloat time )
{
// Add an absolute time in samples.
time_ += time;
while ( time_ < 0.0 )
time_ += TABLE_SIZE;
while ( time_ >= TABLE_SIZE )
time_ -= TABLE_SIZE;
}
void SineWave :: addPhase( StkFloat angle )
void SineWave :: addPhase( StkFloat phase )
{
// Add a time in cycles (one cycle = TABLE_SIZE).
time_ += TABLE_SIZE * angle;
while ( time_ < 0.0 )
time_ += TABLE_SIZE;
while ( time_ >= TABLE_SIZE )
time_ -= TABLE_SIZE;
time_ += TABLE_SIZE * phase;
}
void SineWave :: addPhaseOffset( StkFloat angle )
void SineWave :: addPhaseOffset( StkFloat phaseOffset )
{
// Add a phase offset in cycles, where 1.0 = TABLE_SIZE.
phaseOffset_ = TABLE_SIZE * angle;
// Add a phase offset relative to any previous offset value.
time_ += ( phaseOffset - phaseOffset_ ) * TABLE_SIZE;
phaseOffset_ = phaseOffset;
}
StkFloat SineWave :: computeSample( void )
{
// Check limits of time address ... if necessary, recalculate modulo
// TABLE_SIZE.
while ( time_ < 0.0 )
time_ += TABLE_SIZE;
while ( time_ >= TABLE_SIZE )
time_ -= TABLE_SIZE;
StkFloat tyme;
if ( phaseOffset_ ) {
tyme = time_ + phaseOffset_;
while ( tyme < 0.0 )
tyme += TABLE_SIZE;
while ( tyme >= TABLE_SIZE )
tyme -= TABLE_SIZE;
}
else {
tyme = time_;
}
lastOutput_ = table_.interpolate( tyme );
// Increment time, which can be negative.
time_ += rate_;
return lastOutput_;
}
} // stk namespace

View File

@@ -2,116 +2,52 @@
/*! \class SingWave
\brief STK "singing" looped soundfile class.
This class contains all that is needed to make
a pitched musical sound, like a simple voice
or violin. In general, it will not be used
alone because of munchkinification effects
from pitch shifting. It will be used as an
excitation source for other instruments.
This class loops a specified soundfile and modulates it both
periodically and randomly to produce a pitched musical sound, like
a simple voice or violin. In general, it is not be used alone
because of "munchkinification" effects from pitch shifting.
Within STK, it is used as an excitation source for other
instruments.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "SingWave.h"
namespace stk {
SingWave :: SingWave( std::string fileName, bool raw)
SingWave :: SingWave( std::string fileName, bool raw )
{
// An exception could be thrown here.
wave_ = new WaveLoop( fileName, raw );
wave_.openFile( fileName, raw );
rate_ = 1.0;
sweepRate_ = 0.001;
modulator_.setVibratoRate( 6.0 );
modulator_.setVibratoGain( 0.04 );
modulator_.setRandomGain( 0.005 );
this->setFrequency( 75.0 );
pitchEnvelope_.setRate( 1.0 );
this->computeSample();
this->computeSample();
this->tick();
this->tick();
pitchEnvelope_.setRate( sweepRate_ * rate_ );
}
SingWave :: ~SingWave()
{
delete wave_;
}
void SingWave :: reset()
{
wave_->reset();
lastOutput_ = 0.0;
}
void SingWave :: normalize()
{
wave_->normalize();
}
void SingWave :: normalize(StkFloat peak)
{
wave_->normalize( peak );
}
void SingWave :: setFrequency(StkFloat frequency)
void SingWave :: setFrequency( StkFloat frequency )
{
StkFloat temp = rate_;
rate_ = wave_->getSize() * frequency / Stk::sampleRate();
rate_ = wave_.getSize() * frequency / Stk::sampleRate();
temp -= rate_;
if ( temp < 0) temp = -temp;
pitchEnvelope_.setTarget( rate_ );
pitchEnvelope_.setRate( sweepRate_ * temp );
}
void SingWave :: setVibratoRate(StkFloat rate)
{
modulator_.setVibratoRate( rate );
}
void SingWave :: setVibratoGain(StkFloat gain)
{
modulator_.setVibratoGain(gain);
}
void SingWave :: setRandomGain(StkFloat gain)
{
modulator_.setRandomGain(gain);
}
void SingWave :: setSweepRate(StkFloat rate)
{
sweepRate_ = rate;
}
void SingWave :: setGainRate(StkFloat rate)
{
envelope_.setRate(rate);
}
void SingWave :: setGainTarget(StkFloat target)
{
envelope_.setTarget(target);
}
void SingWave :: noteOn()
{
envelope_.keyOn();
}
void SingWave :: noteOff()
{
envelope_.keyOff();
}
StkFloat SingWave :: computeSample()
{
// Set the wave rate.
StkFloat newRate = pitchEnvelope_.tick();
newRate += newRate * modulator_.tick();
wave_->setRate( newRate );
lastOutput_ = wave_->tick();
lastOutput_ *= envelope_.tick();
return lastOutput_;
}
} // stk namespace

View File

@@ -13,16 +13,17 @@
Stanford, bearing the names of Karplus and/or
Strong.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Sitar.h"
#include <math.h>
Sitar :: Sitar(StkFloat lowestFrequency)
namespace stk {
Sitar :: Sitar( StkFloat lowestFrequency )
{
unsigned long length = (unsigned long) (Stk::sampleRate() / lowestFrequency + 1);
unsigned long length = (unsigned long) ( Stk::sampleRate() / lowestFrequency + 1 );
delayLine_.setMaximumDelay( length );
delay_ = 0.5 * length;
delayLine_.setDelay( delay_ );
@@ -35,17 +36,17 @@ Sitar :: Sitar(StkFloat lowestFrequency)
this->clear();
}
Sitar :: ~Sitar()
Sitar :: ~Sitar( void )
{
}
void Sitar :: clear()
void Sitar :: clear( void )
{
delayLine_.clear();
loopFilter_.clear();
}
void Sitar :: setFrequency(StkFloat frequency)
void Sitar :: setFrequency( StkFloat frequency )
{
StkFloat freakency = frequency;
if ( frequency <= 0.0 ) {
@@ -61,12 +62,12 @@ void Sitar :: setFrequency(StkFloat frequency)
if ( loopGain_ > 0.9995 ) loopGain_ = 0.9995;
}
void Sitar :: pluck(StkFloat amplitude)
void Sitar :: pluck( StkFloat amplitude )
{
envelope_.keyOn();
}
void Sitar :: noteOn(StkFloat frequency, StkFloat amplitude)
void Sitar :: noteOn( StkFloat frequency, StkFloat amplitude )
{
this->setFrequency( frequency );
this->pluck( amplitude );
@@ -78,7 +79,7 @@ void Sitar :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
void Sitar :: noteOff(StkFloat amplitude)
void Sitar :: noteOff( StkFloat amplitude )
{
loopGain_ = (StkFloat) 1.0 - amplitude;
if ( loopGain_ < 0.0 ) {
@@ -98,18 +99,4 @@ void Sitar :: noteOff(StkFloat amplitude)
#endif
}
StkFloat Sitar :: computeSample()
{
if ( fabs(targetDelay_ - delay_) > 0.001 ) {
if ( targetDelay_ < delay_ )
delay_ *= 0.99999;
else
delay_ *= 1.00001;
delayLine_.setDelay( delay_ );
}
lastOutput_ = delayLine_.tick( loopFilter_.tick( delayLine_.lastOut() * loopGain_ ) +
(amGain_ * envelope_.tick() * noise_.tick()));
return lastOutput_;
}
} // stk namespace

View File

@@ -19,13 +19,15 @@
See also SKINI.txt.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Skini.h"
#include "SKINI.tbl"
namespace stk {
Skini :: Skini()
{
}
@@ -215,3 +217,5 @@ std::string Skini :: whatsThisController( long number )
}
return controller;
}
} // stk namespace

View File

@@ -5,12 +5,14 @@
This class provides common functionality for TCP and UDP internet
socket server and client subclasses.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Socket.h"
namespace stk {
Socket :: Socket()
{
soket_ = -1;
@@ -43,28 +45,13 @@ void Socket :: close( int socket )
#endif
}
int Socket :: id( void ) const
{
return soket_;
}
int Socket :: port( void ) const
{
return port_;
}
bool Socket :: isValid( int socket )
{
return socket != -1;
}
void Socket :: setBlocking( int socket, bool enable )
{
if ( !isValid( socket ) ) return;
#if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__))
int tmp = ::fcntl(socket, F_GETFL, 0);
int tmp = ::fcntl( socket, F_GETFL, 0 );
if ( tmp >= 0 )
tmp = ::fcntl( socket, F_SETFL, enable ? (tmp &~ O_NONBLOCK) : (tmp | O_NONBLOCK) );
@@ -88,3 +75,4 @@ int Socket :: readBuffer(int socket, void *buffer, long bufferSize, int flags )
return recv( socket, (char *)buffer, bufferSize, flags );
}
} // stk namespace

View File

@@ -5,49 +5,16 @@
This class implements a spherical ball with
radius, mass, position, and velocity parameters.
by Perry R. Cook, 1995 - 2004.
by Perry R. Cook, 1995 - 2009.
*/
/***************************************************/
#include "Sphere.h"
#include <math.h>
#include <cmath>
Sphere::Sphere(StkFloat radius)
{
radius_ = radius;
mass_ = 1.0;
};
namespace stk {
Sphere::~Sphere()
{
}
void Sphere::setPosition(StkFloat x, StkFloat y, StkFloat z)
{
position_.setXYZ(x, y, z);
};
void Sphere::setVelocity(StkFloat x, StkFloat y, StkFloat z)
{
velocity_.setXYZ(x, y, z);
};
void Sphere::setRadius(StkFloat radius)
{
radius_ = radius;
};
void Sphere::setMass(StkFloat mass)
{
mass_ = mass;
};
Vector3D* Sphere::getPosition()
{
return &position_;
};
Vector3D* Sphere::getRelativePosition(Vector3D* position)
Vector3D* Sphere::getRelativePosition( Vector3D* position )
{
workingVector_.setXYZ(position->getX() - position_.getX(),
position->getY() - position_.getY(),
@@ -55,13 +22,13 @@ Vector3D* Sphere::getRelativePosition(Vector3D* position)
return &workingVector_;
};
StkFloat Sphere::getVelocity(Vector3D* velocity)
StkFloat Sphere::getVelocity( Vector3D* velocity )
{
velocity->setXYZ( velocity_.getX(), velocity_.getY(), velocity_.getZ() );
return velocity_.getLength();
};
StkFloat Sphere::isInside(Vector3D *position)
StkFloat Sphere::isInside( Vector3D *position )
{
// Return directed distance from aPosition to spherical boundary ( <
// 0 if inside).
@@ -73,16 +40,6 @@ StkFloat Sphere::isInside(Vector3D *position)
return distance - radius_;
};
StkFloat Sphere::getRadius()
{
return radius_;
};
StkFloat Sphere::getMass()
{
return mass_;
};
void Sphere::addVelocity(StkFloat x, StkFloat y, StkFloat z)
{
velocity_.setX(velocity_.getX() + x);
@@ -90,10 +47,4 @@ void Sphere::addVelocity(StkFloat x, StkFloat y, StkFloat z)
velocity_.setZ(velocity_.getZ() + z);
}
void Sphere::tick(StkFloat timeIncrement)
{
position_.setX(position_.getX() + (timeIncrement * velocity_.getX()));
position_.setY(position_.getY() + (timeIncrement * velocity_.getY()));
position_.setZ(position_.getZ() + (timeIncrement * velocity_.getZ()));
};
} // stk namespace

View File

@@ -17,7 +17,7 @@
- String Sustain = 11
- String Stretch = 1
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
@@ -25,9 +25,11 @@
#include "SKINI.msg"
#include <cmath>
StifKarp :: StifKarp(StkFloat lowestFrequency)
namespace stk {
StifKarp :: StifKarp( StkFloat lowestFrequency )
{
length_ = (unsigned long) (Stk::sampleRate() / lowestFrequency + 1);
length_ = (unsigned long) ( Stk::sampleRate() / lowestFrequency + 1 );
delayLine_.setMaximumDelay( length_ );
delayLine_.setDelay( 0.5 * length_ );
combDelay_.setMaximumDelay( length_ );
@@ -44,18 +46,18 @@ StifKarp :: StifKarp(StkFloat lowestFrequency)
this->clear();
}
StifKarp :: ~StifKarp()
StifKarp :: ~StifKarp( void )
{
}
void StifKarp :: clear()
void StifKarp :: clear( void )
{
delayLine_.clear();
combDelay_.clear();
filter_.clear();
}
void StifKarp :: setFrequency(StkFloat frequency)
void StifKarp :: setFrequency( StkFloat frequency )
{
lastFrequency_ = frequency;
if ( frequency <= 0.0 ) {
@@ -80,7 +82,7 @@ void StifKarp :: setFrequency(StkFloat frequency)
combDelay_.setDelay( 0.5 * pickupPosition_ * lastLength_ );
}
void StifKarp :: setStretch(StkFloat stretch)
void StifKarp :: setStretch( StkFloat stretch )
{
stretching_ = stretch;
StkFloat coefficient;
@@ -102,7 +104,7 @@ void StifKarp :: setStretch(StkFloat stretch)
}
}
void StifKarp :: setPickupPosition(StkFloat position) {
void StifKarp :: setPickupPosition( StkFloat position ) {
pickupPosition_ = position;
if ( position < 0.0 ) {
errorString_ << "StifKarp::setPickupPosition: parameter is less than zero ... setting to 0.0!";
@@ -119,14 +121,14 @@ void StifKarp :: setPickupPosition(StkFloat position) {
combDelay_.setDelay( 0.5 * pickupPosition_ * lastLength_ );
}
void StifKarp :: setBaseLoopGain(StkFloat aGain)
void StifKarp :: setBaseLoopGain( StkFloat aGain )
{
baseLoopGain_ = aGain;
loopGain_ = baseLoopGain_ + (lastFrequency_ * 0.000005);
if ( loopGain_ > 0.99999 ) loopGain_ = (StkFloat) 0.99999;
}
void StifKarp :: pluck(StkFloat amplitude)
void StifKarp :: pluck( StkFloat amplitude )
{
StkFloat gain = amplitude;
if ( gain > 1.0 ) {
@@ -148,7 +150,7 @@ void StifKarp :: pluck(StkFloat amplitude)
}
}
void StifKarp :: noteOn(StkFloat frequency, StkFloat amplitude)
void StifKarp :: noteOn( StkFloat frequency, StkFloat amplitude )
{
this->setFrequency( frequency );
this->pluck( amplitude );
@@ -159,7 +161,7 @@ void StifKarp :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
void StifKarp :: noteOff(StkFloat amplitude)
void StifKarp :: noteOff( StkFloat amplitude )
{
StkFloat gain = amplitude;
if ( gain > 1.0 ) {
@@ -180,23 +182,7 @@ void StifKarp :: noteOff(StkFloat amplitude)
#endif
}
StkFloat StifKarp :: computeSample()
{
StkFloat temp = delayLine_.lastOut() * loopGain_;
// Calculate allpass stretching.
for (int i=0; i<4; i++)
temp = biquad_[i].tick(temp);
// Moving average filter.
temp = filter_.tick(temp);
lastOutput_ = delayLine_.tick(temp);
lastOutput_ = lastOutput_ - combDelay_.tick( lastOutput_ );
return lastOutput_;
}
void StifKarp :: controlChange(int number, StkFloat value)
void StifKarp :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -227,3 +213,4 @@ void StifKarp :: controlChange(int number, StkFloat value)
#endif
}
} // stk namespace

View File

@@ -22,7 +22,7 @@
STK WWW site: http://ccrma.stanford.edu/software/stk/
The Synthesis ToolKit in C++ (STK)
Copyright (c) 1995-2007 Perry R. Cook and Gary P. Scavone
Copyright (c) 1995-2009 Perry R. Cook and Gary P. Scavone
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
@@ -52,6 +52,8 @@
#include "Stk.h"
namespace stk {
StkFloat Stk :: srate_ = (StkFloat) SRATE;
std::string Stk :: rawwavepath_ = RAWWAVE_PATH;
const Stk::StkFormat Stk :: STK_SINT8 = 0x1;
@@ -224,8 +226,8 @@ void Stk :: handleError( std::string message, StkError::Type type )
// StkFrames definitions
//
StkFrames :: StkFrames( unsigned int nFrames, unsigned int nChannels, bool interleaved )
: nFrames_( nFrames ), nChannels_( nChannels ), interleaved_( interleaved )
StkFrames :: StkFrames( unsigned int nFrames, unsigned int nChannels )
: nFrames_( nFrames ), nChannels_( nChannels )
{
size_ = nFrames_ * nChannels_;
bufferSize_ = size_;
@@ -244,8 +246,8 @@ StkFrames :: StkFrames( unsigned int nFrames, unsigned int nChannels, bool inter
dataRate_ = Stk::sampleRate();
}
StkFrames :: StkFrames( const StkFloat& value, unsigned int nFrames, unsigned int nChannels, bool interleaved )
: nFrames_( nFrames ), nChannels_( nChannels ), interleaved_( interleaved )
StkFrames :: StkFrames( const StkFloat& value, unsigned int nFrames, unsigned int nChannels )
: nFrames_( nFrames ), nChannels_( nChannels )
{
size_ = nFrames_ * nChannels_;
bufferSize_ = size_;
@@ -269,10 +271,22 @@ StkFrames :: ~StkFrames()
if ( data_ ) free( data_ );
}
bool StkFrames :: empty() const
StkFrames :: StkFrames( const StkFrames& f )
: size_(0), bufferSize_(0)
{
if ( size_ > 0 ) return false;
else return true;
resize( f.frames(), f.channels() );
dataRate_ = Stk::sampleRate();
for ( unsigned int i=0; i<size_; i++ ) data_[i] = f[i];
}
StkFrames& StkFrames :: operator= ( const StkFrames& f )
{
size_ = 0;
bufferSize_ = 0;
resize( f.frames(), f.channels() );
dataRate_ = Stk::sampleRate();
for ( unsigned int i=0; i<size_; i++ ) data_[i] = f[i];
return *this;
}
void StkFrames :: resize( size_t nFrames, unsigned int nChannels )
@@ -301,87 +315,25 @@ void StkFrames :: resize( size_t nFrames, unsigned int nChannels, StkFloat value
for ( size_t i=0; i<size_; i++ ) data_[i] = value;
}
StkFloat& StkFrames :: operator[] ( size_t n )
{
#if defined(_STK_DEBUG_)
if ( n >= size_ ) {
std::ostringstream error;
error << "StkFrames::operator[]: invalid index (" << n << ") value!";
Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
}
#endif
return data_[n];
}
StkFloat StkFrames :: operator[] ( size_t n ) const
{
#if defined(_STK_DEBUG_)
if ( n >= size_ ) {
std::ostringstream error;
error << "StkFrames::operator[]: invalid index (" << n << ") value!";
Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
}
#endif
return data_[n];
}
StkFloat& StkFrames :: operator() ( size_t frame, unsigned int channel )
{
#if defined(_STK_DEBUG_)
if ( frame >= nFrames_ || channel >= nChannels_ ) {
std::ostringstream error;
error << "StkFrames::operator(): invalid frame (" << frame << ") or channel (" << channel << ") value!";
Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
}
#endif
if ( interleaved_ )
return data_[ frame * nChannels_ + channel ];
else
return data_[ channel * nFrames_ + frame ];
}
StkFloat StkFrames :: operator() ( size_t frame, unsigned int channel ) const
{
#if defined(_STK_DEBUG_)
if ( frame >= nFrames_ || channel >= nChannels_ ) {
std::ostringstream error;
error << "StkFrames::operator(): invalid frame (" << frame << ") or channel (" << channel << ") value!";
Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
}
#endif
if ( interleaved_ )
return data_[ frame * nChannels_ + channel ];
else
return data_[ channel * nFrames_ + frame ];
}
StkFloat StkFrames :: interpolate( StkFloat frame, unsigned int channel ) const
{
#if defined(_STK_DEBUG_)
if ( frame >= (StkFloat) nFrames_ || channel >= nChannels_ ) {
std::ostringstream error;
error << "StkFrames::interpolate: invalid frame (" << frame << ") or channel (" << channel << ") value!";
Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
}
if ( frame < 0.0 || frame > (StkFloat) ( nFrames_ - 1 ) || channel >= nChannels_ ) {
std::ostringstream error;
error << "StkFrames::interpolate: invalid frame (" << frame << ") or channel (" << channel << ") value!";
Stk::handleError( error.str(), StkError::MEMORY_ACCESS );
}
#endif
size_t iIndex = ( size_t ) frame; // integer part of index
StkFloat output, alpha = frame - (StkFloat) iIndex; // fractional part of index
if ( interleaved_ ) {
iIndex = iIndex * nChannels_ + channel;
output = data_[ iIndex ];
iIndex = iIndex * nChannels_ + channel;
output = data_[ iIndex ];
if ( alpha > 0.0 )
output += ( alpha * ( data_[ iIndex + nChannels_ ] - output ) );
}
else {
iIndex += channel * nFrames_;
output = data_[ iIndex ];
output += ( alpha * ( data_[ ++iIndex ] - output ) );
}
return output;
}
} // stk namespace

View File

@@ -1,47 +0,0 @@
/***************************************************/
/*! \class SubNoise
\brief STK sub-sampled noise generator.
Generates a new random number every "rate" ticks
using the C rand() function. The quality of the
rand() function varies from one OS to another.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
*/
/***************************************************/
#include "SubNoise.h"
SubNoise :: SubNoise( int subRate ) : Noise()
{
if ( subRate <= 0 ) {
errorString_ << "SubNoise: subRate argument is negative ... setting to 16!";
handleError( StkError::WARNING );
rate_ = 16;
}
// Precompute an output.
Noise::computeSample();
counter_ = rate_;
}
SubNoise :: ~SubNoise()
{
}
void SubNoise :: setRate( int subRate )
{
if ( subRate > 0 )
rate_ = subRate;
}
StkFloat SubNoise :: computeSample()
{
if ( counter_-- == 0 ) {
Noise::computeSample();
counter_ = rate_;
}
return lastOutput_;
}

104
src/TapDelay.cpp Normal file
View File

@@ -0,0 +1,104 @@
/***************************************************/
/*! \class TapDelay
\brief STK non-interpolating tapped delay line class.
This class implements a non-interpolating digital delay-line with
an arbitrary number of output "taps". If the maximum length and
tap delays are not specified during instantiation, a fixed maximum
length of 4095 and a single tap delay of zero is set.
A non-interpolating delay line is typically used in fixed
delay-length applications, such as for reverberation.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "TapDelay.h"
namespace stk {
TapDelay :: TapDelay( std::vector<unsigned long> taps, unsigned long maxDelay )
{
// Writing before reading allows delays from 0 to length-1.
// If we want to allow a delay of maxDelay, we need a
// delayline of length = maxDelay+1.
if ( maxDelay < 1 ) {
errorString_ << "TapDelay::TapDelay: maxDelay must be > 0!\n";
handleError( StkError::FUNCTION_ARGUMENT );
}
for ( unsigned int i=0; i<taps.size(); i++ ) {
if ( taps[i] > maxDelay ) {
errorString_ << "TapDelay::TapDelay: maxDelay must be > than all tap delay values!\n";
handleError( StkError::FUNCTION_ARGUMENT );
}
}
if ( ( maxDelay + 1 ) > inputs_.size() )
inputs_.resize( maxDelay + 1, 1, 0.0 );
inPoint_ = 0;
this->setTapDelays( taps );
}
TapDelay :: ~TapDelay()
{
}
void TapDelay :: setMaximumDelay( unsigned long delay )
{
if ( delay < inputs_.size() ) return;
if ( delay < 0 ) {
errorString_ << "TapDelay::setMaximumDelay: argument (" << delay << ") less than zero!\n";
handleError( StkError::WARNING );
return;
}
for ( unsigned int i=0; i<delays_.size(); i++ ) {
if ( delay < delays_[i] ) {
errorString_ << "TapDelay::setMaximumDelay: argument (" << delay << ") less than a current tap delay setting (" << delays_[i] << ")!\n";
handleError( StkError::WARNING );
return;
}
}
inputs_.resize( delay + 1 );
}
void TapDelay :: setTapDelays( std::vector<unsigned long> taps )
{
if ( taps.size() != outPoint_.size() ) {
outPoint_.resize( taps.size() );
delays_.resize( taps.size() );
lastFrame_.resize( 1, taps.size(), 0.0 );
}
for ( unsigned int i=0; i<taps.size(); i++ ) {
if ( taps[i] > inputs_.size() - 1 ) { // The value is too big.
errorString_ << "TapDelay::setTapDelay: argument (" << taps[i] << ") too big ... setting to maximum!\n";
handleError( StkError::WARNING );
// Force delay to maximum length.
outPoint_[i] = inPoint_ + 1;
if ( outPoint_[i] == inputs_.size() ) outPoint_[i] = 0;
delays_[i] = inputs_.size() - 1;
}
else if ( taps[i] < 0 ) {
errorString_ << "TapDelay::setDelay: argument (" << taps[i] << ") less than zero ... setting to zero!\n";
handleError( StkError::WARNING );
outPoint_[i] = inPoint_;
delays_[i] = 0;
}
else { // read chases write
if ( inPoint_ >= taps[i] ) outPoint_[i] = inPoint_ - taps[i];
else outPoint_[i] = inputs_.size() + inPoint_ - taps[i];
delays_[i] = taps[i];
}
}
}
} // stk namespace

View File

@@ -19,20 +19,23 @@
less than or equal to zero indicate a closed
or lost connection or the occurence of an error.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "TcpClient.h"
#include <string.h>
TcpClient :: TcpClient(int port, std::string hostname )
namespace stk {
TcpClient :: TcpClient( int port, std::string hostname )
{
#if defined(__OS_WINDOWS__) // windoze-only stuff
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(1,1);
WSAStartup(wVersionRequested, &wsaData);
if (wsaData.wVersion != wVersionRequested) {
WSAStartup( wVersionRequested, &wsaData );
if ( wsaData.wVersion != wVersionRequested ) {
errorString_ << "TcpClient: Incompatible Windows socket library version!";
handleError( StkError::PROCESS_SOCKET );
}
@@ -42,7 +45,7 @@ TcpClient :: TcpClient(int port, std::string hostname )
connect( port, hostname );
}
TcpClient :: ~TcpClient()
TcpClient :: ~TcpClient( void )
{
}
@@ -52,21 +55,21 @@ int TcpClient :: connect( int port, std::string hostname )
this->close( soket_ );
// Create the client-side socket
soket_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (soket_ < 0) {
soket_ = ::socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if ( soket_ < 0 ) {
errorString_ << "TcpClient: Couldn't create socket client!";
handleError( StkError::PROCESS_SOCKET );
}
int flag = 1;
int result = setsockopt( soket_, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int) );
if (result < 0) {
if ( result < 0 ) {
errorString_ << "TcpClient: Error setting socket options!";
handleError( StkError::PROCESS_SOCKET );
}
struct hostent *hostp;
if ( (hostp = gethostbyname( hostname.c_str() )) == 0 ) {
if ( ( hostp = gethostbyname( hostname.c_str() ) ) == 0 ) {
errorString_ << "TcpClient: unknown host (" << hostname << ")!";
handleError( StkError::PROCESS_SOCKET_IPADDR );
}
@@ -74,12 +77,11 @@ int TcpClient :: connect( int port, std::string hostname )
// Fill in the address structure
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
memcpy((void *)&server_address.sin_addr, hostp->h_addr, hostp->h_length);
memcpy( (void *)&server_address.sin_addr, hostp->h_addr, hostp->h_length );
server_address.sin_port = htons(port);
// Connect to the server
if ( ::connect(soket_, (struct sockaddr *)&server_address,
sizeof(server_address) ) < 0) {
if ( ::connect( soket_, (struct sockaddr *)&server_address, sizeof(server_address) ) < 0 ) {
errorString_ << "TcpClient: Couldn't connect to socket server!";
handleError( StkError::PROCESS_SOCKET );
}
@@ -87,14 +89,16 @@ int TcpClient :: connect( int port, std::string hostname )
return soket_;
}
int TcpClient :: writeBuffer(const void *buffer, long bufferSize, int flags )
int TcpClient :: writeBuffer( const void *buffer, long bufferSize, int flags )
{
if ( !isValid( soket_ ) ) return -1;
return send( soket_, (const char *)buffer, bufferSize, flags );
}
int TcpClient :: readBuffer(void *buffer, long bufferSize, int flags )
int TcpClient :: readBuffer( void *buffer, long bufferSize, int flags )
{
if ( !isValid( soket_ ) ) return -1;
return recv( soket_, (char *)buffer, bufferSize, flags );
}
} // stk namespace

View File

@@ -19,12 +19,14 @@
less than or equal to zero indicate a closed
or lost connection or the occurence of an error.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "TcpServer.h"
namespace stk {
TcpServer :: TcpServer( int port )
{
// Create a socket server.
@@ -93,3 +95,5 @@ int TcpServer :: readBuffer(void *buffer, long bufferSize, int flags )
if ( !isValid( soket_ ) ) return -1;
return recv( soket_, (char *)buffer, bufferSize, flags );
}
} // stk namespace

View File

@@ -2,17 +2,28 @@
/*! \class Thread
\brief STK thread class.
This class provides a uniform interface for
cross-platform thread use. On Linux and IRIX
systems, the pthread library is used. Under Windows,
the Windows thread library is used.
This class provides a uniform interface for cross-platform
threads. On unix systems, the pthread library is used. Under
Windows, the C runtime threadex functions are used.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
Each instance of the Thread class can be used to control a single
thread process. Routines are provided to signal cancelation
and/or joining with a thread, though it is not possible for this
class to know the running status of a thread once it is started.
For cross-platform compatability, thread functions should be
declared as follows:
THREAD_RETURN THREAD_TYPE thread_function(void *ptr)
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Thread.h"
namespace stk {
Thread :: Thread()
{
thread_ = 0;
@@ -91,3 +102,5 @@ void Thread :: testCancel(void)
#endif
}
} // stk namespace

View File

@@ -26,19 +26,21 @@
type who should worry about this (making
money) worry away.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "TubeBell.h"
TubeBell :: TubeBell()
namespace stk {
TubeBell :: TubeBell( void )
: FM()
{
// Concatenate the STK rawwave path to the rawwave files
for ( unsigned int i=0; i<3; i++ )
waves_[i] = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
waves_[3] = new WaveLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
waves_[i] = new FileLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
waves_[3] = new FileLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
this->setRatio(0, 1.0 * 0.995);
this->setRatio(1, 1.414 * 0.995);
@@ -59,11 +61,11 @@ TubeBell :: TubeBell()
vibrato_.setFrequency( 2.0 );
}
TubeBell :: ~TubeBell()
TubeBell :: ~TubeBell( void )
{
}
void TubeBell :: noteOn(StkFloat frequency, StkFloat amplitude)
void TubeBell :: noteOn( StkFloat frequency, StkFloat amplitude )
{
gains_[0] = amplitude * fmGains_[94];
gains_[1] = amplitude * fmGains_[76];
@@ -78,26 +80,4 @@ void TubeBell :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
StkFloat TubeBell :: computeSample()
{
StkFloat temp, temp2;
temp = gains_[1] * adsr_[1]->tick() * waves_[1]->tick();
temp = temp * control1_;
waves_[0]->addPhaseOffset( temp );
waves_[3]->addPhaseOffset( twozero_.lastOut() );
temp = gains_[3] * adsr_[3]->tick() * waves_[3]->tick();
twozero_.tick( temp );
waves_[2]->addPhaseOffset( temp );
temp = ( 1.0 - (control2_ * 0.5)) * gains_[0] * adsr_[0]->tick() * waves_[0]->tick();
temp += control2_ * 0.5 * gains_[2] * adsr_[2]->tick() * waves_[2]->tick();
// Calculate amplitude modulation and apply it to output.
temp2 = vibrato_.tick() * modDepth_;
temp = temp * (1.0 + temp2);
lastOutput_ = temp * 0.5;
return lastOutput_;
}
} // stk namespace

View File

@@ -2,25 +2,28 @@
/*! \class TwoPole
\brief STK two-pole filter class.
This protected Filter subclass implements
a two-pole digital filter. A method is
provided for creating a resonance in the
frequency response while maintaining a nearly
constant filter gain.
This class implements a two-pole digital filter. A method is
provided for creating a resonance in the frequency response while
maintaining a nearly constant filter gain.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "TwoPole.h"
#include <math.h>
#include <cmath>
TwoPole :: TwoPole() : Filter()
namespace stk {
TwoPole :: TwoPole( void )
{
std::vector<StkFloat> b(1, 1.0);
std::vector<StkFloat> a(3, 0.0);
a[0] = 1.0;
Filter::setCoefficients( b, a );
b_.resize( 1 );
a_.resize( 3 );
inputs_.resize( 1, 1, 0.0 );
outputs_.resize( 3, 1, 0.0 );
b_[0] = 1.0;
a_[0] = 1.0;
Stk::addSampleRateAlert( this );
}
@@ -37,27 +40,7 @@ void TwoPole :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
}
}
void TwoPole :: clear(void)
{
Filter::clear();
}
void TwoPole :: setB0(StkFloat b0)
{
b_[0] = b0;
}
void TwoPole :: setA1(StkFloat a1)
{
a_[1] = a1;
}
void TwoPole :: setA2(StkFloat a2)
{
a_[2] = a2;
}
void TwoPole :: setResonance(StkFloat frequency, StkFloat radius, bool normalize)
void TwoPole :: setResonance( StkFloat frequency, StkFloat radius, bool normalize )
{
a_[2] = radius * radius;
a_[1] = (StkFloat) -2.0 * radius * cos(TWO_PI * frequency / Stk::sampleRate());
@@ -70,32 +53,13 @@ void TwoPole :: setResonance(StkFloat frequency, StkFloat radius, bool normalize
}
}
void TwoPole :: setGain(StkFloat gain)
void TwoPole :: setCoefficients( StkFloat b0, StkFloat a1, StkFloat a2, bool clearState )
{
Filter::setGain(gain);
b_[0] = b0;
a_[1] = a1;
a_[2] = a2;
if ( clearState ) this->clear();
}
StkFloat TwoPole :: getGain(void) const
{
return Filter::getGain();
}
StkFloat TwoPole :: lastOut(void) const
{
return Filter::lastOut();
}
StkFloat TwoPole :: tick( StkFloat input )
{
inputs_[0] = gain_ * input;
outputs_[0] = b_[0] * inputs_[0] - a_[2] * outputs_[2] - a_[1] * outputs_[1];
outputs_[2] = outputs_[1];
outputs_[1] = outputs_[0];
return outputs_[0];
}
StkFrames& TwoPole :: tick( StkFrames& frames, unsigned int channel )
{
return Filter::tick( frames, channel );
}
} // stk namespace

View File

@@ -2,25 +2,25 @@
/*! \class TwoZero
\brief STK two-zero filter class.
This protected Filter subclass implements
a two-zero digital filter. A method is
provided for creating a "notch" in the
frequency response while maintaining a
constant filter gain.
This class implements a two-zero digital filter. A method is
provided for creating a "notch" in the frequency response while
maintaining a constant filter gain.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "TwoZero.h"
#include <math.h>
#include <cmath>
TwoZero :: TwoZero() : Filter()
namespace stk {
TwoZero :: TwoZero( void )
{
std::vector<StkFloat> b(3, 0.0);
b[0] = 1.0;
std::vector<StkFloat> a(1, 1.0);
Filter::setCoefficients( b, a );
b_.resize( 3, 0.0 );
inputs_.resize( 3, 1, 0.0 );
b_[0] = 1.0;
Stk::addSampleRateAlert( this );
}
@@ -37,66 +37,27 @@ void TwoZero :: sampleRateChanged( StkFloat newRate, StkFloat oldRate )
}
}
void TwoZero :: clear(void)
{
Filter::clear();
}
void TwoZero :: setB0(StkFloat b0)
void TwoZero :: setCoefficients( StkFloat b0, StkFloat b1, StkFloat b2, bool clearState )
{
b_[0] = b0;
}
void TwoZero :: setB1(StkFloat b1)
{
b_[1] = b1;
}
void TwoZero :: setB2(StkFloat b2)
{
b_[2] = b2;
if ( clearState ) this->clear();
}
void TwoZero :: setNotch(StkFloat frequency, StkFloat radius)
void TwoZero :: setNotch( StkFloat frequency, StkFloat radius )
{
b_[2] = radius * radius;
b_[1] = (StkFloat) -2.0 * radius * cos(TWO_PI * (double) frequency / Stk::sampleRate());
// Normalize the filter gain.
if (b_[1] > 0.0) // Maximum at z = 0.
b_[0] = 1.0 / (1.0+b_[1]+b_[2]);
if ( b_[1] > 0.0 ) // Maximum at z = 0.
b_[0] = 1.0 / ( 1.0 + b_[1] + b_[2] );
else // Maximum at z = -1.
b_[0] = 1.0 / (1.0-b_[1]+b_[2]);
b_[0] = 1.0 / ( 1.0 - b_[1] + b_[2] );
b_[1] *= b_[0];
b_[2] *= b_[0];
}
void TwoZero :: setGain(StkFloat gain)
{
Filter::setGain(gain);
}
StkFloat TwoZero :: getGain(void) const
{
return Filter::getGain();
}
StkFloat TwoZero :: lastOut(void) const
{
return Filter::lastOut();
}
StkFloat TwoZero :: tick( StkFloat input )
{
inputs_[0] = gain_ * input;
outputs_[0] = b_[2] * inputs_[2] + b_[1] * inputs_[1] + b_[0] * inputs_[0];
inputs_[2] = inputs_[1];
inputs_[1] = inputs_[0];
return outputs_[0];
}
StkFrames& TwoZero :: tick( StkFrames& frames, unsigned int channel )
{
return Filter::tick( frames, channel );
}
} // stk namespace

View File

@@ -17,11 +17,14 @@
read/write methods. Values less than or equal to zero indicate
the occurence of an error.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "UdpSocket.h"
#include <string.h>
namespace stk {
UdpSocket :: UdpSocket(int port )
{
@@ -102,3 +105,5 @@ int UdpSocket :: writeBufferTo( const void *buffer, long bufferSize, int port, s
this->setAddress( &address, port, hostname );
return sendto( soket_, (const char *)buffer, bufferSize, flags, (struct sockaddr *)&address, sizeof(address) );
}
} // stk namespace

View File

@@ -1,72 +0,0 @@
/***************************************************/
/*! \class Vector3D
\brief STK 3D vector class.
This class implements a three-dimensional vector.
by Perry R. Cook, 1995 - 2004.
*/
/***************************************************/
#include "Vector3D.h"
#include <math.h>
Vector3D :: Vector3D(StkFloat initX, StkFloat initY, StkFloat initZ)
{
myX_ = initX;
myY_ = initY;
myZ_ = initZ;
}
Vector3D :: ~Vector3D()
{
}
StkFloat Vector3D :: getX()
{
return myX_;
}
StkFloat Vector3D :: getY()
{
return myY_;
}
StkFloat Vector3D :: getZ()
{
return myZ_;
}
StkFloat Vector3D :: getLength()
{
StkFloat temp;
temp = myX_ * myX_;
temp += myY_ * myY_;
temp += myZ_ * myZ_;
temp = sqrt(temp);
return temp;
}
void Vector3D :: setXYZ(StkFloat x, StkFloat y, StkFloat z)
{
myX_ = x;
myY_ = y;
myZ_ = z;
};
void Vector3D :: setX(StkFloat x)
{
myX_ = x;
}
void Vector3D :: setY(StkFloat y)
{
myY_ = y;
}
void Vector3D :: setZ(StkFloat z)
{
myZ_ = z;
}

View File

@@ -21,45 +21,47 @@
- Vibrato Gain = 1
- Loudness (Spectral Tilt) = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "VoicForm.h"
#include "Phonemes.h"
#include "SKINI.msg"
#include <string.h>
#include <cmath>
VoicForm :: VoicForm() : Instrmnt()
namespace stk {
VoicForm :: VoicForm( void ) : Instrmnt()
{
// Concatenate the STK rawwave path to the rawwave file
voiced_ = new SingWave( (Stk::rawwavePath() + "impuls20.raw").c_str(), true );
voiced_->setGainRate( 0.001 );
voiced_->setGainTarget( 0.0 );
voiced_ = new SingWave( (Stk::rawwavePath() + "impuls20.raw").c_str(), true );
voiced_->setGainRate( 0.001 );
voiced_->setGainTarget( 0.0 );
for ( int i=0; i<4; i++ )
filters_[i].setSweepRate( 0.001 );
onezero_.setZero( -0.9 );
onepole_.setPole( 0.9 );
onezero_.setZero( -0.9 );
onepole_.setPole( 0.9 );
noiseEnv_.setRate( 0.001 );
noiseEnv_.setTarget( 0.0 );
noiseEnv_.setRate( 0.001 );
noiseEnv_.setTarget( 0.0 );
this->setPhoneme( "eee" );
this->clear();
this->setPhoneme( "eee" );
this->clear();
}
VoicForm :: ~VoicForm()
VoicForm :: ~VoicForm( void )
{
delete voiced_;
delete voiced_;
}
void VoicForm :: clear()
void VoicForm :: clear( void )
{
onezero_.clear();
onepole_.clear();
onezero_.clear();
onepole_.clear();
for ( int i=0; i<4; i++ ) {
filters_[i].clear();
}
@@ -74,16 +76,16 @@ void VoicForm :: setFrequency( StkFloat frequency )
freakency = 220.0;
}
voiced_->setFrequency( freakency );
voiced_->setFrequency( freakency );
}
bool VoicForm :: setPhoneme( const char *phoneme )
{
bool found = false;
bool found = false;
unsigned int i = 0;
while( i < 32 && !found ) {
if ( !strcmp( Phonemes::name(i), phoneme ) ) {
found = true;
while( i < 32 && !found ) {
if ( !strcmp( Phonemes::name(i), phoneme ) ) {
found = true;
filters_[0].setTargets( Phonemes::formantFrequency(i, 0), Phonemes::formantRadius(i, 0), pow(10.0, Phonemes::formantGain(i, 0 ) / 20.0) );
filters_[1].setTargets( Phonemes::formantFrequency(i, 1), Phonemes::formantRadius(i, 1), pow(10.0, Phonemes::formantGain(i, 1 ) / 20.0) );
filters_[2].setTargets( Phonemes::formantFrequency(i, 2), Phonemes::formantRadius(i, 2), pow(10.0, Phonemes::formantGain(i, 2 ) / 20.0) );
@@ -94,29 +96,19 @@ bool VoicForm :: setPhoneme( const char *phoneme )
errorString_ << "VoicForm::setPhoneme: found formant " << phoneme << " (number " << i << ").";
handleError( StkError::DEBUG_WARNING );
#endif
}
i++;
}
}
i++;
}
if ( !found ) {
if ( !found ) {
errorString_ << "VoicForm::setPhoneme: phoneme " << phoneme << " not found!";
handleError( StkError::WARNING );
}
return found;
return found;
}
void VoicForm :: setVoiced(StkFloat vGain)
{
voiced_->setGainTarget(vGain);
}
void VoicForm :: setUnVoiced(StkFloat nGain)
{
noiseEnv_.setTarget(nGain);
}
void VoicForm :: setFilterSweepRate(unsigned int whichOne, StkFloat rate)
void VoicForm :: setFilterSweepRate( unsigned int whichOne, StkFloat rate )
{
if ( whichOne < 0 || whichOne > 3 ) {
errorString_ << "VoicForm::setFilterSweepRate: filter select argument outside range 0-3!";
@@ -124,57 +116,23 @@ void VoicForm :: setFilterSweepRate(unsigned int whichOne, StkFloat rate)
return;
}
filters_[whichOne].setSweepRate(rate);
filters_[whichOne].setSweepRate(rate);
}
void VoicForm :: setPitchSweepRate(StkFloat rate)
void VoicForm :: quiet( void )
{
voiced_->setSweepRate(rate);
voiced_->noteOff();
noiseEnv_.setTarget( 0.0 );
}
void VoicForm :: speak()
void VoicForm :: noteOn( StkFloat frequency, StkFloat amplitude )
{
voiced_->noteOn();
this->setFrequency( frequency );
voiced_->setGainTarget( amplitude );
onepole_.setPole( 0.97 - (amplitude * 0.2) );
}
void VoicForm :: quiet()
{
voiced_->noteOff();
noiseEnv_.setTarget( 0.0 );
}
void VoicForm :: noteOn(StkFloat frequency, StkFloat amplitude)
{
this->setFrequency( frequency );
voiced_->setGainTarget( amplitude );
onepole_.setPole( 0.97 - (amplitude * 0.2) );
}
void VoicForm :: noteOff(StkFloat amplitude)
{
this->quiet();
}
StkFloat VoicForm :: computeSample()
{
StkFloat temp;
temp = onepole_.tick( onezero_.tick( voiced_->tick() ) );
temp += noiseEnv_.tick() * noise_.tick();
lastOutput_ = filters_[0].tick(temp);
lastOutput_ += filters_[1].tick(temp);
lastOutput_ += filters_[2].tick(temp);
lastOutput_ += filters_[3].tick(temp);
/*
temp += noiseEnv_.tick() * noise_.tick();
lastOutput_ = filters_[0].tick(temp);
lastOutput_ = filters_[1].tick(lastOutput_);
lastOutput_ = filters_[2].tick(lastOutput_);
lastOutput_ = filters_[3].tick(lastOutput_);
*/
return lastOutput_;
}
void VoicForm :: controlChange(int number, StkFloat value)
void VoicForm :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -188,54 +146,56 @@ void VoicForm :: controlChange(int number, StkFloat value)
handleError( StkError::WARNING );
}
if (number == __SK_Breath_) { // 2
this->setVoiced( 1.0 - norm );
this->setUnVoiced( 0.01 * norm );
}
else if (number == __SK_FootControl_) { // 4
if (number == __SK_Breath_) { // 2
this->setVoiced( 1.0 - norm );
this->setUnVoiced( 0.01 * norm );
}
else if (number == __SK_FootControl_) { // 4
StkFloat temp = 0.0;
unsigned int i = (int) value;
if (i < 32) {
unsigned int i = (int) value;
if (i < 32) {
temp = 0.9;
}
else if (i < 64) {
}
else if (i < 64) {
i -= 32;
temp = 1.0;
}
else if (i < 96) {
}
else if (i < 96) {
i -= 64;
temp = 1.1;
}
else if (i < 128) {
}
else if (i < 128) {
i -= 96;
temp = 1.2;
}
else if (i == 128) {
}
else if (i == 128) {
i = 0;
temp = 1.4;
}
}
filters_[0].setTargets( temp * Phonemes::formantFrequency(i, 0), Phonemes::formantRadius(i, 0), pow(10.0, Phonemes::formantGain(i, 0 ) / 20.0) );
filters_[1].setTargets( temp * Phonemes::formantFrequency(i, 1), Phonemes::formantRadius(i, 1), pow(10.0, Phonemes::formantGain(i, 1 ) / 20.0) );
filters_[2].setTargets( temp * Phonemes::formantFrequency(i, 2), Phonemes::formantRadius(i, 2), pow(10.0, Phonemes::formantGain(i, 2 ) / 20.0) );
filters_[3].setTargets( temp * Phonemes::formantFrequency(i, 3), Phonemes::formantRadius(i, 3), pow(10.0, Phonemes::formantGain(i, 3 ) / 20.0) );
this->setVoiced( Phonemes::voiceGain( i ) );
this->setUnVoiced( Phonemes::noiseGain( i ) );
}
else if (number == __SK_ModFrequency_) // 11
voiced_->setVibratoRate( norm * 12.0); // 0 to 12 Hz
else if (number == __SK_ModWheel_) // 1
voiced_->setVibratoGain( norm * 0.2);
else if (number == __SK_AfterTouch_Cont_) { // 128
this->setVoiced( norm );
onepole_.setPole( 0.97 - ( norm * 0.2) );
}
}
else if (number == __SK_ModFrequency_) // 11
voiced_->setVibratoRate( norm * 12.0); // 0 to 12 Hz
else if (number == __SK_ModWheel_) // 1
voiced_->setVibratoGain( norm * 0.2);
else if (number == __SK_AfterTouch_Cont_) { // 128
this->setVoiced( norm );
onepole_.setPole( 0.97 - ( norm * 0.2) );
}
else {
errorString_ << "VoicForm::controlChange: undefined control number (" << number << ")!";
handleError( StkError::WARNING );
}
#if defined(_STK_DEBUG_)
errorString_ << "VoicForm::controlChange: number = " << number << ", value = " << value << '.';
handleError( StkError::DEBUG_WARNING );
errorString_ << "VoicForm::controlChange: number = " << number << ", value = " << value << '.';
handleError( StkError::DEBUG_WARNING );
#endif
}
} // stk namespace

View File

@@ -2,54 +2,54 @@
/*! \class Voicer
\brief STK voice manager class.
This class can be used to manage a group of
STK instrument classes. Individual voices can
be controlled via unique note tags.
Instrument groups can be controlled by channel
number.
This class can be used to manage a group of STK instrument
classes. Individual voices can be controlled via unique note
tags. Instrument groups can be controlled by group number.
A previously constructed STK instrument class
is linked with a voice manager using the
addInstrument() function. An optional channel
number argument can be specified to the
addInstrument() function as well (default
channel = 0). The voice manager does not
delete any instrument instances ... it is the
responsibility of the user to allocate and
deallocate all instruments.
A previously constructed STK instrument class is linked with a
voice manager using the addInstrument() function. An optional
group number argument can be specified to the addInstrument()
function as well (default group = 0). The voice manager does not
delete any instrument instances ... it is the responsibility of
the user to allocate and deallocate all instruments.
The tick() function returns the mix of all
sounding voices. Each noteOn returns a unique
tag (credits to the NeXT MusicKit), so you can
send control changes to specific voices within
an ensemble. Alternately, control changes can
be sent to all voices on a given channel.
The tick() function returns the mix of all sounding voices. Each
noteOn returns a unique tag (credits to the NeXT MusicKit), so you
can send control changes to specific voices within an ensemble.
Alternately, control changes can be sent to all voices in a given
group.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Voicer.h"
#include <stdlib.h>
#include <math.h>
#include <cmath>
namespace stk {
Voicer :: Voicer( StkFloat decayTime )
{
tags_ = 23456;
muteTime_ = (int) ( decayTime * Stk::sampleRate() );
lastFrame_.resize( 1, 1, 0.0 );
}
Voicer :: ~Voicer()
{
}
void Voicer :: addInstrument( Instrmnt *instrument, int channel )
void Voicer :: addInstrument( Instrmnt *instrument, int group )
{
Voicer::Voice voice;
voice.instrument = instrument;
voice.channel = channel;
voice.group = group;
voice.noteNumber = -1;
voices_.push_back( voice );
// Check output channels and resize lastFrame_ if necessary.
if ( instrument->channelsOut() > lastFrame_.channels() ) {
unsigned int startChannel = lastFrame_.channels();
lastFrame_.resize( 1, instrument->channelsOut() );
for ( unsigned int i=startChannel; i<lastFrame_.size(); i++ )
lastFrame_[i] = 0.0;
}
}
void Voicer :: removeInstrument( Instrmnt *instrument )
@@ -63,23 +63,32 @@ void Voicer :: removeInstrument( Instrmnt *instrument )
break;
}
if ( !found ) {
if ( found ) {
// Check output channels and resize lastFrame_ if necessary.
unsigned int maxChannels = 1;
for ( i=voices_.begin(); i!=voices_.end(); ++i ) {
if ( (*i).instrument->channelsOut() > maxChannels ) maxChannels = (*i).instrument->channelsOut();
}
if ( maxChannels < lastFrame_.channels() )
lastFrame_.resize( 1, maxChannels );
}
else {
errorString_ << "Voicer::removeInstrument: instrument pointer not found in current voices!";
handleError( StkError::WARNING );
}
}
long Voicer :: noteOn(StkFloat noteNumber, StkFloat amplitude, int channel )
long Voicer :: noteOn(StkFloat noteNumber, StkFloat amplitude, int group )
{
unsigned int i;
StkFloat frequency = (StkFloat) 220.0 * pow( 2.0, (noteNumber - 57.0) / 12.0 );
for ( i=0; i<voices_.size(); i++ ) {
if (voices_[i].noteNumber < 0 && voices_[i].channel == channel) {
voices_[i].tag = tags_++;
voices_[i].channel = channel;
if (voices_[i].noteNumber < 0 && voices_[i].group == group) {
voices_[i].tag = tags_++;
voices_[i].group = group;
voices_[i].noteNumber = noteNumber;
voices_[i].frequency = frequency;
voices_[i].instrument->noteOn( frequency, amplitude * ONE_OVER_128 );
voices_[i].instrument->noteOn( frequency, amplitude * ONE_OVER_128 );
voices_[i].sounding = 1;
return voices_[i].tag;
}
@@ -88,7 +97,7 @@ long Voicer :: noteOn(StkFloat noteNumber, StkFloat amplitude, int channel )
// All voices are sounding, so interrupt the oldest voice.
int voice = -1;
for ( i=0; i<voices_.size(); i++ ) {
if ( voices_[i].channel == channel ) {
if ( voices_[i].group == group ) {
if ( voice == -1 ) voice = i;
else if ( voices_[i].tag < voices_[voice].tag ) voice = (int) i;
}
@@ -96,7 +105,7 @@ long Voicer :: noteOn(StkFloat noteNumber, StkFloat amplitude, int channel )
if ( voice >= 0 ) {
voices_[voice].tag = tags_++;
voices_[voice].channel = channel;
voices_[voice].group = group;
voices_[voice].noteNumber = noteNumber;
voices_[voice].frequency = frequency;
voices_[voice].instrument->noteOn( frequency, amplitude * ONE_OVER_128 );
@@ -107,10 +116,10 @@ long Voicer :: noteOn(StkFloat noteNumber, StkFloat amplitude, int channel )
return -1;
}
void Voicer :: noteOff( StkFloat noteNumber, StkFloat amplitude, int channel )
void Voicer :: noteOff( StkFloat noteNumber, StkFloat amplitude, int group )
{
for ( unsigned int i=0; i<voices_.size(); i++ ) {
if ( voices_[i].noteNumber == noteNumber && voices_[i].channel == channel ) {
if ( voices_[i].noteNumber == noteNumber && voices_[i].group == group ) {
voices_[i].instrument->noteOff( amplitude * ONE_OVER_128 );
voices_[i].sounding = -muteTime_;
}
@@ -128,11 +137,11 @@ void Voicer :: noteOff( long tag, StkFloat amplitude )
}
}
void Voicer :: setFrequency( StkFloat noteNumber, int channel )
void Voicer :: setFrequency( StkFloat noteNumber, int group )
{
StkFloat frequency = (StkFloat) 220.0 * pow( 2.0, (noteNumber - 57.0) / 12.0 );
for ( unsigned int i=0; i<voices_.size(); i++ ) {
if ( voices_[i].channel == channel ) {
if ( voices_[i].group == group ) {
voices_[i].noteNumber = noteNumber;
voices_[i].frequency = frequency;
voices_[i].instrument->setFrequency( frequency );
@@ -153,7 +162,7 @@ void Voicer :: setFrequency( long tag, StkFloat noteNumber )
}
}
void Voicer :: pitchBend( StkFloat value, int channel )
void Voicer :: pitchBend( StkFloat value, int group )
{
StkFloat pitchScaler;
if ( value < 64.0 )
@@ -161,7 +170,7 @@ void Voicer :: pitchBend( StkFloat value, int channel )
else
pitchScaler = pow(2.0, (value-64.0)/64.0);
for ( unsigned int i=0; i<voices_.size(); i++ ) {
if ( voices_[i].channel == channel )
if ( voices_[i].group == group )
voices_[i].instrument->setFrequency( (StkFloat) (voices_[i].frequency * pitchScaler) );
}
}
@@ -181,10 +190,10 @@ void Voicer :: pitchBend( long tag, StkFloat value )
}
}
void Voicer :: controlChange( int number, StkFloat value, int channel )
void Voicer :: controlChange( int number, StkFloat value, int group )
{
for ( unsigned int i=0; i<voices_.size(); i++ ) {
if ( voices_[i].channel == channel )
if ( voices_[i].group == group )
voices_[i].instrument->controlChange( number, value );
}
}
@@ -207,72 +216,4 @@ void Voicer :: silence( void )
}
}
StkFloat Voicer :: tick()
{
lastOutput_ = lastOutputLeft_ = lastOutputRight_ = 0.0;
for ( unsigned int i=0; i<voices_.size(); i++ ) {
if ( voices_[i].sounding != 0 ) {
lastOutput_ += voices_[i].instrument->tick();
lastOutputLeft_ += voices_[i].instrument->lastOutLeft();
lastOutputRight_ += voices_[i].instrument->lastOutRight();
}
if ( voices_[i].sounding < 0 ) {
voices_[i].sounding++;
if ( voices_[i].sounding == 0 )
voices_[i].noteNumber = -1;
}
}
return lastOutput_ / voices_.size();
}
StkFloat *Voicer :: tick(StkFloat *vector, unsigned int vectorSize)
{
for (unsigned int i=0; i<vectorSize; i++)
vector[i] = tick();
return vector;
}
StkFrames& Voicer :: tick( StkFrames& frames, unsigned int channel )
{
if ( channel == 0 || frames.channels() < channel ) {
errorString_ << "Voicer::tick(): channel argument (" << channel << ") is zero or > channels in StkFrames argument!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( frames.channels() == 1 ) {
for ( unsigned int i=0; i<frames.frames(); i++ )
frames[i] = tick();
}
else if ( frames.interleaved() ) {
unsigned int hop = frames.channels();
unsigned int index = channel - 1;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
frames[index] = tick();
index += hop;
}
}
else {
unsigned int iStart = (channel - 1) * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++ )
frames[iStart + i] = tick();
}
return frames;
}
StkFloat Voicer :: lastOut() const
{
return lastOutput_;
}
StkFloat Voicer :: lastOutLeft() const
{
return lastOutputLeft_;
}
StkFloat Voicer :: lastOutRight() const
{
return lastOutputRight_;
}
} // stk namespace

View File

@@ -12,7 +12,7 @@
- Blowing Frequency Modulation = 2
- Volume = 128
by Perry R. Cook 1996 - 2004.
by Perry R. Cook 1996 - 2009.
*/
/***************************************************/
@@ -20,6 +20,8 @@
#include "SKINI.msg"
#include <cmath>
namespace stk {
const int CAN_RADIUS = 100;
const int PEA_RADIUS = 30;
const int BUMP_RADIUS = 5;
@@ -33,7 +35,7 @@ const StkFloat SLOW_TICK_SIZE = 0.0001;
const StkFloat ENV_RATE = 0.001;
Whistle :: Whistle()
Whistle :: Whistle( void )
{
sine_.setFrequency( 2800.0 );
@@ -54,31 +56,31 @@ Whistle :: Whistle()
envelope_.setRate( ENV_RATE );
envelope_.keyOn();
fippleFreqMod_ = 0.5;
fippleGainMod_ = 0.5;
blowFreqMod_ = 0.25;
noiseGain_ = 0.125;
baseFrequency_ = 2000;
fippleFreqMod_ = 0.5;
fippleGainMod_ = 0.5;
blowFreqMod_ = 0.25;
noiseGain_ = 0.125;
baseFrequency_ = 2000;
tickSize_ = NORM_TICK_SIZE;
canLoss_ = NORM_CAN_LOSS;
tickSize_ = NORM_TICK_SIZE;
canLoss_ = NORM_CAN_LOSS;
subSample_ = 1;
subSampCount_ = subSample_;
subSample_ = 1;
subSampCount_ = subSample_;
}
Whistle :: ~Whistle()
Whistle :: ~Whistle( void )
{
#ifdef WHISTLE_ANIMATION
printf("Exit, Whistle bye bye!!\n");
#endif
}
void Whistle :: clear()
void Whistle :: clear( void )
{
}
void Whistle :: setFrequency(StkFloat frequency)
void Whistle :: setFrequency( StkFloat frequency )
{
StkFloat freakency = frequency * 4; // the whistle is a transposing instrument
if ( frequency <= 0.0 ) {
@@ -90,19 +92,19 @@ void Whistle :: setFrequency(StkFloat frequency)
baseFrequency_ = freakency;
}
void Whistle :: startBlowing(StkFloat amplitude, StkFloat rate)
void Whistle :: startBlowing( StkFloat amplitude, StkFloat rate )
{
envelope_.setRate( ENV_RATE );
envelope_.setTarget( amplitude );
envelope_.setRate( ENV_RATE );
envelope_.setTarget( amplitude );
}
void Whistle :: stopBlowing(StkFloat rate)
void Whistle :: stopBlowing( StkFloat rate )
{
envelope_.setRate( rate );
envelope_.keyOff();
}
void Whistle :: noteOn(StkFloat frequency, StkFloat amplitude)
void Whistle :: noteOn( StkFloat frequency, StkFloat amplitude )
{
this->setFrequency( frequency );
this->startBlowing( amplitude*2.0 ,amplitude * 0.2 );
@@ -112,7 +114,7 @@ void Whistle :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
void Whistle :: noteOff(StkFloat amplitude)
void Whistle :: noteOff( StkFloat amplitude )
{
this->stopBlowing( amplitude * 0.02 );
@@ -124,17 +126,17 @@ void Whistle :: noteOff(StkFloat amplitude)
int frameCount = 0;
StkFloat Whistle :: computeSample()
StkFloat Whistle :: tick( unsigned int )
{
StkFloat soundMix, tempFreq;
StkFloat envOut = 0, temp, temp1, temp2, tempX, tempY;
double phi, cosphi, sinphi;
double gain = 0.5, mod = 0.0;
if ( --subSampCount_ <= 0 ) {
tempVectorP_ = pea_.getPosition();
subSampCount_ = subSample_;
temp = bumper_.isInside( tempVectorP_ );
if ( --subSampCount_ <= 0 ) {
tempVectorP_ = pea_.getPosition();
subSampCount_ = subSample_;
temp = bumper_.isInside( tempVectorP_ );
#ifdef WHISTLE_ANIMATION
frameCount += 1;
if ( frameCount >= (1470 / subSample_) ) {
@@ -151,7 +153,7 @@ StkFloat Whistle :: computeSample()
pea_.addVelocity( tempX, tempY, 0 );
pea_.tick( tickSize_ );
}
mod = exp(-temp * 0.01); // exp. distance falloff of fipple/pea effect
temp = onepole_.tick(mod); // smooth it a little
gain = (1.0 - (fippleGainMod_*0.5)) + (2.0 * fippleGainMod_ * temp);
@@ -164,7 +166,7 @@ StkFloat Whistle :: computeSample()
tempFreq *= baseFrequency_;
sine_.setFrequency(tempFreq);
tempVectorP_ = pea_.getPosition();
temp = can_.isInside(tempVectorP_);
temp = -temp; // We know (hope) it's inside, just how much??
@@ -202,22 +204,22 @@ StkFloat Whistle :: computeSample()
tempX = 0.0;
tempY = 0.0;
}
temp = (0.9 + 0.1*subSample_*noise_.tick()) * envOut * 0.6 * tickSize_;
pea_.addVelocity( temp * tempX, (temp*tempY) - (GRAVITY*tickSize_), 0 );
pea_.tick( tickSize_ );
// bumper_.tick(0.0);
}
}
temp = envOut * envOut * gain / 2;
soundMix = temp * ( sine_.tick() + ( noiseGain_*noise_.tick() ) );
lastOutput_ = 0.25 * soundMix; // should probably do one-zero filter here
temp = envOut * envOut * gain / 2;
soundMix = temp * ( sine_.tick() + ( noiseGain_*noise_.tick() ) );
lastFrame_[0] = 0.20 * soundMix; // should probably do one-zero filter here
return lastOutput_;
return lastFrame_[0];
}
void Whistle :: controlChange(int number, StkFloat value)
void Whistle :: controlChange( int number, StkFloat value )
{
StkFloat norm = value * ONE_OVER_128;
if ( norm < 0 ) {
@@ -252,8 +254,9 @@ void Whistle :: controlChange(int number, StkFloat value)
}
#if defined(_STK_DEBUG_)
errorString_ << "Whistle::controlChange: number = " << number << ", value = " << value << '.';
handleError( StkError::DEBUG_WARNING );
errorString_ << "Whistle::controlChange: number = " << number << ", value = " << value << '.';
handleError( StkError::DEBUG_WARNING );
#endif
}
} // stk namespace

View File

@@ -26,19 +26,21 @@
type who should worry about this (making
money) worry away.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
by Perry R. Cook and Gary P. Scavone, 1995 - 2009.
*/
/***************************************************/
#include "Wurley.h"
Wurley :: Wurley()
namespace stk {
Wurley :: Wurley( void )
: FM()
{
// Concatenate the STK rawwave path to the rawwave files
for ( unsigned int i=0; i<3; i++ )
waves_[i] = new WaveLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
waves_[3] = new WaveLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
waves_[i] = new FileLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
waves_[3] = new FileLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
this->setRatio(0, 1.0);
this->setRatio(1, 4.0);
@@ -59,11 +61,11 @@ Wurley :: Wurley()
vibrato_.setFrequency( 8.0 );
}
Wurley :: ~Wurley()
Wurley :: ~Wurley( void )
{
}
void Wurley :: setFrequency(StkFloat frequency)
void Wurley :: setFrequency( StkFloat frequency )
{
baseFrequency_ = frequency;
waves_[0]->setFrequency( baseFrequency_ * ratios_[0]);
@@ -72,7 +74,7 @@ void Wurley :: setFrequency(StkFloat frequency)
waves_[3]->setFrequency( ratios_[3] );
}
void Wurley :: noteOn(StkFloat frequency, StkFloat amplitude)
void Wurley :: noteOn( StkFloat frequency, StkFloat amplitude )
{
gains_[0] = amplitude * fmGains_[99];
gains_[1] = amplitude * fmGains_[82];
@@ -87,27 +89,4 @@ void Wurley :: noteOn(StkFloat frequency, StkFloat amplitude)
#endif
}
StkFloat Wurley :: computeSample()
{
StkFloat temp, temp2;
temp = gains_[1] * adsr_[1]->tick() * waves_[1]->tick();
temp = temp * control1_;
waves_[0]->addPhaseOffset( temp );
waves_[3]->addPhaseOffset( twozero_.lastOut() );
temp = gains_[3] * adsr_[3]->tick() * waves_[3]->tick();
twozero_.tick(temp);
waves_[2]->addPhaseOffset( temp );
temp = ( 1.0 - (control2_ * 0.5)) * gains_[0] * adsr_[0]->tick() * waves_[0]->tick();
temp += control2_ * 0.5 * gains_[2] * adsr_[2]->tick() * waves_[2]->tick();
// Calculate amplitude modulation and apply it to output.
temp2 = vibrato_.tick() * modDepth_;
temp = temp * (1.0 + temp2);
lastOutput_ = temp * 0.5;
return lastOutput_;
}
} // stk namespace

View File

@@ -1,116 +0,0 @@
/***************************************************/
/*! \class WvIn
\brief STK audio input abstract base class.
This class provides common functionality for a variety of audio
data input subclasses.
WvIn supports multi-channel data. It is important to distinguish
the tick() methods, which return samples produced by averaging
across sample frames, from the tickFrame() methods, which return
references or pointers to multi-channel sample frames.
Both interleaved and non-interleaved data is supported via the use
of StkFrames objects.
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
*/
/***************************************************/
#include "WvIn.h"
#include <cmath>
WvIn :: WvIn()
{
}
WvIn :: ~WvIn()
{
}
StkFloat WvIn :: lastOut( void ) const
{
if ( lastOutputs_.empty() ) return 0.0;
if ( lastOutputs_.size() == 1 )
return lastOutputs_[0];
StkFloat output = 0.0;
for ( unsigned int i=0; i<lastOutputs_.size(); i++ ) {
output += lastOutputs_[i];
}
return output / lastOutputs_.size();
}
StkFloat WvIn :: tick( void )
{
computeFrame();
return lastOut();
}
StkFrames& WvIn :: tick( StkFrames& frames, unsigned int channel )
{
if ( channel >= frames.channels() ) {
errorString_ << "WvIn::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( frames.channels() == 1 ) {
for ( unsigned int i=0; i<frames.frames(); i++ )
frames[i] = tick();
}
else if ( frames.interleaved() ) {
unsigned int hop = frames.channels();
unsigned int index = channel;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
frames[index] = tick();
index += hop;
}
}
else {
unsigned int iStart = channel * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++ )
frames[iStart++] = tick();
}
return frames;
}
StkFrames& WvIn :: tickFrame( StkFrames& frames )
{
unsigned int nChannels = lastOutputs_.channels();
if ( nChannels == 0 ) {
errorString_ << "WvIn::tickFrame(): no data has been loaded!";
handleError( StkError::WARNING );
return frames;
}
if ( nChannels != frames.channels() ) {
errorString_ << "WvIn::tickFrame(): incompatible channel value in StkFrames argument!";
handleError( StkError::FUNCTION_ARGUMENT );
}
unsigned int j;
if ( nChannels == 1 || frames.interleaved() ) {
unsigned int counter = 0;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
this->computeFrame();
for ( j=0; j<nChannels; j++ )
frames[counter++] = lastOutputs_[j];
}
}
else { // non-interleaved data
unsigned int hop = frames.frames();
unsigned int index;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
this->computeFrame();
index = i;
for ( j=0; j<nChannels; j++ ) {
frames[index] = lastOutputs_[j];
index += hop;
}
}
}
return frames;
}

View File

@@ -1,100 +0,0 @@
/***************************************************/
/*! \class WvOut
\brief STK audio output abstract base class.
This class provides common functionality for a variety of audio
data output subclasses.
WvOut supports multi-channel data. It is important to distinguish
the tick() methods, which output single samples to all channels in
a sample frame, from the tickFrame() methods, which take a pointer
or reference to multi-channel sample frame data.
Both interleaved and non-interleaved data is supported via the use
of StkFrames objects.
Currently, WvOut is non-interpolating and the output rate is
always Stk::sampleRate().
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
*/
/***************************************************/
#include "WvOut.h"
WvOut :: WvOut()
: frameCounter_(0), clipping_(false)
{
}
WvOut :: ~WvOut()
{
}
unsigned long WvOut :: getFrameCount( void ) const
{
return frameCounter_;
}
StkFloat WvOut :: getTime( void ) const
{
return (StkFloat) frameCounter_ / Stk::sampleRate();
}
StkFloat& WvOut :: clipTest( StkFloat& sample )
{
bool clip = false;
if ( sample > 1.0 ) {
sample = 1.0;
clip = true;
}
else if ( sample < -1.0 ) {
sample = -1.0;
clip = true;
}
if ( clip == true && clipping_ == false ) {
// First occurrence of clipping since instantiation or reset.
clipping_ = true;
errorString_ << "WvOut: data value(s) outside +-1.0 detected ... clamping at outer bound!";
handleError( StkError::WARNING );
}
return sample;
}
void WvOut :: tick( const StkFloat sample )
{
this->computeSample( sample );
}
void WvOut :: tick( const StkFrames& frames, unsigned int channel )
{
if ( channel >= frames.channels() ) {
errorString_ << "WvOut::tick(): channel argument (" << channel << ") is incompatible with StkFrames argument!";
handleError( StkError::FUNCTION_ARGUMENT );
}
if ( frames.channels() == 1 ) {
for ( unsigned int i=0; i<frames.frames(); i++ )
computeSample( frames[i] );
}
else if ( frames.interleaved() ) {
unsigned int hop = frames.channels();
unsigned int index = channel;
for ( unsigned int i=0; i<frames.frames(); i++ ) {
computeSample( frames[index] );
index += hop;
}
}
else {
unsigned int iStart = channel * frames.frames();
for ( unsigned int i=0; i<frames.frames(); i++ )
computeSample( frames[iStart++] );
}
}
void WvOut :: tickFrame( const StkFrames& frames )
{
this->computeFrames( frames );
}