mirror of
https://github.com/thestk/stk
synced 2026-05-02 20:08:11 +00:00
Version 4.4.0
This commit is contained in:
committed by
Stephen Sinclair
parent
d199342e86
commit
eccd8c9981
121
src/ADSR.cpp
121
src/ADSR.cpp
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
35
src/Blit.cpp
35
src/Blit.cpp
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
120
src/Delay.cpp
120
src/Delay.cpp
@@ -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
|
||||
|
||||
103
src/DelayA.cpp
103
src/DelayA.cpp
@@ -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
|
||||
|
||||
105
src/DelayL.cpp
105
src/DelayL.cpp
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
21
src/Echo.cpp
21
src/Echo.cpp
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
104
src/Envelope.cpp
104
src/Envelope.cpp
@@ -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
|
||||
|
||||
51
src/FM.cpp
51
src/FM.cpp
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
234
src/Filter.cpp
234
src/Filter.cpp
@@ -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
73
src/Fir.cpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
101
src/FormSwep.cpp
101
src/FormSwep.cpp
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
125
src/Iir.cpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
113
src/JCRev.cpp
113
src/JCRev.cpp
@@ -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
|
||||
|
||||
@@ -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_;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
48
src/Moog.cpp
48
src/Moog.cpp
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
115
src/NRev.cpp
115
src/NRev.cpp
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
1005
src/RtAudio.cpp
1005
src/RtAudio.cpp
File diff suppressed because it is too large
Load Diff
402
src/RtMidi.cpp
402
src/RtMidi.cpp
@@ -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!";
|
||||
|
||||
@@ -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
|
||||
|
||||
111
src/RtWvOut.cpp
111
src/RtWvOut.cpp
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
100
src/SingWave.cpp
100
src/SingWave.cpp
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
112
src/Stk.cpp
112
src/Stk.cpp
@@ -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
|
||||
|
||||
@@ -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
104
src/TapDelay.cpp
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
176
src/VoicForm.cpp
176
src/VoicForm.cpp
@@ -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
|
||||
|
||||
169
src/Voicer.cpp
169
src/Voicer.cpp
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
116
src/WvIn.cpp
116
src/WvIn.cpp
@@ -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;
|
||||
}
|
||||
100
src/WvOut.cpp
100
src/WvOut.cpp
@@ -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 );
|
||||
}
|
||||
Reference in New Issue
Block a user