Version 3.0

This commit is contained in:
Gary Scavone
2013-09-25 11:21:51 +02:00
committed by Stephen Sinclair
parent 7c0ee03d60
commit 868787a5f9
348 changed files with 12471 additions and 9135 deletions

197
STK/ADSR.cpp Normal file
View File

@@ -0,0 +1,197 @@
/*******************************************/
/* ADSR Subclass of the Envelope Class, */
/* by Perry R. Cook, 1995-96 */
/* This is the traditional ADSR (Attack */
/* Decay, Sustain, Release) ADSR. */
/* It responds to simple KeyOn and KeyOff */
/* messages, keeping track of it's state. */
/* There are two tick (update value) */
/* methods, one returns the value, and */
/* other returns the state (0 = A, 1 = D, */
/* 2 = S, 3 = R) */
/*******************************************/
#include "ADSR.h"
ADSR :: ADSR() : Envelope()
{
target = (MY_FLOAT) 0.0;
value = (MY_FLOAT) 0.0;
attackRate = (MY_FLOAT) 0.001;
decayRate = (MY_FLOAT) 0.001;
sustainLevel = (MY_FLOAT) 0.5;
releaseRate = (MY_FLOAT) 0.01;
state = 0;
}
ADSR :: ~ADSR()
{
/* Nothing to do here */
}
void ADSR :: keyOn()
{
target = (MY_FLOAT) 1.0;
rate = attackRate;
state = 0;
}
void ADSR :: keyOff()
{
target = (MY_FLOAT) 0.0;
rate = releaseRate;
state = 3;
}
void ADSR :: setAttackRate(MY_FLOAT aRate)
{
if (aRate < 0.0) {
printf("negative rates not allowed!!, correcting\n");
attackRate = -aRate;
}
else attackRate = aRate;
}
void ADSR :: setDecayRate(MY_FLOAT aRate)
{
if (aRate < 0.0) {
printf("negative rates not allowed!!, correcting\n");
decayRate = -aRate;
}
else decayRate = aRate;
}
void ADSR :: setSustainLevel(MY_FLOAT aLevel)
{
if (aLevel < 0.0 ) {
printf("Sustain level out of range!!, correcting\n");
sustainLevel = (MY_FLOAT) 0.0;
}
else sustainLevel = aLevel;
}
void ADSR :: setReleaseRate(MY_FLOAT aRate)
{
if (aRate < 0.0) {
printf("negative rates not allowed!!, correcting\n");
releaseRate = -aRate;
}
else releaseRate = aRate;
}
void ADSR :: setAttackTime(MY_FLOAT aTime)
{
if (aTime < 0.0) {
printf("negative times not allowed!!, correcting\n");
attackRate = ONE_OVER_SRATE / -aTime;
}
else attackRate = ONE_OVER_SRATE / aTime;
}
void ADSR :: setDecayTime(MY_FLOAT aTime)
{
if (aTime < 0.0) {
printf("negative times not allowed!!, correcting\n");
decayRate = ONE_OVER_SRATE / -aTime;
}
else decayRate = ONE_OVER_SRATE / aTime;
}
void ADSR :: setReleaseTime(MY_FLOAT aTime)
{
if (aTime < 0.0) {
printf("negative times not allowed!!, correcting\n");
releaseRate = ONE_OVER_SRATE / -aTime;
}
else releaseRate = ONE_OVER_SRATE / aTime;
}
void ADSR :: setAllTimes(MY_FLOAT attTime, MY_FLOAT decTime, MY_FLOAT susLevel, MY_FLOAT relTime)
{
this->setAttackTime(attTime);
this->setDecayTime(decTime);
this->setSustainLevel(susLevel);
this->setReleaseTime(relTime);
}
void ADSR :: setTarget(MY_FLOAT aTarget)
{
target = aTarget;
if (value < target) {
state = ATTACK;
this->setSustainLevel(target);
rate = attackRate;
}
if (value > target) {
this->setSustainLevel(target);
state = DECAY;
rate = decayRate;
}
}
void ADSR :: setValue(MY_FLOAT aValue)
{
state = SUSTAIN;
target = aValue;
value = aValue;
this->setSustainLevel(aValue);
rate = (MY_FLOAT) 0.0;
}
MY_FLOAT ADSR :: tick()
{
if (state==ATTACK) {
value += rate;
if (value >= target) {
value = target;
rate = decayRate;
target = sustainLevel;
state = DECAY;
}
}
else if (state==DECAY) {
value -= decayRate;
if (value <= sustainLevel) {
value = sustainLevel;
rate = (MY_FLOAT) 0.0;
state = SUSTAIN;
}
}
else if (state==RELEASE) {
value -= releaseRate;
if (value <= 0.0) {
value = (MY_FLOAT) 0.0;
state = 4;
}
}
return value;
}
int ADSR :: informTick()
{
this->tick();
return state;
}
MY_FLOAT ADSR :: lastOut()
{
return value;
}
/************ Test Main ************************/
/*
void main()
{
long i;
ADSR test;
test.setAttackRate(0.15);
test.keyOn();
while(test.informTick()==ATTACK) printf("%lf\n",test.tick());
test.setDecayRate(0.1);
while (test.informTick()==DECAY) printf("%lf\n",test.lastOut());
test.setReleaseRate(0.05);
test.keyOff();
while(test.informTick()==RELEASE) printf("%lf\n",test.lastOut());
}
*/

46
STK/ADSR.h Normal file
View File

@@ -0,0 +1,46 @@
/*******************************************/
/* ADSR Subclass of the Envelope Class, */
/* by Perry R. Cook, 1995-96 */
/* This is the traditional ADSR (Attack */
/* Decay, Sustain, Release) envelope. */
/* It responds to simple KeyOn and KeyOff */
/* messages, keeping track of it's state. */
/* There are two tick (update value) */
/* methods, one returns the value, and */
/* other returns the state (0 = A, 1 = D, */
/* 2 = S, 3 = R) */
/*******************************************/
#if !defined(__ADSR_h)
#define __ADSR_h
#include "Envelope.h"
class ADSR : public Envelope
{
protected:
MY_FLOAT attackRate;
MY_FLOAT decayRate;
MY_FLOAT sustainLevel;
MY_FLOAT releaseRate;
public:
ADSR();
~ADSR();
void keyOn();
void keyOff();
void setAttackRate(MY_FLOAT aRate);
void setDecayRate(MY_FLOAT aRate);
void setSustainLevel(MY_FLOAT aLevel);
void setReleaseRate(MY_FLOAT aRate);
void setAttackTime(MY_FLOAT aTime);
void setDecayTime(MY_FLOAT aTime);
void setReleaseTime(MY_FLOAT aTime);
void setAllTimes(MY_FLOAT attTime, MY_FLOAT decTime, MY_FLOAT susLevel, MY_FLOAT relTime);
void setTarget(MY_FLOAT aTarget);
void setValue(MY_FLOAT aValue);
MY_FLOAT tick();
int informTick();
MY_FLOAT lastOut();
};
#endif

79
STK/AgogoBel.cpp Normal file
View File

@@ -0,0 +1,79 @@
/*******************************************/
/* AgogoBell SubClass of Modal4 Instrument*/
/* by Perry R. Cook, 1995-96 */
/* */
/* Controls: CONTROL1 = stickHardness */
/* CONTROL2 = strikePosition */
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/*******************************************/
/* Modes measured from my Agogo Bell by FFT: */
/* 360, 1470, 2401, 4600 */
#include "AgogoBel.h"
#include "SKINI11.msg"
AgogoBel :: AgogoBel() : Modal4()
{
// Concatenate the STK RAWWAVE_PATH to the rawwave file
char file[128];
strcpy(file, RAWWAVE_PATH);
wave = new RawWvIn(strcat(file,"rawwaves/britestk.raw"), "oneshot");
wave->normalize();
wave->setRate((MY_FLOAT) 7.0); // hardstick
this->setRatioAndReson(0, (MY_FLOAT) 1.00,(MY_FLOAT) 0.999); // Set our
this->setRatioAndReson(1, (MY_FLOAT) 4.08,(MY_FLOAT) 0.999); // resonances
this->setRatioAndReson(2,(MY_FLOAT) 6.669,(MY_FLOAT) 0.999); // here
this->setRatioAndReson(3,(MY_FLOAT) -3725.0, (MY_FLOAT)0.999); // (One fixed)
this->setFiltGain(0,(MY_FLOAT) 0.06); // And filter
this->setFiltGain(1,(MY_FLOAT) 0.05); // gains too
this->setFiltGain(2,(MY_FLOAT) 0.03);
this->setFiltGain(3,(MY_FLOAT) 0.02);
directGain = (MY_FLOAT) 0.25;
}
AgogoBel :: ~AgogoBel()
{
delete wave;
}
void AgogoBel :: setStickHardness(MY_FLOAT hardness)
{
stickHardness = hardness; /* To an approximation, */
wave->setRate((MY_FLOAT) 3.0 + ((MY_FLOAT) 8.0 * stickHardness)); /* hardness <-> center */
masterGain = (MY_FLOAT) 1.0; /* freq and amplitude */
}
void AgogoBel :: setStrikePosition(MY_FLOAT position)
{
MY_FLOAT temp,temp2;
temp2 = position * PI;
strikePosition = position; /* Hack only first */
temp = (MY_FLOAT) sin(0.7 * temp2); /* three modes, */
this->setFiltGain(0,(MY_FLOAT) 0.08 * temp); /* leave the other */
temp = (MY_FLOAT) sin(0.1 + (5.0 * temp2)); /* fixed. Why? */
this->setFiltGain(1,(MY_FLOAT) 0.07 * temp); /* So it doesn't */
temp = (MY_FLOAT) sin(0.2 + (7.0 * temp2)); /* sound like a */
this->setFiltGain(2,(MY_FLOAT) 0.04 * temp); /* sample! */
}
void AgogoBel :: controlChange(int number, MY_FLOAT value)
{
#if defined(_debug_)
printf("AgogoBel : ControlChange: Number=%i Value=%f\n",number,value);
#endif
if (number == __SK_StickHardness_)
this->setStickHardness(value * NORM_7);
else if (number == __SK_StrikePosition_)
this->setStrikePosition(value * NORM_7);
else if (number == __SK_ModFrequency_)
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
else if (number == __SK_ModWheel_)
vibrGain = (value * NORM_7);
else if (number == __SK_AfterTouch_Cont_)
this->strike(value * NORM_7);
else {
printf("AgogoBel : Undefined Control Number!!\n");
}
}

26
STK/AgogoBel.h Normal file
View File

@@ -0,0 +1,26 @@
/*******************************************/
/* AgogoBell SubClass of Modal4 Instrument*/
/* by Perry R. Cook, 1995-96 */
/* */
/* Controls: CONTROL1 = stickHardness */
/* CONTROL2 = strikePosition */
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/*******************************************/
#if !defined(__AgogoBel_h)
#define __AgogoBel_h
#include "Modal4.h"
class AgogoBel : public Modal4
{
public:
AgogoBel();
~AgogoBel();
void setStickHardness(MY_FLOAT hardness);
void setStrikePosition(MY_FLOAT position);
virtual void controlChange(int number, MY_FLOAT value);
};
#endif

81
STK/BeeThree.cpp Normal file
View File

@@ -0,0 +1,81 @@
/******************************************/
/* Hammond(OID) Organ Subclass */
/* of Algorithm 8 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/******************************************/
#include "BeeThree.h"
BeeThree :: BeeThree() : FM4Alg8()
{
// Concatenate the STK RAWWAVE_PATH to the rawwave file
char file1[128];
char file2[128];
char file3[128];
char file4[128];
strcpy(file1, RAWWAVE_PATH);
strcpy(file2, RAWWAVE_PATH);
strcpy(file3, RAWWAVE_PATH);
strcpy(file4, RAWWAVE_PATH);
this->loadWaves(strcat(file1,"rawwaves/sinewave.raw"),
strcat(file2,"rawwaves/sinewave.raw"),
strcat(file3,"rawwaves/sinewave.raw"),
strcat(file4,"rawwaves/fwavblnk.raw"));
this->setRatio(0,(MY_FLOAT) 0.999);
this->setRatio(1,(MY_FLOAT) 1.997);
this->setRatio(2,(MY_FLOAT) 3.006);
this->setRatio(3,(MY_FLOAT) 6.009);
gains[0] = __FM4Op_gains[95];
gains[1] = __FM4Op_gains[95];
gains[2] = __FM4Op_gains[99];
gains[3] = __FM4Op_gains[95];
adsr[0]->setAllTimes((MY_FLOAT) 0.005,(MY_FLOAT) 0.003,(MY_FLOAT) 1.0,(MY_FLOAT) 0.01);
adsr[1]->setAllTimes((MY_FLOAT) 0.005,(MY_FLOAT) 0.003,(MY_FLOAT) 1.0,(MY_FLOAT) 0.01);
adsr[2]->setAllTimes((MY_FLOAT) 0.005,(MY_FLOAT) 0.003,(MY_FLOAT) 1.0,(MY_FLOAT) 0.01);
adsr[3]->setAllTimes((MY_FLOAT) 0.005,(MY_FLOAT) 0.001,(MY_FLOAT) 0.4,(MY_FLOAT) 0.03);
twozero->setGain((MY_FLOAT) 0.1);
}
BeeThree :: ~BeeThree()
{
}
void BeeThree :: setFreq(MY_FLOAT frequency)
{
baseFreq = frequency;
waves[0]->setFreq(baseFreq * ratios[0]);
waves[1]->setFreq(baseFreq * ratios[1]);
waves[2]->setFreq(baseFreq * ratios[2]);
waves[3]->setFreq(baseFreq * ratios[3]);
}
MY_FLOAT BeeThree :: tick()
{
MY_FLOAT temp;
if (modDepth > 0.0) {
temp = (MY_FLOAT) 1.0 + (modDepth * vibWave->tick() * (MY_FLOAT) 0.1);
waves[0]->setFreq(baseFreq * ratios[0] * temp);
waves[1]->setFreq(baseFreq * ratios[1] * temp);
waves[2]->setFreq(baseFreq * ratios[2] * temp);
waves[3]->setFreq(baseFreq * ratios[3] * temp);
}
lastOutput = FM4Alg8 :: tick();
return lastOutput;
}
void BeeThree :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
gains[0] = amp * __FM4Op_gains[95];
gains[1] = amp * __FM4Op_gains[95];
gains[2] = amp * __FM4Op_gains[99];
gains[3] = amp * __FM4Op_gains[95];
this->setFreq(freq);
this->keyOn();
#if defined(_debug_)
printf("BeeThree : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}

23
STK/BeeThree.h Normal file
View File

@@ -0,0 +1,23 @@
/******************************************/
/* HammondOid Organ Subclass */
/* of Algorithm 8 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/******************************************/
#if !defined(__BeeThree_h)
#define __BeeThree_h
#include "FM4Alg8.h"
class BeeThree : public FM4Alg8
{
public:
BeeThree();
~BeeThree();
virtual void setFreq(MY_FLOAT frequency);
MY_FLOAT tick();
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
};
#endif

80
STK/BiQuad.cpp Normal file
View File

@@ -0,0 +1,80 @@
/*******************************************/
/* BiQuad (2-pole, 2-zero) Filter Class, */
/* by Perry R. Cook, 1995-96 */
/* See books on filters to understand */
/* more about how this works. Nothing */
/* out of the ordinary in this version. */
/*******************************************/
#include "BiQuad.h"
BiQuad :: BiQuad() : Filter()
{
inputs = (MY_FLOAT *) malloc(2 * sizeof(MY_FLOAT));
zeroCoeffs[0] = (MY_FLOAT) 0.0;
zeroCoeffs[1] = (MY_FLOAT) 0.0;
poleCoeffs[0] = (MY_FLOAT) 0.0;
poleCoeffs[1] = (MY_FLOAT) 0.0;
gain = (MY_FLOAT) 1.0;
this->clear();
}
BiQuad :: ~BiQuad()
{
free(inputs);
}
void BiQuad :: clear()
{
inputs[0] = (MY_FLOAT) 0.0;
inputs[1] = (MY_FLOAT) 0.0;
lastOutput = (MY_FLOAT) 0.0;
}
void BiQuad :: setPoleCoeffs(MY_FLOAT *coeffs)
{
poleCoeffs[0] = coeffs[0];
poleCoeffs[1] = coeffs[1];
}
void BiQuad :: setZeroCoeffs(MY_FLOAT *coeffs)
{
zeroCoeffs[0] = coeffs[0];
zeroCoeffs[1] = coeffs[1];
}
void BiQuad :: setFreqAndReson(MY_FLOAT freq, MY_FLOAT reson)
{
poleCoeffs[1] = - (reson * reson);
poleCoeffs[0] = (MY_FLOAT) 2.0 * reson * (MY_FLOAT) cos(TWO_PI * freq / SRATE);
}
void BiQuad :: setEqualGainZeroes()
{
zeroCoeffs[1] = (MY_FLOAT) -1.0;
zeroCoeffs[0] = (MY_FLOAT) 0.0;
}
void BiQuad :: setGain(MY_FLOAT aValue)
{
gain = aValue;
}
MY_FLOAT BiQuad :: tick(MY_FLOAT sample) /* Perform Filter Operation */
{ /* Biquad is two pole, two zero filter */
MY_FLOAT temp; /* Look it up in your favorite DSP text */
temp = sample * gain; /* Here's the math for the */
temp += inputs[0] * poleCoeffs[0]; /* version which implements */
temp += inputs[1] * poleCoeffs[1]; /* only 2 state variables. */
lastOutput = temp; /* This form takes */
lastOutput += (inputs[0] * zeroCoeffs[0]); /* 5 multiplies and */
lastOutput += (inputs[1] * zeroCoeffs[1]); /* 4 adds */
inputs[1] = inputs[0]; /* and 3 moves */
inputs[0] = temp; /* like the 2 state-var form*/
return lastOutput;
}

31
STK/BiQuad.h Normal file
View File

@@ -0,0 +1,31 @@
/*******************************************/
/* BiQuad (2-pole, 2-zero) Filter Class, */
/* by Perry R. Cook, 1995-96 */
/* See books on filters to understand */
/* more about how this works. Nothing */
/* out of the ordinary in this version. */
/*******************************************/
#if !defined(__BiQuad_h)
#define __BiQuad_h
#include "Filter.h"
class BiQuad : public Filter
{
protected:
MY_FLOAT poleCoeffs[2];
MY_FLOAT zeroCoeffs[2];
public:
BiQuad();
~BiQuad();
void clear();
void setPoleCoeffs(MY_FLOAT *coeffs);
void setZeroCoeffs(MY_FLOAT *coeffs);
void setGain(MY_FLOAT aValue);
void setFreqAndReson(MY_FLOAT freq, MY_FLOAT reson);
void setEqualGainZeroes();
MY_FLOAT tick(MY_FLOAT sample);
};
#endif

46
STK/BowTabl.cpp Normal file
View File

@@ -0,0 +1,46 @@
/***********************************************/
/* Simple Bow Table Object, after Smith */
/* by Perry R. Cook, 1995-96 */
/***********************************************/
#include "BowTabl.h"
BowTabl :: BowTabl()
{
offSet = (MY_FLOAT) 0.0; /* offset is a bias, really not needed unless */
/* friction is different in each direction */
slope = (MY_FLOAT) 0.1; /* controls width of friction pulse, */
/* related to bowForce */
}
BowTabl :: ~BowTabl()
{
}
void BowTabl :: setOffset(MY_FLOAT aValue)
{
offSet = aValue;
}
void BowTabl :: setSlope(MY_FLOAT aValue)
{
slope = aValue;
}
MY_FLOAT BowTabl :: lookup(MY_FLOAT sample) /* Perform Table Lookup */
{ /* sample is differential */
/* string vs. bow velocity */
MY_FLOAT input;
input = sample + offSet; /* add bias to sample */
input *= slope; /* scale it */
lastOutput = (MY_FLOAT) fabs((double) input) + (MY_FLOAT) 0.75; /* below min delta, friction = 1 */
lastOutput = (MY_FLOAT) pow(lastOutput,(MY_FLOAT) -4.0);
// if (lastOutput < 0.0 ) lastOutput = 0.0; /* minimum friction is 0.0 */
if (lastOutput > 1.0 ) lastOutput = (MY_FLOAT) 1.0; /* maximum friction is 1.0 */
return lastOutput;
}
MY_FLOAT BowTabl :: lastOut()
{
return lastOutput;
}

26
STK/BowTabl.h Normal file
View File

@@ -0,0 +1,26 @@
/***********************************************/
/* Simple Bow Table Object, after Smith */
/* by Perry R. Cook, 1995-96 */
/***********************************************/
#if !defined(__BowTabl_h)
#define __BowTabl_h
#include "Object.h"
class BowTabl : public Object
{
protected:
MY_FLOAT offSet;
MY_FLOAT slope;
MY_FLOAT lastOutput;
public:
BowTabl();
~BowTabl();
void setOffset(MY_FLOAT aValue);
void setSlope(MY_FLOAT aValue);
MY_FLOAT lookup(MY_FLOAT sample);
MY_FLOAT lastOut();
};
#endif

166
STK/Bowed.cpp Normal file
View File

@@ -0,0 +1,166 @@
/******************************************/
/* Bowed String model ala Smith */
/* after McIntyre, Schumacher, Woodhouse */
/* by Perry Cook, 1995-96 */
/* */
/* This is a waveguide model, and thus */
/* relates to various Stanford Univ. */
/* and possibly Yamaha and other patents.*/
/* */
/* Controls: CONTROL1 = bowPressure */
/* CONTROL2 = bowPosition */
/* CONTROL3 = vibrFreq */
/* MOD_WHEEL= vibrGain */
/* */
/******************************************/
#include "Bowed.h"
#include "SKINI11.msg"
Bowed :: Bowed(MY_FLOAT lowestFreq)
{
long length;
length = (long) (SRATE / lowestFreq + 1);
neckDelay = new DLineL(length);
length >>= 1;
bridgeDelay = new DLineL(length);
bowTabl = new BowTabl;
reflFilt = new OnePole;
bodyFilt = new BiQuad;
// Concatenate the STK RAWWAVE_PATH to the rawwave file
char file[128];
strcpy(file, RAWWAVE_PATH);
vibr = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping");
adsr = new ADSR;
vibrGain = (MY_FLOAT) 0.0;
neckDelay->setDelay((MY_FLOAT) 100.0);
bridgeDelay->setDelay((MY_FLOAT) 29.0);
bowTabl->setSlope((MY_FLOAT) 3.0);
reflFilt->setPole((MY_FLOAT) (0.6 - (0.1 * 22050.0 / SRATE)));
reflFilt->setGain((MY_FLOAT) 0.95);
bodyFilt->setFreqAndReson((MY_FLOAT) 500.0, (MY_FLOAT) 0.85);
bodyFilt->setEqualGainZeroes();
bodyFilt->setGain((MY_FLOAT) 0.2);
vibr->normalize();
vibr->setFreq((MY_FLOAT) 6.12723);
adsr->setAllTimes((MY_FLOAT) 0.02,(MY_FLOAT) 0.005,(MY_FLOAT) 0.9,(MY_FLOAT) 0.01);
betaRatio = (MY_FLOAT) 0.127236;
}
Bowed :: ~Bowed()
{
delete neckDelay;
delete bridgeDelay;
delete bowTabl;
delete reflFilt;
delete bodyFilt;
delete vibr;
delete adsr;
}
void Bowed :: clear()
{
neckDelay->clear();
bridgeDelay->clear();
}
void Bowed :: setFreq(MY_FLOAT frequency)
{
baseDelay = SRATE / frequency - (MY_FLOAT) 4.0; /* delay - approx. filter delay */
bridgeDelay->setDelay(baseDelay * betaRatio); /* bow to bridge length */
neckDelay->setDelay(baseDelay * ((MY_FLOAT) 1.0 - betaRatio)); /* bow to nut (finger) length */
}
void Bowed :: startBowing(MY_FLOAT amplitude, MY_FLOAT rate)
{
adsr->setRate(rate);
adsr->keyOn();
maxVelocity = (MY_FLOAT) 0.03 + ((MY_FLOAT) 0.2 * amplitude);
}
void Bowed :: stopBowing(MY_FLOAT rate)
{
adsr->setRate(rate);
adsr->keyOff();
}
void Bowed :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
this->startBowing(amp,amp * (MY_FLOAT) 0.001);
this->setFreq(freq);
#if defined(_debug_)
printf("Bowed : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}
void Bowed :: noteOff(MY_FLOAT amp)
{
this->stopBowing(((MY_FLOAT) 1.0 - amp) * (MY_FLOAT) 0.005);
#if defined(_debug_)
printf("Bowed : NoteOff: Amp=%lf\n",amp);
#endif
}
void Bowed :: setVibrato(MY_FLOAT amount)
{
vibrGain = amount;
}
MY_FLOAT Bowed :: tick()
{
MY_FLOAT bowVelocity;
MY_FLOAT bridgeRefl=(MY_FLOAT) 0,nutRefl=(MY_FLOAT) 0;
MY_FLOAT newVel=(MY_FLOAT) 0,velDiff=(MY_FLOAT) 0,stringVel=(MY_FLOAT) 0;
bowVelocity = maxVelocity * adsr->tick();
bridgeRefl = -reflFilt->tick(
bridgeDelay->lastOut()); /* Bridge Reflection */
nutRefl = -neckDelay->lastOut(); /* Nut Reflection */
stringVel = bridgeRefl + nutRefl; /* Sum is String Velocity */
velDiff = bowVelocity - stringVel; /* Differential Velocity */
newVel = velDiff * bowTabl->lookup(velDiff); /* Non-Lin Bow Function */
neckDelay->tick(bridgeRefl + newVel); /* Do string */
bridgeDelay->tick(nutRefl + newVel); /* propagations */
if (vibrGain > 0.0) {
neckDelay->setDelay((baseDelay * ((MY_FLOAT) 1.0 - betaRatio)) +
(baseDelay * vibrGain*vibr->tick()));
}
lastOutput = bodyFilt->tick(bridgeDelay->lastOut());
return lastOutput;
}
void Bowed :: controlChange(int number, MY_FLOAT value)
{
#if defined(_debug_)
printf("Bowed : ControlChange: Number=%i Value=%f\n",number,value);
#endif
if (number == __SK_BowPressure_)
bowTabl->setSlope((MY_FLOAT) 5.0 - ((MY_FLOAT) 4.0 * value * NORM_7));
else if (number == __SK_BowPosition_) {
betaRatio = (MY_FLOAT) 0.027236 + ((MY_FLOAT) 0.2 * value * NORM_7);
bridgeDelay->setDelay(baseDelay * betaRatio); /* bow to bridge length */
neckDelay->setDelay(baseDelay * ((MY_FLOAT) 1.0 - betaRatio)); /* bow to nut (finger) length */
}
else if (number == __SK_ModFrequency_)
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
else if (number == __SK_ModWheel_)
vibrGain = (value * NORM_7 * (MY_FLOAT) 0.4);
else if (number == __SK_AfterTouch_Cont_)
adsr->setTarget(value * NORM_7);
else {
printf("Bowed : Undefined Control Number!!\n");
}
}

56
STK/Bowed.h Normal file
View File

@@ -0,0 +1,56 @@
/******************************************/
/* Bowed String model ala Smith */
/* after McIntyre, Schumacher, Woodhouse */
/* by Perry Cook, 1995-96 */
/* */
/* This is a waveguide model, and thus */
/* relates to various Stanford Univ. */
/* and possibly Yamaha and other patents.*/
/* */
/* Controls: CONTROL1 = bowPressure */
/* CONTROL2 = bowPosition */
/* CONTROL3 = vibrFreq */
/* MOD_WHEEL= vibrGain */
/* */
/******************************************/
#if !defined(__Bowed_h)
#define __Bowed_h
#include "Instrmnt.h"
#include "DLineL.h"
#include "BowTabl.h"
#include "OnePole.h"
#include "BiQuad.h"
#include "RawWvIn.h"
#include "ADSR.h"
class Bowed : public Instrmnt
{
protected:
DLineL *neckDelay;
DLineL *bridgeDelay;
BowTabl *bowTabl;
OnePole *reflFilt;
BiQuad *bodyFilt;
RawWvIn *vibr;
ADSR *adsr;
MY_FLOAT maxVelocity;
MY_FLOAT baseDelay;
MY_FLOAT vibrGain;
MY_FLOAT betaRatio;
public:
Bowed(MY_FLOAT lowestFreq);
~Bowed();
void clear();
void startBowing(MY_FLOAT amplitude,MY_FLOAT rate);
void stopBowing(MY_FLOAT rate);
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
virtual void noteOff(MY_FLOAT amp);
virtual void setFreq(MY_FLOAT frequency);
void setVibrato(MY_FLOAT amount);
virtual void controlChange(int number, MY_FLOAT value);
virtual MY_FLOAT tick();
};
#endif

318
STK/BowedBar.cpp Normal file
View File

@@ -0,0 +1,318 @@
/*********************************************/
/* Bowed Bar model */
/* by Georg Essl, 1999 */
/* For details refer to: */
/* G.Essl, P.R.Cook: "Banded Waveguides: */
/* Towards Physical Modelling of Bar */
/* Percussion Instruments", ICMC'99 */
/*********************************************/
#include "BowedBar.h"
#include "SKINI11.msg"
#include "Noise.h"
/* Number of banded waveguide modes */
int NR_MODES=4;
/* Contructor */
BowedBar :: BowedBar(MY_FLOAT lowestFreq)
{
long i;
pluck_ = 1;
modes[0] = (MY_FLOAT) 1.0;
modes[1] = (MY_FLOAT) 2.756;
modes[2] = (MY_FLOAT) 5.404;
modes[3] = (MY_FLOAT) 8.933;
for (i=0;i<4;i++) {
gains[i] = (MY_FLOAT) pow(0.9,(double) i);
}
bowTabl = new BowTabl;
adsr = new ADSR;
bandpass_ = new BiQuad[NR_MODES];
bowTabl->setSlope((MY_FLOAT) 3.0);
adsr->setAllTimes((MY_FLOAT) 0.02,(MY_FLOAT) 0.005,(MY_FLOAT) 0.9,(MY_FLOAT) 0.01);
freq = SRATE / 100;
length = 100;
bowPos = 0;
lastBowPos = 0;
for(i = 0; i<NR_MODES; i++)
{
delay[i].setDelay((int)(length/modes[i]));
delay[i].clear();
bandpass_[i].clear();
Zs[i][1] = 0.0;
Zs[i][2] = 0.0;
filtOut[i] = 0.0;
filtIn[i] = 0.0;
}
R = (MY_FLOAT) 0.97;
GAIN = (MY_FLOAT) 0.999;
slope = (MY_FLOAT) 3.0;
tuneBandPasses();
}
BowedBar :: ~BowedBar()
{
delete bowTabl;
delete adsr;
}
void BowedBar :: clear()
{
long i;
for(i = 0; i<NR_MODES; i++)
{
delay[i].clear();
bandpass_[i].clear();
Zs[i][1] = 0.0;
Zs[i][2] = 0.0;
filtOut[i] = 0.0;
filtIn[i] = 0.0;
}
}
void BowedBar :: setFreq(MY_FLOAT frequency)
{
int i;
freq = frequency;
if(freq > 1568.0) freq = 1568.0;
length = (int)(SRATE/freq);
NR_MODES = 4;
for(i = 0; i<NR_MODES; i++)
{
if((int)(length/modes[i]) > 4)
delay[i].setDelay((int)(length/modes[i]));
else {
NR_MODES = i;
break;
}
/* FIX THIS BETTER!!!!! */
delay[i].clear();
bandpass_[i].clear();
Zs[i][1] = 0.0;
Zs[i][2] = 0.0;
filtOut[i] = 0.0;
filtIn[i] = 0.0;
}
tuneBandPasses();
}
void BowedBar :: setStrikePosition(MY_FLOAT position)
{
MY_FLOAT temp2;
temp2 = position * PI;
gains[0] = fabs(sin(temp2 / 2) * pow(0.9,0));
gains[1] = fabs(sin(temp2) * pow(0.9,1));
gains[2] = fabs(sin(temp2 * 3 / 2) * pow(0.9,2));
gains[3] = fabs(sin(temp2 * 2) * pow(0.9,3));
}
void BowedBar :: tuneBandPasses()
{
long i;
for(i=0; i<NR_MODES; i++)
{
R = 1 - 6.28318530718 * freq * modes[i] / SRATE / 2.0;
bandpass_[i].setFreqAndReson(freq * modes[i], R);
bandpass_[i].setEqualGainZeroes();
bandpass_[i].setGain((1.0-R*R)/2.0);
filtGain[i] = (MY_FLOAT) (1.0 - (R*R))/2.0;
coeffs[i][1] = -R * R;
coeffs[i][0] = 2.0 * R * cos(6.28318530718 * freq * modes[i] / SRATE);
delay[i].clear(); //(rand()) - 16384;
}
}
void BowedBar :: startBowing(MY_FLOAT amplitude, MY_FLOAT rate)
{
adsr->setRate(rate);
adsr->keyOn();
maxVelocity = (MY_FLOAT) 0.03 + ((MY_FLOAT) 0.2 * amplitude);
maxVelocity = (MY_FLOAT) 0.03 + ((MY_FLOAT) 0.5 * amplitude);
}
void BowedBar :: stopBowing(MY_FLOAT rate)
{
adsr->setRate(rate);
adsr->keyOff();
}
void BowedBar :: pluck(MY_FLOAT amplitude)
{
long i,j;
int pluckLen;
MY_FLOAT temp;
Noise noise;
pluckLen = (int)(length/modes[NR_MODES-1]);
for (j=1;j<pluckLen/2;j++) {
temp = amplitude*2.0*noise.tick();
for(i=0; i<NR_MODES; i++)
delay[i].tick(temp*j/pluckLen*gains[i]);
}
for (j=pluckLen/2;j>0;j--) {
temp = amplitude*2.0*noise.tick();
for(i=0; i<NR_MODES; i++)
delay[i].tick(temp*j/pluckLen*gains[i]);
}
}
void BowedBar :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
if(!pluck_) {
for(int i=0; i<NR_MODES ; i++)
bandpass_[i].clear();
this->startBowing(amp,amp * (MY_FLOAT) 0.001);
this->setFreq(freq);
pluck_ = 0;
#if defined(_debug_)
printf("BowedBar : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}
else {
for(int i=0; i<NR_MODES ; i++)
bandpass_[i].clear();
this->setFreq(freq);
this->pluck(amp);
pluck_ = 1;
}
}
void BowedBar :: noteOff(MY_FLOAT amp)
{
if(!pluck_) {
this->stopBowing(((MY_FLOAT) 1.0 - amp) * (MY_FLOAT) 0.005);
}
#if defined(_debug_)
printf("BowedBar : NoteOff: Amp=%lf\n",amp);
#endif
}
MY_FLOAT BowedBar :: tick()
{
long k;
MY_FLOAT input;
MY_FLOAT data;
data = 0.0;
input = 0.0;
if(integration_const_ == 0.0)
velinput = 0.0;
else
velinput = integration_const_ * velinput;
for(k=0; k<NR_MODES; k++)
{
velinput += GAIN * delay[k].lastOut();
}
if(trackVel) {
bowvel *= 0.9995;
bowvel += bowTarg;
bowTarg *= 0.995;
}
else
{
bowvel = adsr->tick()*maxVelocity;
}
if(pluck_)
{
input = 0.0;
}
else
{
input = bowvel - velinput;
input = input * bowTabl->lookup(input);
input = input/(MY_FLOAT)NR_MODES;
}
for(k=0; k<NR_MODES; k++)
{
bandpass_[k].tick(input*gains[k] + GAIN * delay[k].lastOut());
delay[k].tick(bandpass_[k].lastOut());
data += bandpass_[k].lastOut();
}
lastOutput = data * 4.0;
return lastOutput;
}
void BowedBar :: controlChange(int number, MY_FLOAT value)
{
#if defined(_debug_)
printf("BowedBar : ControlChange: Number=%i Value=%f\n",number,value);
#endif
if (number == __SK_BowPressure_)
{
bowTabl->setSlope((MY_FLOAT) 10.0 - ((MY_FLOAT) 9.0 * value * NORM_7));
slope = (MY_FLOAT) 10.0 - ((MY_FLOAT) 9.0 * value * NORM_7);
}
else if (number == __SK_BowPosition_)
{
this->setStrikePosition(value*NORM_7);
}
else if (number == __SK_Balance_) {
bowPos = value * NORM_7;
bowTarg += 0.02 * (bowPos - lastBowPos);
lastBowPos = bowPos;
adsr->setTarget(bowPos);
}
else if (number == __SK_AfterTouch_Cont_)
{
bowPos = value * NORM_7;
bowTarg += 0.02 * (bowPos - lastBowPos);
lastBowPos = bowPos;
adsr->setTarget(bowPos);
}
else if (number == __SK_ModWheel_)
{
GAIN = 0.809 + (0.2 * (value * NORM_7));
}
else if(number == __SK_ModFrequency_)
{
integration_const_ = value * NORM_7;
}
else if(number == __SK_Sustain_) {
if(value < 65)
pluck_ = 1;
else
pluck_ = 0;
}
else if(number == __SK_Portamento_) {
if(value < 65)
trackVel = 0;
else
trackVel = 1;
}
else {
printf("BowedBar : Undefined Control Number!!\n");
}
}

62
STK/BowedBar.h Normal file
View File

@@ -0,0 +1,62 @@
/*********************************************/
/* Bowed Bar model */
/* by Georg Essl, 1999 */
/* For details refer to: */
/* G.Essl, P.R.Cook: "Banded Waveguides: */
/* Towards Physical Modelling of Bar */
/* Percussion Instruments", ICMC'99 */
/*********************************************/
#if !defined(__BowedBar_h)
#define __BowedBar_h
#include "Instrmnt.h"
#include "DLineN.h"
#include "BowTabl.h"
#include "ADSR.h"
#include "BiQuad.h"
class BowedBar : public Instrmnt
{
protected:
BowTabl *bowTabl;
ADSR *adsr;
BiQuad *bandpass_;
MY_FLOAT maxVelocity;
MY_FLOAT modes[4];
DLineN delay[4];
float Zs[4][2];
MY_FLOAT coeffs[4][2];
float filtOut[4];
float filtIn[4];
MY_FLOAT filtGain[4];
MY_FLOAT freq;
int length;
MY_FLOAT R;
MY_FLOAT GAIN;
MY_FLOAT gains[4];
MY_FLOAT slope;
MY_FLOAT velinput;
MY_FLOAT integration_const_;
int trackVel;
MY_FLOAT bowvel, bowTarg, bowPos, lastBowPos;
int pluck_;
public:
BowedBar(MY_FLOAT lowestFreq=16);
~BowedBar();
void tuneBandPasses();
void clear();
void startBowing(MY_FLOAT amplitude,MY_FLOAT rate);
void stopBowing(MY_FLOAT rate);
void pluck(MY_FLOAT amp);
void setStrikePosition(MY_FLOAT position);
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
virtual void noteOff(MY_FLOAT amp);
virtual void setFreq(MY_FLOAT frequency);
virtual void controlChange(int number, MY_FLOAT value);
virtual MY_FLOAT tick();
};
#endif

135
STK/Brass.cpp Normal file
View File

@@ -0,0 +1,135 @@
/******************************************/
/* Waveguide Brass Instrument Model ala */
/* Cook (TBone, HosePlayer) */
/* by Perry R. Cook, 1995-96 */
/* */
/* This is a waveguide model, and thus */
/* relates to various Stanford Univ. */
/* and possibly Yamaha and other patents.*/
/* */
/* Controls: CONTROL1 = lipTension */
/* CONTROL2 = slideLength */
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/******************************************/
#include "Brass.h"
#include "SKINI11.msg"
Brass :: Brass(MY_FLOAT lowestFreq)
{
length = (long) (SRATE / lowestFreq + 1);
delayLine = new DLineA(length);
lipFilter = new LipFilt;
dcBlock = new DCBlock;
adsr = new ADSR;
adsr->setAllTimes((MY_FLOAT) 0.005, (MY_FLOAT) 0.001, (MY_FLOAT) 1.0, (MY_FLOAT) 0.010);
// Concatenate the STK RAWWAVE_PATH to the rawwave file
char file[128];
strcpy(file, RAWWAVE_PATH);
vibr = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping");
this->clear();
vibr->normalize();
vibr->setFreq((MY_FLOAT) 6.137);
vibrGain = (MY_FLOAT) 0.05; /* breath periodic vibrato component */
maxPressure = (MY_FLOAT) 0.0;
}
Brass :: ~Brass()
{
delete delayLine;
delete lipFilter;
delete dcBlock;
delete adsr;
delete vibr;
}
void Brass :: clear()
{
delayLine->clear();
lipFilter->clear();
dcBlock->clear();
}
void Brass :: setFreq(MY_FLOAT frequency)
{
slideTarget = (SRATE / frequency * (MY_FLOAT) 2.0) + (MY_FLOAT) 3.0;
/* fudge correction for filter delays */
delayLine->setDelay(slideTarget); /* we'll play a harmonic */
lipTarget = frequency;
lipFilter->setFreq(frequency);
}
void Brass :: setLip(MY_FLOAT frequency)
{
lipFilter->setFreq(frequency);
}
void Brass :: startBlowing(MY_FLOAT amplitude,MY_FLOAT rate)
{
adsr->setAttackRate(rate);
maxPressure = amplitude;
adsr->keyOn();
}
void Brass :: stopBlowing(MY_FLOAT rate)
{
adsr->setReleaseRate(rate);
adsr->keyOff();
}
void Brass :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
this->setFreq(freq);
this->startBlowing(amp, amp * (MY_FLOAT) 0.001);
#if defined(_debug_)
printf("Brass : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}
void Brass :: noteOff(MY_FLOAT amp)
{
this->stopBlowing(amp * (MY_FLOAT) 0.005);
#if defined(_debug_)
printf("Brass : NoteOff: Amp=%lf\n",amp);
#endif
}
MY_FLOAT Brass :: tick()
{
MY_FLOAT breathPressure;
breathPressure = maxPressure * adsr->tick();
breathPressure += vibrGain * vibr->tick();
lastOutput = delayLine->tick( /* bore delay */
dcBlock->tick( /* block DC */
lipFilter->tick((MY_FLOAT) 0.3 * breathPressure, /* mouth input */
(MY_FLOAT) 0.85 * delayLine->lastOut()))); /* and bore reflection */
return lastOutput;
}
void Brass :: controlChange(int number, MY_FLOAT value)
{
MY_FLOAT temp;
#if defined(_debug_)
printf("Brass : ControlChange: Number=%i Value=%f\n",number,value);
#endif
if (number == __SK_LipTension_) {
temp = lipTarget * (MY_FLOAT) pow(4.0,(2.0*value*NORM_7) - 1.0);
this->setLip(temp);
}
else if (number == __SK_SlideLength_)
delayLine->setDelay(slideTarget * ((MY_FLOAT) 0.5 + (value * NORM_7)));
else if (number == __SK_ModFrequency_)
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
else if (number == __SK_ModWheel_ )
vibrGain = (value * NORM_7 * (MY_FLOAT) 0.4);
else if (number == __SK_AfterTouch_Cont_)
adsr->setTarget(value * NORM_7);
else {
printf("Brass : Undefined Control Number!!\n");
}
}

53
STK/Brass.h Normal file
View File

@@ -0,0 +1,53 @@
/******************************************/
/* Simple Brass Instrument Model ala */
/* Cook (TBone, HosePlayer) */
/* by Perry R. Cook, 1995-96 */
/* */
/* This is a waveguide model, and thus */
/* relates to various Stanford Univ. */
/* and possibly Yamaha and other patents.*/
/* */
/* Controls: CONTROL1 = lipTension */
/* CONTROL2 = slideLength */
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/******************************************/
#if !defined(__Brass_h)
#define __Brass_h
#include "Instrmnt.h"
#include "DLineA.h"
#include "LipFilt.h"
#include "DCBlock.h"
#include "ADSR.h"
#include "RawWvIn.h"
class Brass: public Instrmnt
{
protected:
DLineA *delayLine;
LipFilt *lipFilter;
DCBlock *dcBlock;
ADSR *adsr;
RawWvIn *vibr;
long length;
MY_FLOAT lipTarget;
MY_FLOAT slideTarget;
MY_FLOAT vibrGain;
MY_FLOAT maxPressure;
public:
Brass(MY_FLOAT lowestFreq);
~Brass();
void clear();
virtual void setFreq(MY_FLOAT frequency);
void setLip(MY_FLOAT frequency);
void startBlowing(MY_FLOAT amplitude,MY_FLOAT rate);
void stopBlowing(MY_FLOAT rate);
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
virtual void noteOff(MY_FLOAT amp);
virtual void controlChange(int number, MY_FLOAT value);
virtual MY_FLOAT tick();
};
#endif

130
STK/Clarinet.cpp Normal file
View File

@@ -0,0 +1,130 @@
/******************************************/
/* Waveguide Clarinet model ala Smith */
/* after McIntyre, Schumacher, Woodhouse */
/* by Perry Cook, 1995-96 */
/* */
/* This is a waveguide model, and thus */
/* relates to various Stanford Univ. */
/* and possibly Yamaha and other patents.*/
/* */
/* Controls: CONTROL1 = reedStiffns */
/* CONTROL2 = noiseGain */
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/******************************************/
#include "Clarinet.h"
#include "SKINI11.msg"
Clarinet :: Clarinet(MY_FLOAT lowestFreq)
{
length = (long) (SRATE / lowestFreq + 1);
delayLine = new DLineL(length);
reedTable = new ReedTabl;
reedTable->setOffset((MY_FLOAT) 0.7);
reedTable->setSlope((MY_FLOAT) -0.3);
filter = new OneZero;
envelope = new Envelope;
noise = new Noise;
// Concatenate the STK RAWWAVE_PATH to the rawwave file
char file[128];
strcpy(file, RAWWAVE_PATH);
vibr = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping");
vibr->normalize();
vibr->setFreq((MY_FLOAT) 5.735);
outputGain = (MY_FLOAT) 1.0;
noiseGain = (MY_FLOAT) 0.2;
vibrGain = (MY_FLOAT) 0.1;
}
Clarinet :: ~Clarinet()
{
delete delayLine;
delete reedTable;
delete filter;
delete envelope;
delete noise;
delete vibr;
}
void Clarinet :: clear()
{
delayLine->clear();
filter->tick((MY_FLOAT) 0.0);
}
void Clarinet :: setFreq(MY_FLOAT frequency)
{
delayLine->setDelay /* length - approx filter delay */
((SRATE / frequency) * (MY_FLOAT) 0.5 - (MY_FLOAT) 1.5);
}
void Clarinet :: startBlowing(MY_FLOAT amplitude,MY_FLOAT rate)
{
envelope->setRate(rate);
envelope->setTarget(amplitude);
}
void Clarinet :: stopBlowing(MY_FLOAT rate)
{
envelope->setRate(rate);
envelope->setTarget((MY_FLOAT) 0.0);
}
void Clarinet :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
this->setFreq(freq);
this->startBlowing((MY_FLOAT) 0.55 + (amp * (MY_FLOAT) 0.30),amp * (MY_FLOAT) 0.005);
outputGain = amp + (MY_FLOAT) 0.001;
#if defined(_debug_)
printf("Clarinet : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}
void Clarinet :: noteOff(MY_FLOAT amp)
{
this->stopBlowing(amp * (MY_FLOAT) 0.01);
#if defined(_debug_)
printf("Clarinet : NoteOff: Amp=%lf\n",amp);
#endif
}
MY_FLOAT Clarinet :: tick()
{
MY_FLOAT pressureDiff;
MY_FLOAT breathPressure;
breathPressure = envelope->tick();
breathPressure += breathPressure *
noiseGain * noise->tick();
breathPressure += breathPressure *
vibrGain * vibr->tick();
pressureDiff = filter->tick(delayLine->lastOut()); /* differential pressure */
pressureDiff = (pressureDiff * (MY_FLOAT) -0.95) - breathPressure; /* of reflected and mouth */
lastOutput = delayLine->tick(breathPressure + /* perform scattering */
pressureDiff * reedTable->lookup(pressureDiff)); /* in economical way */
lastOutput *= outputGain;
return lastOutput;
}
void Clarinet :: controlChange(int number, MY_FLOAT value)
{
#if defined(_debug_)
printf("Clarinet : ControlChange: Number=%i Value=%f\n",number,value);
#endif
if (number == __SK_ReedStiffness_)
reedTable->setSlope((MY_FLOAT) -0.44 + ((MY_FLOAT) 0.26 * value * NORM_7));
else if (number == __SK_NoiseLevel_)
noiseGain = (value * NORM_7 * (MY_FLOAT) 0.4);
else if (number == __SK_ModFrequency_)
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
else if (number == __SK_ModWheel_)
vibrGain = (value * NORM_7 * (MY_FLOAT) 0.5);
else if (number == __SK_AfterTouch_Cont_) {
envelope->setValue(value * NORM_7);
}
else {
printf("Clarinet : Undefined Control Number!!\n");
}
}

53
STK/Clarinet.h Normal file
View File

@@ -0,0 +1,53 @@
/******************************************/
/* Clarinet model ala Smith */
/* after McIntyre, Schumacher, Woodhouse */
/* by Perry Cook, 1995-96 */
/* */
/* This is a waveguide model, and thus */
/* relates to various Stanford Univ. */
/* and possibly Yamaha and other patents.*/
/* */
/* Controls: CONTROL1 = reedStiffns */
/* CONTROL2 = noiseGain */
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/******************************************/
#if !defined(__Clarinet_h)
#define __Clarinet_h
#include "Instrmnt.h"
#include "DLineL.h"
#include "ReedTabl.h"
#include "OneZero.h"
#include "Envelope.h"
#include "Noise.h"
#include "RawWvIn.h"
class Clarinet : public Instrmnt
{
protected:
DLineL *delayLine;
ReedTabl *reedTable;
OneZero *filter;
Envelope *envelope;
Noise *noise;
RawWvIn *vibr;
long length;
MY_FLOAT outputGain;
MY_FLOAT noiseGain;
MY_FLOAT vibrGain;
public:
Clarinet(MY_FLOAT lowestFreq);
~Clarinet();
void clear();
virtual void setFreq(MY_FLOAT frequency);
void startBlowing(MY_FLOAT amplitude,MY_FLOAT rate);
void stopBlowing(MY_FLOAT rate);
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
virtual void noteOff(MY_FLOAT amp);
virtual MY_FLOAT tick();
virtual void controlChange(int number, MY_FLOAT value);
};
#endif

40
STK/DCBlock.cpp Normal file
View File

@@ -0,0 +1,40 @@
/*******************************************/
/* DC Blocking Filter */
/* by Perry R. Cook, 1995-96 */
/* This guy is very helpful in, uh, */
/* blocking DC. Needed because a simple */
/* low-pass reflection filter allows DC */
/* to build up inside recursive */
/* structures. */
/*******************************************/
#include "DCBlock.h"
DCBlock :: DCBlock()
{
inputs = (MY_FLOAT *) malloc(sizeof(MY_FLOAT));
outputs = (MY_FLOAT *) malloc(sizeof(MY_FLOAT));
this->clear();
}
DCBlock :: ~DCBlock()
{
free(inputs);
free(outputs);
}
void DCBlock :: clear()
{
outputs[0] = (MY_FLOAT) 0.0;
inputs[0] = (MY_FLOAT) 0.0;
lastOutput = (MY_FLOAT) 0.0;
}
MY_FLOAT DCBlock :: tick(MY_FLOAT sample)
{
outputs[0] = sample - inputs[0] + ((MY_FLOAT) 0.99 * outputs[0]);
inputs[0] = sample;
lastOutput = outputs[0];
return lastOutput;
}

26
STK/DCBlock.h Normal file
View File

@@ -0,0 +1,26 @@
/*******************************************/
/* DC Blocking Filter */
/* by Perry R. Cook, 1995-96 */
/* */
/* This guy is very helpful in, uh, */
/* blocking DC. Needed because a simple */
/* low-pass reflection filter allows DC */
/* to build up inside recursive */
/* structures. */
/*******************************************/
#if !defined(__DCBlock_h)
#define __DCBlock_h
#include "Filter.h"
class DCBlock : public Filter
{
public:
DCBlock();
~DCBlock();
void clear();
MY_FLOAT tick(MY_FLOAT sample);
};
#endif

107
STK/DLineA.cpp Normal file
View File

@@ -0,0 +1,107 @@
/*******************************************/
/* AllPass Interpolating Delay Line */
/* Object by Perry R. Cook 1995-96. */
/* Revised by Gary P. Scavone, 1999. */
/* */
/* This one uses a delay line of maximum */
/* length specified on creation, and */
/* interpolates fractional length using */
/* an all-pass filter. This version is */
/* more efficient for computing static */
/* length delay lines (alpha and coeff */
/* are computed only when the length */
/* is set, there probably is a more */
/* efficient computational form if alpha */
/* is changed often (each sample)). */
/* */
/*******************************************/
#include "DLineA.h"
DLineA :: DLineA()
{
long i;
// Default max delay length set to 2047.
length = 2048;
inputs = (MY_FLOAT *) malloc(length * sizeof(MY_FLOAT));
for (i=0;i<length;i++) inputs[i] = (MY_FLOAT) 0;
this->clear();
inPoint = 0;
outPoint = length >> 1;
}
DLineA :: DLineA(long max_length)
{
long i;
length = max_length;
inputs = (MY_FLOAT *) malloc(length * sizeof(MY_FLOAT));
for (i=0;i<length;i++) inputs[i] = (MY_FLOAT) 0;
this->clear();
inPoint = 0;
outPoint = length >> 1;
}
DLineA :: ~DLineA()
{
free(inputs);
}
void DLineA :: clear()
{
long i;
for (i=0;i<length;i++) inputs[i] = (MY_FLOAT) 0.0;
lastIn = (MY_FLOAT) 0;
lastOutput = (MY_FLOAT) 0;
}
void DLineA :: setDelay(MY_FLOAT lag)
{
MY_FLOAT outPointer;
if (lag > length-1) { // if delay is too big,
printf("DLineA: Delay length too big.\n");
printf("Setting to maximum length of %ld.\n",length-1);
outPointer = inPoint - 18.0; // force delay to max_length
}
else if (lag < 0.1) {
printf("DLineA: Delays < 0.1 not possible with current structure.\n");
printf("Setting delay length to 0.1.\n");
outPointer = inPoint + 0.8999999999;
}
else
outPointer = inPoint - lag + 1.0; // outPoint chases inpoint
if (outPointer < 0)
outPointer += length; // modulo table length
outPoint = (long) outPointer; // Integer part of delay
alpha = 1.0 + outPoint - outPointer; // fractional part of delay
if (alpha == 0.0) { // exact integer delay
outPoint -= 1;
if (outPoint < 0) outPoint += length;
}
if (alpha<0.1) { // Hack to avoid pole/zero
outPoint += 1; // cancellation. Keeps allpass
if (outPoint >= length) outPoint -= length;
alpha += (MY_FLOAT) 1.0; // delay in range of .1 to 1.1
}
coeff = ((MY_FLOAT) 1.0 - alpha) /
((MY_FLOAT) 1.0 + alpha); // coefficient for all pass
}
MY_FLOAT DLineA :: tick(MY_FLOAT sample) // Take sample, yield sample
{
MY_FLOAT temp;
inputs[inPoint++] = sample; // Write input sample
if (inPoint == length) // Increment input pointer
inPoint -= length; // modulo length
temp = inputs[outPoint++]; // filter input
if (outPoint == length) // Increment output pointer
outPoint -= length; // modulo length
lastOutput = -coeff * lastOutput; // delayed output
lastOutput += lastIn + (coeff * temp); // input + delayed Input
lastIn = temp;
return lastOutput; // save output and return
}

43
STK/DLineA.h Normal file
View File

@@ -0,0 +1,43 @@
/*******************************************/
/* AllPass Interpolating Delay Line */
/* Object by Perry R. Cook 1995-96. */
/* Revised by Gary P. Scavone, 1999. */
/* */
/* This one uses a delay line of maximum */
/* length specified on creation, and */
/* interpolates fractional length using */
/* an all-pass filter. This version is */
/* more efficient for computing static */
/* length delay lines (alpha and coeff */
/* are computed only when the length */
/* is set, there probably is a more */
/* efficient computational form if alpha */
/* is changed often (each sample)). */
/* */
/*******************************************/
#if !defined(__DLineA_h)
#define __DLineA_h
#include "Filter.h"
class DLineA : public Filter
{
protected:
long inPoint;
long outPoint;
long length;
MY_FLOAT alpha;
MY_FLOAT coeff;
MY_FLOAT lastIn;
public:
DLineA();
DLineA(long max_length);
~DLineA();
void clear();
void setDelay(MY_FLOAT length);
MY_FLOAT tick(MY_FLOAT sample);
};
#endif

77
STK/DLineL.cpp Normal file
View File

@@ -0,0 +1,77 @@
/*******************************************/
/* Linearly Interpolating Delay Line */
/* Object by Perry R. Cook 1995-96 */
/* This one uses a delay line of maximum */
/* length specified on creation, and */
/* linearly interpolates fractional */
/* length. It is designed to be more */
/* efficient if the delay length is not */
/* changed very often. */
/*******************************************/
#include "DLineL.h"
DLineL :: DLineL()
{
// Default max delay length set to 2047.
length = 2048;
inputs = (MY_FLOAT *) malloc(length * sizeof(MY_FLOAT));
this->clear();
inPoint = 0;
outPoint = length >> 1;
}
DLineL :: DLineL(long max_length)
{
length = max_length;
inputs = (MY_FLOAT *) malloc(length * sizeof(MY_FLOAT));
this->clear();
inPoint = 0;
outPoint = length >> 1;
}
DLineL :: ~DLineL()
{
free(inputs);
}
void DLineL :: clear()
{
long i;
for (i=0;i<length;i++) inputs[i] = (MY_FLOAT) 0.0;
lastOutput = (MY_FLOAT) 0;
}
void DLineL :: setDelay(MY_FLOAT lag)
{
MY_FLOAT outPointer;
if (lag > length-1) { // if delay is too big,
printf("DLineL: Delay length too big.\n");
printf("Setting to maximum length of %ld.\n",length-1);
outPointer = inPoint + 1; // force delay to max_length
}
else
outPointer = inPoint - lag; // read chases write
while (outPointer<0)
outPointer += length; // modulo maximum length
outPoint = (long) outPointer; // integer part
alpha = outPointer - outPoint; // fractional part
omAlpha = (MY_FLOAT) 1.0 - alpha; // 1.0 - fractional part (more efficient)
}
MY_FLOAT DLineL :: tick(MY_FLOAT sample) // Take one, yield one
{
inputs[inPoint++] = sample; // Input next sample
if (inPoint == length) // Check for end condition
inPoint -= length;
lastOutput = inputs[outPoint++] * omAlpha; // first 1/2 of interpolation
if (outPoint<length) { // Check for end condition
lastOutput += inputs[outPoint] * alpha; // second 1/2 of interpolation
}
else { // if at end . . .
lastOutput += inputs[0] * alpha; // second 1/2 of interpolation
outPoint -= length;
}
return lastOutput;
}

34
STK/DLineL.h Normal file
View File

@@ -0,0 +1,34 @@
/*******************************************/
/* Linearly Interpolating Delay Line */
/* Object by Perry R. Cook 1995-96 */
/* This one uses a delay line of maximum */
/* length specified on creation, and */
/* linearly interpolates fractional */
/* length. It is designed to be more */
/* efficient if the delay length is not */
/* changed very often. */
/*******************************************/
#if !defined(__DLineL_h)
#define __DLineL_h
#include "Filter.h"
class DLineL : public Filter
{
protected:
long inPoint;
long outPoint;
long length;
MY_FLOAT alpha;
MY_FLOAT omAlpha;
public:
DLineL();
DLineL(long max_length);
~DLineL();
void clear();
void setDelay(MY_FLOAT length);
MY_FLOAT tick(MY_FLOAT sample);
};
#endif

70
STK/DLineN.cpp Normal file
View File

@@ -0,0 +1,70 @@
/*******************************************/
/* Non-Interpolating Delay Line */
/* Object by Perry R. Cook 1995-96. */
/* Revised by Gary Scavone, 1999. */
/* */
/* This one uses either a delay line of */
/* maximum length specified on creation */
/* or a default length of 2048 samples. */
/* A non-interpolating delay line is */
/* typically used in non-time varying */
/* (reverb) applications. */
/*******************************************/
#include "DLineN.h"
DLineN :: DLineN()
{
// Default max delay length set to 2047.
length = 2048;
inputs = (MY_FLOAT *) malloc(length * sizeof(MY_FLOAT));
this->clear();
inPoint = 0;
outPoint = length >> 1;
}
DLineN :: DLineN(long max_length)
{
// Writing before reading allows delays from 0 to length-1.
// Thus, if we want to allow a delay of max_length, we need
// a delay-line of length = max_length+1.
length = max_length+1;
inputs = (MY_FLOAT *) malloc(length * sizeof(MY_FLOAT));
this->clear();
inPoint = 0;
outPoint = length >> 1;
}
DLineN :: ~DLineN()
{
free(inputs);
}
void DLineN :: clear()
{
long i;
for (i=0;i<length;i++) inputs[i] = (MY_FLOAT) 0.0;
lastOutput = (MY_FLOAT) 0;
}
void DLineN :: setDelay(MY_FLOAT lag)
{
if (lag > length-1) { // if delay is too big,
printf("DLineN: Delay length too big ... setting to maximum length of %ld.\n",length-1);
outPoint = inPoint + 1; // force delay to max_length
}
else
outPoint = inPoint - (long) lag; // read chases write
while (outPoint<0) outPoint += length; // modulo maximum length
}
MY_FLOAT DLineN :: tick(MY_FLOAT sample) // Take one, yield one
{
inputs[inPoint++] = sample; // Input next sample
if (inPoint == length) // Check for end condition
inPoint -= length;
lastOutput = inputs[outPoint++]; // Read out next value
if (outPoint>=length) // Check for end condition
outPoint -= length;
return lastOutput;
}

35
STK/DLineN.h Normal file
View File

@@ -0,0 +1,35 @@
/*******************************************/
/* Non-Interpolating Delay Line */
/* Object by Perry R. Cook 1995-96. */
/* Revised by Gary Scavone, 1999. */
/* */
/* This one uses either a delay line of */
/* maximum length specified on creation */
/* or a default length of 2048 samples. */
/* A non-interpolating delay line is */
/* typically used in non-time varying */
/* (reverb) applications. */
/*******************************************/
#if !defined(__DLineN_h)
#define __DLineN_h
#include "Filter.h"
class DLineN : public Filter
{
protected:
long inPoint;
long outPoint;
long length;
public:
DLineN();
DLineN(long max_length);
~DLineN();
void clear();
void setDelay(MY_FLOAT length);
MY_FLOAT tick(MY_FLOAT sample);
};
#endif

0
STK/Debug/.placeholder Normal file
View File

184
STK/DrumSynt.cpp Normal file
View File

@@ -0,0 +1,184 @@
/*******************************************/
/* Master Class for Drum Synthesizer */
/* by Perry R. Cook, 1995-96 */
/* */
/* This instrument contains a bunch of */
/* RawWvIn objects, run through a bunch */
/* of one-pole filters. All the */
/* corresponding rawwave files have been */
/* sampled at 22050 Hz. Thus, if the */
/* compile-time SRATE = 22050, then */
/* no interpolation is used. Otherwise, */
/* the rawwave data is appropriately */
/* interpolated for the current SRATE. */
/* You can specify the maximum Polyphony */
/* (maximum number of simultaneous voices)*/
/* in a #define in the .h file. */
/* */
/* Modified for RawWvIn class */
/* by Gary P. Scavone (4/99) */
/*******************************************/
#include "DrumSynt.h"
#include <string.h>
/* Not really General MIDI yet. Coming soon. */
unsigned char genMIDIMap[128] = { 0,0,0,0,0,0,0,0, // 0-7
0,0,0,0,0,0,0,0, // 8-15
0,0,0,0,0,0,0,0, // 16-23
0,0,0,0,0,0,0,0, // 24-31
0,0,0,0,1,0,2,0, // 32-39
2,3,6,3,6,4,7,4, // 40-47
5,8,5,0,0,0,10,0, // 48-55
9,0,0,0,0,0,0,0, // 56-63
0,0,0,0,0,0,0,0, // 64-71
0,0,0,0,0,0,0,0, // 72-79
0,0,0,0,0,0,0,0, // 80-87
0,0,0,0,0,0,0,0, // 88-95
0,0,0,0,0,0,0,0, // 96-103
0,0,0,0,0,0,0,0, // 104-111
0,0,0,0,0,0,0,0, // 112-119
0,0,0,0,0,0,0,0}; // 120-127
char waveNames[DRUM_NUMWAVES][16] = {
"dope.raw",
"bassdrum.raw",
"snardrum.raw",
"tomlowdr.raw",
"tommiddr.raw",
"tomhidrm.raw",
"hihatcym.raw",
"ridecymb.raw",
"crashcym.raw",
"cowbell1.raw",
"tambourn.raw"
};
DrumSynt :: DrumSynt() : Instrmnt()
{
int i;
for (i=0;i<DRUM_POLYPHONY;i++) {
filters[i] = new OnePole;
sounding[i] = -1;
}
/* This counts the number of sounding voices */
numSounding = 0;
/* Print warning about aliasing if SRATE < 22050 */
if (SRATE < 22050) {
printf("\nWarning: DrumSynt is designed for sampling rates of\n");
printf("22050 Hz or greater. You will likely encounter aliasing\n");
printf("at the current sampling rate of %.0f Hz.\n\n", SRATE);
}
}
DrumSynt :: ~DrumSynt()
{
int i;
for ( i=0; i<numSounding-1; i++ ) delete waves[i];
for ( i=0; i<DRUM_POLYPHONY; i++ ) delete filters[i];
}
void DrumSynt :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
int i, notDone;
int noteNum;
int vel;
char tempString[64];
RawWvIn *tempWv;
OnePole *tempFilt;
/* Yes I know, this is tres kludgey */
noteNum = (int) ((12*log(freq/220)/log(2)) + 57.01);
vel = (int) (amp * 127);
#if defined(_debug_)
printf("NoteOn: %s vel=%i\n",waveNames[genMIDIMap[noteNum]],vel);
#endif
notDone = -1;
for (i=0;i<DRUM_POLYPHONY;i++) { /* Check first to see */
if (sounding[i] == noteNum) notDone = i; /* if there's already */
} /* one like this sounding */
if (notDone<0) { /* If not, then */
if (numSounding == DRUM_POLYPHONY) { /* If we're already */
delete waves[0]; /* at max polyphony, */
filters[0]->clear(); /* then */
tempWv = waves[0];
tempFilt = filters[0];
for (i=0;i<DRUM_POLYPHONY-1;i++) { /* preempt oldest */
waves[i] = waves[i+1]; /* voice and */
filters[i] = filters[i+1]; /* ripple all down */
}
waves[DRUM_POLYPHONY-1] = tempWv;
filters[DRUM_POLYPHONY-1] = tempFilt;
} else {
numSounding += 1; /* otherwise just add one */
}
sounding[numSounding-1] = noteNum; /* allocate new wave */
// Concatenate the STK RAWWAVE_PATH to the rawwave file
strcpy(tempString, RAWWAVE_PATH);
strcat(tempString,"rawwaves/");
strcat(tempString,waveNames[genMIDIMap[noteNum]]);
waves[numSounding-1] = new RawWvIn(tempString, "oneshot");
if (SRATE != 22050) {
waves[numSounding-1]->setRate((MY_FLOAT) (22050.0/SRATE));
}
waves[numSounding-1]->normalize((MY_FLOAT) 0.4);
filters[numSounding-1]->setPole((MY_FLOAT) 0.999 - ((MY_FLOAT) vel * NORM_7 * 0.6));
filters[numSounding-1]->setGain(vel / (MY_FLOAT) 128.0);
}
else {
waves[notDone]->reset();
filters[notDone]->setPole((MY_FLOAT) 0.999 - ((MY_FLOAT) vel * NORM_7 * 0.6));
filters[notDone]->setGain(vel / (MY_FLOAT) 128.0);
}
#if defined(_debug_)
printf("Number Sounding = %i\n",numSounding);
for (i=0;i<numSounding;i++) printf(" %i ",sounding[i]);
printf("\n");
#endif
}
void DrumSynt :: noteOff(MY_FLOAT amp)
{ /* Set all sounding wave filter gains low */
int i = 0;
while(i<numSounding) {
filters[i]->setGain(amp*0.01);
i++;
}
}
MY_FLOAT DrumSynt :: tick()
{
int j, i = 0;
MY_FLOAT output = 0.0;
OnePole *tempFilt;
while (i < numSounding) {
output += filters[i]->tick(waves[i]->lastOut());
if (waves[i]->informTick() == 1) {
delete waves[i];
tempFilt = filters[i];
for (j=i;j<numSounding-1;j++) {
sounding[j] = sounding[j+1];
waves[j] = waves[j+1];
filters[j] = filters[j+1];
}
filters[j] = tempFilt;
filters[j]->clear();
sounding[j] = -1;
numSounding -= 1;
i -= 1;
}
i++;
}
return output;
}

47
STK/DrumSynt.h Normal file
View File

@@ -0,0 +1,47 @@
/*******************************************/
/* Master Class for Drum Synthesizer */
/* by Perry R. Cook, 1995-96 */
/* */
/* This instrument contains a bunch of */
/* RawWvIn objects, run through a bunch */
/* of one-pole filters. All the */
/* corresponding rawwave files have been */
/* sampled at 22050 Hz. Thus, if the */
/* compile-time SRATE = 22050, then */
/* no interpolation is used. Otherwise, */
/* the rawwave data is appropriately */
/* interpolated for the current SRATE. */
/* You can specify the maximum Polyphony */
/* (maximum number of simultaneous voices)*/
/* in a #define in the .h file. */
/* */
/* Modified for RawWvIn class */
/* by Gary P. Scavone (4/99) */
/*******************************************/
#if !defined(__DrumSynt_h)
#define __DrumSynt_h
#include "Instrmnt.h"
#include "RawWvIn.h"
#include "OnePole.h"
#define DRUM_NUMWAVES 11
#define DRUM_POLYPHONY 4
class DrumSynt : public Instrmnt
{
protected:
RawWvIn *waves[DRUM_POLYPHONY];
OnePole *filters[DRUM_POLYPHONY];
int sounding[DRUM_POLYPHONY];
int numSounding;
public:
DrumSynt();
~DrumSynt();
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
void noteOff(MY_FLOAT amp);
virtual MY_FLOAT tick();
};
#endif

122
STK/Envelope.cpp Normal file
View File

@@ -0,0 +1,122 @@
/*******************************************/
/* Envelope Class, Perry R. Cook, 1995-96 */
/* */
/* This is the base class for envelopes. */
/* This one is capable of ramping state */
/* from where it is to a target value by */
/* a rate. It also responds to simple */
/* KeyOn and KeyOff messages, ramping to */
/* 1.0 on keyon and to 0.0 on keyoff. */
/* There are two tick (update value) */
/* methods, one returns the value, and */
/* other returns 0 if the envelope is at */
/* the target value (the state bit). */
/*******************************************/
#include "Envelope.h"
Envelope :: Envelope() : Object()
{
target = (MY_FLOAT) 0.0;
value = (MY_FLOAT) 0.0;
rate = (MY_FLOAT) 0.001;
state = 0;
}
Envelope :: ~Envelope()
{
}
void Envelope :: keyOn()
{
target = (MY_FLOAT) 1.0;
if (value != target) state = 1;
}
void Envelope :: keyOff()
{
target = (MY_FLOAT) 0.0;
if (value != target) state = 1;
}
void Envelope :: setRate(MY_FLOAT aRate)
{
if (aRate < 0.0) {
printf("negative rates not allowed!!, correcting\n");
rate = -aRate;
}
else rate = aRate;
}
void Envelope :: setTime(MY_FLOAT aTime)
{
if (aTime < 0.0) {
printf("negative times not allowed!!, correcting\n");
rate = ONE_OVER_SRATE / -aTime ;
}
else rate = ONE_OVER_SRATE / aTime ;
}
void Envelope :: setTarget(MY_FLOAT aTarget)
{
target = aTarget;
if (value != target) state = 1;
}
void Envelope :: setValue(MY_FLOAT aValue)
{
state = 0;
target = aValue;
value = aValue;
}
MY_FLOAT Envelope :: tick()
{
if (state) {
if (target > value) {
value += rate;
if (value >= target) {
value = target;
state = 0;
}
}
else {
value -= rate;
if (value <= target) {
value = target;
state = 0;
}
}
}
return value;
}
int Envelope :: informTick()
{
this->tick();
return state;
}
MY_FLOAT Envelope :: lastOut()
{
return value;
}
/************ Test Main ************************/
/*
void main()
{
long i;
Envelope test;
test.setRate(0.15);
test.keyOn();
for (i=0;i<10;i++) printf("%lf\n",test.tick());
test.setRate(0.1);
test.setTarget(0.5);
while (test.informTick()) printf("%lf\n",test.lastOut());
test.setRate(0.05);
test.keyOff();
while(test.informTick()) printf("%lf\n",test.lastOut());
}
*/

41
STK/Envelope.h Normal file
View File

@@ -0,0 +1,41 @@
/*******************************************/
/* Envelope Class, Perry R. Cook, 1995-96 */
/* This is the base class for envelopes. */
/* This one is capable of ramping state */
/* from where it is to a target value by */
/* a rate. It also responds to simple */
/* KeyOn and KeyOff messages, ramping to */
/* 1.0 on keyon and to 0.0 on keyoff. */
/* There are two tick (update value) */
/* methods, one returns the value, and */
/* other returns 0 if the envelope is at */
/* the target value (the state bit). */
/*******************************************/
#if !defined(__Envelope_h)
#define __Envelope_h
#include "Object.h"
class Envelope : public Object
{
protected:
MY_FLOAT value;
MY_FLOAT target;
MY_FLOAT rate;
int state;
public:
Envelope();
virtual ~Envelope();
void keyOn();
void keyOff();
void setRate(MY_FLOAT aRate);
void setTime(MY_FLOAT aTime);
void setTarget(MY_FLOAT aTarget);
void setValue(MY_FLOAT aValue);
MY_FLOAT tick();
int informTick();
MY_FLOAT lastOut();
};
#endif

56
STK/FM4Alg3.cpp Normal file
View File

@@ -0,0 +1,56 @@
/******************************************/
/* Algorithm 3 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/* */
/* Alg 3 is : 4--\ */
/* 3-->2-- + -->1-->Out */
/* */
/* Controls: control1 = total mod index */
/* control2 = crossfade of two */
/* modulators */
/* control3 = LFO speed */
/* modWheel = LFO amount */
/* */
/******************************************/
#include "FM4Alg3.h"
FM4Alg3 :: FM4Alg3() : FM4Op()
{
/* We still don't make the waves here yet, because */
/* we still don't know what they will be. */
}
FM4Alg3 :: ~FM4Alg3()
{
}
MY_FLOAT FM4Alg3 :: tick()
{
MY_FLOAT temp;
temp = vibWave->tick() * modDepth * (MY_FLOAT) 0.2;
waves[0]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp) * ratios[0]);
waves[1]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp) * ratios[1]);
waves[2]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp) * ratios[2]);
waves[3]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp) * ratios[3]);
temp = gains[2] * adsr[2]->tick() * waves[2]->tick();
waves[1]->addPhaseOffset(temp);
waves[3]->addPhaseOffset(twozero->lastOut());
temp = ((MY_FLOAT) 1.0 - (control2 * (MY_FLOAT) 0.5)) *
gains[3] * adsr[3]->tick() * waves[3]->tick();
twozero->tick(temp);
temp += control2 * (MY_FLOAT) 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 * (MY_FLOAT) 0.5;
return lastOutput;
}

30
STK/FM4Alg3.h Normal file
View File

@@ -0,0 +1,30 @@
/******************************************/
/* Algorithm 3 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/* */
/* Alg 3 is : 4--\ */
/* 3-->2-- + -->1-->Out */
/* */
/* Controls: control1 = total mod index */
/* control2 = crossfade of two */
/* modulators */
/* control3 = LFO speed */
/* modWheel = LFO amount */
/* */
/******************************************/
#if !defined(__FM4Alg3_h)
#define __FM4Alg3_h
#include "FM4Op.h"
class FM4Alg3 : public FM4Op
{
public:
FM4Alg3();
virtual ~FM4Alg3();
MY_FLOAT tick();
};
#endif

53
STK/FM4Alg4.cpp Normal file
View File

@@ -0,0 +1,53 @@
/******************************************/
/* Algorithm 4 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/* */
/* Alg 4 is : 4->3--\ */
/* 2-- + -->1-->Out */
/* */
/* Controls: control1 = total mod index */
/* control2 = crossfade of two */
/* modulators */
/* control3 = LFO speed */
/* modWheel = LFO amount */
/* */
/******************************************/
#include "FM4Alg4.h"
FM4Alg4 :: FM4Alg4() : FM4Op()
{
/* We still don't make the waves here yet, because */
/* we still don't know what they will be. */
}
FM4Alg4 :: ~FM4Alg4()
{
}
MY_FLOAT FM4Alg4 :: tick()
{
MY_FLOAT temp;
temp = vibWave->tick() * modDepth * (MY_FLOAT) 0.2;
waves[0]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp) * ratios[0]);
waves[1]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp) * ratios[1]);
waves[2]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp) * ratios[2]);
waves[3]->setFreq(baseFreq * ((MY_FLOAT) 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 = ((MY_FLOAT) 1.0 - (control2 * (MY_FLOAT) 0.5)) *
gains[2] * adsr[2]->tick() * waves[2]->tick();
temp += control2 * (MY_FLOAT) 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 * (MY_FLOAT) 0.5;
return lastOutput;
}

30
STK/FM4Alg4.h Normal file
View File

@@ -0,0 +1,30 @@
/******************************************/
/* Algorithm 4 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/* */
/* Alg 4 is : 4->3--\ */
/* 2-- + -->1-->Out */
/* */
/* Controls: control1 = total mod index */
/* control2 = crossfade of two */
/* modulators */
/* control3 = LFO speed */
/* modWheel = LFO amount */
/* */
/******************************************/
#if !defined(__FM4Alg4_h)
#define __FM4Alg4_h
#include "FM4Op.h"
class FM4Alg4 : public FM4Op
{
public:
FM4Alg4();
virtual ~FM4Alg4();
MY_FLOAT tick();
};
#endif

53
STK/FM4Alg5.cpp Normal file
View File

@@ -0,0 +1,53 @@
/******************************************/
/* Algorithm 5 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/* This connection topology is 2 simple */
/* FM Pairs summed together, like: */
/* */
/* Alg 5 is : 4->3--\ */
/* + --> Out */
/* 2->1--/ */
/* */
/* Controls: control1 = mod index 1 */
/* control2 = crossfade of two */
/* outputs */
/* control3 = LFO speed */
/* modWheel = LFO amount */
/* */
/******************************************/
#include "FM4Alg5.h"
FM4Alg5 :: FM4Alg5() : FM4Op()
{
/* We still don't make the waves here yet, because */
/* we still don't know what they will be. */
}
FM4Alg5 :: ~FM4Alg5()
{
}
MY_FLOAT FM4Alg5 :: tick()
{
MY_FLOAT 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 = ((MY_FLOAT) 1.0 - (control2 * (MY_FLOAT) 0.5)) *
gains[0] * adsr[0]->tick() * waves[0]->tick();
temp += control2 * (MY_FLOAT) 0.5 * gains[2] * adsr[2]->tick() * waves[2]->tick();
temp2 = vibWave->tick() * modDepth; /* Calculate amplitude mod */
temp = temp * ((MY_FLOAT) 1.0 + temp2); /* and apply it to output */
lastOutput = temp * (MY_FLOAT) 0.5;
return lastOutput;
}

33
STK/FM4Alg5.h Normal file
View File

@@ -0,0 +1,33 @@
/******************************************/
/* Algorithm 5 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/* This connection topology is 2 simple */
/* FM Pairs summed together, like: */
/* */
/* 1 -> 2 -\ */
/* +-> Out */
/* 3 -> 4 -/ */
/* */
/* Controls: control1 = mod index 1 */
/* control2 = crossfade of two */
/* outputs */
/* control3 = LFO speed */
/* modWheel = LFO amount */
/* */
/******************************************/
#if !defined(__FM4Alg5_h)
#define __FM4Alg5_h
#include "FM4Op.h"
class FM4Alg5 : public FM4Op
{
public:
FM4Alg5();
virtual ~FM4Alg5();
MY_FLOAT tick();
};
#endif

58
STK/FM4Alg6.cpp Normal file
View File

@@ -0,0 +1,58 @@
/******************************************/
/* Algorithm 6 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/* This connection topology is three */
/* Carriers and a common Modulator */
/* */
/* /->1 -\ */
/* 4-|-->2 - +-> Out */
/* \->3 -/ */
/* */
/* Controls: control1 = vowel */
/* control2 = spectral tilt */
/* control3 = LFO speed */
/* modWheel = LFO amount */
/* */
/******************************************/
#include "FM4Alg6.h"
FM4Alg6 :: FM4Alg6() : FM4Op()
{
/* We still don't make the waves here yet, because */
/* we still don't know what they will be. */
}
FM4Alg6 :: ~FM4Alg6()
{
}
MY_FLOAT FM4Alg6 :: tick()
{
MY_FLOAT temp,temp2;
temp = gains[3] * adsr[3]->tick() * waves[3]->tick();
temp2 = vibWave->tick() * modDepth * (MY_FLOAT) 0.1; /* Calculate frequency mod */
waves[0]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp2) * ratios[0]);
waves[1]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp2) * ratios[1]);
waves[2]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp2) * ratios[2]);
waves[3]->setFreq(baseFreq * ((MY_FLOAT) 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();
return temp * (MY_FLOAT) 0.33;
}
void FM4Alg6 :: controlChange(int number, MY_FLOAT value)
{
}

36
STK/FM4Alg6.h Normal file
View File

@@ -0,0 +1,36 @@
/******************************************/
/* Algorithm 6 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/* This connection topology is three */
/* Carriers and a common Modulator */
/* */
/* /->1 -\ */
/* 4-|-->2 - +-> Out */
/* \->3 -/ */
/* */
/* Controls: control1 = vowel */
/* control2 = spectral tilt */
/* control3 = LFO speed */
/* modWheel = LFO amount */
/* */
/******************************************/
#if !defined(__FM4Alg6_h)
#define __FM4Alg6_h
#include "FM4Op.h"
class FM4Alg6 : public FM4Op
{
protected:
MY_FLOAT tilt[3];
MY_FLOAT mods[3];
public:
FM4Alg6();
virtual ~FM4Alg6();
MY_FLOAT tick();
virtual void controlChange(int number, MY_FLOAT value);
};
#endif

47
STK/FM4Alg8.cpp Normal file
View File

@@ -0,0 +1,47 @@
/******************************************/
/* Algorithm 8 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/* This connection topology is simple */
/* Additive Synthesis, like: */
/* */
/* 1 --. */
/* 2 -\| */
/* +-> Out */
/* 3 -/| */
/* 4 -- */
/* */
/* Controls: control1 = op4 (fb) gain */
/* control2 = op3 gain */
/* control3 = LFO speed */
/* modWheel = LFO amount */
/* */
/******************************************/
#include "FM4Alg8.h"
FM4Alg8 :: FM4Alg8() : FM4Op()
{
/* We still don't make the waves here yet, because */
/* we still don't know what they will be. */
}
FM4Alg8 :: ~FM4Alg8()
{
}
MY_FLOAT FM4Alg8 :: tick()
{
MY_FLOAT temp;
waves[3]->addPhaseOffset(twozero->lastOut());
temp = control1 * (MY_FLOAT) 2.0 * gains[3] * adsr[3]->tick() * waves[3]->tick();
twozero->tick(temp);
temp += control2 * (MY_FLOAT) 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 * (MY_FLOAT) 0.125;
return lastOutput;
}

34
STK/FM4Alg8.h Normal file
View File

@@ -0,0 +1,34 @@
/******************************************/
/* Algorithm 8 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/* This connection topology is simple */
/* Additive Synthesis, like: */
/* */
/* 1 --. */
/* 2 -\| */
/* +-> Out */
/* 3 -/| */
/* 4 -- */
/* */
/* Controls: control1 = op4 (fb) gain */
/* control2 = op3 gain */
/* control3 = LFO speed */
/* modWheel = LFO amount */
/* */
/******************************************/
#if !defined(__FM4Alg8_h)
#define __FM4Alg8_h
#include "FM4Op.h"
class FM4Alg8 : public FM4Op
{
public:
FM4Alg8();
virtual ~FM4Alg8();
virtual MY_FLOAT tick();
};
#endif

184
STK/FM4Op.cpp Normal file
View File

@@ -0,0 +1,184 @@
/*******************************************/
/* Master Class for 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/* This instrument contains 4 waves, */
/* 4 adsr, and various state vars. */
/* */
/* The basic Chowning/Stanford FM patent */
/* expired April 1995, but there exist */
/* follow-on patents, mostly assigned to */
/* Yamaha. If you are of the type who */
/* should worry about this (making money) */
/* worry away. */
/* */
/*******************************************/
#include "FM4Op.h"
#include "SKINI11.msg"
FM4Op :: FM4Op()
{
int i;
MY_FLOAT temp;
MY_FLOAT tempCoeffs[2] = {(MY_FLOAT) 0.0, (MY_FLOAT) -1.0};
adsr[0] = new ADSR;
adsr[1] = new ADSR;
adsr[2] = new ADSR;
adsr[3] = new ADSR;
twozero = new TwoZero;
// Concatenate the STK RAWWAVE_PATH to the rawwave file
char file[128];
strcpy(file, RAWWAVE_PATH);
vibWave = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping");
vibWave->normalize();
vibWave->setFreq((MY_FLOAT) 6.0); /* should make this random?? */
modDepth = (MY_FLOAT) 0.0;
/* We don't make the waves here yet, because */
/* we don't know what they will be. */
baseFreq = (MY_FLOAT) 440.0;
ratios[0] = (MY_FLOAT) 1.0;
ratios[1] = (MY_FLOAT) 1.0;
ratios[2] = (MY_FLOAT) 1.0;
ratios[3] = (MY_FLOAT) 1.0;
gains[0] = (MY_FLOAT) 1.0;
gains[1] = (MY_FLOAT) 1.0;
gains[2] = (MY_FLOAT) 1.0;
gains[3] = (MY_FLOAT) 1.0;
twozero->setZeroCoeffs(tempCoeffs);
twozero->setGain((MY_FLOAT) 0.0);
control1 = (MY_FLOAT) 1.0;
control2 = (MY_FLOAT) 1.0;
temp = (MY_FLOAT) 1.0;
for (i=99;i>=0;i--) {
__FM4Op_gains[i] = temp;
temp *= (MY_FLOAT) 0.933033;
}
temp = (MY_FLOAT) 1.0;
for (i=15;i>=0;i--) {
__FM4Op_susLevels[i] = temp;
temp *= (MY_FLOAT) 0.707101;
}
temp = (MY_FLOAT) 8.498186;
for (i=0;i<32;i++) {
__FM4Op_attTimes[i] = temp;
temp *= (MY_FLOAT) 0.707101;
}
}
FM4Op :: ~FM4Op()
{
delete adsr[0];
delete adsr[1];
delete adsr[2];
delete adsr[3];
delete waves[0];
delete waves[1];
delete waves[2];
delete waves[3];
delete vibWave;
delete twozero;
}
void FM4Op :: loadWaves(char* wave1, char* wave2, char* wave3, char* wave4)
{
int i;
waves[0] = new RawWvIn(wave1,"looping");
waves[1] = new RawWvIn(wave2,"looping");
waves[2] = new RawWvIn(wave3,"looping");
waves[3] = new RawWvIn(wave4,"looping");
for (i=0;i<4;i++) {
waves[i]->normalize();
}
}
void FM4Op :: setFreq(MY_FLOAT frequency)
{
baseFreq = frequency;
waves[0]->setFreq(baseFreq * ratios[0]);
waves[1]->setFreq(baseFreq * ratios[1]);
waves[2]->setFreq(baseFreq * ratios[2]);
waves[3]->setFreq(baseFreq * ratios[3]);
}
void FM4Op :: setRatio(int whichOne, MY_FLOAT ratio)
{
ratios[whichOne] = ratio;
if (ratio>0.0)
waves[whichOne]->setFreq(baseFreq * ratio);
else
waves[whichOne]->setFreq(ratio);
}
void FM4Op :: setGain(int whichOne, MY_FLOAT gain)
{
gains[whichOne]=gain;
}
void FM4Op :: keyOn()
{
adsr[0]->keyOn();
adsr[1]->keyOn();
adsr[2]->keyOn();
adsr[3]->keyOn();
}
void FM4Op :: keyOff()
{
adsr[0]->keyOff();
adsr[1]->keyOff();
adsr[2]->keyOff();
adsr[3]->keyOff();
}
void FM4Op :: noteOff(MY_FLOAT amp)
{
this->keyOff();
#if defined(_debug_)
printf("FM4Op : NoteOff: Amp=%lf\n",amp);
#endif
}
void FM4Op :: setModulationSpeed(MY_FLOAT mSpeed)
{
vibWave->setFreq(mSpeed);
}
void FM4Op :: setModulationDepth(MY_FLOAT mDepth)
{
modDepth = mDepth;
}
void FM4Op :: setControl1(MY_FLOAT cVal)
{
control1 = cVal * (MY_FLOAT) 2.0;
}
void FM4Op :: setControl2(MY_FLOAT cVal)
{
control2 = cVal * (MY_FLOAT) 2.0;
}
void FM4Op :: controlChange(int number, MY_FLOAT value)
{
#if defined(_debug_)
printf("FM4Op : ControlChange: Number=%i Value=%f\n",number,value);
#endif
if (number == __SK_Breath_) /* Control Change 2 */
this->setControl1(value * NORM_7);
else if (number == __SK_FootControl_) /* Control Change 4 */
this->setControl2(value * NORM_7);
else if (number == __SK_ModFrequency_) /* Control Change 11 */
this->setModulationSpeed(value * NORM_7 * (MY_FLOAT) 12.0); /* 0 to 12 Hz */
else if (number == __SK_ModWheel_) /* Control Change 1 */
this->setModulationDepth(value * NORM_7);
else if (number == __SK_AfterTouch_Cont_) {
//adsr[0]->setTarget(value * NORM_7);
adsr[1]->setTarget(value * NORM_7);
//adsr[2]->setTarget(value * NORM_7);
adsr[3]->setTarget(value * NORM_7);
}
else {
printf("FM4Op : Undefined Control Number!!\n");
}
}

59
STK/FM4Op.h Normal file
View File

@@ -0,0 +1,59 @@
/*******************************************/
/* Master Class for 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/* This instrument contains an 4 waves, */
/* 4 envelopes, and various state vars. */
/* */
/* The basic Chowning/Stanford FM patent */
/* expired April 1995, but there exist */
/* follow-on patents, mostly assigned to */
/* Yamaha. If you are of the type who */
/* should worry about this (making money) */
/* worry away. */
/* */
/*******************************************/
#if !defined(__FM4Op_h)
#define __FM4Op_h
#include "Instrmnt.h"
#include "ADSR.h"
#include "RawWvIn.h"
#include "TwoZero.h"
class FM4Op : public Instrmnt
{
protected:
ADSR *adsr[4];
RawWvIn *waves[4];
RawWvIn *vibWave;
TwoZero *twozero;
MY_FLOAT baseFreq;
MY_FLOAT ratios[4];
MY_FLOAT gains[4];
MY_FLOAT modDepth;
MY_FLOAT control1;
MY_FLOAT control2;
MY_FLOAT __FM4Op_gains[100];
MY_FLOAT __FM4Op_susLevels[16];
MY_FLOAT __FM4Op_attTimes[32];
public:
FM4Op();
virtual ~FM4Op();
void loadWaves(char* wave1, char* wave2, char* wave3, char* wave4);
void clear();
void setFreq(MY_FLOAT frequency);
void setRatio(int whichOne, MY_FLOAT ratio);
void setGain(int whichOne, MY_FLOAT gain);
void keyOn();
void keyOff();
void noteOff(MY_FLOAT amp);
/* There's no tick() method here, because that depends on the algorithm */
void setModulationSpeed(MY_FLOAT mSpeed);
void setModulationDepth(MY_FLOAT mDepth);
void setControl1(MY_FLOAT cVal);
void setControl2(MY_FLOAT cVal);
virtual void controlChange(int number, MY_FLOAT value);
};
#endif

136
STK/FMVoices.cpp Normal file
View File

@@ -0,0 +1,136 @@
/******************************************/
/* Singing Voice Synthesis Subclass */
/* of Algorithm 6 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1996 */
/******************************************/
#include "FMVoices.h"
#include "SKINI11.msg"
FMVoices :: FMVoices() : FM4Alg6()
{
// Concatenate the STK RAWWAVE_PATH to the rawwave file
char file1[128];
char file2[128];
char file3[128];
char file4[128];
strcpy(file1, RAWWAVE_PATH);
strcpy(file2, RAWWAVE_PATH);
strcpy(file3, RAWWAVE_PATH);
strcpy(file4, RAWWAVE_PATH);
this->loadWaves(strcat(file1,"rawwaves/sinewave.raw"),
strcat(file2,"rawwaves/sinewave.raw"),
strcat(file3,"rawwaves/sinewave.raw"),
strcat(file4,"rawwaves/fwavblnk.raw"));
this->setRatio(0,(MY_FLOAT) 2.00);
this->setRatio(1,(MY_FLOAT) 4.00);
this->setRatio(2,(MY_FLOAT) 12.0);
this->setRatio(3,(MY_FLOAT) 1.00);
gains[3] = __FM4Op_gains[80];
adsr[0]->setAllTimes((MY_FLOAT) 0.050,(MY_FLOAT) 0.050,
__FM4Op_susLevels[15],(MY_FLOAT) 0.050);
adsr[1]->setAllTimes((MY_FLOAT) 0.050,(MY_FLOAT) 0.050,
__FM4Op_susLevels[15],(MY_FLOAT) 0.050);
adsr[2]->setAllTimes((MY_FLOAT) 0.050,(MY_FLOAT) 0.050,
__FM4Op_susLevels[15],(MY_FLOAT) 0.050);
adsr[3]->setAllTimes((MY_FLOAT) 0.010,(MY_FLOAT) 0.010,
__FM4Op_susLevels[15],(MY_FLOAT) 0.500);
twozero->setGain((MY_FLOAT) 0.0);
modDepth = (MY_FLOAT) 0.005;
currentVowel = 0;
tilt[0] = (MY_FLOAT) 1.0;
tilt[1] = (MY_FLOAT) 0.5;
tilt[2] = (MY_FLOAT) 0.2;
mods[0] = (MY_FLOAT) 1.0;
mods[1] = (MY_FLOAT) 1.1;
mods[2] = (MY_FLOAT) 1.1;
baseFreq = (MY_FLOAT) 110.0;
this->setFreq((MY_FLOAT) 110.0);
}
/* #include "phonTabl.h" */
extern double phonGains[32][2];
extern double phonParams[32][4][3];
extern char phonemes[32][4];
void FMVoices :: setFreq(MY_FLOAT frequency)
{
MY_FLOAT temp,temp2;
int tempi,tempi2;
if (currentVowel < 32) {
tempi2 = currentVowel;
temp2 = (MY_FLOAT) 0.9;
}
else if (currentVowel < 64) {
tempi2 = currentVowel - 32;
temp2 = (MY_FLOAT) 1.0;
}
else if (currentVowel < 96) {
tempi2 = currentVowel - 64;
temp2 = (MY_FLOAT) 1.1;
}
else if (currentVowel <= 128) {
tempi2 = currentVowel - 96;
temp2 = (MY_FLOAT) 1.2;
}
baseFreq = frequency;
temp = (temp2 * (MY_FLOAT) phonParams[tempi2][0][0] / baseFreq) + (MY_FLOAT) 0.5;
tempi = (int) temp;
this->setRatio(0,(MY_FLOAT) tempi);
temp = (temp2 * (MY_FLOAT) phonParams[tempi2][1][0] / baseFreq) + (MY_FLOAT) 0.5;
tempi = (int) temp;
this->setRatio(1,(MY_FLOAT) tempi);
temp = (temp2 * (MY_FLOAT) phonParams[tempi2][2][0] / baseFreq) + (MY_FLOAT) 0.5;
tempi = (int) temp;
this->setRatio(2,(MY_FLOAT) tempi);
gains[0] = (MY_FLOAT) 1.0; // pow(10.0,phonParams[tempi2][0][2] * 0.05);
gains[1] = (MY_FLOAT) 1.0; // pow(10.0,phonParams[tempi2][1][2] * 0.05);
gains[2] = (MY_FLOAT) 1.0; // pow(10.0,phonParams[tempi2][2][2] * 0.05);
}
void FMVoices :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
this->setFreq(freq);
tilt[0] = amp;
tilt[1] = amp * amp;
tilt[2] = amp * amp * amp;
this->keyOn();
#if defined(_debug_)
printf("FMVoices : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}
void FMVoices :: controlChange(int number, MY_FLOAT value)
{
MY_FLOAT temp;
int tempi;
#if defined(_debug_)
printf("FM4Op : ControlChange: Number=%i Value=%f\n",number,value);
#endif
if (number == __SK_Breath_)
gains[3] = __FM4Op_gains[(int) (value * 0.78125)];
else if (number == __SK_FootControl_) {
tempi = (int) value;
currentVowel = tempi;
this->setFreq(baseFreq);
}
else if (number == __SK_ModFrequency_)
this->setModulationSpeed(value * NORM_7 * (MY_FLOAT) 12.0); /* 0 to 12 Hz */
else if (number == __SK_ModWheel_)
this->setModulationDepth(value * NORM_7);
else if (number == __SK_AfterTouch_Cont_) {
temp = value * NORM_7;
tilt[0] = temp;
tilt[1] = temp * temp;
tilt[2] = temp * temp * temp;
}
else {
printf("FM4Op : Undefined Control Number!!\n");
}
}

24
STK/FMVoices.h Normal file
View File

@@ -0,0 +1,24 @@
/******************************************/
/* Singing Voice Synthesis Subclass */
/* of Algorithm 6 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1996 */
/******************************************/
#if !defined(__FMVoices_h)
#define __FMVoices_h
#include "FM4Alg6.h"
class FMVoices : public FM4Alg6
{
protected:
int currentVowel;
public:
FMVoices();
virtual void setFreq(MY_FLOAT frequency);
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
virtual void controlChange(int number, MY_FLOAT value);
};
#endif

24
STK/Filter.cpp Normal file
View File

@@ -0,0 +1,24 @@
/*******************************************/
/* Filter Class, by Perry R. Cook, 1995-96*/
/* This is the base class for all filters.*/
/* To me, most anything is a filter, but */
/* I'll be a little less general here, and*/
/* define a filter as something which has */
/* input(s), output(s), and gain. */
/*******************************************/
#include "Filter.h"
Filter :: Filter() : Object()
{
}
Filter :: ~Filter()
{
}
MY_FLOAT Filter :: lastOut()
{
return lastOutput;
}

28
STK/Filter.h Normal file
View File

@@ -0,0 +1,28 @@
/*******************************************/
/* Filter Class, by Perry R. Cook, 1995-96*/
/* This is the base class for all filters.*/
/* To me, most anything is a filter, but */
/* I'll be a little less general here, and*/
/* define a filter as something which has */
/* input(s), output(s), and gain. */
/*******************************************/
#if !defined(__Filter_h)
#define __Filter_h
#include "Object.h"
class Filter : public Object
{
protected:
MY_FLOAT gain;
MY_FLOAT *outputs;
MY_FLOAT *inputs;
MY_FLOAT lastOutput;
public:
Filter();
virtual ~Filter();
MY_FLOAT lastOut();
};
#endif

178
STK/Flute.cpp Normal file
View File

@@ -0,0 +1,178 @@
/******************************************/
/* WaveGuide Flute ala Karjalainen, */
/* Smith, Waryznyk, etc. */
/* with polynomial Jet ala Cook */
/* by Perry Cook, 1995-96 */
/* */
/* This is a waveguide model, and thus */
/* relates to various Stanford Univ. */
/* and possibly Yamaha and other patents.*/
/* */
/* Controls: CONTROL1 = jetDelay */
/* CONTROL2 = noiseGain */
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/******************************************/
#include "Flute.h"
#include "SKINI11.msg"
Flute :: Flute(MY_FLOAT lowestFreq)
{
long length;
length = (long) (SRATE / lowestFreq + 1);
boreDelay = new DLineL(length);
length >>= 1;
jetDelay = new DLineL(length);
jetTable = new JetTabl;
filter = new OnePole;
dcBlock = new DCBlock;
noise = new Noise;
adsr = new ADSR;
// Concatenate the STK RAWWAVE_PATH to the rawwave file
char file[128];
strcpy(file, RAWWAVE_PATH);
vibr = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping");
this->clear();
boreDelay->setDelay((MY_FLOAT) 100.0);
jetDelay->setDelay((MY_FLOAT) 49.0);
filter->setPole((MY_FLOAT) 0.7 - ((MY_FLOAT) 0.1 * (MY_FLOAT) 22050.0 / SRATE));
filter->setGain((MY_FLOAT) -1.0);
vibr->normalize();
vibr->setFreq((MY_FLOAT) 5.925);
adsr->setAllTimes((MY_FLOAT) 0.005, (MY_FLOAT) 0.01, (MY_FLOAT) 0.8, (MY_FLOAT) 0.010);
endRefl = (MY_FLOAT) 0.5;
jetRefl = (MY_FLOAT) 0.5;
noiseGain = (MY_FLOAT) 0.15; /* Breath pressure random component */
vibrGain = (MY_FLOAT) 0.05; /* breath periodic vibrato component */
jetRatio = (MY_FLOAT) 0.32;
maxPressure = (MY_FLOAT) 0.0;
}
Flute :: ~Flute()
{
delete jetDelay;
delete boreDelay;
delete jetTable;
delete filter;
delete dcBlock;
delete noise;
delete adsr;
delete vibr;
}
void Flute :: clear()
{
jetDelay->clear();
boreDelay->clear();
filter->clear();
dcBlock->clear();
}
void Flute :: setFreq(MY_FLOAT frequency)
{
MY_FLOAT temp;
lastFreq = frequency * (MY_FLOAT) 0.66666; /* we're overblowing here */
temp = SRATE / lastFreq - (MY_FLOAT) 2.0; /* Length - approx. filter delay */
boreDelay->setDelay(temp); /* Length of bore tube */
jetDelay->setDelay(temp * jetRatio); /* jet delay shorter */
}
void Flute :: startBlowing(MY_FLOAT amplitude, MY_FLOAT rate)
{
adsr->setAttackRate(rate);
maxPressure = amplitude / (MY_FLOAT) 0.8;
adsr->keyOn();
}
void Flute :: stopBlowing(MY_FLOAT rate)
{
adsr->setReleaseRate(rate);
adsr->keyOff();
}
void Flute :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
this->setFreq(freq);
this->startBlowing((MY_FLOAT) 1.1 + (amp * (MY_FLOAT) 0.20),amp * (MY_FLOAT) 0.02);
outputGain = amp + (MY_FLOAT) 0.001;
#if defined(_debug_)
printf("Flute : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}
void Flute :: noteOff(MY_FLOAT amp)
{
this->stopBlowing(amp * (MY_FLOAT) 0.02);
#if defined(_debug_)
printf("Flute : NoteOff: Amp=%lf\n",amp);
#endif
}
void Flute :: setJetRefl(MY_FLOAT refl)
{
jetRefl = refl;
}
void Flute :: setEndRefl(MY_FLOAT refl)
{
endRefl = refl;
}
void Flute :: setJetDelay(MY_FLOAT aRatio)
{
MY_FLOAT temp;
temp = SRATE / lastFreq - (MY_FLOAT) 2.0; /* Length - approx. filter delay */
jetRatio = aRatio;
jetDelay->setDelay(temp * aRatio); /* Scaled by ratio */
}
MY_FLOAT Flute :: tick()
{
MY_FLOAT temp;
MY_FLOAT pressureDiff;
MY_FLOAT randPressure;
MY_FLOAT breathPressure;
breathPressure = maxPressure * adsr->tick(); /* Breath Pressure */
randPressure = noiseGain * noise->tick(); /* Random Deviation */
randPressure += vibrGain * vibr->tick(); /* + breath vibrato */
randPressure *= breathPressure; /* All scaled by Breath Pressure */
temp = filter->tick(boreDelay->lastOut());
temp = dcBlock->tick(temp); /* Block DC on reflection */
pressureDiff = breathPressure + randPressure - /* Breath Pressure */
(jetRefl * temp); /* - reflected */
pressureDiff = jetDelay->tick(pressureDiff); /* Jet Delay Line */
pressureDiff = jetTable->lookup(pressureDiff) /* Non-Lin Jet + reflected */
+ (endRefl * temp);
lastOutput = (MY_FLOAT) 0.3 * boreDelay->tick(pressureDiff); /* Bore Delay and "bell" filter */
lastOutput *= outputGain;
return lastOutput;
}
void Flute :: controlChange(int number, MY_FLOAT value)
{
#if defined(_debug_)
printf("Flute : ControlChange: Number=%i Value=%f\n",number,value);
#endif
if (number == __SK_JetDelay_)
this->setJetDelay((MY_FLOAT) 0.08 + ((MY_FLOAT) 0.48 * value * NORM_7));
else if (number == __SK_NoiseLevel_)
noiseGain = (value * NORM_7 * (MY_FLOAT) 0.4);
else if (number == __SK_ModFrequency_)
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
else if (number == __SK_ModWheel_)
vibrGain = (value * NORM_7 * (MY_FLOAT) 0.4);
else if (number == __SK_AfterTouch_Cont_)
adsr->setTarget(value * NORM_7);
else {
printf("Flute : Undefined Control Number!!\n");
}
}

64
STK/Flute.h Normal file
View File

@@ -0,0 +1,64 @@
/******************************************/
/* WaveGuide Flute ala Karjalainen, */
/* Smith, Waryznyk, etc. */
/* with polynomial Jet ala Cook */
/* by Perry Cook, 1995-96 */
/* */
/* This is a waveguide model, and thus */
/* relates to various Stanford Univ. */
/* and possibly Yamaha and other patents.*/
/* */
/* Controls: CONTROL1 = jetDelay */
/* CONTROL2 = noiseGain */
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/******************************************/
#if !defined(__Flute_h)
#define __Flute_h
#include "Instrmnt.h"
#include "JetTabl.h"
#include "DLineL.h"
#include "OnePole.h"
#include "DCBlock.h"
#include "Noise.h"
#include "ADSR.h"
#include "RawWvIn.h"
class Flute : public Instrmnt
{
protected:
DLineL *jetDelay;
DLineL *boreDelay;
JetTabl *jetTable;
OnePole *filter;
DCBlock *dcBlock;
Noise *noise;
ADSR *adsr;
RawWvIn *vibr;
MY_FLOAT lastFreq;
MY_FLOAT maxPressure;
MY_FLOAT jetRefl;
MY_FLOAT endRefl;
MY_FLOAT noiseGain;
MY_FLOAT vibrGain;
MY_FLOAT outputGain;
MY_FLOAT jetRatio;
public:
Flute(MY_FLOAT lowestFreq);
~Flute();
void clear();
void startBlowing(MY_FLOAT amplitude,MY_FLOAT rate);
void stopBlowing(MY_FLOAT rate);
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
virtual void noteOff(MY_FLOAT amp);
void setJetRefl(MY_FLOAT refl);
void setEndRefl(MY_FLOAT refl);
virtual void setFreq(MY_FLOAT frequency);
virtual MY_FLOAT tick();
virtual void controlChange(int number, MY_FLOAT value);
void setJetDelay(MY_FLOAT aLength);
};
#endif

139
STK/FormSwep.cpp Normal file
View File

@@ -0,0 +1,139 @@
/*******************************************/
/* Sweepable Formant (2-pole) */
/* Filter Class, by Perry R. Cook, 1995-96*/
/* See books on filters to understand */
/* more about how this works. This drives*/
/* to a target at speed set by rate. */
/*******************************************/
#include "FormSwep.h"
FormSwep :: FormSwep() : Filter()
{
outputs = (MY_FLOAT *) malloc(2 * sizeof(MY_FLOAT));
poleCoeffs[0] = (MY_FLOAT) 0.0;
poleCoeffs[1] = (MY_FLOAT) 0.0;
gain = (MY_FLOAT) 1.0;
freq = (MY_FLOAT) 0.0;
reson = (MY_FLOAT) 0.0;
currentGain = (MY_FLOAT) 1.0;
currentFreq = (MY_FLOAT) 0.0;
currentReson = (MY_FLOAT) 0.0;
targetGain = (MY_FLOAT) 1.0;
targetFreq = (MY_FLOAT) 0.0;
targetReson = (MY_FLOAT) 0.0;
deltaGain = (MY_FLOAT) 0.0;
deltaFreq = (MY_FLOAT) 0.0;
deltaReson = (MY_FLOAT) 0.0;
sweepState = (MY_FLOAT) 0.0;
sweepRate = (MY_FLOAT) 0.002;
dirty = 0;
this->clear();
}
FormSwep :: ~FormSwep()
{
free(outputs);
}
void FormSwep :: clear()
{
outputs[0] = (MY_FLOAT) 0.0;
outputs[1] = (MY_FLOAT) 0.0;
}
void FormSwep :: setPoleCoeffs(MY_FLOAT *coeffs)
{
dirty = 0;
poleCoeffs[0] = coeffs[0];
poleCoeffs[1] = coeffs[1];
}
void FormSwep :: setFreqAndReson(MY_FLOAT aFreq, MY_FLOAT aReson)
{
dirty = 0;
reson = aReson;
freq = aFreq;
currentReson = aReson;
currentFreq = aFreq;
poleCoeffs[1] = - (reson * reson);
poleCoeffs[0] = (MY_FLOAT) 2.0 * reson * (MY_FLOAT) cos(TWO_PI * freq / SRATE);
}
void FormSwep :: setStates(MY_FLOAT aFreq, MY_FLOAT aReson, MY_FLOAT aGain)
{
dirty = 0;
freq = aFreq;
reson = aReson;
gain = aGain;
targetFreq = aFreq;
targetReson = aReson;
targetGain = aGain;
currentFreq = aFreq;
currentReson = aReson;
currentGain = aGain;
}
void FormSwep :: setTargets(MY_FLOAT aFreq, MY_FLOAT aReson, MY_FLOAT aGain)
{
dirty = 1;
targetFreq = aFreq;
targetReson = aReson;
targetGain = aGain;
deltaFreq = aFreq - currentFreq;
deltaReson = aReson - currentReson;
deltaGain = aGain - currentGain;
sweepState = (MY_FLOAT) 0.0;
}
void FormSwep :: setSweepRate(MY_FLOAT aRate)
{
sweepRate = aRate;
}
void FormSwep :: setSweepTime(MY_FLOAT aTime)
{
sweepRate = ONE_OVER_SRATE / aTime;
}
void FormSwep :: setGain(MY_FLOAT aValue)
{
gain = aValue;
}
MY_FLOAT FormSwep :: tick(MY_FLOAT sample) // Perform Filter Operation
{
MY_FLOAT temp;
if (dirty) {
sweepState += sweepRate;
if (sweepState>= 1.0) {
sweepState = (MY_FLOAT) 1.0;
dirty = 0;
currentReson = targetReson;
reson = targetReson;
currentFreq = targetFreq;
freq = targetFreq;
currentGain = targetGain;
gain = targetGain;
}
else {
currentReson = reson + (deltaReson * sweepState);
currentFreq = freq + (deltaFreq * sweepState);
currentGain = gain + (deltaGain * sweepState);
}
poleCoeffs[1] = - (currentReson * currentReson);
poleCoeffs[0] = (MY_FLOAT) 2.0 * currentReson *
(MY_FLOAT) cos(TWO_PI * currentFreq / SRATE);
}
temp = currentGain * sample;
temp += poleCoeffs[0] * outputs[0];
temp += poleCoeffs[1] * outputs[1];
outputs[1] = outputs[0];
outputs[0] = temp;
lastOutput = outputs[0];
return lastOutput;
}

46
STK/FormSwep.h Normal file
View File

@@ -0,0 +1,46 @@
/*******************************************/
/* Sweepable Formant (2-pole) */
/* Filter Class, by Perry R. Cook, 1995-96*/
/* See books on filters to understand */
/* more about how this works. Nothing */
/* out of the ordinary in this version. */
/*******************************************/
#if !defined(__FormSwep_h)
#define __FormSwep_h
#include "Filter.h"
class FormSwep : public Filter
{
protected:
MY_FLOAT poleCoeffs[2];
MY_FLOAT freq;
MY_FLOAT reson;
int dirty;
MY_FLOAT targetFreq;
MY_FLOAT targetReson;
MY_FLOAT targetGain;
MY_FLOAT currentFreq;
MY_FLOAT currentReson;
MY_FLOAT currentGain;
MY_FLOAT deltaFreq;
MY_FLOAT deltaReson;
MY_FLOAT deltaGain;
MY_FLOAT sweepState;
MY_FLOAT sweepRate;
public:
FormSwep();
~FormSwep();
void clear();
void setPoleCoeffs(MY_FLOAT *coeffs);
void setGain(MY_FLOAT aValue);
void setFreqAndReson(MY_FLOAT aFreq, MY_FLOAT aReson);
void setStates(MY_FLOAT aFreq, MY_FLOAT aReson, MY_FLOAT aGain);
void setTargets(MY_FLOAT aFreq, MY_FLOAT aReson, MY_FLOAT aGain);
void setSweepRate(MY_FLOAT aRate);
void setSweepTime(MY_FLOAT aTime);
MY_FLOAT tick(MY_FLOAT sample);
};
#endif

68
STK/HeavyMtl.cpp Normal file
View File

@@ -0,0 +1,68 @@
/******************************************/
/* Heavy Metal Synth Subclass */
/* of Algorithm 3 (TX81Z) Subclass of */
/* 3 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/******************************************/
#include "HeavyMtl.h"
HeavyMtl :: HeavyMtl() : FM4Alg3()
{
char file1[128];
char file2[128];
char file3[128];
char file4[128];
strcpy(file1, RAWWAVE_PATH);
strcpy(file2, RAWWAVE_PATH);
strcpy(file3, RAWWAVE_PATH);
strcpy(file4, RAWWAVE_PATH);
this->loadWaves(strcat(file1,"rawwaves/sinewave.raw"),
strcat(file2,"rawwaves/sinewave.raw"),
strcat(file3,"rawwaves/sinewave.raw"),
strcat(file4,"rawwaves/fwavblnk.raw"));
this->setRatio(0,(MY_FLOAT) (1.00 * 1.000));
this->setRatio(1,(MY_FLOAT) (4.00 * 0.999));
this->setRatio(2,(MY_FLOAT) (3.00 * 1.001));
this->setRatio(3,(MY_FLOAT) (0.50 * 1.002));
gains[0] = __FM4Op_gains[92];
gains[1] = __FM4Op_gains[76];
gains[2] = __FM4Op_gains[91];
gains[3] = __FM4Op_gains[68];
adsr[0]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 0.001,(MY_FLOAT) 1.0,(MY_FLOAT) 0.01);
adsr[1]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 0.010,(MY_FLOAT) 1.0,(MY_FLOAT) 0.50);
adsr[2]->setAllTimes((MY_FLOAT) 0.010,(MY_FLOAT) 0.005,(MY_FLOAT) 1.0,(MY_FLOAT) 0.20);
adsr[3]->setAllTimes((MY_FLOAT) 0.030,(MY_FLOAT) 0.010,(MY_FLOAT) 0.2,(MY_FLOAT) 0.20);
twozero->setGain((MY_FLOAT) 2.0);
vibWave->setFreq((MY_FLOAT) 5.5);
modDepth = (MY_FLOAT) 0.00;
}
HeavyMtl :: ~HeavyMtl()
{
}
void HeavyMtl :: setFreq(MY_FLOAT frequency)
{
baseFreq = frequency;
waves[0]->setFreq(baseFreq * ratios[0]);
waves[1]->setFreq(baseFreq * ratios[1]);
waves[2]->setFreq(baseFreq * ratios[2]);
waves[3]->setFreq(baseFreq * ratios[3]);
}
void HeavyMtl :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
gains[0] = amp * __FM4Op_gains[92];
gains[1] = amp * __FM4Op_gains[76];
gains[2] = amp * __FM4Op_gains[91];
gains[3] = amp * __FM4Op_gains[68];
this->setFreq(freq);
this->keyOn();
#if defined(_debug_)
printf("HeavyMtl : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}

22
STK/HeavyMtl.h Normal file
View File

@@ -0,0 +1,22 @@
/******************************************/
/* Heavy Metal Synth Subclass */
/* of Algorithm 3 (TX81Z) Subclass of */
/* 3 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/******************************************/
#if !defined(__HeavyMtl_h)
#define __HeavyMtl_h
#include "FM4Alg3.h"
class HeavyMtl : public FM4Alg3
{
public:
HeavyMtl();
~HeavyMtl();
virtual void setFreq(MY_FLOAT frequency);
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
};
#endif

45
STK/Instrmnt.cpp Normal file
View File

@@ -0,0 +1,45 @@
/******************************************/
/* Instrument SuperClass for Toolkit96 */
/* Perry R. Cook, Princeton University */
/******************************************/
#include "Instrmnt.h"
Instrmnt :: Instrmnt()
{
}
Instrmnt :: ~Instrmnt()
{
}
void Instrmnt :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
printf("Warning!! Instrument Class noteOn here!! %f %f\n",freq,amp);
}
void Instrmnt :: noteOff(MY_FLOAT amp)
{
printf("Warning!! Instrument Class noteOff here!! %f\n",amp);
}
void Instrmnt :: setFreq(MY_FLOAT freq)
{
printf("Warning!! Instrument Class setFreq here!! %f\n",freq);
}
MY_FLOAT Instrmnt :: tick()
{
printf("Warning!! Instrument Class tick here!!\n");
return lastOutput;
}
MY_FLOAT Instrmnt :: lastOut()
{
return lastOutput;
}
void Instrmnt :: controlChange(int number, MY_FLOAT value)
{
printf("Warning!! Instrument Class Control Change here!! %i %f\n",number,value);
}

26
STK/Instrmnt.h Normal file
View File

@@ -0,0 +1,26 @@
/******************************************/
/* Instrument SuperClass for Toolkit96 */
/* Perry R. Cook, Princeton University */
/******************************************/
#if !defined(__Instrmnt_h)
#define __Instrmnt_h
#include "Object.h"
class Instrmnt : public Object
{
protected:
MY_FLOAT lastOutput;
public:
Instrmnt();
virtual ~Instrmnt();
MY_FLOAT lastOut();
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
virtual void noteOff(MY_FLOAT amp);
virtual void setFreq(MY_FLOAT frequency);
virtual MY_FLOAT tick();
virtual void controlChange(int number, MY_FLOAT value);
};
#endif

166
STK/JCRev.cpp Normal file
View File

@@ -0,0 +1,166 @@
/*******************************************/
/* JVRev Reverb Subclass */
/* by Tim Stilson, 1998 */
/* based on CLM JCRev */
/* Integrated into STK by Gary Scavone */
/* */
/* This is based on some of the famous */
/* Stanford CCRMA reverbs (NRev, KipRev) */
/* all based on the the Chowning/Moorer/ */
/* Schroeder reverberators, which use */
/* networks of simple allpass and comb */
/* delay filters. This particular */
/* arrangement consists of 3 allpass */
/* filters in series, followed by 4 comb */
/* filters in parallel, an optional */
/* lowpass filter, and two decorrelation */
/* delay lines in parallel at the output. */
/*******************************************/
#include "JCRev.h"
//#define LOWPASS
JCRev :: JCRev(MY_FLOAT T60)
{
/* These are the values from CLM's JCRev.ins ... I found that the
impulse response sounded better with the shorter delay lengths.
--Gary Scavone, 2/1998
int lens[9] = {4799,4999,5399,5801,1051,337,113,573,487};
*/
int lens[9] = {1777,1847,1993,2137,389,127,43,211,179};
int val, i;
if (SRATE < 44100.0) {
double srscale = SRATE / 44100.0;
for (i=0; i<9; i++) {
val = (int) floor(srscale * lens[i]);
if ((val & 1) == 0) val++;
while (!this->isprime(val)) val += 2;
lens[i] = val;
}
}
for (i=0; i<3; i++)
{
APdelayLine[i] = new DLineN(lens[i+4] + 2);
APdelayLine[i]->setDelay(lens[i+4]);
}
for (i=0; i<4; i++)
{
CdelayLine[i] = new DLineN(lens[i] + 2);
CdelayLine[i]->setDelay(lens[i]);
combCoeff[i] = pow(10,(-3 * lens[i] / (T60 * SRATE)));
// printf("combCoeff[%d] = %f\n", i, combCoeff[i]);
}
outLdelayLine = new DLineN(lens[7] + 2);
outLdelayLine->setDelay(lens[7]);
outRdelayLine = new DLineN(lens[8] + 2);
outRdelayLine->setDelay(lens[8]);
allPassCoeff = 0.7;
effectMix = 0.3;
this->clear();
}
JCRev :: ~JCRev()
{
delete APdelayLine[0];
delete APdelayLine[1];
delete APdelayLine[2];
delete CdelayLine[0];
delete CdelayLine[1];
delete CdelayLine[2];
delete CdelayLine[3];
delete outLdelayLine;
delete outRdelayLine;
}
void JCRev :: clear()
{
APdelayLine[0]->clear();
APdelayLine[1]->clear();
APdelayLine[2]->clear();
CdelayLine[0]->clear();
CdelayLine[1]->clear();
CdelayLine[2]->clear();
CdelayLine[3]->clear();
outRdelayLine->clear();
outLdelayLine->clear();
lastOutL = 0.0;
lastOutR = 0.0;
combsum1=0.0;
combsum2=0.0;
combsum=0.0;
}
void JCRev :: setEffectMix(MY_FLOAT mix)
{
effectMix = mix;
}
MY_FLOAT JCRev :: lastOutput()
{
return (lastOutL + lastOutR) * 0.5;
}
MY_FLOAT JCRev :: lastOutputL()
{
return lastOutL;
}
MY_FLOAT JCRev :: lastOutputR()
{
return lastOutR;
}
MY_FLOAT JCRev :: tick(MY_FLOAT input)
{
MY_FLOAT temp,temp0,temp1,temp2,temp3,temp4,temp5,temp6;
MY_FLOAT filtout;
temp = APdelayLine[0]->lastOut();
temp0 = allPassCoeff * temp;
temp0 += input;
APdelayLine[0]->tick(temp0);
temp0 = -(allPassCoeff * temp0) + temp;
temp = APdelayLine[1]->lastOut();
temp1 = allPassCoeff * temp;
temp1 += temp0;
APdelayLine[1]->tick(temp1);
temp1 = -(allPassCoeff * temp1) + temp;
temp = APdelayLine[2]->lastOut();
temp2 = allPassCoeff * temp;
temp2 += temp1;
APdelayLine[2]->tick(temp2);
temp2 = -(allPassCoeff * temp2) + temp;
temp3 = temp2 + (combCoeff[0] * CdelayLine[0]->lastOut());
temp4 = temp2 + (combCoeff[1] * CdelayLine[1]->lastOut());
temp5 = temp2 + (combCoeff[2] * CdelayLine[2]->lastOut());
temp6 = temp2 + (combCoeff[3] * CdelayLine[3]->lastOut());
CdelayLine[0]->tick(temp3);
CdelayLine[1]->tick(temp4);
CdelayLine[2]->tick(temp5);
CdelayLine[3]->tick(temp6);
#ifdef LOWPASS
combsum2=combsum1;
combsum1=combsum;
combsum = temp3+temp4+temp5+temp6;
filtout= 0.5*combsum1+0.25*(combsum+combsum2);
#else
filtout = temp3+temp4+temp5+temp6;
#endif
lastOutL = effectMix * (outLdelayLine->tick(filtout));
lastOutR = effectMix * (outRdelayLine->tick(filtout));
temp = (1.0 - effectMix) * input;
lastOutL += temp;
lastOutR += temp;
return (lastOutL + lastOutR) * 0.5;
}

52
STK/JCRev.h Normal file
View File

@@ -0,0 +1,52 @@
/*******************************************/
/* JVRev Reverb Subclass */
/* by Tim Stilson, 1998 */
/* based on CLM JCRev */
/* Integrated into STK by Gary Scavone */
/* */
/* This is based on some of the famous */
/* Stanford CCRMA reverbs (NRev, KipRev) */
/* all based on the the Chowning/Moorer/ */
/* Schroeder reverberators, which use */
/* networks of simple allpass and comb */
/* delay filters. This particular */
/* arrangement consists of 3 allpass */
/* filters in series, followed by 4 comb */
/* filters in parallel, an optional */
/* lowpass filter, and two decorrelation */
/* delay lines in parallel at the output. */
/*******************************************/
#if !defined(__JCRev_h)
#define __JCRev_h
#include "Object.h"
#include "Reverb.h"
#include "DLineN.h"
class JCRev : public Reverb
{
protected:
DLineN *APdelayLine[3];
DLineN *CdelayLine[4];
DLineN *outLdelayLine;
DLineN *outRdelayLine;
MY_FLOAT allPassCoeff;
MY_FLOAT combCoeff[4];
MY_FLOAT combsum,combsum1,combsum2;
MY_FLOAT lastOutL;
MY_FLOAT lastOutR;
MY_FLOAT effectMix;
public:
JCRev(MY_FLOAT T60);
~JCRev();
void clear();
void setEffectMix(MY_FLOAT mix);
MY_FLOAT lastOutput();
MY_FLOAT lastOutputL();
MY_FLOAT lastOutputR();
MY_FLOAT tick(MY_FLOAT input);
};
#endif

36
STK/JetTabl.cpp Normal file
View File

@@ -0,0 +1,36 @@
/**********************************************/
/* Jet Table Object by Perry R. Cook, 1995-96 */
/* Consult Fletcher and Rossing, Karjalainen, */
/* Cook, more, for information. */
/* This, as with many other of my "tables", */
/* is not a table, but is computed by poly- */
/* nomial calculation. */
/**********************************************/
#include "JetTabl.h"
JetTabl :: JetTabl()
{
lastOutput = (MY_FLOAT) 0.0;
}
JetTabl :: ~JetTabl()
{
}
MY_FLOAT JetTabl :: lookup(MY_FLOAT sample) /* Perform "Table Lookup" */
{ /* By Polynomial Calculation */
lastOutput = sample *
(sample*sample - (MY_FLOAT) 1.0); /* (x^3 - x) approximates sigmoid of jet */
if (lastOutput > 1.0)
lastOutput = (MY_FLOAT) 1.0; /* Saturation at +/- 1.0 */
if (lastOutput < -1.0)
lastOutput = (MY_FLOAT) -1.0;
return lastOutput;
}
MY_FLOAT JetTabl :: lastOut()
{
return lastOutput;
}

26
STK/JetTabl.h Normal file
View File

@@ -0,0 +1,26 @@
/**********************************************/
/* Jet Table Object by Perry R. Cook, 1995-96 */
/* Consult Fletcher and Rossing, Karjalainen, */
/* Cook, more, for information. */
/* This, as with many other of my "tables", */
/* is not a table, but is computed by poly- */
/* nomial calculation. */
/**********************************************/
#if !defined(__JetTabl_h)
#define __JetTabl_h
#include "Object.h"
class JetTabl : public Object
{
protected:
MY_FLOAT lastOutput;
public:
JetTabl();
~JetTabl();
MY_FLOAT lookup(MY_FLOAT deltaP);
MY_FLOAT lastOut();
};
#endif

67
STK/LipFilt.cpp Normal file
View File

@@ -0,0 +1,67 @@
/**********************************************/
/* Lip Filter Object by Perry R. Cook, 1995-96*/
/* The lip of the brass player has dynamics */
/* which are controlled by the mass, spring */
/* constant, and damping of the lip. This */
/* filter simulates that behavior and the */
/* transmission/reflection properties as */
/* well. See Cook TBone and HosePlayer */
/* instruments and articles. */
/**********************************************/
#include "LipFilt.h"
LipFilt :: LipFilt()
{
MY_FLOAT coeffs[2];
filter = new BiQuad;
coeffs[0] = (MY_FLOAT) 0.0;
coeffs[1] = (MY_FLOAT) 0.0;
filter->setZeroCoeffs(coeffs);
this->clear();
}
LipFilt :: ~LipFilt()
{
delete filter;
}
void LipFilt :: clear()
{
filter->clear();
lastOutput = (MY_FLOAT) 0.0;
}
void LipFilt :: setFreq(MY_FLOAT frequency)
{
MY_FLOAT coeffs[2];
coeffs[0] = (MY_FLOAT) 2.0 * (MY_FLOAT) 0.997 *
(MY_FLOAT) cos(TWO_PI * frequency / SRATE); /* damping should change with */
coeffs[1] = (MY_FLOAT) (-0.997 * 0.997); /* lip parameters, but not yet.*/
filter->setPoleCoeffs(coeffs);
filter->setGain((MY_FLOAT) 0.03);
}
/* NOTE: Here we should add lip tension */
/* settings based on Mass/Spring/Damping */
/* Maybe in TookKit97 */
MY_FLOAT LipFilt :: tick(MY_FLOAT mouthSample,MY_FLOAT boreSample)
/* Perform "Table Lookup" By Polynomial Calculation */
{
MY_FLOAT temp;
temp = mouthSample - boreSample; /* Differential pressure */
temp = filter->tick(temp); /* Force -> position */
temp = temp*temp; /* Simple position to area mapping */
if (temp > 1.0) temp = (MY_FLOAT) 1.0; /* Saturation at + 1.0 */
lastOutput = temp * mouthSample; /* Assume mouth input = area */
lastOutput += ((MY_FLOAT) 1.0 - temp)
* boreSample; /* and Bore reflection is compliment. */
return lastOutput;
}
MY_FLOAT LipFilt :: lastOut()
{
return lastOutput;
}

28
STK/LipFilt.h Normal file
View File

@@ -0,0 +1,28 @@
/**********************************************/
/* Lip Filter Object by Perry R. Cook, 1995-96*/
/* The lip of the brass player has dynamics */
/* which are controlled by the mass, spring */
/* constant, and damping of the lip. This */
/* filter simulates that behavior and the */
/* transmission/reflection properties as */
/* well. See Cook TBone and HosePlayer */
/* instruments and articles. */
/**********************************************/
#include "Object.h"
#include "BiQuad.h"
class LipFilt : public Object
{
protected:
BiQuad *filter;
MY_FLOAT lastOutput;
public:
LipFilt();
~LipFilt();
void clear();
void setFreq(MY_FLOAT frequency);
MY_FLOAT tick(MY_FLOAT mouthSample,MY_FLOAT boreSample);
MY_FLOAT lastOut();
};

411
STK/MD2SKINI.cpp Normal file
View File

@@ -0,0 +1,411 @@
/*******************************************/
/* Simple Realtime MIDI to SKINI Parser */
/* Gary P. Scavone, February 1998. */
/* Revised for sockets, May & June 1998. */
/* SKINI/MIDI merge added August 1999. */
/* */
/* This object takes MIDI from the input */
/* stream (via the MIDIIO class), */
/* parses it, and turns it into SKINI */
/* messages. */
/*******************************************/
#include "MIDIIO.h"
#include "SKINI11.msg"
#if defined(__STK_REALTIME_)
int outAHere = 0;
// Do OS dependent declarations and includes
#if defined(__OS_IRIX_)
#include <sys/types.h>
#include <sys/prctl.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
pid_t exit_thread;
#elif defined(__OS_Linux_)
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
pthread_t exit_thread;
#elif defined(__OS_Win_)
#include <process.h>
#include <winsock.h>
unsigned long exit_thread;
#endif
// The thread function definition protocols are slightly
// different under Irix, Linux, and Windoze.
#if defined(__OS_IRIX_)
void monitorStdin(void *)
#elif defined(__OS_Linux_)
void *monitorStdin(void *)
#elif defined(__OS_Win_)
void monitorStdin(void *)
#endif
{
char inputString[128];
printf("Type 'Exit<cr>' to quit.\n");
while (!outAHere) {
fgets(inputString, 128, stdin);
if (inputString[3] == 't' && inputString[1] == 'x'
&& inputString[2] == 'i' && inputString[0] == 'E') {
outAHere = 1;
}
else {
printf(inputString);
fflush(stdout);
}
}
}
void errorf(void) {
printf("useage: MD2SKINI <flag(s)>\n\n");
printf(" With no arguments, MD2SKINI converts MIDI input to SKINI\n");
printf(" format and sends the output directly to stdout.\n");
printf(" With flag = -s <hostname>, the output is sent over a socket\n");
printf(" connection to the optional hostname (default = localhost).\n");
printf(" With flag = -f <filename>, the output stream is simultaneously\n");
printf(" written to the file specified by the optional <filename>\n");
printf(" (default = test.ski).\n\n");
exit(0);
}
void main(int argc,char *argv[])
{
long j, i = 1;
MY_FLOAT byte2, byte3;
int channel;
int firstMessage = 1;
int writeFileOut = 0;
FILE *fileOut;
MIDIIO *controller;
char hostName[256];
char fileName[256];
int useSocket = 0;
int theSocket;
struct sockaddr_in saServer;
if (argc>5) {
errorf();
}
// Parse the command-line arguments.
while (i < argc) {
if (argv[i][0] == '-') {
switch(argv[i][1]) {
case 's':
if ((i+1 < argc) && argv[i+1][0] != '-') {
i++;
strcpy(hostName,argv[i]);
}
else strcpy(hostName,"localhost");
useSocket = 1;
break;
case 'f':
if ((i+1 < argc) && argv[i+1][0] != '-') {
i++;
strcpy(fileName,argv[i]);
if (strstr(fileName,".ski") == NULL) strcat(fileName,".ski");
}
else strcpy(fileName,"test.ski");
fileOut = fopen(fileName,"wb");
writeFileOut = 1;
break;
default:
errorf();
break;
}
}
else errorf();
i++;
}
MY_FLOAT dt=0.0;
controller = new MIDIIO();
// If using sockets, setup the client socket
if (useSocket) {
#if defined(__OS_Win_) // Stupid Windoze only stuff
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(1,1);
WSAStartup(wVersionRequested, &wsaData);
if (wsaData.wVersion != wVersionRequested) {
fprintf(stderr,"\n Wrong Windoze socket library version!\n");
exit(0);
}
#endif
// Create the client-side socket
theSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (theSocket < 0) {
fprintf(stderr,"Couldn't create socket ... aborting!\n");
exit(0);
}
struct hostent *hostp;
if ((hostp = gethostbyname(hostName)) == 0) {
fprintf(stderr,"%s: unknown host ... aborting!\n", hostName);
exit(0);
}
// Fill in the address structure
saServer.sin_family = AF_INET;
memcpy((void *)&saServer.sin_addr, hostp->h_addr, hostp->h_length);
saServer.sin_port = htons(2001); // Port number
// Connect to the server
if(connect(theSocket, (struct sockaddr *)&saServer, sizeof(saServer)) < 0) {
fprintf(stderr,"Socket connect failed ... aborting!\n");
#if defined(__OS_Win_)
closesocket(theSocket);
WSACleanup();
#else
close(theSocket);
#endif
exit(0);
}
}
// Setup the exit thread.
#if defined(__OS_IRIX_)
exit_thread = sproc(monitorStdin, PR_SALL);
if (exit_thread == -1) {
fprintf(stderr, "Unable to create exit thread ... aborting.\n");
exit(0);
}
#elif defined(__OS_Linux_)
int err = 0;
err = pthread_create(&exit_thread, NULL, monitorStdin, NULL);
if (err) {
fprintf(stderr, "Unable to create exit thread ... aborting.\n");
exit(0);
}
#elif defined(__OS_Win_)
exit_thread = _beginthread(monitorStdin, 0, NULL);
if (exit_thread == -1) {
fprintf(stderr, "Unable to create exit thread ... aborting.\n");
exit(0);
}
#endif
/* Write SKINI messages to buffer 's'. This is the easiest way
to allow this single executable to work for both socketing
and printf's to stdout.
*/
char s[128];
while (!outAHere) {
if (controller->nextMessage() > 0) {
byte3 = controller->getByteThree();
byte2 = controller->getByteTwo();
channel = controller->getChannel();
if (writeFileOut) dt = controller->getDeltaTime();
if (firstMessage) { /* first MIDI message time stamp is meaningless */
dt = 0.0;
firstMessage = 0;
}
switch(controller->getType()) {
case __SK_NoteOn_:
if (byte3 < 1.0) {
sprintf(s,"NoteOff\t\t%.3f %d %.1f %.1f\n",0.0,channel,byte2,64.0);
if (writeFileOut) {
fprintf(fileOut,"NoteOff\t\t%.3f %d %.1f %.1f\n",dt,channel,byte2,64.0);
}
} else {
sprintf(s,"NoteOn\t\t%.3f %d %.1f %.1f\n",0.0,channel,byte2,byte3);
if (writeFileOut) {
fprintf(fileOut,"NoteOn\t\t%.3f %d %.1f %.1f\n",dt,channel,byte2,byte3);
}
}
break;
case __SK_NoteOff_:
if (byte3 < 2.0) byte3 = 64.0;
sprintf(s,"NoteOff\t\t%.3f %d %.1f %.1f\n",0.0,channel,byte2,byte3);
if (writeFileOut) {
fprintf(fileOut,"NoteOff\t\t%.3f %d %.1f %.1f\n",dt,channel,byte2,byte3);
}
break;
case __SK_PolyPressure_:
sprintf(s,"PolyPressure\t%.3f %d %.1f %.1f\n",0.0,channel,byte2,byte3);
if (writeFileOut) {
fprintf(fileOut,"PolyPressure\t%.3f %d %.1f %.1f\n",dt,channel,byte2,byte3);
}
break;
case __SK_ControlChange_:
j = (int) byte2;
switch(j) {
case __SK_Volume_:
sprintf(s,"Volume\t%.3f %d %.1f\n",0.0,channel,byte3);
if (writeFileOut) {
fprintf(fileOut,"Volume\t%.3f %d %.1f\n",dt,channel,byte3);
}
break;
case __SK_ModWheel_:
sprintf(s,"ModWheel\t%.3f %d %.1f\n",0.0,channel,byte3);
if (writeFileOut) {
fprintf(fileOut,"ModWheel\t%.3f %d %.1f\n",dt,channel,byte3);
}
break;
case __SK_Breath_:
sprintf(s,"Breath\t\t%.3f %d %.1f\n",0.0,channel,byte3);
if (writeFileOut) {
fprintf(fileOut,"Breath\t\t%.3f %d %.1f\n",dt,channel,byte3);
}
break;
case __SK_FootControl_:
sprintf(s,"FootControl\t%.3f %d %.1f\n",0.0,channel,byte3);
if (writeFileOut) {
fprintf(fileOut,"FootControl\t%.3f %d %.1f\n",dt,channel,byte3);
}
break;
case __SK_Portamento_:
sprintf(s,"Portamento\t%.3f %d %.1f\n",0.0,channel,byte3);
if (writeFileOut) {
fprintf(fileOut,"Portamento\t%.3f %d %.1f\n",dt,channel,byte3);
}
break;
case __SK_Balance_:
sprintf(s,"Balance\t%.3f %d %.1f\n",0.0,channel,byte3);
if (writeFileOut) {
fprintf(fileOut,"Balance\t%.3f %d %.1f\n",dt,channel,byte3);
}
break;
case __SK_Pan_:
sprintf(s,"Pan\t\t%.3f %d %.1f\n",0.0,channel,byte3);
if (writeFileOut) {
fprintf(fileOut,"Pan\t\t%.3f %d %.1f\n",dt,channel,byte3);
}
break;
case __SK_Sustain_:
sprintf(s,"Sustain\t%.3f %d %.1f\n",0.0,channel,byte3);
if (writeFileOut) {
fprintf(fileOut,"Sustain\t%.3f %d %.1f\n",dt,channel,byte3);
}
break;
case __SK_Expression_:
sprintf(s,"Expression\t%.3f %d %.1f\n",0.0,channel,byte3);
if (writeFileOut) {
fprintf(fileOut,"Expression\t%.3f %d %.1f\n",dt,channel,byte3);
}
break;
default:
sprintf(s,"ControlChange\t%.3f %d %ld %.1f\n",0.0,channel,j,byte3);
if (writeFileOut) {
fprintf(fileOut,"ControlChange\t%.3f %d %ld %.1f\n",dt,channel,j,byte3);
}
break;
}
break;
case __SK_ProgramChange_:
j = (int) byte2;
sprintf(s,"ProgramChange\t%.3f %d %ld\n",0.0,channel,j);
if (writeFileOut) {
fprintf(fileOut,"ProgramChange\t%.3f %d %ld\n",dt,channel,j);
}
break;
case __SK_ChannelPressure_:
sprintf(s,"ChannelPressure\t%.3f %d %.1f\n",0.0,channel,byte2);
if (writeFileOut) {
fprintf(fileOut,"ChannelPressure\t%.3f %d %.1f\n",dt,channel,byte2);
}
break;
case __SK_PitchBend_:
sprintf(s,"PitchBend\t%.3f %d %f\n",0.0,channel,byte2);
if (writeFileOut) {
fprintf(fileOut,"PitchBend\t%.3f %d %f\n",dt,channel,byte2);
}
break;
default:
sprintf(s,"// Unknown\t%.3f %d %f %f\n",0.0,channel,byte2,byte3);
if (writeFileOut) {
fprintf(fileOut,"// Unknown\t\t%.3f %d %f %f\n",dt,channel,byte2,byte3);
}
break;
}
if (useSocket) {
if (send(theSocket, s, strlen(s), 0) < 0) {
fprintf(stderr,"Socket connection failed ... aborting.\n");
#if defined(__OS_Win_)
closesocket(theSocket);
WSACleanup();
#else
close(theSocket);
#endif
outAHere = 1;
exit(0);
}
}
else {
printf("%s", s);
fflush(stdout);
}
memset(s, 0, sizeof(s));
#if defined(__OS_Win_)
} else Sleep ( (DWORD) 2);
#else
} else usleep( (unsigned long) 2000);
#endif
}
sprintf(s,"Exiting MD2SKINI process ... bye!\n");
if (useSocket) {
send(theSocket, s, strlen(s), 0);
#if defined(__OS_Win_)
closesocket(theSocket);
WSACleanup();
#else
close(theSocket);
#endif
}
else {
printf("%s", s);
fflush(stdout);
}
if (writeFileOut) {
printf("Wrote SKINI output to file %s.\n", fileName);
fclose(fileOut);
}
delete controller;
}
#endif

582
STK/MIDIIO.cpp Normal file
View File

@@ -0,0 +1,582 @@
/******************************************/
/* MIDIIO.cpp */
/* Realtime MIDI I/O Object for STK, */
/* by Gary P. Scavone, 1998. */
/* Based in part on code by Perry */
/* Cook (SGI), Paul Leonard (Linux), */
/* the RoseGarden team (Linux), and */
/* Bill Putnam (Win95/NT). */
/* */
/* At the moment, this object only */
/* handles MIDI Input, though MIDI */
/* Output code can go here when someone */
/* decides they need it (and writes it). */
/* */
/* This object opens a MIDI Input device */
/* and parses MIDI messages into a MIDI */
/* buffer. Time stamp info is converted */
/* to deltaTime. MIDI data is stored as */
/* MY_FLOAT to conform with SKINI. */
/******************************************/
#include "MIDIIO.h"
#if defined(__STK_REALTIME_)
#define MIDI_BUFFER_SIZE 1024
int writeOffset;
int readOffset;
#if defined(__OS_IRIX_)
/*************************************/
/* SGI MIDI INPUT */
/*************************************/
#include <dmedia/midi.h>
#include <sys/types.h>
#include <sys/prctl.h>
#include <signal.h>
MDport inport;
MDevent *midiBuffer;
pid_t midi_input_pid;
void midiInputThread(void *)
{
MDevent newMessage;
int status;
while (1) {
mdReceive(inport, &newMessage, 1);
status = (newMessage.msg[0] & MD_STATUSMASK);
// Ignore Active Sensing messages
if (!((status & 0xff) == 0xfe || (status & 0xff) == 0xf8)) {
midiBuffer[writeOffset] = newMessage;
writeOffset++;
if( writeOffset >= MIDI_BUFFER_SIZE )
writeOffset = 0;
}
}
}
MIDIIO :: MIDIIO()
{
int nports;
nports = mdInit();
printf("%d MIDI devices available\n", nports);
inport = mdOpenInPort(NULL);
if (inport == NULL) {
fprintf(stderr,"Cannot open MIDI device.\n");
printf("Exiting MIDIIO Process.\n");
exit(0);
}
mdSetStampMode(inport, MD_NOSTAMP);
// Set up the circular buffer for the Midi Input Messages
midiBuffer = new MDevent[MIDI_BUFFER_SIZE];
readOffset = 0;
writeOffset = 0;
midi_input_pid = sproc(midiInputThread, PR_SALL);
if (midi_input_pid == -1) {
fprintf(stderr, "unable to create MIDI input thread...aborting.\n");
exit(0);
}
}
MIDIIO :: ~MIDIIO()
{
kill (midi_input_pid, SIGKILL);
mdClosePort(inport);
delete [] midiBuffer;
}
int MIDIIO :: nextMessage()
{
int status;
int byte1;
int byte2;
MDevent lastEvent;
static unsigned long long lastTimeStamp = 0;
if ( readOffset == writeOffset ) return 0;
lastEvent = midiBuffer[readOffset];
readOffset++;
if ( readOffset >= MIDI_BUFFER_SIZE ) readOffset = 0;
status = (lastEvent.msg[0] & MD_STATUSMASK);
byte1 = lastEvent.msg[1];
byte2 = lastEvent.msg[2];
channel = (lastEvent.msg[0] & MD_CHANNELMASK);
if ((status == MD_PROGRAMCHANGE) ||
(status == MD_CHANNELPRESSURE))
{
messageType = status;
byteTwo = (float) byte1;
deltaTime = (MY_FLOAT) ((lastEvent.stamp - lastTimeStamp) * 0.000000001);
lastTimeStamp = lastEvent.stamp;
}
else if ((status == MD_NOTEON) || (status == MD_NOTEOFF) ||
(status == MD_CONTROLCHANGE) || (status == MD_POLYKEYPRESSURE))
{
messageType = status;
byteTwo = (float) byte1;
byteThree = (float) byte2;
deltaTime = (MY_FLOAT) ((lastEvent.stamp - lastTimeStamp) * 0.000000001);
lastTimeStamp = lastEvent.stamp;
}
else if (status == MD_PITCHBENDCHANGE)
{
messageType = status;
byteTwo = (float) byte1 * NORM_7;
byteTwo += (float) byte2;
deltaTime = (MY_FLOAT) ((lastEvent.stamp - lastTimeStamp) * 0.000000001);
lastTimeStamp = lastEvent.stamp;
}
else
{
messageType = -1;
}
return messageType;
}
#elif defined(__OSS_API_)
/*************************************/
/* OSS MIDI INPUT */
/*************************************/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/soundcard.h>
#include <pthread.h>
//#include <pthread/mit/pthread.h>
int _seqfd;
typedef unsigned char byte;
typedef struct {
byte data[4];
unsigned long time;
} MIDIMESSAGE;
MIDIMESSAGE *midiBuffer;
/* System Messages */
#define MIDI_SYSTEM_MSG ((byte)0xF0)
#define MessageType(MSG) (byte)((MSG) & ((byte)0xF0))
#define SEQUENCER_PATH "/dev/sequencer"
/* MIDI time code at 100 ticks per second. */
#define OSS_MIDI_CLOCK_RATE 100
pthread_t midi_input_thread;
void *midiInputThread(void *)
{
byte NumArgs = 0;
byte ArgsLeft = 0;
unsigned long lastTime = 0;
unsigned long newTime = 0;
byte InBytes[4];
static MIDIMESSAGE newMessage;
int n;
while (1) {
if ((n = read(_seqfd, &InBytes, sizeof(InBytes))) == -1) {
fprintf(stderr,"Error reading " SEQUENCER_PATH "\n");
exit(0);
}
if (n == 4) { /* ignore reads returning less than 4 bytes */
switch ( InBytes[0] )
{
case SEQ_WAIT:
/* MIDI clock ticks ... the first MIDI message deltaTime is calculated
* with respect to the start of the MIDI clock.
*/
newTime = ((InBytes[3]<<16)|(InBytes[2]<<8)| InBytes[1]);
break;
case SEQ_ECHO:
/* no echo events yet defined */
#ifdef DEBUG
fprintf(stderr,"ECHO EVENT\n");
#endif
break;
case SEQ_MIDIPUTC:
/* Determination of a full MIDI message from the input MIDI stream is based
here on the observation that MIDI status bytes and subsequent data bytes
are NOT returned in the same read() call. Rather, they are spread out
over multiple read() returns, with only a single value per return. So,
if we find a status byte, we then determine the number of expected
operands and process that number of subsequent read()s to determine the
complete MIDI message.
*/
if (InBytes[1] & 0x80) { /* Status Byte */
if (MessageType(InBytes[1]) == MIDI_SYSTEM_MSG)
{
NumArgs = 0; /* no timing info */
#ifdef DEBUG
fprintf(stderr, "SYSTEM MESSAGE\n");
#endif
}
else if (MessageType(InBytes[1]) == MIDI_PGM_CHANGE ||
MessageType(InBytes[1]) == MIDI_CHN_PRESSURE)
{
NumArgs = 1;
}
else
{
NumArgs = 2;
}
newMessage.data[0] = InBytes[1];
ArgsLeft = NumArgs;
newMessage.data[1] = 0;
newMessage.data[2] = 0;
}
if (ArgsLeft && !(InBytes[1] & 0x80)) { /* not a status byte */
if (ArgsLeft == NumArgs)
newMessage.data[1] = InBytes[1];
else
{
newMessage.data[2] = InBytes[1];
}
--ArgsLeft;
/* If MIDI message complete, then setup for running status mode
(another event of the same type without status byte).
*/
if ( !ArgsLeft ) {
if (MessageType(newMessage.data[0]) == (int) MIDI_PGM_CHANGE ||
MessageType(newMessage.data[0]) == (int) MIDI_CHN_PRESSURE)
{
ArgsLeft = 1;
}
else
{
ArgsLeft = 2;
}
newMessage.time = newTime - lastTime;
lastTime = newTime;
// Put newMessage in the circular buffer
midiBuffer[writeOffset] = newMessage;
writeOffset++;
if( writeOffset >= MIDI_BUFFER_SIZE )
writeOffset = 0;
break;
}
}
default:
break;
}
}
}
}
MIDIIO :: MIDIIO()
{
int err = 0;
_seqfd = 0;
#ifdef NONBLOCKING_MIDI
if((_seqfd = open(SEQUENCER_PATH, O_RDONLY+O_NONBLOCK, 0)) == -1) {
#else
if((_seqfd = open(SEQUENCER_PATH, O_RDONLY, 0)) == -1) {
#endif
fprintf(stderr,"Cannot open " SEQUENCER_PATH ". \n");
printf("Exiting MIDIIO Process.\n");
exit(0);
}
// Set up the circular buffer for the Midi Input Messages
midiBuffer = new MIDIMESSAGE[MIDI_BUFFER_SIZE];
readOffset = 0;
writeOffset = 0;
err = pthread_create(&midi_input_thread, NULL, midiInputThread, NULL);
if (err)
{
fprintf(stderr, "Unable to create MIDI input thread.\n");
printf("Exiting MIDIIO Process.\n");
exit(0);
}
}
MIDIIO :: ~MIDIIO()
{
pthread_cancel(midi_input_thread);
if (_seqfd != 0) close(_seqfd);
delete [] midiBuffer;
}
int MIDIIO::nextMessage()
{
MIDIMESSAGE lastEvent;
if ( readOffset == writeOffset ) return 0;
lastEvent = midiBuffer[readOffset];
readOffset++;
if ( readOffset >= MIDI_BUFFER_SIZE ) readOffset = 0;
messageType = (int) (lastEvent.data[0] & 0xf0);
channel = (int) (lastEvent.data[0] & 0x0f);
byteTwo = (float) lastEvent.data[1];
if (messageType == (int) MIDI_PITCH_BEND)
byteTwo = (float) lastEvent.data[2] + (byteTwo * NORM_7);
else
byteThree = (float) lastEvent.data[2];
deltaTime = (float) lastEvent.time / OSS_MIDI_CLOCK_RATE;
return messageType;
}
#elif defined(__OS_Win_)
/*************************************/
/* Windoze MIDI INPUT */
/*************************************/
#include <stdio.h>
#include "MIDIIO.h"
#define MIDI_NOTEON 0x90
#define MIDI_NOTEOFF 0x80
#define MIDI_POLYKEYPRESSURE 0xA0
#define MIDI_CHANNELPRESSURE 0xD0
#define MIDI_PROGRAMCHANGE 0xC0
#define MIDI_CONTROLCHANGE 0xB0
#define MIDI_PITCHBEND 0xE0
typedef struct {
DWORD data;
DWORD time;
} MIDIMESSAGE;
MIDIMESSAGE *midiBuffer;
static void CALLBACK midiInputCallback( HMIDIOUT hmin, UINT inputStatus,
DWORD instancePtr, DWORD midiMessage, DWORD timestamp)
{
MIDIMESSAGE newMessage;
switch (inputStatus) {
case MIM_OPEN:
#ifdef TESTING_MIDI_IN
printf("MIM_OPEN\n");
#endif
break;
case MIM_CLOSE:
#ifdef TESTING_MIDI_IN
printf("MIM_CLOSE\n");
#endif
break;
case MIM_DATA:
#ifdef TESTING_MIDI_IN
printf("MIM_DATA\n");
#endif
// Ignore Active Sensing messages
if ((midiMessage & 0xff) == 0xfe || (midiMessage & 0xff) == 0xf8) {
break;
}
newMessage.data = midiMessage;
newMessage.time = timestamp;
// Put newMessage in the circular buffer
midiBuffer[writeOffset] = newMessage;
writeOffset++;
if( writeOffset >= MIDI_BUFFER_SIZE )
writeOffset = 0;
break;
case MIM_ERROR:
fprintf(stderr,"Invalid MIDI message received!\n");
#ifdef TESTING_MIDI_IN
printf("MIM_ERROR\n");
#endif
break;
case MIM_LONGDATA:
/* System exclusive buffer is returned */
break;
case MIM_LONGERROR:
#ifdef TESTING_MIDI_IN
printf("MIM_LONGERROR\n");
#endif
break;
default:
break;
}
}
HMIDIIN hMidiIn ; // Handle to Midi Output Device
MIDIIO :: MIDIIO()
{
MMRESULT result;
UINT uDeviceID;
MIDIINCAPS deviceCaps;
UINT i;
char inputString[128];
uDeviceID = midiInGetNumDevs();
printf("%i MIDI Input Devices Available.\n",uDeviceID);
if (uDeviceID == 0) {
printf("Exiting MIDIIO Process.\n");
exit(0);
}
for (i=0; i<uDeviceID; i++) {
result = midiInGetDevCaps(i, &deviceCaps, sizeof(MIDIINCAPS));
printf("MIDI Device %d is %s.\n", i, deviceCaps.szPname);
}
if (uDeviceID > 1) {
printf("\nType the MIDI Device to open: ");
fgets(inputString, 128, stdin);
uDeviceID = (UINT) atoi(inputString);
}
else uDeviceID -= 1;
// Open the port and return any errors
result = midiInOpen(&hMidiIn, uDeviceID, (DWORD)&midiInputCallback, (DWORD)NULL, CALLBACK_FUNCTION);
if (result != MMSYSERR_NOERROR) {
fprintf(stderr,"Cannot open MIDI Input Device %d!\n", uDeviceID);
printf("Exiting MIDIIO Process.\n");
exit(0);
}
// Set up the circular buffer for the Midi Input Messages
midiBuffer = new MIDIMESSAGE[MIDI_BUFFER_SIZE];
readOffset = 0;
writeOffset = 0;
midiInStart( hMidiIn );
}
MIDIIO :: ~MIDIIO()
{
midiInReset( hMidiIn );
midiInStop( hMidiIn );
midiInClose( hMidiIn );
delete [] midiBuffer;
}
int MIDIIO :: nextMessage()
{
int status;
int byte1;
int byte2;
MIDIMESSAGE lastEvent;
static DWORD lastTime = 0;
static DWORD newTime = 0;
if ( readOffset == writeOffset ) return 0;
lastEvent = midiBuffer[readOffset];
readOffset++;
if ( readOffset >= MIDI_BUFFER_SIZE ) readOffset = 0;
status = (int) (lastEvent.data & 0xff);
byte1 = (int) (lastEvent.data & 0xff00) >> 8;
byte2 = (int) (lastEvent.data & 0xff0000) >> 16;
channel = (int) (status & 0x0f);
status &= 0xf0; // Clear lower byte of status
newTime = lastEvent.time;
deltaTime = (float) (newTime - lastTime) * 0.001;
lastTime = newTime;
if ((status == MIDI_PROGRAMCHANGE) ||
(status == MIDI_CHANNELPRESSURE))
{
messageType = status;
byteTwo = (float) byte1;
}
else if ((status == MIDI_NOTEON) || (status == MIDI_NOTEOFF) ||
(status == MIDI_CONTROLCHANGE) || (status == MIDI_POLYKEYPRESSURE))
{
messageType = status;
byteTwo = (float) byte1;
byteThree = (float) byte2;
}
else if (status == MIDI_PITCHBEND)
{
messageType = status;
byteTwo = (float) (byte1 * NORM_7);
byteTwo += (float) byte2;
}
else
{
messageType = -1;
}
return messageType;
}
#endif
void MIDIIO :: printMessage()
{
printf("type = %d, channel = %d, byte2 = %f, byte3 = %f\n",
this->getType(), this->getChannel(), this->getByteTwo(),
this->getByteThree());
}
int MIDIIO :: getType()
{
return messageType;
}
int MIDIIO :: getChannel()
{
return channel;
}
MY_FLOAT MIDIIO :: getByteTwo()
{
return byteTwo;
}
MY_FLOAT MIDIIO :: getByteThree()
{
return byteThree;
}
MY_FLOAT MIDIIO :: getDeltaTime()
{
return deltaTime;
}
#endif

56
STK/MIDIIO.h Normal file
View File

@@ -0,0 +1,56 @@
/******************************************/
/* MIDIIO.h */
/* Realtime MIDI I/O Object for STK, */
/* by Gary P. Scavone, 1998. */
/* Based in part on code by Perry */
/* Cook (SGI), Paul Leonard (Linux), */
/* the RoseGarden team (Linux), and */
/* Bill Putnam (Win95/NT). */
/* */
/* At the moment, this object only */
/* handles MIDI Input, though MIDI */
/* Output code can go here when someone */
/* decides they need it (and writes it). */
/* */
/* This object opens a MIDI Input device */
/* and parses MIDI data. Time stamp */
/* info is converted to deltaTime. */
/* MIDI data is stored as MY_FLOAT to */
/* conform with SKINI. */
/******************************************/
#if !defined(__MIDIIO_h)
#define __MIDIIO_h
#include "Object.h"
class MIDIIO : public Object
{
protected:
int messageType;
int channel;
float byteTwo;
float byteThree;
MY_FLOAT deltaTime;
public:
MIDIIO();
~MIDIIO();
void printMessage();
int nextMessage();
int getType();
int getChannel();
MY_FLOAT getByteTwo();
MY_FLOAT getByteThree();
MY_FLOAT getDeltaTime();
};
#if defined(__OS_Win_)
#include <windows.h>
#include <mmsystem.h>
static void CALLBACK midiInputCallback( HMIDIOUT hmin, UINT inputStatus,
DWORD instancePtr, DWORD midiMessage, DWORD timestamp);
#endif
#endif

152
STK/Mandolin.cpp Normal file
View File

@@ -0,0 +1,152 @@
/********************************************/
/* Commuted Mandolin Subclass of enhanced */
/* dual plucked-string model */
/* by Perry Cook, 1995-96 */
/* */
/* Controls: CONTROL1 = bodySize */
/* CONTROL2 = pluckPosition */
/* CONTROL3 = loopGain */
/* MOD_WHEEL= deTuning */
/* */
/* Note: Commuted Synthesis, as with many */
/* other WaveGuide techniques, is covered */
/* by patents, granted, pending, and/or */
/* applied-for. Many are assigned to the */
/* Board of Trustees, Stanford University. */
/* For information, contact the Office of */
/* Technology Licensing, Stanford U. */
/********************************************/
#include "Mandolin.h"
#include "SKINI11.msg"
Mandolin :: Mandolin(MY_FLOAT lowestFreq) : Plucked2(lowestFreq)
{
// Concatenate the STK RAWWAVE_PATH to the rawwave file
char temp[128];
strcpy(temp, RAWWAVE_PATH);
soundfile[0] = new RawWvIn(strcat(temp,"rawwaves/mand1.raw"),"oneshot");
strcpy(temp, RAWWAVE_PATH);
soundfile[1] = new RawWvIn(strcat(temp,"rawwaves/mand2.raw"),"oneshot");
strcpy(temp, RAWWAVE_PATH);
soundfile[2] = new RawWvIn(strcat(temp,"rawwaves/mand3.raw"),"oneshot");
strcpy(temp, RAWWAVE_PATH);
soundfile[3] = new RawWvIn(strcat(temp,"rawwaves/mand4.raw"),"oneshot");
strcpy(temp, RAWWAVE_PATH);
soundfile[4] = new RawWvIn(strcat(temp,"rawwaves/mand5.raw"),"oneshot");
strcpy(temp, RAWWAVE_PATH);
soundfile[5] = new RawWvIn(strcat(temp,"rawwaves/mand6.raw"),"oneshot");
strcpy(temp, RAWWAVE_PATH);
soundfile[6] = new RawWvIn(strcat(temp,"rawwaves/mand7.raw"),"oneshot");
strcpy(temp, RAWWAVE_PATH);
soundfile[7] = new RawWvIn(strcat(temp,"rawwaves/mand8.raw"),"oneshot");
strcpy(temp, RAWWAVE_PATH);
soundfile[8] = new RawWvIn(strcat(temp,"rawwaves/mand9.raw"),"oneshot");
strcpy(temp, RAWWAVE_PATH);
soundfile[9] = new RawWvIn(strcat(temp,"rawwaves/mand10.raw"),"oneshot");
strcpy(temp, RAWWAVE_PATH);
soundfile[10] = new RawWvIn(strcat(temp,"rawwaves/mand11.raw"),"oneshot");
strcpy(temp, RAWWAVE_PATH);
soundfile[11] = new RawWvIn(strcat(temp,"rawwaves/mand12.raw"),"oneshot");
directBody = 1.0;
mic = 0;
dampTime = 0;
waveDone = 1;
}
Mandolin :: ~Mandolin()
{
}
void Mandolin :: pluck(MY_FLOAT amplitude)
{ /* this function gets interesting here, */
/* because pluck may be longer than */
/* string length, so we just reset the */
/* soundfile and add in the pluck in */
/* the tick method. */
soundfile[mic]->reset();
pluckAmp = amplitude;
/* Set Pick Position which puts zeroes at pos*length */
combDelay->setDelay((MY_FLOAT) 0.5 * pluckPos * lastLength);
dampTime = (long) lastLength; /* See tick method below */
waveDone = 0;
}
void Mandolin :: pluck(MY_FLOAT amplitude, MY_FLOAT position)
{
pluckPos = position; /* pluck position is zeroes at pos*length */
this->pluck(amplitude);
}
void Mandolin :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
this->setFreq(freq);
this->pluck(amp);
#if defined(_debug_)
printf("Mandolin : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}
void Mandolin :: setBodySize(MY_FLOAT size)
{
int i;
for (i=0;i<12;i++) {
soundfile[i]->setRate(size);
}
}
MY_FLOAT Mandolin :: tick()
{
MY_FLOAT temp = (MY_FLOAT) 0;
if (!waveDone) {
waveDone = soundfile[mic]->informTick(); /* as long as it goes . . . */
temp = soundfile[mic]->lastOut() * pluckAmp; /* scaled pluck excitation */
temp = temp - combDelay->tick(temp); /* with comb filtering */
}
if (dampTime>=0) { /* Damping hack to help avoid */
dampTime -= 1; /* overflow on replucking */
lastOutput = delayLine->tick( /* Calculate 1st delay */
filter->tick( /* filterered reflection */
temp + /* plus pluck excitation */
(delayLine->lastOut() * (MY_FLOAT) 0.7)));
lastOutput += delayLine2->tick( /* and 2nd delay */
filter2->tick( /* just like the 1st */
temp +
(delayLine2->lastOut() * (MY_FLOAT) 0.7)));
}
else { /* No damping hack after 1 period */
lastOutput = delayLine->tick( /* Calculate 1st delay */
filter->tick( /* filtered reflection */
temp + /* plus pluck excitation */
(delayLine->lastOut() * loopGain)));
lastOutput += delayLine2->tick( /* and 2nd delay */
filter2->tick( /* just like the 1st */
temp +
(delayLine2->lastOut() * loopGain)));
}
lastOutput *= (MY_FLOAT) 0.3 / 32768.0;
return lastOutput;
}
void Mandolin :: controlChange(int number, MY_FLOAT value)
{
#if defined(_debug_)
printf("Mandolin : ControlChange: Number=%i Value=%f\n",number,value);
#endif
if (number == __SK_BodySize_)
this->setBodySize(value * (MY_FLOAT) NORM_7 * (MY_FLOAT) 2.0);
else if (number == __SK_PickPosition_)
this->setPluckPos(value * (MY_FLOAT) NORM_7);
else if (number == __SK_StringDamping_)
this->setBaseLoopGain((MY_FLOAT) 0.97 + (value * (MY_FLOAT) NORM_7 * (MY_FLOAT) 0.03));
else if (number == __SK_StringDetune_)
this->setDetune((MY_FLOAT) 1.0 - (value * (MY_FLOAT) NORM_7 * (MY_FLOAT) 0.1));
else if (number == __SK_AfterTouch_)
this->pluck(value * (MY_FLOAT) NORM_7);
else if (number == 411) {
mic = (int) value % 12;
}
else {
printf("Mandolin : Undefined Control Number!! %i\n",number);
}
}

44
STK/Mandolin.h Normal file
View File

@@ -0,0 +1,44 @@
/********************************************/
/* Commuted Mandolin Subclass of enhanced */
/* dual plucked-string model */
/* by Perry Cook, 1995-96 */
/* Controls: CONTROL1 = bodySize */
/* CONTROL2 = pluckPosition */
/* CONTROL3 = loopGain */
/* MOD_WHEEL= deTuning */
/* */
/* Note: Commuted Synthesis, as with many */
/* other WaveGuide techniques, is covered */
/* by patents, granted, pending, and/or */
/* applied-for. All are assigned to the */
/* Board of Trustees, Stanford University. */
/* For information, contact the Office of */
/* Technology Licensing, Stanford U. */
/********************************************/
#if !defined(__Mandolin_h)
#define __Mandolin_h
#include "Plucked2.h"
#include "RawWvIn.h"
class Mandolin : public Plucked2
{
protected:
RawWvIn *soundfile[12];
MY_FLOAT directBody;
int mic;
long dampTime;
int waveDone;
public:
Mandolin(MY_FLOAT lowestFreq);
virtual ~Mandolin();
void pluck(MY_FLOAT amplitude);
void pluck(MY_FLOAT amplitude,MY_FLOAT position);
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
void setBodySize(MY_FLOAT size);
virtual void controlChange(int number, MY_FLOAT value);
virtual MY_FLOAT tick();
};
#endif

116
STK/Marimba.cpp Normal file
View File

@@ -0,0 +1,116 @@
/*******************************************/
/* Marimba SubClass of Modal4 Instrument, */
/* by Perry R. Cook, 1995-96 */
/* */
/* Controls: CONTROL1 = stickHardness */
/* CONTROL2 = strikePosition*/
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/*******************************************/
#include "Marimba.h"
#include "SKINI11.msg"
Marimba :: Marimba() : Modal4()
{
// Concatenate the STK RAWWAVE_PATH to the rawwave file
char file[128];
strcpy(file, RAWWAVE_PATH);
wave = new RawWvIn(strcat(file,"rawwaves/marmstk1.raw"),"oneshot");
wave->normalize();
wave->setRate((MY_FLOAT) 0.5); /* normal stick */
this->setRatioAndReson(0, (MY_FLOAT) 1.00,(MY_FLOAT) 0.9996); /* Set all 132.0 */
this->setRatioAndReson(1, (MY_FLOAT) 3.99,(MY_FLOAT) 0.9994); /* of our 523.0 */
this->setRatioAndReson(2,(MY_FLOAT) 10.65,(MY_FLOAT) 0.9994); /* default 1405.0 */
this->setRatioAndReson(3,-(MY_FLOAT) 2443.0,(MY_FLOAT) 0.999); /* resonances 2443.0 */
this->setFiltGain(0,(MY_FLOAT) 0.04); /* and */
this->setFiltGain(1,(MY_FLOAT) 0.01); /* gains */
this->setFiltGain(2,(MY_FLOAT) 0.01); /* for each */
this->setFiltGain(3,(MY_FLOAT) 0.008); /* resonance */
directGain = (MY_FLOAT) 0.1;
multiStrike = 0;
}
Marimba :: ~Marimba()
{
delete wave;
}
void Marimba :: setStickHardness(MY_FLOAT hardness)
{
stickHardness = hardness;
wave->setRate((MY_FLOAT) (0.25 * (MY_FLOAT) pow(4.0,stickHardness)));
masterGain = (MY_FLOAT) 0.1 + ((MY_FLOAT) 1.8 * stickHardness);
}
void Marimba :: setStrikePosition(MY_FLOAT position)
{
MY_FLOAT temp,temp2;
temp2 = position * PI;
strikePosition = position; /* Hack only first three modes */
temp = (MY_FLOAT) sin(temp2);
this->setFiltGain(0,(MY_FLOAT) 0.12 * temp); /* 1st mode function of pos. */
temp = (MY_FLOAT) sin(0.05 + (3.9 * temp2));
this->setFiltGain(1,(MY_FLOAT) -0.03 * temp); /* 2nd mode function of pos. */
temp = (MY_FLOAT) sin(-0.05 + (11 * temp2));
this->setFiltGain(2,(MY_FLOAT) 0.11 * temp); /* 3rd mode function of pos. */
}
void Marimba :: setModulationSpeed(MY_FLOAT mSpeed)
{
/* don't bother here, marimba decay so fast, mod doesn't make sense */
}
void Marimba :: setModulationDepth(MY_FLOAT mDepth)
{
}
void Marimba :: strike(MY_FLOAT amplitude)
{
int temp;
temp = rand() >> 10;
if (temp < 2) {
multiStrike = 1;
#if defined(_debug_)
printf("striking twice here!!\n");
#endif
}
else if (temp < 1) {
multiStrike = 2;
#if defined(_debug_)
printf("striking three times here!!!\n");
#endif
}
else multiStrike = 0;
Modal4::strike(amplitude);
}
void Marimba :: controlChange(int number, MY_FLOAT value)
{
#if defined(_debug_)
printf("Marimba : ControlChange: Number=%i Value=%f\n",number,value);
#endif
if (number == __SK_StickHardness_)
this->setStickHardness(value * NORM_7);
else if (number == __SK_StrikePosition_)
this->setStrikePosition(value * NORM_7);
else if (number == __SK_ModFrequency_)
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
else if (number == __SK_ModWheel_)
vibrGain = (value * NORM_7);
else if (number == __SK_AfterTouch_Cont_)
this->strike(value * NORM_7);
else {
printf("Marimba : Undefined Control Number!!\n");
}
}
MY_FLOAT Marimba :: tick()
{
if (multiStrike>0)
if (wave->isFinished()) {
wave->reset();
multiStrike -= 1;
}
return Modal4::tick();
}

32
STK/Marimba.h Normal file
View File

@@ -0,0 +1,32 @@
/*******************************************/
/* Marimba SubClass of Modal4 Instrument, */
/* by Perry R. Cook, 1995-96 */
/* */
/* Controls: CONTROL1 = stickHardness */
/* CONTROL2 = strikePosition*/
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/*******************************************/
#if !defined(__Marimba_h)
#define __Marimba_h
#include "Modal4.h"
class Marimba : public Modal4
{
private:
int multiStrike;
public:
Marimba();
~Marimba();
void setStickHardness(MY_FLOAT hardness);
void setStrikePosition(MY_FLOAT position);
void setModulationSpeed(MY_FLOAT mSpeed);
void setModulationDepth(MY_FLOAT mDepth);
virtual void strike(MY_FLOAT amplitude);
virtual void controlChange(int number, MY_FLOAT value);
virtual MY_FLOAT tick();
};
#endif

178
STK/MatWvIn.cpp Normal file
View File

@@ -0,0 +1,178 @@
/*******************************************/
/* MatWvIn Input Class, */
/* by Gary P. Scavone, 1999 */
/* */
/* This object inherits from WvIn and is */
/* used to open Matlab MAT-file data */
/* (doubles) files for playback. In */
/* order for this class to work, the */
/* MAT-file must contain a single array */
/* (matrix) of double-precision floating */
/* point values (can be multi-channel). */
/* It does not work for any other data */
/* formats. */
/* */
/* MAT-file data is either big- or */
/* little-endian, which can be determined */
/* from the header. */
/*******************************************/
#include "MatWvIn.h"
#include "swapstuf.h"
MatWvIn :: MatWvIn(char *fileName, char *mode)
{
extern double SwapDouble(double);
// Open the file and get header info
FILE *fd;
fd = fopen(fileName,"rb");
if (!fd) {
printf("Couldn't open or find MAT-file %s !!!\n",fileName);
exit(0);
}
// Make sure this is a version 5 MAT-file format and find its endian-ness
char head[4];
fseek(fd,0,SEEK_SET);
fread(&head,4,1,fd); // If any of the first 4 characters of the header = 0,
if (strstr(head,"0")) { // then this is a Version 4 MAT-file.
printf("This looks like a Version 4 MAT-file. I don't support\n");
printf("that at the moment, but you can add the code to MatWvIn if\n");
printf("you really need it.\n");
exit(0);
}
char mi[2];
int swap = 0;
fseek(fd,126,SEEK_SET); // Locate "M" and "I" characters in header
fread(&mi,2,1,fd);
#ifdef __LITTLE_ENDIAN__
if (!strncmp(mi,"MI",2)) {
swap = 1;
} else if (strncmp(mi,"IM",2)) {
printf("This doesn't appear to be a MAT-file %s !!!\n",fileName);
exit(0);
}
#else
if (!strncmp(mi,"IM",2)) {
swap = 1;
} else if (strncmp(mi,"MI",2)) {
printf("This doesn't appear to be a MAT-file %s !!!\n",fileName);
exit(0);
}
#endif
// Check the data element type
INT32 datatype;
fread(&datatype,4,1,fd);
if (swap) datatype = SwapINT32(datatype);
if (datatype != 14) {
printf("I'm expecting a single array (or matrix) data element.\n");
printf("This doesn't appear to be the case with your data. Sorry!\n");
exit(0);
}
// Check the array data type
INT32 tmp;
INT32 size;
fseek(fd,168,SEEK_SET);
fread(&tmp,4,1,fd);
if (swap) tmp = SwapINT32(tmp);
if (tmp == 1) { // array name > 4 characters
fread(&tmp,4,1,fd); // get array name length
if (swap) tmp = SwapINT32(tmp);
size = (INT32) ceil((float)tmp/8);
fseek(fd,size*8,SEEK_CUR); // jump over array name
}
else { // array name <= 4 characters, compressed data element
fseek(fd,4,SEEK_CUR);
}
fread(&tmp,4,1,fd);
if (swap) tmp = SwapINT32(tmp);
if (tmp != 9) {
printf("I'm expecting the array data to be in double precision\n");
printf("floating-point format. This doesn't appear to be the case\n");
printf("with your data. Sorry!\n");
exit(0);
}
// Get number of rows from the header
INT32 rows;
fseek(fd,160,SEEK_SET);
fread(&rows,4,1,fd); // rows
if (swap) rows = SwapINT32(rows);
// Get number of columns from the header
INT32 columns;
fread(&columns,4,1,fd); // columns
if (swap) columns = SwapINT32(columns);
// Make channels = smaller of rows or columns
if (rows < columns) {
channels = rows;
length = columns;
}
else {
channels = columns;
length = rows;
}
data = (MY_FLOAT *) new MY_FLOAT[(length+1)*channels];
// Move read pointer to the data in the file
INT32 headsize;
fseek(fd,132,SEEK_SET);
fread(&headsize,4,1,fd); // file size from 132nd byte
if (swap) headsize = SwapINT32(headsize);
headsize -= length * 8 * channels;
fseek(fd,headsize,SEEK_CUR);
// Read samples into data[]
long i = 0;
double temp;
if (channels == rows) {
while (fread(&temp,8,1,fd)) {
if (swap) temp = SwapDouble(temp);
data[i++] = (MY_FLOAT) temp;
}
} else {
long j = 0;
while (fread(&temp,8,1,fd)) {
if (swap) temp = SwapDouble(temp);
data[channels*i+j] = (MY_FLOAT) temp;
i++;
if (!(i<length)) {
i = 0;
j++;
}
}
}
fclose(fd);
// Setup for looping or one-shot playback
if (!strcmp(mode,"looping")) {
looping = 1;
for (int j=0; j<channels; j++)
data[length*channels+j] = data[j]; // extra sample for interpolation
}
else if (!strcmp(mode,"oneshot")) {
looping = 0;
for (int j=0; j<channels; j++)
data[length*channels+j] = data[(length-1)*channels+j]; // extra sample for interpolation
}
else {
fprintf(stderr,"ERROR: Unsupported MatWvIn mode: %s\n",mode);
free(data);
exit(0);
}
rate = (MY_FLOAT) 1.0;
interpolate = 0;
time = (MY_FLOAT) 0.0;
phaseOffset = (MY_FLOAT) 0.0;
finished = 0;
lastOutput = (MY_FLOAT *) calloc(channels, sizeof(MY_FLOAT));
}
MatWvIn :: ~MatWvIn()
{
}

33
STK/MatWvIn.h Normal file
View File

@@ -0,0 +1,33 @@
/*******************************************/
/* MatWvIn Input Class, */
/* by Gary P. Scavone, 1999 */
/* */
/* This object inherits from WvIn and is */
/* used to open Matlab MAT-file data */
/* (doubles) files for playback. In */
/* order for this class to work, the */
/* MAT-file must contain a single array */
/* (matrix) of double-precision floating */
/* point values (can be multi-channel). */
/* It does not work for any other data */
/* formats. */
/* */
/* MAT-file data is either big- or */
/* little-endian, which can be determined */
/* from the header. */
/*******************************************/
#if !defined(__MatWvIn_h)
#define __MatWvIn_h
#include "Object.h"
#include "WvIn.h"
class MatWvIn : public WvIn
{
public:
MatWvIn(char *fileName, char *mode);
~MatWvIn();
};
#endif

199
STK/MatWvOut.cpp Normal file
View File

@@ -0,0 +1,199 @@
/*******************************************/
/* Matlab MAT-file Output Class, */
/* by Gary P. Scavone, 1999. */
/* This object creates a Matlab MAT-file */
/* structure with a numeric array */
/* subelement and fills it with buffers */
/* of samples (doubles). */
/* */
/* When originally created, the Matlab */
/* MAT-file format was not public and I */
/* had to reverse-engineer the format. */
/* Matlab finally released the format in */
/* the Spring of 1999, and this class was */
/* updated to more closely adhere to */
/* specifications. */
/*******************************************/
#include "MatWvOut.h"
/******** Matlab Matfile Header Struct *******/
struct matheaderform {
char heading[124]; // Header text field
INT16 hff[2]; // Header flag fields
INT32 adf[11]; // Array data format fields
// There's more, but it's of variable length
};
FILE *openMatFile(int chans,char *fileName) {
struct matheaderform hdr;
FILE *fd;
char tempName[128];
char arrayName[128];
int i;
INT32 tmp, headsize, namelen;
strcpy(hdr.heading,"MATLAB 5.0 MAT-file, Generated using the Synthesis ToolKit (STK). By Gary P. Scavone, CCRMA, Stanford University, 1999.");
for (i=strlen(hdr.heading);i<124;i++) hdr.heading[i] = ' ';
// Header Flag Fields
hdr.hff[0] = (INT16) 0x0100; // Version field
hdr.hff[1] = (INT16) 'M'; // Endian indicator field ("MI")
hdr.hff[1] <<= 8;
hdr.hff[1] += 'I';
hdr.adf[0] = (INT32) 14; // Matlab array data type value
hdr.adf[1] = (INT32) 0; // Size of file after this point to end (in bytes)
// Don't know size yet.
// Numeric Array Subelements (4):
// 1. Array Flags
hdr.adf[2] = (INT32) 6; // Matlab 32-bit unsigned integer data type value
hdr.adf[3] = (INT32) 8; // 8 bytes of data to follow
hdr.adf[4] = (INT32) 6; // Double-precision array, no array flags set
hdr.adf[5] = (INT32) 0; // 4 bytes undefined
// 2. Array Dimensions
hdr.adf[6] = (INT32) 5; // Matlab 32-bit signed integer data type value
hdr.adf[7] = (INT32) 8; // 8 bytes of data to follow (2D array)
hdr.adf[8] = (INT32) chans; // This is the number of rows
hdr.adf[9] = (INT32) 0; // This is the number of columns
// 3. Array Name
// We'll use fileName for the matlab array name (as well as the file name).
// If fileName is 4 characters or less, we have to use a compressed data element
// format for the array name data element. Otherwise, the array name must
// be formatted in 8-byte increments (up to 31 characters + NULL).
namelen = strlen(fileName);
if (strstr(fileName,".mat")) namelen -= 4;
if (namelen > 31) { // Check length of array name
namelen = 31;
printf("File name too long for MATLAB array name.\n");
printf("Using first 31 characters only.\n");
}
strncpy(arrayName,fileName,namelen);
if (namelen > 4) {
hdr.adf[10] = 1; // Matlab 8-bit signed integer data type value
}
else { // Compressed data element format
hdr.adf[10] = namelen;
hdr.adf[10] <<=16;
hdr.adf[10] += 1;
}
headsize = 40; // Number of bytes in data element so far
// Format file name
strcpy(tempName,fileName);
if (strstr(tempName,".mat")==NULL) strcat(tempName,".mat");
// Open file and write fixed header information
fd = fopen(tempName,"w+b");
if (!fd) {
printf("Couldn't create matfile %s !!!!!!!!\n",fileName);
exit(0);
}
arrayName[namelen] = '\0';
printf("\nCreating MAT-file %s with MATLAB array %s\n\n", tempName, arrayName);
fwrite(&hdr,sizeof(char),172,fd); // Write the fixed portion of the header
// Write MATLAB array name
if (namelen > 4) {
fwrite(&namelen,sizeof(INT32),1,fd); // Size of array name in bytes (chars)
fwrite(arrayName,sizeof(char),namelen,fd);
tmp = (INT32) ceil((float)namelen/8);
fseek(fd,tmp*8-namelen,SEEK_CUR);
headsize += tmp*8;
}
else { // Compressed data element format
fwrite(arrayName,sizeof(char),namelen,fd);
tmp = 4-namelen;
fseek(fd,tmp,SEEK_CUR);
}
// Finish writing known header information
tmp = 9; // Matlab IEEE 754 double data type
fwrite(&tmp,sizeof(INT32),1,fd);
tmp = 0; // Size of real part subelement in bytes (8 per sample)
fwrite(&tmp,sizeof(INT32),1,fd);
headsize += 8; // Total number of bytes in data element so far
fseek(fd,132,SEEK_SET);
fwrite(&headsize,sizeof(INT32),1,fd); // Write header size ... will update at end
fseek(fd,0,SEEK_END);
return fd;
}
MatWvOut :: MatWvOut(char *fileName)
{
channels = 1;
fd = openMatFile(channels,fileName);
counter = 0;
totalCount = 0;
}
MatWvOut :: MatWvOut(int chans, char *fileName)
{
channels = chans;
fd = openMatFile(channels,fileName);
counter = 0;
totalCount = 0;
}
MatWvOut :: ~MatWvOut()
{
double temp;
INT32 headsize, temp1;
fwrite(data,sizeof(double),counter,fd);
temp = (double) totalCount * ONE_OVER_SRATE;
printf("%f Seconds Computed\n",temp);
fseek(fd,164,SEEK_SET);
fwrite(&totalCount,sizeof(INT32),1,fd); /* Write number of columns */
fseek(fd,132,SEEK_SET);
fread(&headsize,sizeof(INT32),1,fd);
temp1 = headsize;
headsize += (INT32) (totalCount * 8 * channels);
fseek(fd,132,SEEK_SET);
fwrite(&headsize,sizeof(INT32),1,fd); /* Write file size (minus some header info) */
fseek(fd,temp1+132,SEEK_SET);
temp1 = totalCount * 8 * channels;
fwrite(&temp1,sizeof(INT32),1,fd); /* Write data size (in bytes) */
fclose(fd);
}
INT32 MatWvOut :: getCounter()
{
return totalCount;
}
MY_FLOAT MatWvOut :: getTime()
{
return (MY_FLOAT) totalCount * ONE_OVER_SRATE;
}
void MatWvOut :: tick(MY_FLOAT sample)
{
for (int i=0;i<channels;i++)
data[counter++] = (double) (sample);
totalCount++;
if (counter == MAT_BUFFER_SIZE) {
fwrite(data,sizeof(double),MAT_BUFFER_SIZE,fd);
counter = 0;
}
}
void MatWvOut :: mtick(MY_MULTI samples)
{
for (int i=0;i<channels;i++)
data[counter++] = (double) *samples++;
totalCount++;
if (counter == MAT_BUFFER_SIZE) {
fwrite(data,sizeof(double),MAT_BUFFER_SIZE,fd);
counter = 0;
}
}

44
STK/MatWvOut.h Normal file
View File

@@ -0,0 +1,44 @@
/*******************************************/
/* Matlab MAT-file Output Class, */
/* by Gary P. Scavone, 1999. */
/* This object creates a Matlab MAT-file */
/* structure with a numeric array */
/* subelement and fills it with buffers */
/* of samples (doubles). */
/* */
/* When originally created, the Matlab */
/* MAT-file format was not public and I */
/* had to reverse-engineer the format. */
/* Matlab finally released the format in */
/* the Spring of 1999, and this class was */
/* updated to more closely adhere to */
/* specifications. */
/*******************************************/
#include "Object.h"
#include "WvOut.h"
#if !defined(__MatWvOut_h)
#define __MatWvOut_h
#define MAT_BUFFER_SIZE 1024
class MatWvOut : public WvOut
{
protected:
FILE *fd;
double data[MAT_BUFFER_SIZE]; /* not MY_FLOAT because MAT-file uses doubles */
INT32 counter;
INT32 totalCount;
int channels;
public:
MatWvOut(char *infileName);
MatWvOut(int chans, char *infileName);
~MatWvOut();
INT32 getCounter();
MY_FLOAT getTime();
void tick(MY_FLOAT sample);
void mtick(MY_MULTI samples);
};
#endif // defined(__MatWvOut_h)

189
STK/Modal4.cpp Normal file
View File

@@ -0,0 +1,189 @@
/*******************************************/
/* 4 Resonance Modal Synthesis Instrument */
/* by Perry R. Cook, 1995-96 */
/* This instrument contains an excitation */
/* wavetable, an envelope, and four reso- */
/* nances (Non-Sweeping BiQuad Filters). */
/*******************************************/
#include "Modal4.h"
Modal4 :: Modal4()
{
envelope = new Envelope;
// We don't make the excitation wave here yet,
// because we don't know what it's going to be.
filters[0] = new BiQuad;
filters[1] = new BiQuad;
filters[2] = new BiQuad;
filters[3] = new BiQuad;
onepole = new OnePole;
// Concatenate the STK RAWWAVE_PATH to the rawwave file
char file[128];
strcpy(file, RAWWAVE_PATH);
vibr = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping");
vibr->normalize();
vibr->setFreq((MY_FLOAT) 6.0);
vibrGain = (MY_FLOAT) 0.05;
directGain = (MY_FLOAT) 0.0;
masterGain = (MY_FLOAT) 1.0;
baseFreq = (MY_FLOAT) 440.0;
this->setRatioAndReson(0,(MY_FLOAT) 1.00,(MY_FLOAT) 0.9997); /* Set some */
this->setRatioAndReson(1,(MY_FLOAT) 1.30,(MY_FLOAT) 0.9997); /* silly */
this->setRatioAndReson(2,(MY_FLOAT) 1.77,(MY_FLOAT) 0.9997); /* default */
this->setRatioAndReson(3,(MY_FLOAT) 2.37,(MY_FLOAT) 0.9997); /* values here */
this->setFiltGain(0,(MY_FLOAT) 0.01);
this->setFiltGain(1,(MY_FLOAT) 0.01);
this->setFiltGain(2,(MY_FLOAT) 0.01);
this->setFiltGain(3,(MY_FLOAT) 0.01);
this->clear();
filters[0]->setEqualGainZeroes();
filters[1]->setEqualGainZeroes();
filters[2]->setEqualGainZeroes();
filters[3]->setEqualGainZeroes();
stickHardness = (MY_FLOAT) 0.5;
strikePosition = (MY_FLOAT) 0.561;
}
Modal4 :: ~Modal4()
{
delete envelope;
delete filters[0];
delete filters[1];
delete filters[2];
delete filters[3];
delete onepole;
delete vibr;
}
void Modal4 :: clear()
{
onepole->clear();
filters[0]->clear();
filters[1]->clear();
filters[2]->clear();
filters[3]->clear();
}
void Modal4 :: setFreq(MY_FLOAT frequency)
{
baseFreq = frequency;
this->setRatioAndReson(0,ratios[0],resons[0]);
this->setRatioAndReson(1,ratios[1],resons[1]);
this->setRatioAndReson(2,ratios[2],resons[2]);
this->setRatioAndReson(3,ratios[3],resons[3]);
}
#include <stdio.h>
void Modal4 :: setRatioAndReson(int whichOne, MY_FLOAT ratio,MY_FLOAT reson)
{
MY_FLOAT temp;
if (ratio*baseFreq < SRATE_OVER_TWO) {
ratios[whichOne] = ratio;
}
else {
temp = ratio;
while (temp*baseFreq > SRATE_OVER_TWO) temp *= (MY_FLOAT) 0.5;
ratios[whichOne] = temp;
#if defined(_debug_)
printf("Modal4 : Aliasing would occur here, correcting.\n");
#endif
}
resons[whichOne] = reson;
if (ratio<0)
temp = -ratio;
else
temp = ratio*baseFreq;
filters[whichOne]->setFreqAndReson(temp,reson);
}
void Modal4 :: setMasterGain(MY_FLOAT aGain)
{
masterGain = aGain;
}
void Modal4 :: setDirectGain(MY_FLOAT aGain)
{
directGain = aGain;
}
void Modal4 :: setFiltGain(int whichOne, MY_FLOAT gain)
{
filters[whichOne]->setGain(gain);
}
void Modal4 :: strike(MY_FLOAT amplitude)
{
int i;
MY_FLOAT temp;
envelope->setRate((MY_FLOAT) 1.0);
envelope->setTarget(amplitude);
onepole->setPole((MY_FLOAT) 1.0 - amplitude);
envelope->tick();
wave->reset();
for (i=0;i<4;i++) {
if (ratios[i] < 0)
temp = -ratios[i];
else
temp = ratios[i] * baseFreq;
filters[i]->setFreqAndReson(temp,resons[i]);
}
}
void Modal4 :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
this->strike(amp);
this->setFreq(freq);
#if defined(_debug_)
printf("Modal4 : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}
void Modal4 :: noteOff(MY_FLOAT amp) /* This calls damp, but inverts the */
{ /* meaning of amplitude. */
this->damp((MY_FLOAT) 1.0 - (amp * (MY_FLOAT) 0.03)); /* (high amplitude means fast damping) */
#if defined(_debug_)
printf("Modal4 : NoteOff: Amp=%lf\n",amp);
#endif
}
void Modal4 :: damp(MY_FLOAT amplitude)
{
int i;
MY_FLOAT temp;
for (i=0;i<4;i++) {
if (ratios[i] < 0)
temp = -ratios[i];
else
temp = ratios[i] * baseFreq;
filters[i]->setFreqAndReson(temp,resons[i]*amplitude);
}
}
void Modal4 :: controlChange(int number, MY_FLOAT value)
{
}
MY_FLOAT Modal4 :: tick()
{
MY_FLOAT temp,temp2;
temp = masterGain * onepole->tick(wave->tick() * envelope->tick());
temp2 = filters[0]->tick(temp);
temp2 += filters[1]->tick(temp);
temp2 += filters[2]->tick(temp);
temp2 += filters[3]->tick(temp);
temp2 = temp2 - (temp2 * directGain);
temp2 += directGain * temp;
if (vibrGain != 0.0) {
temp = (MY_FLOAT) 1.0 + (vibr->tick() * vibrGain); /* Calculate AM */
temp2 = temp * temp2; /* and apply to master out */
}
lastOutput = temp2 * (MY_FLOAT) 2.0;
return lastOutput;
}

51
STK/Modal4.h Normal file
View File

@@ -0,0 +1,51 @@
/*******************************************/
/* 4 Resonance Modal Synthesis Instrument */
/* by Perry R. Cook, 1995-96 */
/* This instrument contains an excitation */
/* wavetable, an envelope, and four reso- */
/* nances (Non-Sweeping BiQuad Filters). */
/*******************************************/
#if !defined(__Modal4_h)
#define __Modal4_h
#include "Instrmnt.h"
#include "Envelope.h"
#include "RawWvIn.h"
#include "BiQuad.h"
#include "OnePole.h"
class Modal4 : public Instrmnt
{
protected:
Envelope *envelope;
RawWvIn *wave;
BiQuad *filters[4];
OnePole *onepole;
RawWvIn *vibr;
MY_FLOAT vibrGain;
MY_FLOAT masterGain;
MY_FLOAT directGain;
MY_FLOAT stickHardness;
MY_FLOAT strikePosition;
MY_FLOAT baseFreq;
MY_FLOAT ratios[4];
MY_FLOAT resons[4];
public:
Modal4();
virtual ~Modal4();
void clear();
virtual void setFreq(MY_FLOAT frequency);
void setRatioAndReson(int whichOne, MY_FLOAT ratio, MY_FLOAT reson);
void setMasterGain(MY_FLOAT aGain);
void setDirectGain(MY_FLOAT aGain);
void setFiltGain(int whichOne, MY_FLOAT gain);
virtual void strike(MY_FLOAT amplitude);
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
virtual void noteOff(MY_FLOAT amp);
void damp(MY_FLOAT amplitude);
virtual void controlChange(int number, MY_FLOAT value);
virtual MY_FLOAT tick();
};
#endif

86
STK/Modulatr.cpp Normal file
View File

@@ -0,0 +1,86 @@
/*******************************************/
/* Modulator Class, Perry R. Cook, 1995-96*/
/* This Object combines random and */
/* periodic modulations to give a nice */
/* natural human modulation function. */
/*******************************************/
#define POLE_POS (MY_FLOAT) 0.999
#define RND_SCALE (MY_FLOAT) 10.0
#include "Modulatr.h"
Modulatr :: Modulatr()
{
// Concatenate the STK RAWWAVE_PATH to the rawwave file
char file[128];
strcpy(file, RAWWAVE_PATH);
vibwave = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping");
vibwave->normalize();
vibwave->setFreq((MY_FLOAT) 6.0);
vibAmt = (MY_FLOAT) 0.04;
noise = new SubNoise(330);
rndAmt = (MY_FLOAT) 0.005;
onepole = new OnePole;
onepole->setPole(POLE_POS);
onepole->setGain(rndAmt * RND_SCALE);
}
Modulatr :: ~Modulatr()
{
delete vibwave;
delete noise;
delete onepole;
}
void Modulatr :: reset()
{
lastOutput = (MY_FLOAT) 0.0;
}
void Modulatr :: setVibFreq(MY_FLOAT vibFreq)
{
vibwave->setFreq(vibFreq);
}
void Modulatr :: setVibAmt(MY_FLOAT vibAmount)
{
vibAmt = vibAmount;
}
void Modulatr :: setRndAmt(MY_FLOAT rndAmount)
{
rndAmt = rndAmount;
onepole->setGain(RND_SCALE * rndAmt);
}
MY_FLOAT Modulatr :: tick()
{
lastOutput = vibAmt * vibwave->tick(); /* Compute periodic and */
lastOutput += onepole->tick(noise->tick()); /* random modulations */
return lastOutput;
}
MY_FLOAT Modulatr :: lastOut()
{
return lastOutput;
}
/************ Test Main Program *****************/
/*
void main()
{
Modulatr testMod;
FILE *fd;
short data;
long i;
fd = fopen("test.raw","wb");
for (i=0;i<20000;i++) {
data = testMod.tick() * 32000.0;
fwrite(&data,2,1,fd);
}
fclose(fd);
}
*/

36
STK/Modulatr.h Normal file
View File

@@ -0,0 +1,36 @@
/*******************************************/
/* Modulator Class, Perry R. Cook, 1995-96*/
/* This Object combines random and */
/* periodic modulations to give a nice */
/* natural human modulation function. */
/*******************************************/
#if !defined(__Modulatr_h)
#define __Modulatr_h
#include "Object.h"
#include "RawWvIn.h"
#include "SubNoise.h"
#include "OnePole.h"
class Modulatr : public Object
{
protected:
RawWvIn *vibwave;
SubNoise *noise;
OnePole *onepole;
MY_FLOAT vibAmt;
MY_FLOAT rndAmt;
MY_FLOAT lastOutput;
public:
Modulatr();
~Modulatr();
void reset();
void setVibFreq(MY_FLOAT vibFreq);
void setVibAmt(MY_FLOAT vibAmount);
void setRndAmt(MY_FLOAT rndAmount);
MY_FLOAT tick();
MY_FLOAT lastOut();
};
#endif

114
STK/Moog1.cpp Normal file
View File

@@ -0,0 +1,114 @@
/******************************************/
/* Test Sampler Subclass of */
/* Sampling Synthesizer Class */
/* by Perry R. Cook, 1995-96 */
/* */
/* Controls: CONTROL1 = filterQ */
/* CONTROL2 = filterRate */
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/******************************************/
#include "Moog1.h"
#include "SKINI11.msg"
Moog1 :: Moog1() : SamplFlt()
{
// Concatenate the STK RAWWAVE_PATH to the rawwave file
char temp[128];
char file[128];
strcpy(temp, RAWWAVE_PATH);
strcpy(file,temp);
attacks[0] = new RawWvIn(strcat(file,"rawwaves/mandpluk.raw"),"oneshot");
strcpy(file,temp);
loops[0] = new RawWvIn(strcat(file,"rawwaves/impuls20.raw"),"looping");
strcpy(file,temp);
loops[1] = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping"); /* Steal one for vibrato */
attacks[0]->normalize();
loops[0]->normalize();
loops[1]->normalize();
loops[1]->setFreq((MY_FLOAT) 6.122);
adsr->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 1.5,(MY_FLOAT) 0.6,(MY_FLOAT) 0.250);
filterQ = (MY_FLOAT) 0.85;
filterRate = (MY_FLOAT) 0.0001;
modDepth = (MY_FLOAT) 0.0;
}
Moog1 :: ~Moog1()
{
delete attacks[0];
delete loops[0];
delete loops[1];
}
void Moog1 :: setFreq(MY_FLOAT frequency)
{
baseFreq = frequency;
attacks[0]->setFreq(baseFreq * (MY_FLOAT) 0.01);
loops[0]->setFreq(baseFreq);
}
void Moog1 :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
MY_FLOAT temp;
this->setFreq(freq);
this->keyOn();
attackGain = amp * (MY_FLOAT) 0.5;
loopGain = amp;
temp = filterQ + (MY_FLOAT) 0.05;
filters[0]->setStates((MY_FLOAT) 2000.0,temp,(MY_FLOAT) 2.0 * ((MY_FLOAT) 1.0 - temp));
filters[1]->setStates((MY_FLOAT) 2000.0,temp,(MY_FLOAT) 2.0 * ((MY_FLOAT) 1.0 - temp));
temp = filterQ + (MY_FLOAT) 0.099;
filters[0]->setTargets((MY_FLOAT) freq,temp,(MY_FLOAT) 2.0 * ((MY_FLOAT) 1.0 - temp));
filters[1]->setTargets((MY_FLOAT) freq,temp,(MY_FLOAT) 2.0 * ((MY_FLOAT) 1.0 - temp));
filters[0]->setSweepRate(filterRate * (MY_FLOAT) 22050.0 / SRATE);
filters[1]->setSweepRate(filterRate * (MY_FLOAT) 22050.0 / SRATE);
#if defined(_debug_)
printf("Moog1 : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}
void Moog1 :: setModulationSpeed(MY_FLOAT mSpeed)
{
loops[1]->setFreq(mSpeed);
}
void Moog1 :: setModulationDepth(MY_FLOAT mDepth)
{
modDepth = mDepth * (MY_FLOAT) 0.5;
}
void Moog1 :: controlChange(int number, MY_FLOAT value)
{
#if defined(_debug_)
printf("Moog1 : ControlChange: Number=%i Value=%f\n",number,value);
#endif
if (number == __SK_FilterQ_)
filterQ = (MY_FLOAT) 0.80 + ((MY_FLOAT) 0.1 * value * NORM_7);
else if (number == __SK_FilterSweepRate_)
filterRate = (value * NORM_7 * (MY_FLOAT) 0.0002);
else if (number == __SK_ModFrequency_)
this->setModulationSpeed(value * NORM_7 * (MY_FLOAT) 12.0);
else if (number == __SK_ModWheel_)
this->setModulationDepth(value * NORM_7);
else if (number == __SK_AfterTouch_Cont_)
adsr->setTarget(value * NORM_7);
else {
printf("Moog1 : Undefined Control Number!!\n");
}
}
MY_FLOAT Moog1 :: tick()
{
MY_FLOAT temp;
if (modDepth!=0.0) {
temp = loops[1]->tick() * modDepth;
loops[0]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp));
}
lastOutput = SamplFlt :: tick();
return lastOutput;
}

34
STK/Moog1.h Normal file
View File

@@ -0,0 +1,34 @@
/******************************************/
/* Moog1 Subclass of */
/* Sampling Synthesizer Class */
/* by Perry R. Cook, 1995-96 */
/* */
/* Controls: CONTROL1 = filterQ */
/* CONTROL2 = filterRate */
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/******************************************/
#if !defined(__Moog1_h)
#define __Moog1_h
#include "SamplFlt.h"
class Moog1 : public SamplFlt
{
private:
MY_FLOAT modDepth;
MY_FLOAT filterQ;
MY_FLOAT filterRate;
public:
Moog1();
~Moog1();
virtual void setFreq(MY_FLOAT frequency);
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
void setModulationSpeed(MY_FLOAT mSpeed);
void setModulationDepth(MY_FLOAT mDepth);
virtual void controlChange(int number, MY_FLOAT value);
virtual MY_FLOAT tick();
};
#endif

138
STK/NRev.cpp Normal file
View File

@@ -0,0 +1,138 @@
/******************************************/
/* NRev Reverb Subclass */
/* by Tim Stilson, 1998 */
/* based on CLM NRev */
/* Integrated into STK by Gary Scavone */
/* */
/* This is based on some of the famous */
/* Stanford CCRMA reverbs (NRev, KipRev) */
/* all based on the the Chowning/Moorer/ */
/* Schroeder reverberators, which use */
/* 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. */
/******************************************/
#include "NRev.h"
NRev :: NRev(MY_FLOAT T60)
{
int lens[15]={1433,1601,1867,2053,2251,2399,347,113,37,59,53,43,37,29,19};
double srscale= SRATE / 25641.0;
int val;
int i;
for (i=0; i<15; i++)
{
val = (int)floor(srscale*lens[i]);
if ((val & 1) == 0) val++;
while (!this->isprime(val)) val+=2;
lens[i]=val;
}
for (i=0; i<6; i++)
{
CdelayLine[i] = new DLineN((long) (lens[i]) + 2);
CdelayLine[i]->setDelay((long) (lens[i]));
combCoef[i] = pow(10,(-3 * lens[i] / (T60 * SRATE)));
}
for (i=0; i<8; i++)
{
APdelayLine[i] = new DLineN((long) (lens[i+6]) + 2);
APdelayLine[i]->setDelay((long) (lens[i+6]));
}
allPassCoeff = 0.7;
effectMix = 0.3;
this->clear();
}
NRev :: ~NRev()
{
int i;
for (i=0; i<6; i++) delete CdelayLine[i];
for (i=0; i<8; i++) delete APdelayLine[i];
}
void NRev :: clear()
{
int i;
for (i=0; i<6; i++) CdelayLine[i]->clear();
for (i=0; i<8; i++) APdelayLine[i]->clear();
lastOutL = 0.0;
lastOutR = 0.0;
lpLastout = 0.0;
}
void NRev :: setEffectMix(MY_FLOAT mix)
{
effectMix = mix;
}
MY_FLOAT NRev :: lastOutput()
{
return (lastOutL + lastOutR) * 0.5;
}
MY_FLOAT NRev :: lastOutputL()
{
return lastOutL;
}
MY_FLOAT NRev :: lastOutputR()
{
return lastOutR;
}
MY_FLOAT NRev :: tick(MY_FLOAT input)
{
MY_FLOAT temp,temp0,temp1,temp2,temp3;
int i;
temp0 = 0.0;
for (i=0; i<6; i++)
{
temp = input + (combCoef[i] * CdelayLine[i]->lastOut());
temp0 += CdelayLine[i]->tick(temp);
}
for (i=0; i<3; i++)
{
temp = APdelayLine[i]->lastOut();
temp1 = allPassCoeff * temp;
temp1 += temp0;
APdelayLine[i]->tick(temp1);
temp0 = -(allPassCoeff * temp1) + temp;
}
lpLastout = 0.7*lpLastout + 0.3*temp0; // onepole LP filter
temp = APdelayLine[3]->lastOut();
temp1 = allPassCoeff * temp;
temp1 += lpLastout;
APdelayLine[3]->tick(temp1);
temp1 = -(allPassCoeff * temp1) + temp;
temp = APdelayLine[4]->lastOut();
temp2 = allPassCoeff * temp;
temp2 += temp1;
APdelayLine[4]->tick(temp2);
lastOutL = effectMix*(-(allPassCoeff * temp2) + temp);
temp = APdelayLine[5]->lastOut();
temp3 = allPassCoeff * temp;
temp3 += temp1;
APdelayLine[5]->tick(temp3);
lastOutR = effectMix*(-(allPassCoeff * temp3) + temp);
temp = (1.0 - effectMix) * input;
lastOutL += temp;
lastOutR += temp;
return (lastOutL + lastOutR) * 0.5;
}

52
STK/NRev.h Normal file
View File

@@ -0,0 +1,52 @@
/******************************************/
/* NRev Reverb Subclass */
/* by Tim Stilson, 1998 */
/* based on CLM NRev */
/* Integrated into STK by Gary Scavone */
/* */
/* This is based on some of the famous */
/* Stanford CCRMA reverbs (NRev, KipRev) */
/* all based on the the Chowning/Moorer/ */
/* Schroeder reverberators, which use */
/* 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. */
/******************************************/
#if !defined(__NRev_h)
#define __NRev_h
#include "Object.h"
#include "Reverb.h"
#include "DLineN.h"
class NRev : public Reverb
{
protected:
DLineN *APdelayLine[8];
DLineN *CdelayLine[6];
MY_FLOAT allPassCoeff;
MY_FLOAT combCoef[6];
MY_FLOAT lpLastout;
MY_FLOAT lastOutL;
MY_FLOAT lastOutR;
MY_FLOAT effectMix;
public:
NRev(MY_FLOAT T60);
~NRev();
void clear();
void setEffectMix(MY_FLOAT mix);
MY_FLOAT lastOutput();
MY_FLOAT lastOutputL();
MY_FLOAT lastOutputR();
MY_FLOAT tick(MY_FLOAT input);
};
#endif

52
STK/Noise.cpp Normal file
View File

@@ -0,0 +1,52 @@
/*******************************************/
/* Noise Generator Class, */
/* by Perry R. Cook, 1995-96 */
/* White noise as often as you like. */
/*******************************************/
#include "Noise.h"
#ifdef __OS_NeXT_
#include <libc.h>
#endif
#if defined(__OS_Win_) /* For Windoze */
#define ONE_OVER_RANDLIMIT 0.00006103516
#else /* This is for Linux, NeXT and SGI */
#define ONE_OVER_RANDLIMIT 0.00000000093132258
#endif
Noise :: Noise() : Object()
{
lastOutput = (MY_FLOAT) 0.0;
}
Noise :: ~Noise()
{
}
MY_FLOAT Noise :: tick()
{
#if defined(__OS_Win_) /* For Windoze */
lastOutput = (MY_FLOAT) (rand() - 16383);
#else /* This is for Linux, NeXT and SGI */
lastOutput = (MY_FLOAT) random() - 1073741823.0;
#endif
lastOutput *= (MY_FLOAT) ONE_OVER_RANDLIMIT;
return lastOutput;
}
MY_FLOAT Noise :: lastOut()
{
return lastOutput;
}
/************ Test Main ************************/
/*
void main()
{
long i;
Noise test;
for (i=0;i<20;i++) printf("%lf\n",test.tick());
}
*/

23
STK/Noise.h Normal file
View File

@@ -0,0 +1,23 @@
/*******************************************/
/* Noise Generator Class, */
/* by Perry R. Cook, 1995-96 */
/* White noise as often as you like. */
/*******************************************/
#if !defined(__Noise_h)
#define __Noise_h
#include "Object.h"
class Noise : public Object
{
protected:
MY_FLOAT lastOutput;
public:
Noise();
virtual ~Noise();
MY_FLOAT tick();
MY_FLOAT lastOut();
};
#endif

23
STK/Object.cpp Normal file
View File

@@ -0,0 +1,23 @@
/*******************************************/
/* Object Class, by Perry R. Cook, 1995-96*/
/* This is mostly here for compatibility */
/* with Objective C. We'll also stick */
/* global defines here, so everyone will */
/* see them. */
/*******************************************/
#include "Object.h"
// #include "byteswap.c"
/* This is just here for compatibility and convenience,
so there's no need to do any real calculations.
I do set up some redefinable variables here. */
Object :: Object()
{
}
Object :: ~Object()
{
}

131
STK/Object.h Normal file
View File

@@ -0,0 +1,131 @@
/*********************************************/
/* Object Class, by Perry R. Cook, 1995-99 */
/* */
/* This is mostly here for compatibility */
/* with Objective C. We'll also stick */
/* global defines here, so everyone will */
/* see them. */
/*********************************************/
#if !defined(__Object_h)
#define __Object_h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
class Object
{
public:
protected:
Object();
virtual ~Object();
};
/* The OS type definitions are made in the Makefile */
#if defined(__OS_NeXT_) /* For NeXTStep - Black or White Hardware */
// No special defines at this time
#elif defined(__OS_IRIX_) /* For SGI */
#define __STK_REALTIME_
#elif defined(__OS_Linux_) /* For Linux */
#define __STK_REALTIME_
#define __OSS_API_ /* Use OSS API */
#define __LITTLE_ENDIAN__
#elif defined(__OS_Win_) /* For WindowsXX or NT */
#define __STK_REALTIME_
#define __WINDS_API_ /* For DirectSound API */
// #define __WINMM_API_ /* For Win MM API */
#define __LITTLE_ENDIAN__
#endif
/* Real-time output buffer size. If clicks are occuring in the
* output sound stream, a larger buffer size may help. Larger
* buffer sizes, however, produce more latency between input and
* output.
* NOTE FOR WINDOZE USERS: Given inherent delays in the sound
* output mechanism under Windoze, there is a trade-off between
* smoothness of fast SKINI parameter updates and input/output
* latency as discussed above. You can use buffer sizes as low
* as 100 (maybe lower) for delay critical applications, but in
* this case SKINI parameter updates will be clumped together
* and sound unnatural. If you want smoother parameter updates
* and you can live with more delay, try using buffer sizes
* closer to 1000. If you need smooth parameter updates AND
* low delay, don't use Windoze!
*/
#define RT_BUFFER_SIZE 256
/* This sets the maximum number of simultaneous
* (within a buffer) MIDI messages that can be
* serviced before messages begin to be lost or
* overwritten. It should be a function of
* RT_BUFFER_SIZE
*/
#define MAX_IN_STRINGS 25
/* The following definition is concatenated to the
* beginning of all references to rawwave files in
* the various STK core classes (ex. Clarinet.cpp).
* If you wish to move the rawwaves directory to a
* different location in your file system, you will
* need to set this path definition appropriately.
* The current definition is a relative reference
* that will work "out of the box" for the STK
* distribution.
*/
#define RAWWAVE_PATH "../"
/* Sampling Rate */
#define SRATE (MY_FLOAT) 22050.0
/* Other SRATE derived defines */
#define SRATE_OVER_TWO (MY_FLOAT) (SRATE / 2)
#define ONE_OVER_SRATE (MY_FLOAT) (1 / SRATE)
#define TWO_PI_OVER_SRATE (MY_FLOAT) (2 * PI / SRATE)
/* Yer Basic Trigonometric constants */
#if !defined(PI)
#define PI (MY_FLOAT) 3.14159265359
#endif
#define TWO_PI (MY_FLOAT) 6.28318530718
#define ONE_OVER_TWO_PI (MY_FLOAT) 0.15915494309
#define SQRT_TWO 1.414213562
/* States for Envelopes, etc. */
#define ATTACK 0
#define DECAY 1
#define SUSTAIN 2
#define RELEASE 3
/* Machine dependent stuff, possibly useful for optimization.
* For example, changing double to float here increases
* performance (speed) by a whopping 4-6% on 486-flavor machines.
* BUT!! a change from float to double here increases speed by
* 30% or so on SGI machines.
*/
#define MY_FLOAT double
//#define MY_FLOAT float
/* MY_MULTI is just a pointer to MY_FLOAT. This type is used
* to pass multichannel data back and forth within STK.
*/
typedef MY_FLOAT *MY_MULTI;
/* INT16 is just that ... a 16-bit signed integer. */
typedef signed short INT16;
/* INT32 is just that ... a 32-bit signed integer. */
typedef signed long INT32;
/* Debugging define, causes massive printf's to come out.
* Also enables timing calculations in WaveOut class, other stuff.
* Uncomment to enable.
*/
//#define _debug_ 1
/* MIDI definitions */
#define NORM_7 (MY_FLOAT) 0.0078125 /* this is 1/128 */
#endif

62
STK/OnePole.cpp Normal file
View File

@@ -0,0 +1,62 @@
/*******************************************/
/* One Pole Filter Class, */
/* by Perry R. Cook, 1995-96 */
/* The parameter gain is an additional */
/* gain parameter applied to the filter */
/* on top of the normalization that takes */
/* place automatically. So the net max */
/* gain through the system equals the */
/* value of gain. sgain is the combina- */
/* tion of gain and the normalization */
/* parameter, so if you set the poleCoeff */
/* to alpha, sgain is always set to */
/* gain * (1.0 - fabs(alpha)). */
/*******************************************/
#include "OnePole.h"
OnePole :: OnePole() : Filter()
{
poleCoeff = (MY_FLOAT) 0.9;
gain = (MY_FLOAT) 1.0;
sgain = (MY_FLOAT) 0.1;
outputs = (MY_FLOAT *) malloc(sizeof(MY_FLOAT));
outputs[0] = (MY_FLOAT) 0.0;
}
OnePole :: ~OnePole()
{
free(outputs);
}
void OnePole :: clear()
{
outputs[0] = (MY_FLOAT) 0.0;
lastOutput = (MY_FLOAT) 0.0;
}
void OnePole :: setPole(MY_FLOAT aValue)
{
poleCoeff = aValue;
if (poleCoeff > 0.0) // Normalize gain to 1.0 max
sgain = gain * ((MY_FLOAT) 1.0 - poleCoeff);
else
sgain = gain * ((MY_FLOAT) 1.0 + poleCoeff);
}
void OnePole :: setGain(MY_FLOAT aValue)
{
gain = aValue;
if (poleCoeff > 0.0)
sgain = gain * ((MY_FLOAT) 1.0 - poleCoeff); // Normalize gain to 1.0 max
else
sgain = gain * ((MY_FLOAT) 1.0 + poleCoeff);
}
MY_FLOAT OnePole :: tick(MY_FLOAT sample) // Perform Filter Operation
{
outputs[0] = (sgain * sample) + (poleCoeff * outputs[0]);
lastOutput = outputs[0];
return lastOutput;
}

35
STK/OnePole.h Normal file
View File

@@ -0,0 +1,35 @@
/*******************************************/
/* One Pole Filter Class, */
/* by Perry R. Cook, 1995-96 */
/* The parameter gain is an additional */
/* gain parameter applied to the filter */
/* on top of the normalization that takes */
/* place automatically. So the net max */
/* gain through the system equals the */
/* value of gain. sgain is the combina- */
/* tion of gain and the normalization */
/* parameter, so if you set the poleCoeff */
/* to alpha, sgain is always set to */
/* gain * (1.0 - fabs(alpha)). */
/*******************************************/
#if !defined(__OnePole_h)
#define __OnePole_h
#include "Filter.h"
class OnePole : public Filter
{
protected:
MY_FLOAT poleCoeff;
MY_FLOAT sgain;
public:
OnePole();
~OnePole();
void clear();
void setPole(MY_FLOAT aValue);
void setGain(MY_FLOAT aValue);
MY_FLOAT tick(MY_FLOAT sample);
};
#endif

64
STK/OneZero.cpp Normal file
View File

@@ -0,0 +1,64 @@
/*******************************************/
/* One Zero Filter Class, */
/* by Perry R. Cook, 1995-96 */
/* The parameter gain is an additional */
/* gain parameter applied to the filter */
/* on top of the normalization that takes */
/* place automatically. So the net max */
/* gain through the system equals the */
/* value of gain. sgain is the combina- */
/* tion of gain and the normalization */
/* parameter, so if you set the poleCoeff */
/* to alpha, sgain is always set to */
/* gain / (1.0 - fabs(alpha)). */
/*******************************************/
#include "OneZero.h"
OneZero :: OneZero()
{
gain = (MY_FLOAT) 1.0;
zeroCoeff = (MY_FLOAT) 1.0;
sgain = (MY_FLOAT) 0.5;
inputs = (MY_FLOAT *) malloc(sizeof(MY_FLOAT));
this->clear();
}
OneZero :: ~OneZero()
{
free(inputs);
}
void OneZero :: clear()
{
inputs[0] = (MY_FLOAT) 0.0;
lastOutput = (MY_FLOAT) 0.0;
}
void OneZero :: setGain(MY_FLOAT aValue)
{
gain = aValue;
if (zeroCoeff > 0.0) // Normalize gain to 1.0 max
sgain = gain / ((MY_FLOAT) 1.0 + zeroCoeff);
else
sgain = gain / ((MY_FLOAT) 1.0 - zeroCoeff);
}
void OneZero :: setCoeff(MY_FLOAT aValue)
{
zeroCoeff = aValue;
if (zeroCoeff > 0.0) // Normalize gain to 1.0 max
sgain = gain / ((MY_FLOAT) 1.0 + zeroCoeff);
else
sgain = gain / ((MY_FLOAT) 1.0 - zeroCoeff);
}
MY_FLOAT OneZero :: tick(MY_FLOAT sample) // Perform Filter Operation
{
MY_FLOAT temp;
temp = sgain * sample;
lastOutput = (inputs[0] * zeroCoeff) + temp;
inputs[0] = temp;
return lastOutput;
}

35
STK/OneZero.h Normal file
View File

@@ -0,0 +1,35 @@
/*******************************************/
/* One Zero Filter Class, */
/* by Perry R. Cook, 1995-96 */
/* The parameter gain is an additional */
/* gain parameter applied to the filter */
/* on top of the normalization that takes */
/* place automatically. So the net max */
/* gain through the system equals the */
/* value of gain. sgain is the combina- */
/* tion of gain and the normalization */
/* parameter, so if you set the poleCoeff */
/* to alpha, sgain is always set to */
/* gain / (1.0 - fabs(alpha)). */
/*******************************************/
#if !defined(__OneZero_h)
#define __OneZero_h
#include "Filter.h"
class OneZero : public Filter
{
protected:
MY_FLOAT zeroCoeff;
MY_FLOAT sgain;
public:
OneZero();
~OneZero();
void clear();
void setGain(MY_FLOAT aValue);
void setCoeff(MY_FLOAT aValue);
MY_FLOAT tick(MY_FLOAT sample);
};
#endif

113
STK/PRCRev.cpp Normal file
View File

@@ -0,0 +1,113 @@
/*******************************************/
/* PRCRev, a simple reverb unit */
/* by Perry Cook, 1996. */
/* Incorporated into the Reverb superclass */
/* by Gary Scavone, 1998. */
/* */
/* This is based on some of the famous */
/* Stanford CCRMA reverbs (NRev, KipRev) */
/* all based on the the Chowning/Moorer/ */
/* Schroeder reverberators, which use */
/* networks of simple allpass and comb */
/* delay filters. This particular */
/* structure consists of 2 allpass units */
/* in series followed by 2 comb filters in */
/* parallel. */
/*******************************************/
#include "PRCRev.h"
PRCRev :: PRCRev(MY_FLOAT T60)
{
int lens[4]={353,1097,1777,2137};
double srscale = SRATE / 44100.0;
int val, i;
if (SRATE < 44100.0) {
for (i=0; i<4; i++) {
val = (int) floor(srscale * lens[i]);
if ((val & 1) == 0) val++;
while (!this->isprime(val)) val += 2;
lens[i] = val;
}
}
for (i=0; i<2; i++)
{
APdelayLine[i] = new DLineN(lens[i] + 2);
APdelayLine[i]->setDelay(lens[i]);
CdelayLine[i] = new DLineN(lens[i+2] + 2);
CdelayLine[i]->setDelay(lens[i+2]);
combCoeff[i] = pow(10,(-3 * lens[i+2] / (T60 * SRATE)));
}
allPassCoeff = (MY_FLOAT) 0.7;
effectMix = (MY_FLOAT) 0.5;
this->clear();
}
PRCRev :: ~PRCRev()
{
delete APdelayLine[0];
delete APdelayLine[1];
delete CdelayLine[0];
delete CdelayLine[1];
}
void PRCRev :: clear()
{
APdelayLine[0]->clear();
APdelayLine[1]->clear();
CdelayLine[0]->clear();
CdelayLine[1]->clear();
lastOutL = (MY_FLOAT) 0.0;
lastOutR = (MY_FLOAT) 0.0;
}
void PRCRev :: setEffectMix(MY_FLOAT mix)
{
effectMix = mix;
}
MY_FLOAT PRCRev :: lastOutput()
{
return (lastOutL + lastOutR) * (MY_FLOAT) 0.5;
}
MY_FLOAT PRCRev :: lastOutputL()
{
return lastOutL;
}
MY_FLOAT PRCRev :: lastOutputR()
{
return lastOutR;
}
MY_FLOAT PRCRev :: tick(MY_FLOAT input)
{
MY_FLOAT temp,temp0,temp1,temp2,temp3;
temp = APdelayLine[0]->lastOut();
temp0 = allPassCoeff * temp;
temp0 += input;
APdelayLine[0]->tick(temp0);
temp0 = -(allPassCoeff * temp0) + temp;
temp = APdelayLine[1]->lastOut();
temp1 = allPassCoeff * temp;
temp1 += temp0;
APdelayLine[1]->tick(temp1);
temp1 = -(allPassCoeff * temp1) + temp;
temp2 = temp1 + (combCoeff[0] * CdelayLine[0]->lastOut());
temp3 = temp1 + (combCoeff[1] * CdelayLine[1]->lastOut());
lastOutL = effectMix * (CdelayLine[0]->tick(temp2));
lastOutR = effectMix * (CdelayLine[1]->tick(temp3));
temp = (MY_FLOAT) (1.0 - effectMix) * input;
lastOutL += temp;
lastOutR += temp;
return (lastOutL + lastOutR) * (MY_FLOAT) 0.5;
}

43
STK/PRCRev.h Normal file
View File

@@ -0,0 +1,43 @@
/*******************************************/
/* PRCRev, a simple reverb unit */
/* by Perry Cook, 1996. */
/* Incorporated into the Reverb superclass */
/* by Gary Scavone, 1998. */
/* */
/* This is based on some of the famous */
/* Stanford CCRMA reverbs (NRev, KipRev) */
/* all based on the the Chowning/Moorer/ */
/* Schroeder reverberators, which use */
/* networks of simple allpass and comb */
/* delay filters. */
/*******************************************/
#if !defined(__PRCRev_h)
#define __PRCRev_h
#include "Reverb.h"
#include "DLineN.h"
class PRCRev : public Reverb
{
protected:
DLineN *APdelayLine[2];
DLineN *CdelayLine[2];
MY_FLOAT allPassCoeff;
MY_FLOAT combCoeff[2];
MY_FLOAT lastOutL;
MY_FLOAT lastOutR;
MY_FLOAT effectMix;
public:
PRCRev(MY_FLOAT T60);
~PRCRev();
void clear();
void setEffectMix(MY_FLOAT mix);
MY_FLOAT lastOutput();
MY_FLOAT lastOutputL();
MY_FLOAT lastOutputR();
MY_FLOAT tick(MY_FLOAT input);
};
#endif

63
STK/PercFlut.cpp Normal file
View File

@@ -0,0 +1,63 @@
/******************************************/
/* Percussive Flute Subclass */
/* of Algorithm 4 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/******************************************/
#include "PercFlut.h"
PercFlut :: PercFlut() : FM4Alg4()
{
// Concatenate the STK RAWWAVE_PATH to the rawwave file
char file1[128];
char file2[128];
char file3[128];
char file4[128];
strcpy(file1, RAWWAVE_PATH);
strcpy(file2, RAWWAVE_PATH);
strcpy(file3, RAWWAVE_PATH);
strcpy(file4, RAWWAVE_PATH);
this->loadWaves(strcat(file1,"rawwaves/sinewave.raw"),
strcat(file2,"rawwaves/sinewave.raw"),
strcat(file3,"rawwaves/sinewave.raw"),
strcat(file4,"rawwaves/fwavblnk.raw"));
this->setRatio(0,(MY_FLOAT) (1.50 * 1.000));
this->setRatio(1,(MY_FLOAT) (3.00 * 0.995));
this->setRatio(2,(MY_FLOAT) (2.99 * 1.005));
this->setRatio(3,(MY_FLOAT) (6.00 * 0.997));
gains[0] = __FM4Op_gains[99];
gains[1] = __FM4Op_gains[71];
gains[2] = __FM4Op_gains[93];
gains[3] = __FM4Op_gains[85];
adsr[0]->setAllTimes((MY_FLOAT) 0.05,(MY_FLOAT) 0.05,
__FM4Op_susLevels[14],(MY_FLOAT) 0.05);
adsr[1]->setAllTimes((MY_FLOAT) 0.02,(MY_FLOAT) 0.50,
__FM4Op_susLevels[13],(MY_FLOAT) 0.5);
adsr[2]->setAllTimes((MY_FLOAT) 0.02,(MY_FLOAT) 0.30,
__FM4Op_susLevels[11],(MY_FLOAT) 0.05);
adsr[3]->setAllTimes((MY_FLOAT) 0.02,(MY_FLOAT) 0.05,
__FM4Op_susLevels[13],(MY_FLOAT) 0.01);
twozero->setGain((MY_FLOAT) 0.0);
modDepth = (MY_FLOAT) 0.005;
}
void PercFlut :: setFreq(MY_FLOAT frequency)
{
baseFreq = frequency;
}
void PercFlut :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
gains[0] = amp * __FM4Op_gains[99] * 0.5;
gains[1] = amp * __FM4Op_gains[71] * 0.5;
gains[2] = amp * __FM4Op_gains[93] * 0.5;
gains[3] = amp * __FM4Op_gains[85] * 0.5;
this->setFreq(freq);
this->keyOn();
#if defined(_debug_)
printf("PercFlut : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}

21
STK/PercFlut.h Normal file
View File

@@ -0,0 +1,21 @@
/******************************************/
/* Percussive Flute Subclass */
/* of Algorithm 4 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/******************************************/
#if !defined(__PercFlut_h)
#define __PercFlut_h
#include "FM4Alg4.h"
class PercFlut : public FM4Alg4
{
public:
PercFlut();
virtual void setFreq(MY_FLOAT frequency);
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
};
#endif

83
STK/Plucked.cpp Normal file
View File

@@ -0,0 +1,83 @@
/******************************************/
/* Karplus-Strong plucked string model */
/* by Perry Cook, 1995-96 */
/* */
/* There exist at least two patents, */
/* assigned to Stanford, bearing the */
/* names of Karplus and/or Strong. */
/******************************************/
#include "Plucked.h"
Plucked :: Plucked(MY_FLOAT lowestFreq)
{
length = (long) (SRATE / lowestFreq + 1);
loopGain = (MY_FLOAT) 0.999;
delayLine = new DLineA(length);
loopFilt = new OneZero;
pickFilt = new OnePole;
noise = new Noise;
this->clear();
}
Plucked :: ~Plucked()
{
delete delayLine;
delete loopFilt;
delete pickFilt;
delete noise;
}
void Plucked :: clear()
{
delayLine->clear();
loopFilt->clear();
pickFilt->clear();
}
void Plucked :: setFreq(MY_FLOAT frequency)
{
MY_FLOAT delay;
delay = (SRATE / frequency) - (MY_FLOAT) 0.5; /* length - delays */
delayLine->setDelay(delay);
loopGain = (MY_FLOAT) 0.995 + (frequency * (MY_FLOAT) 0.000005);
if (loopGain>1.0) loopGain = (MY_FLOAT) 0.99999;
}
void Plucked :: pluck(MY_FLOAT amplitude)
{
long i;
pickFilt->setPole((MY_FLOAT) 0.999 - (amplitude * (MY_FLOAT) 0.15));
pickFilt->setGain(amplitude * (MY_FLOAT) 0.5);
for (i=0;i<length;i++)
delayLine->tick(delayLine->lastOut() * (MY_FLOAT) 0.6 /* fill delay with noise */
+ pickFilt->tick(noise->tick())); /* additively with current */
/* contents */
}
void Plucked :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
this->setFreq(freq);
this->pluck(amp);
#if defined(_debug_)
printf("Plucked : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}
void Plucked :: noteOff(MY_FLOAT amp)
{
loopGain = (MY_FLOAT) 1.0 - amp;
#if defined(_debug_)
printf("Plucked : NoteOff: Amp=%lf\n",amp);
#endif
}
MY_FLOAT Plucked :: tick()
{
/* check this out */
/* here's the whole inner loop of the instrument!! */
lastOutput = delayLine->tick(loopFilt->tick(delayLine->lastOut() * loopGain));
lastOutput *= (MY_FLOAT) 3.0;
return lastOutput;
}

40
STK/Plucked.h Normal file
View File

@@ -0,0 +1,40 @@
/******************************************/
/* Karplus-Strong plucked string model */
/* by Perry Cook, 1995-96 */
/* */
/* There exist at least two patents, */
/* assigned to Stanford, bearing the */
/* names of Karplus and/or Strong. */
/******************************************/
#if !defined(__Plucked_h)
#define __Plucked_h
#include "Instrmnt.h"
#include "DLineA.h"
#include "OneZero.h"
#include "OnePole.h"
#include "Noise.h"
class Plucked : public Instrmnt
{
protected:
DLineA *delayLine;
OneZero *loopFilt;
OnePole *pickFilt;
Noise *noise;
long length;
MY_FLOAT loopGain;
public:
Plucked(MY_FLOAT lowestFreq);
~Plucked();
void clear();
virtual void setFreq(MY_FLOAT frequency);
void pluck(MY_FLOAT amplitude);
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
virtual void noteOff(MY_FLOAT amp);
virtual MY_FLOAT tick();
};
#endif

90
STK/Plucked2.cpp Normal file
View File

@@ -0,0 +1,90 @@
/******************************************/
/* Enhanced (Jaffe-Smith, Smith, others) */
/* Karplus-Strong plucked model */
/* by Perry Cook, 1995-96 */
/* This is the super-class, with no */
/* excitation specified. So this one by */
/* itself doesn't make any sound. */
/******************************************/
#include "Plucked2.h"
Plucked2 :: Plucked2(MY_FLOAT lowestFreq)
{
length = (long) (SRATE / lowestFreq + 1);
baseLoopGain = (MY_FLOAT) 0.995;
loopGain = (MY_FLOAT) 0.999;
delayLine = new DLineA(length);
delayLine2 = new DLineA(length);
combDelay = new DLineL(length);
filter = new OneZero;
filter2 = new OneZero;
pluckAmp = (MY_FLOAT) 0.3;
pluckPos = (MY_FLOAT) 0.4;
detuning = (MY_FLOAT) 0.995;
lastFreq = lowestFreq * (MY_FLOAT) 2.0;
lastLength = length * (MY_FLOAT) 0.5;
}
Plucked2 :: ~Plucked2()
{
delete delayLine;
delete delayLine2;
delete combDelay;
delete filter;
delete filter2;
}
void Plucked2 :: clear()
{
delayLine->clear();
delayLine2->clear();
combDelay->clear();
filter->clear();
filter2->clear();
}
void Plucked2 :: setFreq(MY_FLOAT frequency)
{
lastFreq = frequency;
lastLength = ((MY_FLOAT) SRATE / lastFreq); /* length - delays */
delayLine->setDelay((lastLength / detuning) - (MY_FLOAT) 0.5);
delayLine2->setDelay((lastLength * detuning) - (MY_FLOAT) 0.5);
loopGain = baseLoopGain + (frequency * (MY_FLOAT) 0.000005);
if (loopGain>1.0) loopGain = (MY_FLOAT) 0.99999;
}
void Plucked2 :: setDetune(MY_FLOAT detune)
{
detuning = detune;
delayLine->setDelay((lastLength / detuning) - (MY_FLOAT) 0.5);
delayLine2->setDelay((lastLength * detuning) - (MY_FLOAT) 0.5);
}
void Plucked2 :: setFreqAndDetune(MY_FLOAT frequency,MY_FLOAT detune)
{
lastFreq = frequency;
detuning = detune;
this->setFreq(frequency);
}
void Plucked2 :: setPluckPos(MY_FLOAT position)
{
pluckPos = position;
}
void Plucked2 :: setBaseLoopGain(MY_FLOAT aGain)
{
baseLoopGain = aGain;
loopGain = baseLoopGain + (lastFreq * (MY_FLOAT) 0.000005);
if (loopGain>1.0) loopGain = (MY_FLOAT) 0.99999;
}
void Plucked2 :: noteOff(MY_FLOAT amp)
{
loopGain = ((MY_FLOAT) 1.0 - amp) * (MY_FLOAT) 0.5;
#if defined(_debug_)
printf("Plucked2 : NoteOff: Amp=%lf\n",amp);
#endif
}

46
STK/Plucked2.h Normal file
View File

@@ -0,0 +1,46 @@
/******************************************/
/* Enhanced (Jaffe-Smith, Smith, others) */
/* Karplus-Strong plucked model */
/* by Perry Cook, 1995-96 */
/* This is the super-class, with no */
/* excitation specified. So this one by */
/* itself doesn't make any sound. */
/******************************************/
#if !defined(__Plucked2_h)
#define __Plucked2_h
#include "Instrmnt.h"
#include "DLineL.h"
#include "DLineA.h"
#include "OneZero.h"
class Plucked2 : public Instrmnt
{
protected:
DLineA *delayLine;
DLineA *delayLine2;
DLineL *combDelay;
OneZero *filter;
OneZero *filter2;
long length;
MY_FLOAT loopGain;
MY_FLOAT baseLoopGain;
MY_FLOAT lastFreq;
MY_FLOAT lastLength;
MY_FLOAT detuning;
MY_FLOAT pluckAmp;
MY_FLOAT pluckPos;
public:
Plucked2(MY_FLOAT lowestFreq);
virtual ~Plucked2();
void clear();
virtual void setFreq(MY_FLOAT frequency);
void setDetune(MY_FLOAT detune);
void setFreqAndDetune(MY_FLOAT frequency, MY_FLOAT detune);
void setPluckPos(MY_FLOAT position);
void setBaseLoopGain(MY_FLOAT aGain);
virtual void noteOff(MY_FLOAT amp);
};
#endif

63
STK/PoleZero.cpp Normal file
View File

@@ -0,0 +1,63 @@
/*******************************************/
/* PoleZero (1-pole, 1-zero) Filter Class */
/* by Gary P. Scavone, 1999 */
/* */
/* See books on filters to understand */
/* more about how this works. Nothing */
/* out of the ordinary in this version. */
/*******************************************/
#include "PoleZero.h"
PoleZero :: PoleZero() : Filter()
{
inputs = (MY_FLOAT *) malloc(sizeof(MY_FLOAT));
zeroCoeff = (MY_FLOAT) 0.0;
poleCoeff = (MY_FLOAT) 0.0;
gain = (MY_FLOAT) 1.0;
this->clear();
}
PoleZero :: ~PoleZero()
{
free(inputs);
}
void PoleZero :: clear()
{
inputs[0] = (MY_FLOAT) 0.0;
lastOutput = (MY_FLOAT) 0.0;
}
void PoleZero :: setPoleCoeff(MY_FLOAT coeff)
{
poleCoeff = coeff;
}
void PoleZero :: setZeroCoeff(MY_FLOAT coeff)
{
zeroCoeff = coeff;
}
void PoleZero :: setGain(MY_FLOAT aValue)
{
gain = aValue;
}
// PoleZero is one pole, one zero filter
// Look it up in your favorite DSP text
MY_FLOAT PoleZero :: tick(MY_FLOAT sample)
{
MY_FLOAT temp;
// Direct Form II Implementation - only 1 state variable
temp = sample * gain;
temp += inputs[0] * poleCoeff;
lastOutput = temp;
lastOutput += (inputs[0] * zeroCoeff);
inputs[0] = temp;
return lastOutput;
}

30
STK/PoleZero.h Normal file
View File

@@ -0,0 +1,30 @@
/*******************************************/
/* PoleZero (1-pole, 1-zero) Filter Class */
/* by Gary P. Scavone, 1999 */
/* */
/* See books on filters to understand */
/* more about how this works. Nothing */
/* out of the ordinary in this version. */
/*******************************************/
#if !defined(__PoleZero_h)
#define __PoleZero_h
#include "Filter.h"
class PoleZero : public Filter
{
protected:
MY_FLOAT poleCoeff;
MY_FLOAT zeroCoeff;
public:
PoleZero();
~PoleZero();
void clear();
void setPoleCoeff(MY_FLOAT coeff);
void setZeroCoeff(MY_FLOAT coeff);
void setGain(MY_FLOAT aValue);
MY_FLOAT tick(MY_FLOAT sample);
};
#endif

97
STK/RTDuplex.cpp Normal file
View File

@@ -0,0 +1,97 @@
/*******************************************/
/* Real-Time Duplex Input/Output Class, */
/* by Gary P. Scavone, 1999 */
/* */
/* This object opens the sound i/o */
/* device, reads buffers in from it, and */
/* pokes buffers of samples out to it. */
/* */
/* At the moment, duplex mode is possible */
/* only on Linux (OSS), IRIX, and */
/* Windows95/98 platforms. */
/*******************************************/
#include "RTDuplex.h"
#if (defined(__STK_REALTIME_) )
RTDuplex :: RTDuplex(MY_FLOAT srate, int chans)
{
// We'll let RTSoundIO deal with channel and srate limitations.
channels = chans;
soundIO = new RTSoundIO(SRATE, channels, "duplex");
writeCounter = 0;
gain = 0.00003052;
insamples = new MY_FLOAT[channels];
#if (defined(__STK_REALTIME_) && defined(__OS_IRIX_))
// This is necessary under IRIX because it scales the input by 0.5
// when using single-channel input.
if (channels == 1) gain *= 2;
#endif
// Read half a buffer to get started
readCounter = RT_BUFFER_SIZE / 2;
soundIO->recordBuffer(&indata[readCounter],(RT_BUFFER_SIZE/2));
}
RTDuplex :: ~RTDuplex()
{
soundIO->playBuffer(outdata,writeCounter);
writeCounter = 0;
while (writeCounter<RT_BUFFER_SIZE) {
outdata[writeCounter++] = 0;
}
soundIO->playBuffer(outdata,writeCounter);
soundIO->playBuffer(outdata,writeCounter); // Are these extra writes necessary?
soundIO->playBuffer(outdata,writeCounter);
delete soundIO;
delete [ ] insamples;
}
MY_FLOAT RTDuplex :: tick(MY_FLOAT outsample)
{
// We offset the data read and data write calls by RT_BUFFER_SIZE / 2
if (readCounter >= RT_BUFFER_SIZE) {
soundIO->recordBuffer(indata,RT_BUFFER_SIZE);
readCounter = 0;
}
*insamples = (MY_FLOAT) indata[readCounter++];
if (channels > 1) {
int i;
for (i=1;i<channels;i++)
*insamples += (MY_FLOAT) indata[readCounter++];
*insamples /= i;
}
*insamples *= gain;
for (int i=0;i<channels;i++)
outdata[writeCounter++] = (short) (outsample * 32000.0);
if (writeCounter >= RT_BUFFER_SIZE) {
soundIO->playBuffer(outdata,writeCounter);
writeCounter = 0;
}
return *insamples;
}
MY_MULTI RTDuplex :: mtick(MY_MULTI outsamples)
{
int i;
// We offset the data read and data write calls by RT_BUFFER_SIZE / 2
if (readCounter >= RT_BUFFER_SIZE) {
soundIO->recordBuffer(indata,RT_BUFFER_SIZE);
readCounter = 0;
}
for (i=0;i<channels;i++)
insamples[i] = (MY_FLOAT) (indata[readCounter++]*gain);
for (i=0;i<channels;i++)
outdata[writeCounter++] = (short) (*outsamples++ * 32000.0);
if (writeCounter >= RT_BUFFER_SIZE) {
soundIO->playBuffer(outdata,writeCounter);
writeCounter = 0;
}
return insamples;
}
#endif

38
STK/RTDuplex.h Normal file
View File

@@ -0,0 +1,38 @@
/*******************************************/
/* Real-Time Duplex Input/Output Class, */
/* by Gary P. Scavone, 1999 */
/* */
/* This object opens the sound i/o */
/* device, reads buffers in from it, and */
/* pokes buffers of samples out to it. */
/* */
/* At the moment, duplex mode is possible */
/* only on Linux (OSS), IRIX, and */
/* Windows95/98 platforms. */
/*******************************************/
#if !defined(__RTDuplex_h)
#define __RTDuplex_h
#include "Object.h"
#include "RTSoundIO.h"
class RTDuplex : public Object
{
protected:
RTSoundIO *soundIO;
short indata[RT_BUFFER_SIZE];
short outdata[RT_BUFFER_SIZE];
long readCounter;
long writeCounter;
int channels;
MY_FLOAT gain;
MY_FLOAT *insamples;
public:
RTDuplex(MY_FLOAT srate, int chans);
~RTDuplex();
MY_FLOAT tick(MY_FLOAT outsample);
MY_MULTI mtick(MY_MULTI outsamples);
};
#endif // defined(__RTDuplex_h)

Some files were not shown because too many files have changed in this diff Show More