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

161
Bowed.cpp
View File

@@ -1,161 +0,0 @@
/******************************************/
/* 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;
vibr = new RawLoop("rawwaves/sinewave.raw");
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
Bowed.h
View File

@@ -1,56 +0,0 @@
/******************************************/
/* 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 "RawLoop.h"
#include "ADSR.h"
class Bowed : public Instrmnt
{
protected:
DLineL *neckDelay;
DLineL *bridgeDelay;
BowTabl *bowTabl;
OnePole *reflFilt;
BiQuad *bodyFilt;
RawLoop *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

131
Brass.cpp
View File

@@ -1,131 +0,0 @@
/******************************************/
/* 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);
vibr = new RawLoop("rawwaves/sinewave.raw");
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");
}
}

View File

@@ -1,105 +0,0 @@
/*******************************************/
/* */
/* AllPass Interpolating Delay Line */
/* Object by Perry R. Cook 1995-96 */
/* 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 max_length)
{
long i;
length = max_length;
inputs = (MY_FLOAT *) malloc(length * MY_FLOAT_SIZE);
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 outputPointer;
outputPointer = inPoint - lag + 2; /* outPoint chases inpoint */
/* + 2 for interp and other */
while (outputPointer<0)
outputPointer += length; /* modulo table length */
outPoint = (long) outputPointer; /* Integer part of delay */
alpha = (MY_FLOAT) 1.0 + outPoint - outputPointer; /* fractional part of delay */
if (alpha<0.1) {
outputPointer += (MY_FLOAT) 1.0;/* Hack to avoid pole/zero */
outPoint += 1; /* cancellation. Keeps allpass */
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 */
}
/************ Test Main Program *****************/
/*
void main()
{
DLineA delay(140);
FILE *fd;
MY_FLOAT temp;
short data;
long i;
fd = fopen("test.raw","wb");
delay.setDelay(128);
for (i=0;i<4096;i++) {
if (i%256 != 0) temp = 0.0; else temp = 1.0;
data = (temp + delay.tick(temp)) * 16000.0;
fwrite(&data,2,1,fd);
}
delay.setDelay(64.5);
for (i=0;i<4096;i++) {
if (i%256 != 0) temp = 0.0; else temp = 1.0;
data = (temp + delay.tick(temp)) * 16000.0;
fwrite(&data,2,1,fd);
}
fclose(fd);
}
*/

View File

@@ -1,90 +0,0 @@
/*******************************************/
/* 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(long max_length)
{
length = max_length;
inputs = (MY_FLOAT *) malloc(length * MY_FLOAT_SIZE);
this->clear();
outPoint = 0;
inPoint = 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 outputPointer;
outputPointer = inPoint - lag; /* read chases write, add 1 for interp. */
while (outputPointer<0)
outputPointer += length; /* modulo maximum length */
outPoint = (long) outputPointer; /* integer part */
alpha = outputPointer - 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;
}
/************ Test Main Program *****************/
/*
void main()
{
DLineL delay(140);
FILE *fd;
MY_FLOAT temp;
short data;
long i;
fd = fopen("test.raw","wb");
delay.setDelay(128);
for (i=0;i<4096;i++) {
if (i%256 != 0) temp = 0.0; else temp = 1.0;
data = (temp + delay.tick(temp)) * 16000.0;
fwrite(&data,2,1,fd);
}
delay.setDelay(64.5);
for (i=0;i<4096;i++) {
if (i%256 != 0) temp = 0.0; else temp = 1.0;
data = (temp + delay.tick(temp)) * 16000.0;
fwrite(&data,2,1,fd);
}
fclose(fd);
}
*/

View File

@@ -1,80 +0,0 @@
/*******************************************/
/* Non-Interpolating Delay Line */
/* Object by Perry R. Cook 1995-96 */
/* This one uses a delay line of maximum */
/* length specified on creation. A non- */
/* interpolating delay line should be */
/* used in non-time varying (reverb) or */
/* non-critical (????) applications. */
/*******************************************/
#include "DLineN.h"
DLineN :: DLineN(long max_length)
{
length = max_length;
inputs = (MY_FLOAT *) malloc(length * MY_FLOAT_SIZE);
this->clear();
this->setDelay(length * (MY_FLOAT) 0.5);
inPoint = 0;
outPoint = 0;
}
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)
{
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++]; // first 1/2 of interpolation */
if (outPoint>=length) { // Check for end condition */
outPoint -= length;
}
return lastOutput;
}
/************ Test Main Program *****************/
/*
void main()
{
DLineN delay(140);
FILE *fd;
MY_FLOAT temp;
short data;
long i;
fd = fopen("test.raw","wb");
delay.setDelay(128);
for (i=0;i<4096;i++) {
if (i%256 != 0) temp = 0.0; else temp = 1.0;
data = (temp + delay.tick(temp)) * 16000.0;
fwrite(&data,2,1,fd);
}
delay.setDelay(64.5);
for (i=0;i<4096;i++) {
if (i%256 != 0) temp = 0.0; else temp = 1.0;
data = (temp + delay.tick(temp)) * 16000.0;
fwrite(&data,2,1,fd);
}
fclose(fd);
}
*/

View File

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

180
FM4Op.cpp
View File

@@ -1,180 +0,0 @@
/*******************************************/
/* 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;
vibWave = new RawLoop("rawwaves/sinewave.raw");
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 RawLoop(wave1);
waves[1] = new RawLoop(wave2);
waves[2] = new RawLoop(wave3);
waves[3] = new RawLoop(wave4);
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_)
this->setControl1(value * NORM_7);
else if (number == __SK_FootControl_)
this->setControl2(value * NORM_7);
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_) {
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
FM4Op.h
View File

@@ -1,59 +0,0 @@
/*******************************************/
/* 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 "RawLoop.h"
#include "TwoZero.h"
class FM4Op : public Instrmnt
{
protected:
ADSR *adsr[4];
RawLoop *waves[4];
RawLoop *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

175
Flute.cpp
View File

@@ -1,175 +0,0 @@
/******************************************/
/* 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;
vibr = new RawLoop("rawwaves/sinewave.raw");
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();
/* adsr->reset(); */
}
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
Flute.h
View File

@@ -1,64 +0,0 @@
/******************************************/
/* 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 "RawLoop.h"
class Flute : public Instrmnt
{
protected:
DLineL *jetDelay;
DLineL *boreDelay;
JetTabl *jetTable;
OnePole *filter;
DCBlock *dcBlock;
Noise *noise;
ADSR *adsr;
RawLoop *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

View File

@@ -1,176 +0,0 @@
/*******************************************/
/* 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 * MY_FLOAT_SIZE);
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;
}
/************ Test Main Program *****************/
/*
void main()
{
FormSwep filter;
FILE *fd;
MY_FLOAT temp;
short data;
long i;
fd = fopen("test.raw","wb");
filter.setTargets(100.0,0.99,0.01);
for (i=0;i<20000;i++) {
if (i%100 != 0) temp = 0.0; else temp = 1.0;
data = filter.tick(temp) * 32000.0;
fwrite(&data,2,1,fd);
}
filter.setTargets(1000.0,0.99,0.01);
for (i=0;i<20000;i++) {
if (i%100 != 0) temp = 0.0; else temp = 1.0;
data = filter.tick(temp) * 32000.0;
fwrite(&data,2,1,fd);
}
filter.setTargets(500.0,0.9999,0.001);
for (i=0;i<20000;i++) {
if (i%100 != 0) temp = 0.0; else temp = 1.0;
data = filter.tick(temp) * 32000.0;
fwrite(&data,2,1,fd);
}
fclose(fd);
}
*/

View File

@@ -1,46 +0,0 @@
/*******************************************/
/* 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

View File

@@ -1,60 +0,0 @@
/******************************************/
/* 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()
{
this->loadWaves("rawwaves/sinewave.raw",
"rawwaves/twopeaks.raw",
"rawwaves/twopeaks.raw",
"rawwaves/sinewave.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
}

View File

@@ -1,18 +1,20 @@
Brief Descriptions of Classes in STK98, ver. 2.01
A ToolKit of Sound Synthesis Classes
and Instruments in C++
Perry Cook, 1995-96, free distribution for
academic, instructional, tutorial, etc. purposes.
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
Version 3.0
By Perry R. Cook, 1995-99
and Gary P. Scavone, 1997-99.
STK Classes, Version 3.0
Please read README.txt for more information.
<--------Building Blocks---------->|<----------------Instruments------------------>
SourcSink Filters Reverb Non-Lin ModalSyn FM Physical Sampling PhISM
& Formant
SourcSink Filters Reverb Non-Lin Modal & FM Physical Sampling PhISM
Formant
Object-----------------------------------Instrmnt----------.
| | | | | | |
Envelope| Filter Reverb BowTabl | .------------------|---------------------.
Envelope| Filter Reverb BowTabl | .----------------------------------------.
| | | | JetTabl | | | | | | | | |
ADSR | OneZero PRCRev ReedTabl| Modal4 | FM4Op---.| | | | Shakers
| OnePole JCRev | | | | || | | | |
@@ -21,53 +23,55 @@ ADSR | OneZero PRCRev ReedTabl| Modal4 | FM4Op---.| | | | Sh
Noise | DCBlock LipFilt AgogoBel| HeavyMtl|| Brass SamplFlt| Cabasa
| | BiQuad | || Flute | | Bamboo
SubNoise| DlineL .____| .____|| Bowed Moog1 | Water Drops
| DLineA | | || | Tambourine
| DLineA | | || BowedBar | Tambourine
._____| DLineN VoicForm FM4Alg4 ||____. | SleighBells
| | FormSwep | | | | Guiro
RawWave | PercFlut| Plucked2 |
| | | |
._____| .____| Mandolin .____|
| | | | |
RawLoop | FM4Alg5 | DrumSynt
| | |
._____| Rhodey |
| | Wurley |
Modulatr| TubeBell |
| .____|
WvIn | PoleZero PercFlut| Plucked2 | Wrench
| |____. | | | Coke Can
WavWvIn | | .____| Mandolin .____| Sticks
SndWvIn | TablLook | | | Crunch
RawWvIn | FM4Alg5 | DrumSynt Sand Paper
MatWvIn | | |
RTWvIn | Rhodey |
| Wurley |
._____| TubeBell |
| | .____|
Modulatr| | |
| FM4Alg6 |
._____| | |
| | FM4Alg6 |
SingWave| | |
| FMVoices|
._____|_____. |
| | | .____|
VoicMang| WvOut |
| | FM4Alg8
._____| WavWvOut |
| | SndWvOut BeeThree
RawWvIn | RTWvOut
| | FMVoices|
SingWave|_____. |
| | .____|
._____| WvOut |
| | | FM4Alg8
VoicMang| WavWvOut |
| SndWvOut BeeThree
| RTWvOut
| MatWvOut
._____|
._____| RawWvOut
|
MIDIInpt
MIDIIO
********** Instruments and Algorithms **************
********** INSTRUMENTS AND ALGORITHMS **************
Each Class will be listed either with all UGs it uses,
or the <<Algorithm>> of which it is a flavor.
All inherit from Instrmnt, which inherits from Object.
Plucked.cpp Basic Plucked String DLineA,OneZero,OnePole,Noise
Plucked2.cpp Not so Basic Pluck DLineL,DlineA,OneZero
Mandolin.cpp My Own Mandolin <<flavor of PLUCKED2>>
Plucked2.cpp Not So Basic Pluck DLineL,DlineA,OneZero
Mandolin.cpp My Own Mandolin <<flavor of Plucked2>>
Bowed.cpp Not Hideous Bowed String DlineL,BowTabl,OnePole,BiQuad,RawWave,ADSR
Brass.cpp Not So Bad Brass Inst. DLineA,LipFilt,DCBlock,ADSR,RawLoop
Clarinet.cpp Pretty Good Clarinet DLineL,ReedTabl,OneZero,Envelope,Noise,RawLoop
Flute.cpp Pretty Good Flute JetTabl,DLineL,OnePole,DCBlock,Noise,ADSR,RawLoop
Modal4.cpp 4 Resonances Envelope,RawWave,RawLoop,BiQuad,OnePole
Brass.cpp Not So Bad Brass Inst. DLineA,LipFilt,DCBlock,ADSR,RawWvIn
Clarinet.cpp Pretty Good Clarinet DLineL,ReedTabl,OneZero,Envelope,Noise,RawWvIn
Flute.cpp Pretty Good Flute JetTabl,DLineL,OnePole,DCBlock,Noise,ADSR,RawWvIn
BowedBar.cpp Pretty Good Bowed Bar DLineN,BowTabl,ADSR,BiQuad
Modal4.cpp 4 Resonances Envelope,RawWvIn,RawWvIn,BiQuad,OnePole
Marimba.cpp <<flavor of MODAL4>>
Vibraphn.cpp <<flavor of MODAL4>>
Agogobel.cpp <<flavor of MODAL4>>
FM4Op.cpp 4 Operator FM Master ADSR,RawLoop,TwoZero
FM4Op.cpp 4 Operator FM Master ADSR,RawWvIn,TwoZero
FM4Alg3.cpp 3 Cascade w/ FB Mod. <<flavor of FM4OP>>
FM4Alg4.cpp Like Alg3 but diff. <<flavor of FM4OP>>
FM4Alg5.cpp 2 Parallel Simple FMs <<flavor of FM4OP>>
@@ -80,36 +84,44 @@ Wurley.cpp Wurlitz. Elec. Piano <<flavor of FM4Alg5>>
TubeBell.cpp Classic FM Bell <<flavor of FM4Alg5>>
FMVoices.cpp 3-Formant Voice Synth. <<flavor of FM4Alg6>>
BeeThree.cpp Cheezy Organ for Paul <<flavor of FM4Alg8>>
Sampler.cpp Sampling Synth. 4 each ADSR, RawWave (att), RawLoop (loop), OnePole
Sampler.cpp Sampling Synth. 4 each ADSR, RawWvIn (att), RawWvIn (loop), OnePole
SamplFlt.cpp Sampler with Swept Filter <<flavor of Sampler>>
Moog1.cpp Swept filter flavor of <<flavor of SamplFlt>>
VoicForm.cpp Source/Filter Voice Envelope,Noise,SingWave,FormSwep,OnePole,OneZero
DrumSynt.cpp Drum Synthesizer bunch of RawWvIn, and OnePole
Shakers.cpp Stochastic Event Models
*********** Basic Unit Generators **************
*********** BASIC UNIT GENERATORS **************
Master Object: Object.cpp For compatibility with Objective C
Source&Sink: RawWave.cpp Lin-Interp Wavetable, Looped or 1 Shot
RawLoop.cpp Lin-Interp Wavetable, Looping
RawWvIn.cpp Lin-Interp Wave In streaming 'device'
Envelope.cpp Linearly Goes to Target by Rate, + noteOn/Off
Source&Sink: Envelope.cpp Linearly Goes to Target by Rate, + noteOn/Off
ADSR.cpp ADSR Flavor of Envelope
Noise.cpp Random Number Generator
SubNoise.cpp Random Numbers each N samples
Inputs: TablLook.cpp Lookup Table (assumes given data in big-endian format)
WvIn.cpp Input Master Class (Looping, One-Shot,
Interpolating, Non-Interpolating)
RawWvIn.cpp STK Raw-file Input
SndWvIn.cpp .snd Input Class
WavWvIn.cpp .wav Input Class
MatWvIn.cpp Matlab MAT-file Input Class
RTWvIn.cpp Realtime Input Class
Outputs: WvOut.cpp Output Master Class
RawWvOut.cpp STK Raw-file Output Class
SndWvOut.cpp .snd Output Class
WavWvOut.cpp .wav Output Class
RTWvOut.cpp Realtime Output Class
MatWvOut.cpp Matlab Matfile Output Class
MatWvOut.cpp Matlab MaT-file Output Class
Inputs: MIDIInpt.cpp MIDI Stream Parser Class
MIDI: MIDIIO.cpp MIDI I/O Class
Filters: Filter.cpp Filter Master Class
OneZero.cpp One Zero Filter
OnePole.cpp One Pole Filter
PoleZero.cpp One Pole/One Zero Filter
DCBlock.cpp DC Blocking 1Pole/1Zero Filter
TwoZero.cpp Two Zero Filter
TwoPole.cpp Two Pole Filter
@@ -129,5 +141,5 @@ NonLin&Lookup: JetTabl.cpp Cubic Jet NonLinearity
ReedTabl.cpp 1 break point Reed NonLinearity
LipFilt.cpp Pressure Controlled BiQuad with NonLin
Derived: Modulatr.cpp Per. and Rnd. Vibrato: RawWave,SubNoise,OnePole
SingWave.cpp Looping Wavetable with: Modulatr,Envelope
Derived: Modulatr.cpp Per. and Rnd. Vibrato: RawWave, SubNoise, OnePole
SingWave.cpp Looping Wavetable with: Modulatr, Envelope

View File

@@ -1,47 +0,0 @@
# STK98 Makefile - NeXTStep solo version
O_FILES = Object.o Envelope.o ADSR.o Noise.o SubNoise.o \
RawWave.o RawShot.o RawLoop.o RawInterp.o \
Modulatr.o Filter.o OneZero.o \
OnePole.o TwoZero.o TwoPole.o DCBlock.o \
BiQuad.o DLineA.o DLineL.o DLineN.o VoicMang.o \
FormSwep.o BowTabl.o JetTabl.o ReedTabl.o \
LipFilt.o Modal4.o FM4Op.o FM4Alg3.o FM4Alg4.o \
FM4Alg5.o FM4Alg6.o FM4Alg8.o Plucked2.o \
SamplFlt.o Sampler.o SKINI11.o Simple.o \
SingWave.o VoicForm.o FMVoices.o swapstuf.o \
\
Instrmnt.o Marimba.o Vibraphn.o AgogoBel.o Shakers.o \
Plucked.o Mandolin.o Clarinet.o Flute.o Moog1.o \
Brass.o Bowed.o Rhodey.o Wurley.o TubeBell.o \
HeavyMtl.o PercFlut.o BeeThree.o DrumSynt.o \
\
WvOut.o SndWvOut.o WavWvOut.o MatWvOut.o \
Reverb.o PRCRev.o JCRev.o NRev.o
RM = /bin/rm
CC = cc -arch m68k -arch i386 -Wall
INSTR = syntmono
.SUFFIXES: .cpp
.cpp.o: Object.h
$(CC) -c $*.cpp
all: $(INSTR)
syntmono: syntmono.cpp $(O_FILES)
$(CC) $(INCLUDE) -o syntmono syntmono.cpp $(O_FILES) $(LIBRARY)
MD2SKINI: MD2SKINI.cpp $(O_FILES)
$(CC) -o MD2SKINI MD2SKINI.cpp $(O_FILES) $(LIBRARY)
clean :
rm *.o
rm $(INSTR)
cleanIns :
rm $(INSTR)
strip :
strip $(INSTR)

View File

@@ -1,68 +0,0 @@
# STK98 Makefile - Global version for Unix systems which have GNU
# Makefile utilities installed. If this Makefile does not work on
# your system, try using the platform specific Makefiles (.sgi,
# .next, and .linux).
OS = $(shell uname)
O_FILES = Object.o Envelope.o ADSR.o Noise.o SubNoise.o \
RawWave.o RawWvIn.o RawLoop.o \
Modulatr.o Filter.o OneZero.o \
OnePole.o TwoZero.o TwoPole.o DCBlock.o \
BiQuad.o DLineA.o DLineL.o DLineN.o VoicMang.o \
FormSwep.o BowTabl.o JetTabl.o ReedTabl.o \
LipFilt.o Modal4.o FM4Op.o FM4Alg3.o FM4Alg4.o \
FM4Alg5.o FM4Alg6.o FM4Alg8.o Plucked2.o \
SamplFlt.o Sampler.o SKINI11.o Simple.o \
SingWave.o VoicForm.o FMVoices.o swapstuf.o \
\
Instrmnt.o Marimba.o Vibraphn.o AgogoBel.o Shakers.o \
Plucked.o Mandolin.o Clarinet.o Flute.o Moog1.o \
Brass.o Bowed.o Rhodey.o Wurley.o TubeBell.o \
HeavyMtl.o PercFlut.o BeeThree.o DrumSynt.o \
\
WvOut.o SndWvOut.o WavWvOut.o MatWvOut.o \
Reverb.o PRCRev.o JCRev.o NRev.o
RM = /bin/rm
ifeq ($(OS),NEXTSTEP) # These are for NeXT
CC = cc -arch m68k -arch i386 -Wall
INSTR = syntmono
endif
ifeq ($(OS),IRIX) # These are for SGI
INSTR = MD2SKINI syntmono
CC = CC -O # -g -fullwarn -D__SGI_CC__
O_FILES += RTWvOut.o RTSoundIO.o MIDIIO.o
LIBRARY = -L/usr/sgitcl/lib -laudio -lmd -lm
endif
ifeq ($(OS),Linux) # These are for Linux
INSTR = syntmono MD2SKINI
CC = gcc -O3 # -g -pg -O3
O_FILES += RTWvOut.o RTSoundIO.o MIDIIO.o
LIBRARY = -lpthread -lm
endif
.SUFFIXES: .cpp
.cpp.o: Object.h
$(CC) -c $*.cpp
all: $(INSTR)
syntmono: syntmono.cpp $(O_FILES)
$(CC) $(INCLUDE) -o syntmono syntmono.cpp $(O_FILES) $(LIBRARY)
MD2SKINI: MD2SKINI.cpp $(O_FILES)
$(CC) -o MD2SKINI MD2SKINI.cpp $(O_FILES) $(LIBRARY)
clean :
rm *.o
rm $(INSTR)
cleanIns :
rm $(INSTR)
strip :
strip $(INSTR)

View File

@@ -1,49 +0,0 @@
# STK98 Makefile - Linux solo version
O_FILES = Object.o Envelope.o ADSR.o Noise.o SubNoise.o \
RawWave.o RawShot.o RawLoop.o RawInterp.o \
Modulatr.o Filter.o OneZero.o \
OnePole.o TwoZero.o TwoPole.o DCBlock.o \
BiQuad.o DLineA.o DLineL.o DLineN.o VoicMang.o \
FormSwep.o BowTabl.o JetTabl.o ReedTabl.o \
LipFilt.o Modal4.o FM4Op.o FM4Alg3.o FM4Alg4.o \
FM4Alg5.o FM4Alg6.o FM4Alg8.o Plucked2.o \
SamplFlt.o Sampler.o SKINI11.o Simple.o \
SingWave.o VoicForm.o FMVoices.o swapstuf.o \
\
Instrmnt.o Marimba.o Vibraphn.o AgogoBel.o Shakers.o \
Plucked.o Mandolin.o Clarinet.o Flute.o Moog1.o \
Brass.o Bowed.o Rhodey.o Wurley.o TubeBell.o \
HeavyMtl.o PercFlut.o BeeThree.o DrumSynt.o \
\
WvOut.o SndWvOut.o WavWvOut.o MatWvOut.o \
Reverb.o PRCRev.o JCRev.o NRev.o \
RTWvOut.o RTSoundIO.o MIDIIO.o
RM = /bin/rm
INSTR = syntmono MD2SKINI
CC = gcc -O3 # -g -pg -O3
LIBRARY = -lpthread -lm
.SUFFIXES: .cpp
.cpp.o: Object.h
$(CC) -c $*.cpp
all: $(INSTR)
syntmono: syntmono.cpp $(O_FILES)
$(CC) $(INCLUDE) -o syntmono syntmono.cpp $(O_FILES) $(LIBRARY)
MD2SKINI: MD2SKINI.cpp $(O_FILES)
$(CC) -o MD2SKINI MD2SKINI.cpp $(O_FILES) $(LIBRARY)
clean :
rm *.o
rm $(INSTR)
cleanIns :
rm $(INSTR)
strip :
strip $(INSTR)

View File

@@ -1,49 +0,0 @@
# STK98 Makefile - SGI solo version
O_FILES = Object.o Envelope.o ADSR.o Noise.o SubNoise.o \
RawWave.o RawShot.o RawLoop.o RawInterp.o \
Modulatr.o Filter.o OneZero.o \
OnePole.o TwoZero.o TwoPole.o DCBlock.o \
BiQuad.o DLineA.o DLineL.o DLineN.o VoicMang.o \
FormSwep.o BowTabl.o JetTabl.o ReedTabl.o \
LipFilt.o Modal4.o FM4Op.o FM4Alg3.o FM4Alg4.o \
FM4Alg5.o FM4Alg6.o FM4Alg8.o Plucked2.o \
SamplFlt.o Sampler.o SKINI11.o Simple.o \
SingWave.o VoicForm.o FMVoices.o swapstuf.o \
\
Instrmnt.o Marimba.o Vibraphn.o AgogoBel.o Shakers.o \
Plucked.o Mandolin.o Clarinet.o Flute.o Moog1.o \
Brass.o Bowed.o Rhodey.o Wurley.o TubeBell.o \
HeavyMtl.o PercFlut.o BeeThree.o DrumSynt.o \
\
WvOut.o SndWvOut.o WavWvOut.o MatWvOut.o \
Reverb.o PRCRev.o JCRev.o NRev.o \
RTWvOut.o RTSoundIO.o MIDIIO.o
RM = /bin/rm
INSTR = MD2SKINI syntmono
CC = CC -O # -g -fullwarn -D__SGI_CC__
LIBRARY = -L/usr/sgitcl/lib -laudio -lmd -lm
.SUFFIXES: .cpp
.cpp.o: Object.h
$(CC) -c $*.cpp
all: $(INSTR)
syntmono: syntmono.cpp $(O_FILES)
$(CC) $(INCLUDE) -o syntmono syntmono.cpp $(O_FILES) $(LIBRARY)
MD2SKINI: MD2SKINI.cpp $(O_FILES)
$(CC) -o MD2SKINI MD2SKINI.cpp $(O_FILES) $(LIBRARY)
clean :
rm *.o
rm $(INSTR)
cleanIns :
rm $(INSTR)
strip :
strip $(INSTR)

View File

@@ -1,113 +0,0 @@
/*******************************************/
/* 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()
{
wave = new RawInterp("rawwaves/marmstk1.raw");
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();
}

View File

@@ -1,214 +0,0 @@
/*******************************************/
/* Matlab MAT File Output Class, */
/* by Gary P. Scavone, 1998. */
/* This object creates a Matlab MAT-file */
/* structure and fills it with buffers of */
/* samples (doubles). */
/* */
/* The Matlab MAT-file format is not */
/* available to the general public. I */
/* spent several days reverse-engineering */
/* the file format to create this class. */
/* I couldn't figure out what a few of */
/* the header fields correspond to, but */
/* for the purposes of STK, this */
/* shouldn't create any problems. */
/*******************************************/
#include "MatWvOut.h"
/******** Matlab Matfile Header Struct *******/
struct matheaderform {
char heading[124];
short a[2];
long b[10];
/* There's more, but it's of variable length */
};
FILE *openMatFile(int chans,char *fileName) {
struct matheaderform hdr;
FILE *fd;
char tempName[128];
int i, namelen;
long longtmp, headsize;
strcpy(hdr.heading,"MATLAB 5.0 MAT-file, Generated by STK98. This file format was hacked by Gary P. Scavone, CCRMA, Stanford University, 1998.");
for (i=strlen(hdr.heading);i<124;i++) hdr.heading[i] = ' ';
hdr.a[0] = (short) 256;
hdr.a[1] = (short) 'M';
hdr.a[1] <<= 8;
hdr.a[1] += 'I';
hdr.b[0] = (long) 14;
hdr.b[1] = (long) 0; /* Size of file after this point to end (in bytes) */
hdr.b[2] = (long) 6;
hdr.b[3] = (long) 8;
hdr.b[4] = (long) 6;
hdr.b[5] = (long) 0;
hdr.b[6] = (long) 5;
hdr.b[7] = (long) 8;
hdr.b[8] = (long) chans; /* This is the number of rows */
hdr.b[9] = (long) 0; /* This is the number of columns */
strcpy(tempName,fileName);
strcat(tempName,".mat");
fd = fopen(tempName,"w+b");
if (!fd) {
printf("Couldn't create matfile %s !!!!!!!!\n",fileName);
exit(0);
}
printf("Creating matfile %s.\n", tempName);
fwrite(&hdr,sizeof(char),168,fd); /* Write the fixed portion of the header */
/* The next 4 bytes can be viewed as two shorts, but they are byteswapped
as a long. The first short value seems to always be one; the second
short will be the length of the variable name IF IT IS <= 4; if the
variable name length is >4, this short is zero and the length is put
in the next 4 bytes. The variable name length is limited to 31
characters (32 with a '\n'). The actual variable name then follows.
The variable name is "zero-padded" out to the following minimum
lengths (in bits): 4, 8, 16, 24, 32.
*/
namelen = strlen(fileName);
if (namelen > 31) { /* Check length of variable name (file name) */
fprintf(stderr, "File name too long ... should be 31 characters or less.\n");
fclose(fd);
exit(0);
}
if (namelen > 4) {
longtmp = 1;
fwrite(&longtmp,sizeof(long),1,fd);
fwrite(&namelen,sizeof(long),1,fd);
headsize = 44 + namelen;
} else {
longtmp = namelen;
longtmp <<= 16;
longtmp += 1;
fwrite(&longtmp,sizeof(long),1,fd);
headsize = 40 + namelen;
}
fwrite(fileName,sizeof(char),namelen,fd); /* Write the variable (file) name */
if (namelen < 5)
longtmp = 4 - namelen;
else if (namelen < 9)
longtmp = 8 - namelen;
else if (namelen < 17)
longtmp = 16 - namelen;
else if (namelen < 25)
longtmp = 24 - namelen;
else longtmp = 32 - namelen;
headsize += longtmp + 8; /* Add length (8) of following bytes */
fseek(fd,longtmp,SEEK_CUR);
longtmp = 9;
fwrite(&longtmp,sizeof(long),1,fd);
longtmp = 0; /* Size of data in bytes (8 per sample) */
fwrite(&longtmp,sizeof(long),1,fd);
fseek(fd,132,SEEK_SET);
fwrite(&headsize,sizeof(long),1,fd); /* Write header size ... will update at end */
fseek(fd,0,SEEK_END);
return fd;
}
MatWvOut :: MatWvOut(char *fileName)
{
chans = 1;
pan = 0.5;
fd = openMatFile(chans,fileName);
counter = 0;
totalCount = 0;
}
MatWvOut :: MatWvOut(int channels, char *fileName)
{
chans = channels;
pan = 0.5;
fd = openMatFile(chans,fileName);
counter = 0;
totalCount = 0;
}
MatWvOut :: ~MatWvOut()
{
double temp;
long 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(long),1,fd); /* Write number of columns */
fseek(fd,132,SEEK_SET);
fread(&headsize,sizeof(long),1,fd);
temp1 = headsize;
headsize += (long) (totalCount * 8 * 2);
fseek(fd,132,SEEK_SET);
fwrite(&headsize,sizeof(long),1,fd); /* Write file size (minus some header info) */
fseek(fd,temp1+128,SEEK_SET);
temp1 = totalCount * 8 * 2;
fwrite(&temp1,sizeof(long),1,fd); /* Write data size (in bytes) */
fclose(fd);
}
long MatWvOut :: getCounter()
{
return totalCount;
}
MY_FLOAT MatWvOut :: getTime()
{
return (MY_FLOAT) totalCount * ONE_OVER_SRATE;
}
void MatWvOut :: tick(MY_FLOAT sample)
{
if (chans==1) {
data[counter++] = (double) (sample);
}
else {
data[counter++] = (double) (sample * (1.0 - pan));
data[counter++] = (double) (sample * pan);
}
totalCount += 1;
if (counter == MAT_BUFFER_SIZE) {
fwrite(data,sizeof(double),MAT_BUFFER_SIZE,fd);
counter = 0;
}
}
void MatWvOut :: tick(MY_FLOAT lsamp, MY_FLOAT rsamp)
{
if (chans==1) {
data[counter++] = (double) (lsamp + rsamp);
}
else {
data[counter++] = (double) (lsamp);
data[counter++] = (double) (rsamp);
}
totalCount += 1;
if (counter == MAT_BUFFER_SIZE) {
fwrite(data,sizeof(double),MAT_BUFFER_SIZE,fd);
counter = 0;
}
}
void MatWvOut :: setMonoPan(MY_FLOAT aPan)
{
pan = aPan;
if (aPan < 0.0) {
pan = 0.0;
printf("Pan < 0.0, correcting to 0.0\n");
}
if (aPan > 1.0) {
pan = 1.0;
printf("Pan > 1.0, correcting to 1.0\n");
}
}

View File

@@ -1,46 +0,0 @@
/*******************************************/
/* Matlab MAT File Output Class, */
/* by Gary P. Scavone, 1998. */
/* This object creates a Matlab MAT-file */
/* structure and fills it with buffers of */
/* samples (doubles). */
/* */
/* The Matlab MAT-file format is not */
/* available to the general public. I */
/* spent several days reverse-engineering */
/* the file format to create this class. */
/* I couldn't figure out what a few of */
/* the header fields correspond to, but */
/* for the purposes of STK, this */
/* shouldn't create any problems. */
/*******************************************/
#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 uses doubles */
long counter;
long totalCount;
int chans;
MY_FLOAT pan;
public:
MatWvOut(char *infileName);
MatWvOut(int channels, char *infileName);
~MatWvOut();
long getCounter();
MY_FLOAT getTime();
void setMonoPan(MY_FLOAT aPan);
void tick(MY_FLOAT sample);
void tick(MY_FLOAT lsamp, MY_FLOAT rsamp);
};
#endif // defined(__MatWvOut_h)

107
Moog1.cpp
View File

@@ -1,107 +0,0 @@
/******************************************/
/* 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()
{
attacks[0] = new RawInterp("rawwaves/mandpluk.raw");
loops[0] = new RawLoop("rawwaves/impuls20.raw");
loops[1] = new RawLoop("rawwaves/sinewave.raw"); /* 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;
}

134
Object.h
View File

@@ -1,134 +0,0 @@
/*********************************************/
/* 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. */
/*********************************************/
#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();
};
/* Uncomment your OS type below! */
/* #define __OS_NeXT_ */
#define __OS_IRIX_
/* #define __OS_Linux_ */
/* #define __OS_Win_ */
#if defined(__OS_NeXT_) /* For NeXTStep - Black or White Hardware */
#define __NeXT_
#elif defined(__OS_IRIX_) /* For SGI */
#define __SGI_REALTIME_
typedef int bool;
#elif defined(__OS_Linux_) /* For Linux */
#define __USS_REALTIME_
#define __LITTLE_ENDIAN__
#elif defined(__OS_Win_) /* For Windows95 or NT */
#define __WINDS_REALTIME_ /* For Direct Sound API */
/* #define __WINMM_REALTIME_ */ /* For Win MM API */
#define __SOCKET
#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.
*/
#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
/* SRATE here is 44100, others are derived accordingly */
/*
#define SRATE (MY_FLOAT) 44100.0
#define SRATE_OVER_TWO (MY_FLOAT) 22050.0
#define ONE_OVER_SRATE (MY_FLOAT) 0.00002267573696
#define RATE_NORM (MY_FLOAT) 0.5
#define TWO_PI_OVER_SRATE (MY_FLOAT) 0.0001424758573
*/
/* SRATE here is 22050, others are derived accordingly */
#define SRATE (MY_FLOAT) 22050.0
#define SRATE_OVER_TWO (MY_FLOAT) 11025.0
#define ONE_OVER_SRATE (MY_FLOAT) 0.00004535147392
#define RATE_NORM (MY_FLOAT) 1.0
#define TWO_PI_OVER_SRATE (MY_FLOAT) 0.0002849517146
/* SRATE here is 16000, others are derived accordingly */
/*
#define SRATE (MY_FLOAT) 16000.0
#define SRATE_OVER_TWO (MY_FLOAT) 8000.0
#define ONE_OVER_SRATE (MY_FLOAT) 0.0000625
#define RATE_NORM (MY_FLOAT) 1.375
#define TWO_PI_OVER_SRATE (MY_FLOAT) 0.000392699
*/
/* SRATE here is 8k, others are derived accordingly */
/*
#define SRATE (MY_FLOAT) 8000.0
#define SRATE_OVER_TWO (MY_FLOAT) 4000
#define ONE_OVER_SRATE (MY_FLOAT) 0.00012500000000
#define RATE_NORM (MY_FLOAT) 2.75625
#define TWO_PI_OVER_SRATE (MY_FLOAT) 0.0002849517146
*/
/* 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 increasesf
* 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_SIZE 8
/*
#define MY_FLOAT float
#define MY_FLOAT_SIZE 4
*/
/* Debugging define, causes massive printf's to come out.
* Also enables timing calculations in WaveOut class, other stuff.
*/
/* #define _debug_ 1 */
/* MIDI definitions */
#define NORM_7 (MY_FLOAT) 0.0078125 /* this is 1/128 */
#endif

View File

@@ -1,81 +0,0 @@
/*******************************************/
/* 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(MY_FLOAT_SIZE);
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;
}
/************ Test Main ************************/
/*
#include <stdio.h>
void main()
{
long i;
OnePole test;
test.setPole(0.99);
for (i=0;i<150;i++) printf("%lf ",test.tick(1.0));
printf("\n\n");
test.clear();
test.setPole(0.9);
test.setGain(2.0);
for (i=0;i<150;i++) printf("%lf ",test.tick(0.5));
printf("\n\n");
}
*/

View File

@@ -1,54 +0,0 @@
/******************************************/
/* 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()
{
this->loadWaves("rawwaves/sinewave.raw",
"rawwaves/sinewave.raw",
"rawwaves/sinewave.raw",
"rawwaves/sinewave.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
}

View File

@@ -1,42 +1,17 @@
STK98v2: A ToolKit of Audio Synthesis Classes and Instruments in C++
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
Version 3.0
By Perry R. Cook, 1995-98
With recent help by Gary P. Scavone
By Perry R. Cook, 1995-99
and Gary P. Scavone, 1997-99.
Please read the file README.txt for more general STK information.
STK98 for Linux is currently using the OSS sound and MIDI API. The free version of OSS will probably work, though it doesn't work with as many soundcards as the commercial version (costs about $20).
STK for Linux is currently using the OSS sound and MIDI API. The free version of OSS will probably work, though it doesn't work with as many soundcards as the commercial version (which costs about $20).
STK98 should compile without much trouble, after you make the appropriate settings in Object.h and select an appropriate Makefile. Since all Linux systems should come with the GNU makefile utilities, you should be able to use either Makefile.all or Makefile.linux (which should be renamed "Makefile" before using). Typing "make" should initiate the compilation process.
STK should compile without much trouble under Linux. Since all Linux distributions typically include the GNU makefile utilities, you should be able to use the default Makefile. Typing "make" will initiate the compilation process.
NOTE REGARDING PTHREADS: The only issue which seems to crop up on different versions of Linux concerns threads. I am using the MIT pthreads API. Under RedHat Linux 4.x, I had to specifically include <pthread/mit/pthread.h> (the default pthread library didn't work). However, under RedHat Linux 5.0, the default works and the <pthread/mit/> path doesn't exist. I've decided to assume the default works. If you get errors with regard to pthreads when you compile, you'll have to search your system for the MIT pthread distribution and change the appropriate include statements in MIDIIO.cpp, MD2SKINI.cpp, and syntmono.cpp.
NOTE REGARDING PTHREADS:
Once everything is compiled, you can use the scripts in "TCLSpecs" to run GUIs or invoke direct MIDI input controls. However, these scripts have been written for Tcl/Tk 8.0 ... they seem to work OK on older versions of Tcl/Tk under Linux, but not under IRIX. Tcl/Tk is free, so you might as well download the newest version.
Two primary executables are created during compilation - syntmono and MD2SKINI. Syntmono is the core STK synthesis server. All distributed STK instruments are run using syntmono. MD2SKINI takes raw MIDI input, converts it to SKINI format, and outputs the result to stdout or a socket port ID (under Windoze). Control data (in the form of SKINI messages) can be fed to syntmono through three principal means - SKINI scorefiles, MD2SKINI output, and Tcl/Tk GUIs. A variety of SKINI scorefiles are distributed with STK98 and can be found in the "scores" directory. Under all platforms, a scorefile can be piped or redirected to syntmono in the following way:
more scores/streetsf.ski | syntmono Clarinet -r
or
syntmono Clarinet -r < scores/streetsf.ski
A number of Tcl/Tk GUIs are provided in the "TCLSpecs" directory, though you will have to install Tcl/Tk on your system to use them. Realtime SKINI control data (via MD2SKINI or GUIs) can be piped to syntmono on Unix platforms in the following way:
MD2SKINI | syntmono Clarinet -r -i
or
wish < TCLSpecs/TCLPhys.tcl | syntmono Clarinet -r -i
The only issue which seems to crop up on different versions of Linux concerns threads. I am using the MIT pthreads API. Under RedHat Linux 4.x, I had to specifically include <pthread/mit/pthread.h> (the default pthread library didn't work). However, under RedHat Linux 5.0 and higher, the default works and the <pthread/mit/> path doesn't exist. I've decided to assume the default works. If you get errors with regard to pthreads when you compile, you'll have to search your system for the MIT pthread distribution and change the appropriate include statements in MIDIIO.cpp, MD2SKINI.cpp, and threads.cpp.
/******************************************************/
Legal and Ethical:
This software was designed and created to be made publicly available for free, primarily for academic purposes, so if you use it, pass it on with this documentation, and for free.
If you make a million dollars with it, give me some. If you make compositions with it, put me in the program notes.
Some of the concepts are covered by various patents, some known to me and likely others which are unknown. Many of the ones known to me are administered by the Stanford Office of Technology and Licensing.
The good news is that large hunks of the techniques used here are public domain. To avoid subtle legal issues, I'll not state what's freely useable here, but I'll try to note within the various classes where certain things are likely to be protected by patents.
/******************************************************/

View File

@@ -1,38 +1,11 @@
STK98v2: A ToolKit of Audio Synthesis Classes and Instruments in C++
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
Version 3.0
By Perry R. Cook, 1995-98
With recent help by Gary P. Scavone
By Perry R. Cook, 1995-99
and Gary P. Scavone, 1997-99.
Please read the file README.txt for more general STK information.
STK98 should compile without much trouble, after you make the appropriate settings in Object.h and select an appropriate Makefile. Apparently, SGI systems are not distributed with the GNU makefile utilities, so your safest bet is to use Makefile.sgi (which should be renamed "Makefile" before using). If you do have the GNU makefile utilities on your system, you could also use Makefile.all (which is convenient if you are on a network with a variety of different computer systems). Typing "make" should initiate the compilation process.
Once everything is compiled, you can use the scripts in "TCLSpecs" to run GUIs or invoke direct MIDI input controls.
Two primary executables are created during compilation - syntmono and MD2SKINI. Syntmono is the core STK synthesis server. All distributed STK instruments are run using syntmono. MD2SKINI takes raw MIDI input, converts it to SKINI format, and outputs the result to stdout or a socket port ID (under Windoze). Control data (in the form of SKINI messages) can be fed to syntmono through three principal means - SKINI scorefiles, MD2SKINI output, and Tcl/Tk GUIs. A variety of SKINI scorefiles are distributed with STK98 and can be found in the "scores" directory. Under all platforms, a scorefile can be piped or redirected to syntmono in the following way:
more scores/streetsf.ski | syntmono Clarinet -r
or
syntmono Clarinet -r < scores/streetsf.ski
A number of Tcl/Tk GUIs are provided in the "TCLSpecs" directory, though you will have to install Tcl/Tk on your system to use them. Realtime SKINI control data (via MD2SKINI or GUIs) can be piped to syntmono on Unix platforms in the following way:
MD2SKINI | syntmono Clarinet -r -i
or
wish < TCLSpecs/TCLPhys.tcl | syntmono Clarinet -r -i
/******************************************************/
Legal and Ethical:
This software was designed and created to be made publicly available for free, primarily for academic purposes, so if you use it, pass it on with this documentation, and for free.
If you make a million dollars with it, give me some. If you make compositions with it, put me in the program notes.
Some of the concepts are covered by various patents, some known to me and likely others which are unknown. Many of the ones known to me are administered by the Stanford Office of Technology and Licensing.
The good news is that large hunks of the techniques used here are public domain. To avoid subtle legal issues, I'll not state what's freely useable here, but I'll try to note within the various classes where certain things are likely to be protected by patents.
/******************************************************/
It seems that SGI systems are not distributed with the GNU Makefile utilities. The default Make utility has very limited functionality, so your safest bet is to download the GNU Makefile utilities from the Internet and use STK's default Makefile. If this is not possible, try using Makefile.sgi (make -f Makefile.sgi).
Aside from the Makefile issues, STK should compile and run on SGI platforms without any problems.

View File

@@ -1,17 +1,23 @@
STK98v2: A ToolKit of Audio Synthesis Classes and Instruments in C++
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
Version 3.0
By Perry R. Cook, 1995-98
With recent help by Gary P. Scavone
By Perry R. Cook, 1995-99
and Gary P. Scavone, 1997-99.
Please read the file README.txt for more general STK information.
Realtime sound output under Win95 is supported using either the Direct Sound (dsound.lib) API or the old WinMM (winmm.lib) API. The Direct Sound version appears to well out-perform the older API. All new versions of Win95/NT come with the Direct Sound library, but early versions did not. If you have trouble running the distributed executables (compiled for Direct Sound API), then you probably don't have Direct Sound installed on your system. You can download the necessary Direct Sound stuff from Microsoft's WWW pages (http://www.microsoft.com/directx/download.asp). If all else fails, you should be able to compile using the winmm.lib routines ... more latency, but at least it will work.
DirectX and WindowsNT Issues:
-----------------------------
The newly offered STK realtime sound input capabilities under Windoze are only supported using the DirectSoundCapture API. The latency is pretty horrendous, but what do you expect? Also, there is a good chance you don't have DirectSoundCapture support on your computer. You should download the DirectX 6.0 (or higher) runtime libraries from Microsoft's WWW site (http://www.microsoft.com/directx/download.asp) in order to run the pre-compiled STK executables for Windoze. HOWEVER, there is no DirectSoundCapture support for WindowsNT at this time ... you'll have to wait for Windows 2000. If you wish to compile STK under WindowsNT (without realtime audio input support), you'll have to uncomment the __WINMM_API_ flag (and comment out the __WINDS_API flag) in Object.h and recompile the source code.
Realtime sound output under Windoze is supported using either the DirectSound (dsound.lib) API or the old WinMM (winmm.lib) API. The DirectSound version appears to well out-perform the older API. All new versions of Win95/98/NT come with the DirectSound library, but early versions did not. If you have trouble running the distributed executables (compiled for DirectSound API), then you probably don't have DirectSound installed on your system. You can download the necessary DirectSound stuff from Microsoft's WWW pages (http://www.microsoft.com/directx/download.asp). If all else fails, you should be able to compile using the winmm.lib routines ... more latency, but at least it will work.
Realtime MIDI input is supported using the winmm.lib API.
A Visual C++ workspace has been created for STK98, with two projects - syntmono and MD2SKINI. Everything has already been configured for you. The intermediate .obj files will be written to either the "Release" or "Debug" directories, but the executable files will be written to the main STK98 directory (where they need to be for proper execution). If you should somehow lose or hose the VC++ workspace file (STK98v2.dsw), then you will have to do a LOT of configuring to recreate it ... it's probably easier just to download the distribution again from our WWW sites. Anyway, for your benefit and mine, here is a list of things that need to be added to the various "Project Settings":
Visual C++ workspaces have been created for the various STK projects. Everything has already been configured for you. The intermediate .obj files will be written to either the "Release" or "Debug" directories, but the executable files will be written to the main project directories (where they need to be for proper execution). If you should somehow lose or hose the VC++ workspace file (STK.dsw), then you will have to do a LOT of configuring to recreate it ... it's probably easier just to download the distribution again from our WWW sites. Anyway, for your benefit and mine, here is a list of things that need to be added to the various "Project Settings":
1. Under General: Set "Output files:" to <blank> (this will put the executable in the main STK directory.
1. Under General: Set "Output files:" to <blank> (this will put the executable in the main project directory.
2. Under C/C++ > Code Generation: Set "Use run-time library:" to Multithreaded.
@@ -29,37 +35,32 @@ In order for socketing to work, it is necessary to have the TCP protocol install
Finally, to use it all -
PLAY SKINI SCOREFILES IN REALTIME:
syntmono Clarinet -r < scores/streetsf.ski
USE TCL/TK GUIs FOR REALTIME CONTROL:
1. Open a DOS console window and start syntmono (eg. syntmono Clarinet -r -i).
1. Open a DOS console window and start syntmono (eg. syntmono Clarinet -r -is).
2. Double click on a Tcl/Tk file in TCLSpecs (eg. TCLPhys.tcl) from the Windows Explorer to start the GUI. Select the "communications" menu item and "Socket" and make the connection.
3. Start moving the sliders to control the instrument.
USE REALTIME MIDI INPUT FOR CONTROL:
1. Open a DOS console window and start syntmono (eg. syntmono Clarinet -r -i).
1. Open a DOS console window and start syntmono (eg. syntmono Clarinet -r -is).
2. Open another DOS console window and start MD2SKINI (assumes you already have
MIDI setup correctly for your computer).
2. Open another DOS console window and start MD2SKINI in the following way:
MD2SKINI -s <optional hostname>
This assumes you already have MIDI setup correctly for your computer.
/******************************************************/
Legal and Ethical:
This software was designed and created to be made publicly available for free, primarily for academic purposes, so if you use it, pass it on with this documentation, and for free.
If you make a million dollars with it, give me some. If you make compositions with it, put me in the program notes.
Some of the concepts are covered by various patents, some known to me and likely others which are unknown. Many of the ones known to me are administered by the Stanford Office of Technology and Licensing.
The good news is that large hunks of the techniques used here are public domain. To avoid subtle legal issues, I'll not state what's freely useable here, but I'll try to note within the various classes where certain things are likely to be protected by patents.
/******************************************************/
WINDOWS NT ONLY:
Realtime piping seems to work under WindowsNT in much the same way as on Unix platforms. Thus, it is possible to pipe realtime control data to syntmono under WindowsNT as well.

View File

@@ -1,33 +1,77 @@
STK98v2: A ToolKit of Audio Synthesis Classes and Instruments in C++
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
Version 3.0
By Perry R. Cook, 1995-98
With recent help by Gary P. Scavone
By Perry R. Cook, 1995-99
and Gary P. Scavone, 1997-99.
Please read the Legal and Ethical notes at the bottom of this document.
Please read the Legal and Ethical notes near the bottom of this document.
STK has undergone a large number of revisions, changes, and additions since its initial release in 1996. With this version 2.0 release, it has been completely ported to Linux and Win95 (not tested on WinNT but should work), as well as SGI and NeXTStep (no real time capabilities under NeXTStep). See the individual README's (eg. README-linux) for platform specific information and system requirements. In general, you will have to specify your system type in Object.h and then use either the Makefile (Unix platforms) or the VC++ workspace file (STK98v2.dsw) to compile the code.
STK now features realtime sound output and MIDI input under SGI, Linux (OSS), and Win95/NT (Direct Sound and Winmm routines). It is also possible to generate simultaneous .snd, .wav, and .mat (Matlab) output file types, as well as SKINI scorefiles using MD2SKINI.
OVERVIEW:
Two primary executables are created during compilation - syntmono and MD2SKINI. Syntmono is the core STK synthesis server. All distributed STK instruments are run using syntmono. MD2SKINI takes raw MIDI input, converts it to SKINI format, and outputs the result to stdout or a socket port ID (under Windoze). Control data (in the form of SKINI messages) can be fed to syntmono through three principal means - SKINI scorefiles, MD2SKINI output, and Tcl/Tk GUIs. A variety of SKINI scorefiles are distributed with STK98 and can be found in the "scores" directory. Under all platforms, a scorefile can be piped or redirected to syntmono in the following way:
STK is a set of audio signal processing C++ classes and instruments for music synthesis. You can use these classes to create programs which make cool sounds using a variety of synthesis techniques. This is not a terribly novel concept, except that STK is very portable (it's mostly platform-independent C and C++ code) AND it's completely user-extensible. So, the code you write using STK actually has some chance of working in another 5-10 years. STK currently runs on SGI (Irix), Linux, NeXTStep, and Windows computer platforms. Oh, and it's free for non-commercial use. The only parts of STK that are platform-dependent concern real-time sound and MIDI input and output ... but we've taken care of that for you. The interface for MIDI input and the simple Tcl/Tk graphical user interfaces (GUIs) provided is the same, so it's easy to voice and experiment in real time using either the GUIs or MIDI.
more scores/streetsf.ski | syntmono Clarinet -r
STK isn't one particular program. Rather, STK is a set of C++ classes that you can use to create your own programs. We've provided a few example applications that demonstrate some of the ways that you could use these classes. But if you have specific needs you will probably have to either modify the example programs or write a new program altogether. Further, the example programs don't have a fancy GUI wrapper. If you feel the need to have a "drag and drop" GUI, you probably don't want to use STK. Spending hundreds of hours making platform-dependent GUI code would go against one of the fundamental design goals of STK - platform independence. STK can generate simultaneous .snd, .wav, and .mat output soundfile formats (beside realtime sound output), so you can view your results using one of the numerous sound/signal analysis tools already available over the WWW (e.g. Snd, Cool Edit, Matlab). For those instances where a simple GUI with sliders and buttons is helpful, we use Tcl/Tk (which is freely distributed for all the STK supported platforms). A number of Tcl/Tk GUI scripts are distributed with the STK release.
SYSTEM REQUIREMENTS:
See the individual README's (eg. README-linux) for platform specific information and system requirements. In general, you will use either the provided Makefiles (Unix platforms) or the VC++ workspace files to compile the example programs. To use the Tcl/Tk GUIs, you will need Tcl/Tk version 8.0 or higher.
WHAT'S NEW:
STK has undergone several key revisions, changes, and additions since its last release in 1998. Despite being available in one form or another since 1996, we still consider STK to be alpha software. Thus, backward compatability has not been a priority. Please read the ReleaseNotes to see what has changed since the last release.
Realtime audio input capabilities have now been added to STK, though the behavior of such is very hardware dependent. Under Linux and Irix, audio input and output are possible with very low latency. Using the Windoze DirectSound API, minimum dependable output sound latency seems to be around 15 milliseconds, while input sound latency is on the order of several hundred milliseconds! It is also possible to generate simultaneous .snd, .wav, .raw, and .mat (Matlab MAT-file) output file types, as well as SKINI scorefiles using MD2SKINI. Finally, STK should compile with non-realtime functionality on any platform with a generic C++ compiler.
Socketing capabilities have been extended in this release to function under Unix platforms, as well as Windoze platforms. Further, the socket server thread has been updated to accept multiple simultaneous socket connections. Thus, it is now possible to have several different socket clients sending SKINI control messages to the server at the same time. Under Linux and Irix, it is also possible to pipe GUI messages through MD2SKINI, enabling both MIDI and GUI control via piping at the same time.
GETTING STARTED:
A number of example executables are provided with this distribution. The effects directory contains a program that demonstrates realtime duplex mode (simultaneous audio input and output) operation, as well as several simple delay-line based effects algorithms. The MUS151 directory contains a simple two-oscillator program that can be used to demonstrate psychoacoustic masking effects. The syntmono directory offers a program for monophonic STK instrument playback and manipulation. Syntmono is the primary STK synthesis server and is used to demonstrate all the current STK instruments. MD2SKINI is an executable (currently compiles from the syntmono project) which takes raw MIDI input, converts it to SKINI format, and outputs the result to stdout or any socket host and port ID. Control data (in the form of SKINI messages) can be fed to syntmono through three principal means - SKINI scorefiles, MD2SKINI output, and Tcl/Tk GUIs. A variety of SKINI scorefiles are distributed with STK and can be found in the "scores" directory of the syntmono project.
Unless you downloaded the distribution with precompiled Windoze binaries, it is necessary to first compile the sources. Under Linux or Irix, simply typing "make" in any of the particular project directories will begin the compilation process. If your Unix system does not have the GNU Makefile utilities, you will have to use one of the platform specific Makefiles (eg. make -f Makefile.sgi). To compile the projects under Windoze, you should use the VC++ project files provided with the STK distribution.
SYNTMONO:
Syntmono is the primary STK synthesis server and is used to demonstrate all the current STK instruments. Syntmono can take realtime control (SKINI) input via pipes or sockets, or it can be fed SKINI scorefile (non-realtime) input. Syntmono can output data in realtime, .wav, .snd, .mat (Matlab MAT-file), and/or .raw formats. Assuming you have successfully compiled the syntmono executable, a scorefile can be redirected to syntmono and the output heard in realtime in the following way:
syntmono Clarinet -r < scores/streetsf.ski
The "-r" flag specifies the realtime output option. Typing syntmono without arguments will provide a brief description of the instruments possible and the various input/output option flags. Tcl/Tk GUIs are provided in the "tcl" directory of each project, though you will have to install Tcl/Tk version 8.0 or higher on your system to use them (older versions of Tcl/Tk under Linux seem to be more forgiving than under IRIX). Realtime SKINI control data (via MD2SKINI or GUIs) can be piped to syntmono on Unix platforms and WinNT in the following way:
MD2SKINI | syntmono Clarinet -r -ip
or
syntmono Clarinet -r < scores/streetsf.ski
wish < TCLSpecs/TCLPhys.tcl | syntmono Clarinet -r -ip
A number of Tcl/Tk GUIs are provided in the "TCLSpecs" directory, though you will have to install Tcl/Tk version 8.0 or higher on your system to use them (older versions of Tcl/Tk under Linux seem to be more forgiving than under IRIX). Realtime SKINI control data (via MD2SKINI or GUIs) can be piped to syntmono on Unix platforms and perhaps under WinNT in the following way:
The "-ip" flag specifies piped realtime input. It is not possible to use realtime pipes under Windoze95/98, so socket communication must be used instead. For socket communication, it is necessary to first start the syntmono socket server using the "-is" flag (socketed realtime input). For the time being, a default (hardwired) socket port of 2001 is being used by syntmono. After syntmono is running (and waiting for a socket client connection), either MD2SKINI or a Tcl/Tk GUI can be started. When using the GUI, it is necessary to invoke the "communications" menu item and select "socket" to establish the connection. The same procedure is also possible on Unix platforms.
MD2SKINI | syntmono Clarinet -r -i
or
wish < TCLSpecs/TCLPhys.tcl | syntmono Clarinet -r -i
It is not possible to use realtime pipes under Win95, so socket communication is used instead. Perhaps in the future, all STK communications will be conducted using sockets. For socket communication, it is necessary to first start the syntmono socket server. For the time being, a default (hardwired) socket port of 2001 is being used by syntmono. After syntmono is running (and waiting for a socket client connection), either MD2SKINI or a Tcl/Tk GUI can be started. When using the GUI, it is necessary to invoke the "communications" menu item and select "socket" to establish the connection.
For more documentation on this ToolKit, the classes, etc, read the file HIERARCH.txt and the individual class definitions. Also check the platform specific README's for specific system requirements.
DISCLAIMER:
You probably already guessed this, but just to be sure, we don't guarantee anything works. :-) It's free ... what do you expect? If you find a bug, please let us know and we'll try to correct it. You can also make suggestions, but again, no guarantees. Send email to prc@cs.princeton.edu and gary@ccrma.stanford.edu.
Perry's comments from the original distribution:
LEGAL AND ETHICAL:
This software was designed and created to be made publicly available for free, primarily for academic purposes, so if you use it, pass it on with this documentation, and for free.
If you make a million dollars with it, give us some. If you make compositions with it, put us in the program notes.
Some of the concepts are covered by various patents, some known to us and likely others which are unknown. Many of the ones known to us are administered by the Stanford Office of Technology and Licensing.
The good news is that large hunks of the techniques used here are public domain. To avoid subtle legal issues, we'll not state what's freely useable here, but we'll try to note within the various classes where certain things are likely to be protected by patents.
FURTHER READING:
For more documentation on this ToolKit, the classes, etc., read the file HIERARCH.txt and the individual class definitions. Also check the platform specific README's for specific system requirements.
PERRY'S NOTES FROM THE ORIGINAL DISTRIBUTION:
This whole world was created with no particular hardware in mind. These examples are intended to be tutorial in nature, as a platform for the continuation of my research, and as a possible starting point for a software synthesis system. The basic motivation was to create the necessary unit generators to do the synthesis, processing, and control that I want to do and teach about. Little thought for optimization was given (see Object.cpp), and therefore improvements, especially speed enhancements, should be possible with these classes. It was written with some basic concepts in mind about how to let compilers optimize.
@@ -54,8 +98,8 @@ Your question at this point might be, "But Perry, with CMix, CMusic, CSound, CSh
meaningful parameter values is required to
get the models to work at all.
This set of C++ unitgenerators and instruments
might help to diminish the scores of EMails I
This set of C++ unit generators and instruments
might help to diminish the scores of emails I
get asking what to do with those block diagrams
I put in my papers.
@@ -75,17 +119,5 @@ Your question at this point might be, "But Perry, with CMix, CMusic, CSound, CSh
6) More rationalizations to follow . . .
/******************************************************/
Legal and Ethical:
This software was designed and created to be made publicly available for free, primarily for academic purposes, so if you use it, pass it on with this documentation, and for free.
If you make a million dollars with it, give me some. If you make compositions with it, put me in the program notes.
Some of the concepts are covered by various patents, some known to me and likely others which are unknown. Many of the ones known to me are administered by the Stanford Office of Technology and Licensing.
The good news is that large hunks of the techniques used here are public domain. To avoid subtle legal issues, I'll not state what's freely useable here, but I'll try to note within the various classes where certain things are likely to be protected by patents.
/******************************************************/

View File

@@ -1,492 +0,0 @@
/******************************************/
/* RTSoundIO.cpp */
/* Realtime Sound I/O Object for STK, */
/* by Gary P. Scavone, 1998. */
/* Based in part on code by Doug */
/* Scott (SGI), Tim Stilson (Linux), */
/* Bill Putnam (Win Wav), and */
/* R. Marsanyi (DirectSound). */
/* */
/* At the moment, this object only */
/* handles realtime sound output, though */
/* input code can go here when someone */
/* decides they need it (and writes it). */
/* */
/* This object provides a standard API */
/* across all platforms for STK realtime */
/* sound output. At the moment, this */
/* object is only used by RTWvOut. */
/******************************************/
#include "RTSoundIO.h"
#if defined(__SGI_REALTIME_)
#include <stdio.h>
#include <unistd.h>
RTSoundIO :: RTSoundIO(MY_FLOAT srate, int channels)
{
ALconfig audio_port_config;
int lookaheadbuffers = 8; // number of lookahead buffers
long pvbuf[2];
int nbuf, totalBufSize;
audio_port_config = ALnewconfig();
if(ALsetchannels(audio_port_config, channels) < 0) {
fprintf(stderr,"Cannot initialize audio port\n");
exit(0);
}
/* Size the output queue */
nbuf = (channels == 2) ? lookaheadbuffers : lookaheadbuffers/2;
totalBufSize = RT_BUFFER_SIZE * nbuf;
if(ALsetqueuesize(audio_port_config, totalBufSize) < 0) {
fprintf(stderr,"Cannot initialize audio port\n");
exit(0);
}
if(audio_port) ALcloseport(audio_port);
audio_port = ALopenport("sgi.driver", "w", audio_port_config);
if(!audio_port) {
fprintf(stderr,"Cannot initialize audio port\n");
exit(0);
}
ALfreeconfig(audio_port_config);
audio_port_config = 0;
pvbuf[0] = AL_OUTPUT_RATE;
pvbuf[1] = (long) srate;
ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 2); /* set output SR */
/* tell port to accept refill at buffers - 1 */
ALsetfillpoint(audio_port,RT_BUFFER_SIZE * (lookaheadbuffers - 1));
}
RTSoundIO :: ~RTSoundIO()
{
if(audio_port) ALcloseport(audio_port);
audio_port=0;
}
int RTSoundIO :: playBuffer(short *buf, int bufsize)
{
ALwritesamps(audio_port, buf, bufsize);
return 0;
}
#elif defined(__USS_REALTIME_)
#define ABS(x) ((x < 0) ? (-x) : (x))
#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/soundcard.h>
RTSoundIO :: RTSoundIO(MY_FLOAT srate, int channels)
{
int lookaheadbuffers = 8; // number of lookahead buffers
int nbuf, totalBufSize;
char DEVICE_NAME[100];
int format;
int stereo; /* 0=mono, 1=stereo */
int stereoset;
int speed;
int BUFFER_SIZE_LOG;
int fragsize;
BUFFER_SIZE_LOG = (int)(log10((double)RT_BUFFER_SIZE)/log10(2.0));
if (channels > 2)
{
fprintf(stderr,"Unsupported # of output channels!\n");
exit(0);
}
if (channels == 2) stereo = 1;
else stereo = 0;
strcpy(DEVICE_NAME,"/dev/dspW");
if ((audio_fd = open(DEVICE_NAME, O_WRONLY, 0)) == -1)
{ /* Opening device failed */
fprintf(stderr,"Cannot open audio device: %s\n",DEVICE_NAME);
exit(0);
}
/* Size the output queue */
nbuf = (channels == 2) ? lookaheadbuffers : lookaheadbuffers/2;
totalBufSize = RT_BUFFER_SIZE * nbuf;
fragsize = (nbuf << 16) + BUFFER_SIZE_LOG;
if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &fragsize))
{
close(audio_fd);
fprintf(stderr,"Error setting audio buffer size!\n");
exit(0);
}
format = AFMT_S16_LE;
if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format)==-1)
{ /* Fatal error */
close(audio_fd);
fprintf(stderr,"SNDCTL_DSP_SETFMT error\n");
exit(0);
}
if (format != AFMT_S16_LE)
{
close(audio_fd);
fprintf(stderr,"Soundcard doesn't support 16-bit signed LE format\n");
exit(0);
}
stereoset = stereo;
if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereoset)==-1)
{ /* Fatal error */
close(audio_fd);
fprintf(stderr,"SNDCTL_DSP_STEREO\n");
exit(0);
}
if (stereoset != stereo)
{
close(audio_fd);
fprintf(stderr,"The sound card did not set correct stereo mode\n");
exit(0);
}
speed = (int)srate;
if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &speed)==-1)
{ /* Fatal error */
close(audio_fd);
fprintf(stderr,"SNDCTL_DSP_SPEED\n");
exit(0);
}
if (ABS(speed - srate)>100)
{
close(audio_fd);
fprintf(stderr,"The device doesn't support the requested speed.\n");
exit(0);
}
}
RTSoundIO :: ~RTSoundIO()
{
if(audio_fd) close(audio_fd);
audio_fd=0;
}
int RTSoundIO :: playBuffer(short *buf, int bufsize)
{
/* The OSS write() routine takes the buffer size in bytes, thus the
multiplication by two.
*/
int len;
if ((len = write(audio_fd, buf, 2*bufsize)) == -1)
{
fprintf(stderr,"Audio write error!\n");
return -1;
}
return 0;
}
#elif defined(__WINDS_REALTIME_)
#include <stdio.h>
RTSoundIO :: RTSoundIO(MY_FLOAT srate, int channels)
{
HRESULT result;
HWND hWnd;
DWORD dwDataLen;
WAVEFORMATEX wfFormat;
DSBUFFERDESC dsbdDesc, primarydsbDesc;
LPDIRECTSOUNDBUFFER m_pDSPrimeBuffer;
BYTE *pDSBuffData;
/* Number of buffers of size RT_BUFFER_SIZE to make secondary DS buffer */
int nBufs = 16;
/* Initialize pointers to NULL */
m_pDirectSound = NULL;
m_pDSBuffer = NULL;
m_pDSPrimeBuffer = NULL;
/* Create the DS object */
if ((result = DirectSoundCreate(NULL, &m_pDirectSound, NULL)) != DS_OK)
{
fprintf(stderr,"Cannot open default sound device!!\n");
exit(0);
}
hWnd = GetForegroundWindow();
if ((result = m_pDirectSound->SetCooperativeLevel(hWnd, DSSCL_EXCLUSIVE)) != DS_OK)
{
fprintf(stderr,"DS Constructor: couldn't set cooperative level!\n");
exit(0);
}
/* Define the wave format structure */
wfFormat.wFormatTag = WAVE_FORMAT_PCM;
wfFormat.nChannels = channels;
wfFormat.nSamplesPerSec = (unsigned long) srate;
wfFormat.wBitsPerSample = 8 * sizeof(short);
wfFormat.nBlockAlign = wfFormat.nChannels * wfFormat.wBitsPerSample / 8;
wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
wfFormat.cbSize = 0;
/* Setup the primary DS buffer description */
ZeroMemory(&primarydsbDesc, sizeof(DSBUFFERDESC));
primarydsbDesc.dwSize = sizeof(DSBUFFERDESC);
primarydsbDesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
primarydsbDesc.dwBufferBytes = 0;
primarydsbDesc.lpwfxFormat = NULL;
/* Create the primary DS buffer */
if ((result = m_pDirectSound->CreateSoundBuffer(&primarydsbDesc,
&m_pDSPrimeBuffer, NULL)) != DS_OK)
{
fprintf(stderr,"Cannot get the primary DS buffer address!\n");
exit(0);
}
/* Set the primary DS buffer sound format. We have to do this because
the default primary buffer is 8-bit, 22kHz! */
if ((result = m_pDSPrimeBuffer->SetFormat(&wfFormat)) != DS_OK)
{
fprintf(stderr,"Cannot set the primary DS buffer to proper sound format!\n");
exit(0);
}
/* Setup the secondary DS buffer description */
m_cbBufSize = RT_BUFFER_SIZE * sizeof(short) * nBufs;
ZeroMemory(&dsbdDesc, sizeof(DSBUFFERDESC));
dsbdDesc.dwSize = sizeof(DSBUFFERDESC);
dsbdDesc.dwFlags = DSBCAPS_GLOBALFOCUS;
dsbdDesc.dwBufferBytes = m_cbBufSize;
dsbdDesc.lpwfxFormat = &wfFormat;
/* Create the secondary DS buffer */
if ((result = m_pDirectSound->CreateSoundBuffer(&dsbdDesc,
&m_pDSBuffer, NULL)) != DS_OK)
{
fprintf(stderr,"DS Constructor: couldn't create sound buffer!\n");
exit(0);
}
/* Lock the DS buffer */
if ((result = m_pDSBuffer->Lock(0, m_cbBufSize, (LPLPVOID)&pDSBuffData,
&dwDataLen, NULL, NULL, 0)) != DS_OK)
{
fprintf(stderr,"DS Constructor: couldn't lock sound buffer!\n");
exit(0);
}
/* Zero the DS buffer */
ZeroMemory(pDSBuffData, dwDataLen);
/* Unlock the DS buffer */
if ((result = m_pDSBuffer->Unlock(pDSBuffData, dwDataLen, NULL, 0)) != DS_OK)
{
fprintf(stderr,"DS Constructor: couldn't unlock sound buffer!\n");
exit(0);
}
m_cbBufOffset = 0; // reset last write position to start of buffer
/* Start the buffer playback */
if ((result = m_pDSBuffer->Play( 0, 0, DSBPLAY_LOOPING ) != DS_OK))
{
fprintf(stderr,"DS Constructor: couldn't play sound buffer!\n");
exit(0);
}
}
RTSoundIO :: ~RTSoundIO()
{
// Cleanup the sound buffer
if (m_pDSBuffer)
{
m_pDSBuffer->Stop();
m_pDSBuffer->Release();
m_pDSBuffer = NULL;
}
// Cleanup the DS object
if (m_pDirectSound)
{
m_pDirectSound->Release();
m_pDirectSound = NULL;
}
}
int RTSoundIO :: playBuffer(short *buf, int bufsize)
{
HRESULT hr;
DWORD status;
LPVOID lpbuf1 = NULL;
LPVOID lpbuf2 = NULL;
DWORD dwsize1 = 0;
DWORD dwsize2 = 0;
DWORD playPos, safePos, endWrite;
DWORD millis;
// Should be playing, right?
hr = m_pDSBuffer->GetStatus( &status );
if (!(status && DSBSTATUS_PLAYING))
{
printf("Buffer not playing!\n");
}
// Sleep until we have enough room in buffer.
hr = m_pDSBuffer->GetCurrentPosition( &playPos, &safePos );
if( hr != DS_OK ) return -1;
if( playPos < m_cbBufOffset ) playPos += m_cbBufSize; // unwrap offset
endWrite = m_cbBufOffset + RT_BUFFER_SIZE * sizeof(short);
while ( playPos < endWrite ) {
// Calculate number of milliseconds until we will have room, as
// time = distance * (milliseconds/second) / ((bytes/sample) * (samples/second)),
// rounded up.
millis = (DWORD) (1.0 + ((endWrite - playPos) * 1000.0) / ( sizeof(short) * SRATE));
// Sleep for that long
Sleep( millis );
// Wake up, find out where we are now
hr = m_pDSBuffer->GetCurrentPosition( &playPos, &safePos );
if( hr != DS_OK ) return -1;
if( playPos < m_cbBufOffset ) playPos += m_cbBufSize; // unwrap offset
}
// Lock free space in the DS
hr = m_pDSBuffer->Lock (m_cbBufOffset, RT_BUFFER_SIZE * sizeof(short), &lpbuf1, &dwsize1, &lpbuf2, &dwsize2, 0);
if (hr == DS_OK)
{
// Copy the buffer into the DS
CopyMemory(lpbuf1, buf, dwsize1);
if(NULL != lpbuf2) CopyMemory(lpbuf2, buf+dwsize1, dwsize2);
// Update our buffer offset and unlock sound buffer
m_cbBufOffset = (m_cbBufOffset + dwsize1 + dwsize2) % m_cbBufSize;
m_pDSBuffer->Unlock (lpbuf1, dwsize1, lpbuf2, dwsize2);
}
return 0;
}
#elif defined(__WINMM_REALTIME_)
#include <stdio.h>
#define FRAMETIME (long) (1000.0 * RT_BUFFER_SIZE / SRATE)
RTSoundIO :: RTSoundIO(MY_FLOAT srate, int channels)
{
MMRESULT result;
WAVEFORMATEX wfx;
int bufferSize = RT_BUFFER_SIZE;
audioPort = NULL;
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = channels;
wfx.nSamplesPerSec = (unsigned long) srate;
wfx.nBlockAlign = sizeof(short) * channels;
wfx.nAvgBytesPerSec = (unsigned long) srate * wfx.nBlockAlign;
wfx.wBitsPerSample = 8 * sizeof(short);
wfx.cbSize = 0;
/* Open a Wave Out device using the wave mapper to guide us */
result = waveOutOpen(&audioPort,WAVE_MAPPER,&wfx,(DWORD)NULL,(DWORD)NULL,CALLBACK_NULL);
if (result != MMSYSERR_NOERROR) {
fprintf(stderr,"Cannot open audio port!\n");
exit(0);
}
for( outBufNum = 0; outBufNum < (UINT)NUM_OUT_BUFFERS; outBufNum++ )
{
/* set up a couple of wave headers */
whOut[outBufNum].lpData = (LPSTR)calloc(channels*bufferSize, sizeof(short));
if (whOut[outBufNum].lpData == NULL){
waveOutClose( audioPort );
fprintf(stderr,"Error initializing audio buffers!\n");
exit(0);
}
whOut[outBufNum].dwBufferLength = channels*bufferSize*sizeof(short);
whOut[outBufNum].dwBytesRecorded = 0;
whOut[outBufNum].dwUser = 1;
//whOut[outBufNum].dwFlags = 0;
whOut[outBufNum].dwFlags = WHDR_DONE;
whOut[outBufNum].dwLoops = 0;
whOut[outBufNum].lpNext = NULL;
whOut[outBufNum].reserved = 0;
}
/* Write the first buffer out to get things going */
outBufNum = 0;
result = waveOutPrepareHeader(audioPort, &whOut[outBufNum],sizeof(WAVEHDR));
result = waveOutWrite(audioPort, &whOut[outBufNum], sizeof(WAVEHDR));
/* Keep track of time so that we know how long we can sleep */
lastWriteTime = timeGetTime();
}
RTSoundIO :: ~RTSoundIO()
{
MMRESULT result;
long timeToGo;
/* Close Audio Port */
if (audioPort != NULL) {
result = waveOutReset(audioPort);
for( outBufNum = 0; outBufNum < (UINT)NUM_OUT_BUFFERS; outBufNum++ )
{
/* Loop until the next waveheader indicates that we are done */
while( !(whOut[outBufNum].dwFlags & WHDR_DONE) )
{
//printf(".");
timeToGo = (long) (FRAMETIME - (timeGetTime()-lastWriteTime));
if( timeToGo > 0 ) Sleep( (long) timeToGo );
}
/* Unprepare the header */
result = waveOutUnprepareHeader(audioPort, &whOut[outBufNum],sizeof(WAVEHDR));
if (whOut[outBufNum].lpData != NULL) {
free(whOut[outBufNum].lpData);
whOut[outBufNum].lpData = NULL;
}
}
result = waveOutClose(audioPort);
}
}
int RTSoundIO :: playBuffer(short *buf, int bufsize)
{
MMRESULT result;
long timeToGo;
outBufNum++;
if( outBufNum >= (UINT)NUM_OUT_BUFFERS ) outBufNum = 0;
/* Loop until the next waveheader indicates that we are done */
while( !(whOut[outBufNum].dwFlags & WHDR_DONE) )
{
//printf(".");
timeToGo = (long) (FRAMETIME - (timeGetTime()-lastWriteTime));
//timeToGo = (long) (FRAMETIME * 0.5);
if( timeToGo > 0 ) Sleep( (long) timeToGo );
}
result = waveOutUnprepareHeader(audioPort, &whOut[outBufNum], sizeof(WAVEHDR));
memcpy( whOut[outBufNum].lpData, buf, bufsize*sizeof(short));
result = waveOutPrepareHeader(audioPort, &whOut[outBufNum], sizeof(WAVEHDR));
result = waveOutWrite(audioPort, &whOut[outBufNum], sizeof(WAVEHDR));
lastWriteTime = timeGetTime();
return 0;
}
#endif

View File

@@ -1,61 +0,0 @@
/******************************************/
/* RTSoundIO.h */
/* Realtime Sound I/O Object for STK, */
/* by Gary P. Scavone, 1998. */
/* Based in part on code by Doug */
/* Scott (SGI), Tim Stilson (Linux), */
/* Bill Putnam (Win Wav), and */
/* R. Marsanyi (DirectSound). */
/* */
/* At the moment, this object only */
/* handles realtime sound output, though */
/* input code can go here when someone */
/* decides they need it (and writes it). */
/* */
/* This object provides a standard API */
/* across all platforms for STK realtime */
/* sound output. At the moment, this */
/* object is only used by RTWvOut. */
/******************************************/
#if !defined(__RTSOUNDIO_h)
#define __RTSOUNDIO_h
#include "Object.h"
#if defined(__SGI_REALTIME_)
#include <audio.h>
#elif defined(__WINDS_REALTIME_)
#include <windows.h>
#include "include/dsound.h"
#elif defined(__WINMM_REALTIME_)
#include <windows.h>
#include <MMSystem.h>
#define NUM_OUT_BUFFERS 6
#endif
class RTSoundIO : public Object
{
protected:
#if defined(__SGI_REALTIME_)
ALport audio_port;
#elif defined(__USS_REALTIME_)
int audio_fd;
#elif defined(__WINDS_REALTIME_)
LPDIRECTSOUND m_pDirectSound;
LPDIRECTSOUNDBUFFER m_pDSBuffer;
UINT m_cbBufOffset;
UINT m_cbBufSize;
#elif defined(__WINMM_REALTIME_)
HWAVEOUT audioPort;
WAVEHDR whOut[NUM_OUT_BUFFERS];
UINT outBufNum;
DWORD lastWriteTime;
#endif
public:
RTSoundIO(MY_FLOAT srate, int channels);
~RTSoundIO();
int playBuffer(short *buf, int bufsize);
};
#endif

View File

@@ -1,56 +0,0 @@
/*******************************************/
/* Raw Wave File Output Class, */
/* by Perry R. Cook, 1995-96 */
/* This version opens a mono NeXT .snd */
/* file 16bit data at 22KHz, and */
/* pokes buffers of samples into it. */
/*******************************************/
/*******************************************/
/* SGI Real-Time Wave File Output Class, */
/* by Perry R. Cook, 1996 */
/* This Object can opens the SGI soundout */
/* device, and pokes buffers of samples */
/* into it. The real code that does the */
/* is from Doug Scott of SGI. */
/*******************************************/
/*******************************************/
/* USS Real-Time Wave File Output Class, */
/* by Tim Stilson, 1996 */
/* based on code by Perry R. Cook, 1996 */
/* This Object opens the USS sound output */
/* device, and pokes buffers of samples */
/* into it. */
/*******************************************/
#include "RTWvOut.h"
RTWvOut :: RTWvOut()
{
soundIO = new RTSoundIO(SRATE, 1);
counter = 0;
}
RTWvOut :: ~RTWvOut()
{
soundIO->playBuffer(data,counter);
counter = 0;
while (counter<RT_BUFFER_SIZE) {
data[counter++] = 0;
}
soundIO->playBuffer(data,counter);
soundIO->playBuffer(data,counter); // Are these extra writes necessary in USS?
soundIO->playBuffer(data,counter);
delete soundIO;
}
void RTWvOut :: tick(MY_FLOAT sample)
{
data[counter++] = (short) (sample * 32000.0);
if (counter >= RT_BUFFER_SIZE) {
soundIO->playBuffer(data,counter);
counter = 0;
}
}

View File

@@ -1,46 +0,0 @@
/*******************************************/
/* Real-Time Output Class, */
/* by Perry R. Cook, 1995-96 */
/* Separated into just realtime by */
/* Tim Stilson, 1996 */
/*******************************************/
/*******************************************/
/* SGI Real-Time Wave File Output Class, */
/* by Perry R. Cook, 1995-96 */
/* This Object can opens the SGI soundout */
/* device, and pokes buffers of samples */
/* into it. The real code that does the */
/* is originally from Doug Scott of SGI. */
/*******************************************/
/*******************************************/
/* USS Real-Time Wave File Output Class, */
/* by Tim Stilson, 1996 */
/* based on code by Perry R. Cook, 1996 */
/* This Object opens the USS sound output */
/* device, and pokes buffers of samples */
/* into it. */
/*******************************************/
#include "Object.h"
#include "WvOut.h"
#include "RTSoundIO.h"
#if !defined(__RTWvOut_h)
#define __RTWvOut_h
class RTWvOut : public WvOut
{
protected:
RTSoundIO *soundIO;
short data[RT_BUFFER_SIZE];
long counter;
public:
RTWvOut();
~RTWvOut();
void tick(MY_FLOAT sample);
};
#endif // defined(__RTWvOut_h)

View File

@@ -1,245 +0,0 @@
/*******************************************/
/* Interpolating RawWave Class, */
/* by Perry R. Cook, 1995-96 */
/* This object can open a raw 16bit data */
/* (signed integers) file, and play back */
/* the data once or looping, with linear */
/* interpolation on playback. */
/* */
/* Made inherited from RawWave */
/* by Gary P. Scavone (11/11/98) */
/*******************************************/
#include "RawInterp.h"
#ifdef __LITTLE_ENDIAN__
#include "swapstuf.h"
#endif
RawInterp :: RawInterp(char *fileName)
{
long i;
short temp;
FILE *fd;
fd = fopen(fileName,"rb");
if (!fd) {
printf("Couldn't find soundfile %s !!!!!!!!\n",fileName);
exit(0);
}
i = 0;
while (fread(&temp,2,1,fd)) i++;
length = i;
fseek(fd,0,0);
data = (MY_FLOAT *) malloc(MY_FLOAT_SIZE * (length + 1));
myData = 1;
i = 0;
while (fread(&temp,2,1,fd)) {
#ifdef __LITTLE_ENDIAN__
temp = SwapShort (temp);
#endif
data[i] = temp;
i++;
}
data[length] = data[length-1];
fclose(fd);
looping = 0;
time = (MY_FLOAT) 0.0;
phaseOffset = (MY_FLOAT) 0.0;
rate = (MY_FLOAT) 1.0;
finished = 0;
}
RawInterp :: RawInterp(MY_FLOAT *someData, long aLength)
{
length = aLength;
data = someData;
myData = 0;
looping = 0;
time = (MY_FLOAT) 0.0;
phaseOffset = (MY_FLOAT) 0.0;
rate = (MY_FLOAT) 1.0;
}
RawInterp :: ~RawInterp()
{
if (myData) {
free(data);
data = 0;
}
}
void RawInterp :: reset()
{
time = (MY_FLOAT) 0.0;
lastOutput = (MY_FLOAT) 0.0;
finished = 0;
}
void RawInterp :: normalize()
{
this->normalize((MY_FLOAT) 1.0);
}
void RawInterp :: normalize(MY_FLOAT newPeak)
{
long i;
MY_FLOAT max = (MY_FLOAT) 0.0;
for (i=0;i<=length;i++)
if (fabs(data[i]) > max)
max = (MY_FLOAT) fabs(data[i]);
if (max > 0.0) {
max = (MY_FLOAT) 1.0 / max;
max *= newPeak;
for (i=0;i<=length;i++)
data[i] *= max;
}
}
void RawInterp :: setRate(MY_FLOAT aRate)
{
rate = aRate;
}
void RawInterp :: setFreq(MY_FLOAT aFreq)
{
rate = length * (MY_FLOAT) ONE_OVER_SRATE * aFreq;
}
void RawInterp :: addTime(MY_FLOAT aTime) /* Add an absolute time */
{ /* in samples */
time += aTime;
}
void RawInterp :: addPhase(MY_FLOAT anAngle) /* Add a time in cycles */
{ /* Cycles here means */
time += length * anAngle; /* 1.0 = length */
}
void RawInterp :: addPhaseOffset(MY_FLOAT anAngle)
{ /* Add a phase offset */
phaseOffset = length * anAngle; /* in cycles, where */
} /* 1.0 = length */
void RawInterp :: setLooping(int aLoopStatus)
{
time = (MY_FLOAT) 0;
looping = aLoopStatus;
if (looping) data[length] = data[0];
}
long RawInterp :: getLength()
{
return length;
}
MY_FLOAT* RawInterp :: getData()
{
return data;
}
MY_FLOAT RawInterp :: tick()
{
this->informTick();
return lastOutput;
}
int RawInterp :: isFinished()
{
return finished;
}
int RawInterp :: informTick()
{
long temp;
MY_FLOAT temp_time, alpha;
time += rate; /* Update current time */
if (looping) {
while (time >= length) /* Check for end of sound */
time -= length; /* loop back to beginning */
while (time < 0.0) /* Check for end of sound */
time += length; /* loop back to beginning */
}
else {
if (time >= length) { /* Check for end of sound */
time = length-(MY_FLOAT) 1; /* stick at end */
finished = 1; /* Information for one-shot use */
}
else if (time < 0.0) /* Check for end of sound */
time = (MY_FLOAT) 0.0; /* stick at beg */
}
temp_time = time;
if (phaseOffset != 0.0) {
temp_time += phaseOffset; /* Add phase offset */
if (looping) {
while (temp_time >= length) /* Check for end of sound */
temp_time -= length; /* loop back to beginning */
while (temp_time < 0.0) /* Check for end of sound */
temp_time += length; /* loop back to beginning */
}
else {
if (temp_time >= length) /* Check for end of sound */
temp_time = length - (MY_FLOAT) 1; /* stick at end */
else if (temp_time < 0.0) /* check for end of sound */
temp_time = (MY_FLOAT) 0.0; /* stick at beg */
}
}
temp = (long) temp_time; /* Integer part of time address */
alpha = temp_time - (MY_FLOAT) temp; /* fractional part of time address */
lastOutput = data[temp]; /* Do linear interpolation */
lastOutput = lastOutput + /* same as alpha*data[temp+1] */
(alpha * (data[temp+1] -
lastOutput)); /* + (1-alpha)data[temp] */
return finished;
}
MY_FLOAT RawInterp :: lastOut()
{
return lastOutput;
}
/************ Test Main Program *****************/
/*
void main()
{
RawInterp loopWave("rawwaves/sinewave.raw");
RawInterp oneShot("rawwaves/mandpluk.raw");
FILE *fd;
short data;
long i;
loopWave.setLooping(1);
loopWave.setFreq(5500);
fd = fopen("test.raw","wb");
for (i=0;i<4096;i++) {
data = loopWave.tick();
fwrite(&data,2,1,fd);
}
loopWave.setFreq(2750);
for (i=0;i<4096;i++) {
data = loopWave.tick();
fwrite(&data,2,1,fd);
}
oneShot.setLooping(0);
for (i=0;i<8192;i++) {
data = oneShot.tick();
fwrite(&data,2,1,fd);
}
oneShot.reset();
oneShot.setRate(0.5);
for (i=0;i<16384;i++) {
data = oneShot.tick();
fwrite(&data,2,1,fd);
}
fclose(fd);
}
*/

View File

@@ -1,52 +0,0 @@
/*******************************************/
/* Interpolating RawWave Class, */
/* by Perry R. Cook, 1995-96 */
/* This object can open a raw 16bit data */
/* (signed integers) file, and play back */
/* the data once or looping, with linear */
/* interpolation on playback. */
/* */
/* Made inherited from RawWave */
/* by Gary P. Scavone (11/11/98) */
/*******************************************/
#if !defined(__RawInterp_h)
#define __RawInterp_h
#include "Object.h"
#include "RawWave.h"
class RawInterp : public RawWave
{
protected:
int looping;
int myData;
int finished;
long length;
MY_FLOAT *data;
MY_FLOAT rate;
MY_FLOAT time;
MY_FLOAT phaseOffset;
MY_FLOAT lastOutput;
public:
RawInterp(char *fileName);
RawInterp(MY_FLOAT *someData,long aLength);
~RawInterp();
void reset();
void normalize();
void normalize(MY_FLOAT newPeak);
void setRate(MY_FLOAT aRate);
void setFreq(MY_FLOAT aFreq);
void addTime(MY_FLOAT aTime);
void addPhase(MY_FLOAT anAngle);
void addPhaseOffset(MY_FLOAT anAngle);
void setLooping(int aLoopStatus);
int isFinished();
long getLength();
MY_FLOAT* getData();
MY_FLOAT tick();
int informTick();
MY_FLOAT lastOut();
};
#endif

View File

@@ -1,160 +0,0 @@
/*******************************************/
/* Raw Looped Soundfile Class, */
/* by Perry R. Cook, 1995-96 */
/* This Object can open a raw 16bit data */
/* (signed integers) file, and play back */
/* the data, looping only, with linear */
/* interpolation on playback. */
/*******************************************/
#include "RawLoop.h"
#include "swapstuf.h"
RawLoop :: RawLoop(char *fileName)
{
long i;
short temp;
FILE *fd;
fd = fopen(fileName,"rb");
if (!fd) {
printf("Couldn't find soundfile %s !!!!!!!!\n",fileName);
exit(0);
}
i = 0;
while (fread(&temp,2,1,fd)) i++;
length = i;
fseek(fd,0,0);
data = (MY_FLOAT *) malloc(MY_FLOAT_SIZE * (length + 1));
i = 0;
while (fread(&temp,2,1,fd)) {
#ifdef __LITTLE_ENDIAN__
temp = SwapShort (temp);
#endif
data[i] = temp;
i++;
}
data[length] = data[0];
fclose(fd);
time = (MY_FLOAT) 0.0;
phaseOffset = (MY_FLOAT) 0.0;
rate = (MY_FLOAT) 1.0;
}
RawLoop :: ~RawLoop()
{
free(data);
}
void RawLoop :: reset()
{
time = (MY_FLOAT) 0.0;
lastOutput = (MY_FLOAT) 0.0;
}
void RawLoop :: normalize()
{
this->normalize((MY_FLOAT) 1.0);
}
void RawLoop :: normalize(MY_FLOAT newPeak)
{
long i;
MY_FLOAT max = (MY_FLOAT) 0.0;
for (i=0;i<=length;i++)
if (fabs(data[i]) > max)
max = (MY_FLOAT) fabs((double) data[i]);
if (max > 0.0) {
max = (MY_FLOAT) 1.0 / max;
max *= newPeak;
for (i=0;i<=length;i++)
data[i] *= max;
}
}
void RawLoop :: setRate(MY_FLOAT aRate)
{
rate = aRate;
}
void RawLoop :: setFreq(MY_FLOAT aFreq)
{
rate = length * ONE_OVER_SRATE * aFreq;
}
void RawLoop :: addTime(MY_FLOAT aTime) /* Add an absolute time */
{ /* in samples */
time += aTime;
}
void RawLoop :: addPhase(MY_FLOAT anAngle) /* Add a time in cycles */
{ /* Cycles here means */
time += length * anAngle; /* 1.0 = length */
}
void RawLoop :: addPhaseOffset(MY_FLOAT anAngle)
{ /* Add a phase offset */
phaseOffset = length * anAngle; /* in cycles, where */
} /* 1.0 = length */
MY_FLOAT RawLoop :: tick()
{
long temp;
MY_FLOAT temp_time, alpha;
time += rate; /* Update current time */
while (time >= length) /* Check for end of sound */
time -= length; /* loop back to beginning */
while (time < 0.0) /* Check for end of sound */
time += length; /* loop back to beginning */
temp_time = time;
if (phaseOffset != 0.0) {
temp_time += phaseOffset; /* Add phase offset */
while (temp_time >= length) /* Check for end of sound */
temp_time -= length; /* loop back to beginning */
while (temp_time < 0.0) /* Check for end of sound */
temp_time += length; /* loop back to beginning */
}
temp = (long) temp_time; /* Integer part of time address */
alpha = temp_time - (MY_FLOAT) temp; /* fractional part of time address */
lastOutput = data[temp]; /* Do linear interpolation */
lastOutput = lastOutput + /* same as alpha*data[temp+1] */
(alpha * (data[temp+1]
- lastOutput)); /* + (1-alpha)data[temp] */
return lastOutput;
}
MY_FLOAT RawLoop :: lastOut()
{
return lastOutput;
}
/************ Test Main Program *****************/
/*
void main()
{
RawLoop loopWave("rawwaves/sinewave.raw");
FILE *fd;
short data;
long i;
loopWave.setFreq(5500);
fd = fopen("test.raw","wb");
for (i=0;i<4096;i++) {
data = loopWave.tick();
fwrite(&data,2,1,fd);
}
loopWave.setFreq(2750);
for (i=0;i<4096;i++) {
data = loopWave.tick();
fwrite(&data,2,1,fd);
}
fclose(fd);
}
*/

View File

@@ -1,40 +0,0 @@
/*******************************************/
/* Raw Looped Soundfile Class, */
/* by Perry R. Cook, 1995-96 */
/* This Object can open a raw 16bit data */
/* (signed integers) file, and play back */
/* the data, looping only, with linear */
/* interpolation on playback. */
/*******************************************/
#if !defined(__RawLoop_h)
#define __RawLoop_h
#include "Object.h"
#include "RawWave.h"
class RawLoop : public RawWave
{
protected:
long length;
MY_FLOAT *data;
MY_FLOAT rate;
MY_FLOAT time;
MY_FLOAT phaseOffset;
MY_FLOAT lastOutput;
public:
RawLoop(char *fileName);
~RawLoop();
void reset();
void normalize();
void normalize(MY_FLOAT newPeak);
void setRate(MY_FLOAT aRate);
void setFreq(MY_FLOAT aFreq);
void addTime(MY_FLOAT aTime);
void addPhase(MY_FLOAT anAngle);
void addPhaseOffset(MY_FLOAT anAngle);
MY_FLOAT tick();
MY_FLOAT lastOut();
};
#endif

View File

@@ -1,178 +0,0 @@
/*******************************************/
/* Non-Interpolating One-Shot Raw Sound- */
/* file Class, by Perry R. Cook, 1995-96 */
/* This Object can open a raw 16bit data */
/* (signed integers) file, and play back */
/* the data once, with no interpolation */
/* on playback. Once finished, it closes */
/* the file, the file is reopened with */
/* the reset() method. */
/* This is useful for small memory model, */
/* applications, or for streaming from */
/* disk (and generally non real-time */
/* applications). */
/*******************************************/
#include "RawShot.h"
#ifdef __LITTLE_ENDIAN__
#include "swapstuf.h"
#endif
RawShot :: RawShot(char *fileName)
{
long i;
strcpy(fileNm,fileName);
myFile = fopen(fileNm,"rb");
if (!myFile) {
printf("Couldn't find soundfile %s !!!!!!!!\n",fileName);
exit(0);
}
i = 0;
while (fread(&data,2,1,myFile)) i++;
length = i;
fseek(myFile,0,0);
time = (MY_FLOAT) 0.0;
rate = (MY_FLOAT) 1.0;
lastTime = 0;
finished = 0;
gain = (MY_FLOAT) 1.0;
lastOutput = (MY_FLOAT) 0.0;
}
RawShot :: ~RawShot()
{
this->finish();
}
void RawShot :: reset()
{
if (finished) {
myFile = fopen(fileNm,"rb");
}
fseek(myFile,0,0);
#if defined(_debug_)
printf("Resetting\n");
#endif
time = (MY_FLOAT) 0.0;
lastTime = 0;
finished = 0;
lastOutput = (MY_FLOAT) 0.0;
}
void RawShot :: normalize()
{
this->normalize((MY_FLOAT) 1.0);
}
void RawShot :: normalize(MY_FLOAT newPeak)
{
long i;
FILE *fd;
gain = (MY_FLOAT) 0.0;
fd = fopen(fileNm,"rb");
for (i=0;i<length;i++) {
fread(&data,2,1,fd);
#ifdef __LITTLE_ENDIAN_
data = SwapShort(data);
#endif
if (fabs(data) > gain)
gain = (MY_FLOAT) fabs((double) data);
}
if (gain > 0.0) {
gain = newPeak / gain;
}
fclose(fd);
}
void RawShot :: setRate(MY_FLOAT aRate)
{
rate = aRate;
}
void RawShot :: finish()
{
finished = 1;
lastOutput = (MY_FLOAT) 0.0;
if (myFile) {
fclose(myFile);
myFile = 0;
}
}
int RawShot :: isFinished()
{
return finished;
}
MY_FLOAT RawShot :: tick()
{
this->informTick();
return lastOutput;
}
int RawShot :: informTick()
{
long temp;
if (!finished) {
time += rate; /* Update current time */
if (time >= length) { /* Check for end of sound */
time = (MY_FLOAT) length - 1; /* stick at end */
finished = 1; /* Information for one-shot use */
fclose(myFile);
myFile = 0;
}
else {
temp = (long) time; /* Integer part of time address */
if (temp > lastTime) { /* If we cross next sample time */
lastTime = temp;
fread(&data,2,1,myFile); /* Snarf next sample from file */
#ifdef __LITTLE_ENDIAN__
data = SwapShort(data);
#endif
lastOutput = data * gain; /* And save as non-interpolated data */
}
}
}
return finished;
}
MY_FLOAT RawShot :: lastOut()
{
return lastOutput;
}
/************ Test Main Program *****************/
/*
void main()
{
RawShot oneShot("rawwaves/mandpluk.raw");
FILE *fd;
short data;
long i;
fd = fopen("test.raw","wb");
oneShot.setRate(1.0);
while (!oneShot.informTick()) {
data = oneShot.lastOut();
fwrite(&data,2,1,fd);
}
oneShot.reset();
oneShot.setRate(0.5);
for (i=0;i<16384;i++) {
data = oneShot.tick();
fwrite(&data,2,1,fd);
}
fclose(fd);
}
*/

View File

@@ -1,49 +0,0 @@
/*******************************************/
/* Non-Interpolating One-Shot Raw Sound- */
/* file Class, by Perry R. Cook, 1995-96 */
/* This Object can open a raw 16bit data */
/* (signed integers) file, and play back */
/* the data once, with no interpolation */
/* on playback. Once finished, it closes */
/* the file, the file is reopened with */
/* the reset() method. */
/* This is useful for small memory model, */
/* applications, or for streaming from */
/* disk (and generally non real-time */
/* applications). */
/*******************************************/
#if !defined(__RawShot_h)
#define __RawShot_h
#include "Object.h"
#include "RawWave.h"
class RawShot : public RawWave
{
protected:
long length;
long lastTime;
int finished;
short data;
char fileNm[128];
FILE *myFile;
MY_FLOAT rate;
MY_FLOAT time;
MY_FLOAT gain;
MY_FLOAT lastOutput;
public:
RawShot(char *fileName);
~RawShot();
void reset();
void normalize();
void normalize(MY_FLOAT newPeak);
void setRate(MY_FLOAT aRate);
void finish();
int isFinished();
MY_FLOAT tick();
int informTick();
MY_FLOAT lastOut();
};
#endif

View File

@@ -1,42 +0,0 @@
/********************************************/
/* RawWave Abstract Class, */
/* by Gary P. Scavone, 1998 */
/********************************************/
#include "RawWave.h"
RawWave :: RawWave()
{
}
RawWave :: ~RawWave()
{
}
void RawWave :: reset()
{
}
void RawWave :: normalize(MY_FLOAT newPeak)
{
}
void RawWave :: setRate(MY_FLOAT aRate)
{
}
int RawWave :: informTick()
{
return 0;
}
MY_FLOAT RawWave :: tick()
{
return 0.0;
}
MY_FLOAT RawWave :: lastOut()
{
return 0.0;
}

View File

@@ -1,25 +0,0 @@
/********************************************/
/* RawWave Abstract Class, */
/* by Gary P. Scavone, 1998 */
/********************************************/
#include "Object.h"
#if !defined(__RawWave_h)
#define __RawWave_h
class RawWave : public Object
{
public:
RawWave();
virtual ~RawWave();
virtual void reset();
virtual void normalize(MY_FLOAT newPeak);
virtual void setRate(MY_FLOAT aRate);
virtual int informTick();
virtual MY_FLOAT tick();
virtual MY_FLOAT lastOut();
};
#endif // defined(__RawWave_h)

View File

@@ -1,11 +1,32 @@
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
Release 3.0
By Perry R. Cook, 1995-98
and Gary P. Scavone, 1997-98
By Perry R. Cook, 1995-99
and Gary P. Scavone, 1997-99
I'll call this latest release STK98v2.02. There was a v2.01 release shortly after the initial v2.0 release in July 1998, to correct a few SGI/Win return character incompatibilities. Since I am just creating this set of release notes with v2.02, I'll just gloss over the past changes. Hopefully, I'll be able to keep this document updated with future releases.
--Gary Scavone
v3.0
- new #define flags for OS and realtime dependencies (this will probably cause problems for most everyone, but it was necessary to make future ports easier)
- fixed Linux MIDI input bug
- fixed MIDI status masking problem in Windows
- OS type defines now in Makefile
- new RAWWAVE_PATH define in Object.h
- syntmono pulled out to separate directory and cleaned up
- socketing capabilities under Unix, as well as Windoze
- multiple simultaneous socket client connections to STK servers now possible
- MD2SKINI now can merge MIDI and piped messages under Irix and Linux (for TCL->MD2SKINI->syntmono control)
- defined INT16 and INT32 types and fixed various WvIn and WvOut classes
- updated MatWvIn and MatWvOut for new MAT-file documentation from Matlab
- new demo GUI
- minor fixes to FM behavior
- added record/duplex capabilities to RTSoundIO (Linux, SGI, and Windoze)
- fixed bugs in WavWvOut and MatWvOut header specifications
- added RawWvOut class
- new WvIn class with RawWvIn, SndWvIn, WavWvIn, MatWvIn, and RTWvIn subclasses
- removed RawWave, RawShot, RawInterp, and RawLoop classes (supplanted by RawWvIn)
- multi-channel data support in WvIn and WvOut classes using MY_MULTI data type (pointer to MY_FLOAT) and the methods mtick() and mlastOutput()
- now writing to primary buffer under Windoze when allowed by hardware
- cleaned up Object.h a bit
- pulled various utility and thread functions out of syntmono.cpp (to aid readability of the code)
v2.02:

View File

@@ -1,57 +0,0 @@
/******************************************/
/* Fender Rhodes Electric Piano Subclass */
/* of Algorithm 5 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/******************************************/
#include "Rhodey.h"
Rhodey :: Rhodey() : FM4Alg5()
{
this->loadWaves("rawwaves/sinewave.raw",
"rawwaves/sinewave.raw",
"rawwaves/sinewave.raw",
"rawwaves/fwavblnk.raw");
this->setRatio(0,(MY_FLOAT) 1.0);
this->setRatio(1,(MY_FLOAT) 0.5);
this->setRatio(2,(MY_FLOAT) 1.0);
this->setRatio(3,(MY_FLOAT) 15.0);
gains[0] = __FM4Op_gains[99];
gains[1] = __FM4Op_gains[90];
gains[2] = __FM4Op_gains[99];
gains[3] = __FM4Op_gains[67];
adsr[0]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 1.50,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
adsr[1]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 1.50,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
adsr[2]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 1.00,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
adsr[3]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 0.25,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
twozero->setGain((MY_FLOAT) 1.0);
}
Rhodey :: ~Rhodey()
{
}
void Rhodey :: setFreq(MY_FLOAT frequency)
{
baseFreq = frequency * (MY_FLOAT) 2.0;
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 Rhodey :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
gains[0] = amp * __FM4Op_gains[99];
gains[1] = amp * __FM4Op_gains[90];
gains[2] = amp * __FM4Op_gains[99];
gains[3] = amp * __FM4Op_gains[67];
this->setFreq(freq);
this->keyOn();
#if defined(_debug_)
printf("Rhodey : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}

View File

@@ -1,345 +0,0 @@
/******************************************/
/* 2nd generation SKINI Text File Reader */
/* Class, by Perry R. Cook, 1996 */
/* This Object can open a SKINI File */
/* and parse it. The file spec is mine */
/* and mine alone, but it's all text so */
/* that should help you figuring it out. */
/* */
/* SKINI (Synthesis toolKit Instrument */
/* Network Interface) is like MIDI, but */
/* allows for floating point control */
/* changes, note numbers, etc. Example: */
/* noteOn 60.01 111.132 plays a sharp */
/* middle C with a velocity of 111.132 */
/* See SKINI11.txt for more information */
/* */
/******************************************/
#include "SKINI11.h"
SKINI11 :: SKINI11(char *fileName) /* Constructor for reading SKINI files */
{ /* Use nextMessage() method */
myFile = fopen(fileName,"r");
if ((int) myFile < 0) printf("SKINI11: Can't open SKINI score file\n");
this->nextMessage();
}
SKINI11 :: SKINI11() /* Constructor to use this object for parsing */
{ /* SKINI Strings (coming over socket for example */
} /* Use parseThis() method with string argument */
SKINI11 :: ~SKINI11()
{
}
/***************** SOME HANDY ROUTINES *******************/
#include "SKINI11.tbl"
#define __SK_MAX_FIELDS_ 5
#define __SK_MAX_SIZE_ 32
short ignore(char aChar)
{
short ignoreIt = 0;
if (aChar == 0) ignoreIt = 1; // Null String Termination
if (aChar == '\n') ignoreIt = 1; // Carraige Return???
if (aChar == '/') ignoreIt = 2; // Comment Line
return ignoreIt;
}
short delimit(char aChar)
{
if (aChar == ' ' || // Space
aChar == ',' || // Or Comma
aChar == '\t') // Or Tab
return 1;
else
return 0;
}
short nextChar(char* aString)
{
int i;
for (i=0;i<__SK_MAX_SIZE_;i++) {
if ( aString[i] != ' ' && // Space
aString[i] != ',' && // Or Comma
aString[i] != '\t' ) // Or Tab
return i;
}
return 1024;
}
int subStrings(char *aString,
char someStrings[__SK_MAX_FIELDS_][__SK_MAX_SIZE_],
int somePointrs[__SK_MAX_FIELDS_],
char *remainderString)
{
int notDone,howMany,point,temp;
notDone = 1;
howMany = 0;
point = 0;
temp = nextChar(aString);
if (temp >= __SK_MAX_SIZE_) {
notDone = 0;
printf("Confusion here: Ignoring this line\n");
printf("%s\n",aString);
return howMany;
}
point = temp;
somePointrs[howMany] = point;
temp = 0;
while (notDone) {
if (aString[point] == '\n') {
notDone = 0;
}
else {
someStrings[howMany][temp++] = aString[point++];
if (temp >= __SK_MAX_SIZE_) {
howMany = 0;
return howMany;
}
if (delimit(aString[point]) || aString[point] == '\n') {
someStrings[howMany][temp] = 0;
howMany += 1;
if (howMany < __SK_MAX_FIELDS_) {
temp = nextChar(&aString[point]);
point += temp;
somePointrs[howMany-1] = point;
temp = 0;
}
else {
temp = 0;
somePointrs[howMany-1] = point;
while(aString[point] != '\n')
remainderString[temp++] = aString[point++];
remainderString[temp] = aString[point];
}
}
}
}
// printf("Got: %i Strings:\n",howMany);
// for (temp=0;temp<howMany;temp++)
// printf("%s\n",someStrings[temp]);
return howMany;
}
/**************** THE ENCHILLADA !!!! **********************/
/*** This function parses a single string (if it can) ****/
/*** of SKINI message, setting the appropriate variables ***/
/*************************************************************/
long SKINI11 :: parseThis(char* aString)
{
int which,aField;
int temp,temp2;
char someStrings[__SK_MAX_FIELDS_][__SK_MAX_SIZE_];
int somePointrs[__SK_MAX_FIELDS_];
temp = nextChar(aString);
if (which = ignore(aString[temp])) {
if (which == 2) printf("// CommentLine: %s\n",aString);
messageType = 0;
return messageType;
}
else {
temp = subStrings(aString,someStrings,somePointrs,remainderString);
if (temp > 0)
which = 0;
aField = 0;
strcpy(msgTypeString,someStrings[aField]);
while ((which < __SK_MaxMsgTypes_) &&
(strcmp(msgTypeString,
skini_msgs[which].messageString))) {
which += 1;
}
if (which >= __SK_MaxMsgTypes_) {
messageType = -1;
printf("Couldn't parse this message field: =%s\n %s\n",
msgTypeString,aString);
return messageType;
}
else {
messageType = skini_msgs[which].type;
// printf("Message Token = %s type = %i\n",
// msgTypeString,messageType);
}
aField += 1;
if (someStrings[0][0] == '=') {
deltaTime = (MY_FLOAT) atof(&someStrings[aField][1]);
deltaTime = -deltaTime;
}
else {
deltaTime = (MY_FLOAT) atof(someStrings[aField]);
}
// printf("DeltaTime = %f\n",deltaTime);
aField += 1;
channel = atoi(someStrings[aField]);
// printf("Channel = %i\n",channel);
aField += 1;
if (skini_msgs[which].data2 != NOPE) {
if (skini_msgs[which].data2 == SK_INT) {
byteTwoInt = atoi(someStrings[aField]);
byteTwo = (MY_FLOAT) byteTwoInt;
}
else if (skini_msgs[which].data2 == SK_DBL) {
byteTwo = (MY_FLOAT) atof(someStrings[aField]);
byteTwoInt = (long) byteTwo;
}
else if (skini_msgs[which].data2 == SK_STR) {
temp = somePointrs[aField-1]; /* Hack Danger Here, Why -1??? */
temp2 = 0;
while (aString[temp] != '\n') {
remainderString[temp2++] = aString[temp++];
}
remainderString[temp2] = 0;
}
else {
byteTwoInt = skini_msgs[which].data2;
byteTwo = (MY_FLOAT) byteTwoInt;
aField -= 1;
}
aField += 1;
if (skini_msgs[which].data3 != NOPE) {
if (skini_msgs[which].data3 == SK_INT) {
byteThreeInt = atoi(someStrings[aField]);
byteThree = (MY_FLOAT) byteThreeInt;
}
else if (skini_msgs[which].data3 == SK_DBL) {
byteThree = (MY_FLOAT) atof(someStrings[aField]);
byteThreeInt = (long) byteThree;
}
else if (skini_msgs[which].data3 == SK_STR) {
temp = somePointrs[aField-1]; /* Hack Danger Here, Why -1??? */
temp2 = 0;
while (aString[temp] != '\n') {
remainderString[temp2++] = aString[temp++];
}
remainderString[temp2] = 0;
}
else {
byteThreeInt = skini_msgs[which].data3;
byteThree = (MY_FLOAT) byteThreeInt;
}
}
else {
byteThreeInt = byteTwoInt;
byteThree = byteTwo;
}
}
}
return messageType;
}
long SKINI11 :: nextMessage()
{
int notDone;
char inputString[1024];
notDone = 1;
while (notDone) {
notDone = 0;
if (!fgets(inputString,1024,myFile)) {
printf("//End of Score. Thanks for using SKINI0.9 Bye Bye!!\n");
messageType = -1;
return messageType;
}
else if (parseThis(inputString) == 0) {
notDone = 1;
}
}
return messageType;
}
long SKINI11 :: getType()
{
return messageType;
}
long SKINI11 :: getChannel()
{
return channel;
}
MY_FLOAT SKINI11 :: getDelta()
{
return deltaTime;
}
MY_FLOAT SKINI11 :: getByteTwo()
{
return byteTwo;
}
long SKINI11 :: getByteTwoInt()
{
return byteTwoInt;
}
MY_FLOAT SKINI11 :: getByteThree()
{
return byteThree;
}
long SKINI11 :: getByteThreeInt()
{
return byteThreeInt;
}
char* SKINI11 :: getRemainderString()
{
return remainderString;
}
char* SKINI11 :: getMessageTypeString()
{
return msgTypeString;
}
char sk_tempString[1024];
char* SKINI11 :: whatsThisType(long type)
{
int i = 0;
sk_tempString[0] = 0;
for (i=0;i<__SK_MaxMsgTypes_;i++) {
if (type == skini_msgs[i].type) {
strcat(sk_tempString,skini_msgs[i].messageString);
strcat(sk_tempString,",");
}
}
return sk_tempString;
}
char* SKINI11 :: whatsThisController(long contNum)
{
int i = 0;
sk_tempString[0] = 0;
for (i=0;i<__SK_MaxMsgTypes_;i++) {
if (skini_msgs[i].type == __SK_ControlChange_
&& contNum == skini_msgs[i].data2) {
strcat(sk_tempString,skini_msgs[i].messageString);
strcat(sk_tempString,",");
}
}
return sk_tempString;
}
/************ Test Main Program *****************/
/*
void main(int argc,char *argv[])
{
SKINI11 testFile(argv[1]);
while(testFile.nextMessage() > 0) ;
}
*/

View File

@@ -1,8 +1,10 @@
This describes the 0.9 implementation of SKINI:
This describes the 1.1 implementation of SKINI,
updated for the 2.x release of STK:
Synthesis toolKit Instrument Network Interface
for the Synthesis Toolkit in C++ by Perry R. Cook 1996.
for the Synthesis Toolkit in C++ by Perry R. Cook
and Gary Scavone, 1999.
*********************************
* Too good to be true? *
@@ -10,9 +12,10 @@ for the Synthesis Toolkit in C++ by Perry R. Cook 1996.
* A SKINI Haiku. *
*********************************
Profound thanks to Dan Trueman and Brad Garton for input on
this revision. Thanks also to MIDI, the NeXT MusicKit, ZIPI
and all the creators and modifiers of these for good bases
Profound thanks to Dan Trueman, Brad Garton, and
Gary Scavone for input on this revision. Thanks
also to MIDI, the NeXT MusicKit, ZIPI and all
the creators and modifiers of these for good bases
upon/from which to build and depart.
1) MIDI Compatibility
@@ -59,7 +62,7 @@ upon/from which to build and depart.
SKINI was designed to be extensable and hackable for a number
of applications: imbedded synthesis in a game or VR simulation,
scoring and mixing tasks, real-time and non-real time applications
which could benefit from a controllable sound synthesis,
which could benefit from controllable sound synthesis,
JAVA controlled synthesis, or eventually maybe JAVA synthesis,
etc. SKINI is not intended to be "the mother of scorefiles,"
but since the entire system is based on text representations
@@ -69,14 +72,11 @@ upon/from which to build and depart.
I am basically a bottom-up designer with an awareness of top-
down design ideas, so SKINI above all reflects the needs of my
particular research and creative projects as they have arisen and
developed. SKINI09 represents a profound advance beyond SKINI08
(the first version), but it is likely that SKINI1.0x will
developed. SKINI11 represents a profound advance beyond SKINI08
and SKINI09 (the first versions), future SKINI's might
reflect some changes. Compatibility with prior scorefiles
will be attempted, but there aren't that many scorefiles out
there yet. The one thing I will attempt to keep in mind is
enough consistency to allow the creation of a SKINI0x to SKINIx0
file and stream converter object. SKINI09 should be fully
compatible with SKINI08.
there yet.
3) SKINI MESSAGES
@@ -87,13 +87,14 @@ upon/from which to build and depart.
the channel number is scanned as a long int. Channels could be socket
numbers, machine IDs, serial numbers, or even unique tags for each
event in a synthesis. Other fields might be used, as specified in the
SKINI09.tbl file. This is described in more detail later.
SKINI11.tbl file. This is described in more detail later.
Fields in a SKINI line are delimited by spaces, commas, or
tabs. The SKINI parser only operates on a line at a time,
so a newline means the message is over. Multiple messages are
NOT allowed directly on a single line (by use of the ; for
example in C). This could be supported, but it isn't in 0.9.
example in C). This could be supported, but it isn't in
version 1.1.
Message types include standard MIDI types like NoteOn, NoteOff,
ControlChange, etc. MIDI extension message types (messages
@@ -110,31 +111,31 @@ upon/from which to build and depart.
All fields other than type, time, and channel are optional, and the
types and useage of the additional fields is defined in the file
SKINI09.tbl.
SKINI11.tbl.
The other important file used by SKINI is SKINI09.msg, which is a
The other important file used by SKINI is SKINI11.msg, which is a
set of #defines to make C code more readable, and to allow reasonably
quick re-mapping of control numbers, etc.. All of these defined
symbols are assigned integer values. For JAVA, the #defines could
be replaced by declaration and assignment statements, preserving
the look and behavior of the rest of the code.
4) C Files Used To Implement SKINI09
4) C Files Used To Implement SKINI11
SKINI09.cpp is an object which can either open a SKINI file, and
SKINI11.cpp is an object which can either open a SKINI file, and
successively read and parse lines of text as SKINI strings, or
accept strings from another object and parse them. The latter
functionality would be used by a socket, pipe, or other connection
receiving SKINI messages a line at a time, usually in real time,
but not restricted to real time.
SKINI09.msg should be included by anything wanting to use the
SKINI09.cpp object. This is not mandatory, but use of the __SK_blah_
SKINI11.msg should be included by anything wanting to use the
SKINI11.cpp object. This is not mandatory, but use of the __SK_blah_
symbols which are defined in the .msg file will help to ensure
clarity and consistency when messages are added and changed.
SKINI09.tbl is used only by the SKINI parser object (SKINI09.cpp).
In the file SKINI09.tbl, an array of structures is declared and
SKINI11.tbl is used only by the SKINI parser object (SKINI11.cpp).
In the file SKINI11.tbl, an array of structures is declared and
assigned values which instruct the parser as to what the message
types are, and what the fields mean for those message types.
This table is compiled and linked into applications using SKINI, but
@@ -162,7 +163,7 @@ upon/from which to build and depart.
so it's unlikely to be supported later).
d) The first field must be a SKINI message name. (like NoteOn).
These might become case-insensitive in SKINI09+, so don't plan
These might become case-insensitive in SKINI11+, so don't plan
on exciting clever overloading of names (like noTeOn being
different from NoTeON). There can be a number of leading
spaces or tabs, but don't exceed 32 or so.
@@ -180,8 +181,8 @@ upon/from which to build and depart.
if you've sent 100 total delta-time messages of 1.0 seconds, and
then send an absolute time message of =90.0 seconds, or if you
send two absolute time messages of =100.0 and =90.0 in that
order, things will get really fouled up. The SKINI0.9 parser
doesn't know about time, however. The RawWvOut device is the
order, things will get really fouled up. The SKINI1.1 parser
doesn't know about time, however. The WvOut device is the
master time keeper in the Synthesis Toolkit, so it should be
queried to see if absolute time messages are making sense.
There's an example of how to do that later in this document.
@@ -197,7 +198,7 @@ upon/from which to build and depart.
A -1 channel can be used as don't care, omni, or other functions
depending on your needs and taste.
g) All remaining fields are specified in the SKINI09.tbl file.
g) All remaining fields are specified in the SKINI11.tbl file.
In general, there are maximum two more fields, which are either
SK_INT (long), SK_DBL (double float), or SK_STR (string). The
latter is the mechanism by which more arguments can be specified
@@ -207,7 +208,7 @@ upon/from which to build and depart.
6) A Short SKINI File:
/* Howdy!!! Welcome to SKINI09, by P. Cook 1996
/* Howdy!!! Welcome to SKINI11, by P. Cook 1999
NoteOn 0.000082 2 55 82
NoteOff 1.000000 2 55 0
@@ -239,10 +240,10 @@ upon/from which to build and depart.
NoteOff 0.000000 2 71 82
NoteOff 0.000000 2 79 82
7) The SKINI09.tbl File, How Messages are Parsed
7) The SKINI11.tbl File, How Messages are Parsed
The SKINI09.tbl file contains an array of structures which
are accessed by the parser object SKINI09.cpp. The struct is:
The SKINI11.tbl file contains an array of structures which
are accessed by the parser object SKINI11.cpp. The struct is:
struct SKINISpec { char messageString[32];
long type;
@@ -278,7 +279,7 @@ upon/from which to build and depart.
something else stored in the SK_STR field, or
as a new type of multi-line message.
Here's a couple of lines from the SKINI09.tbl file
Here's a couple of lines from the SKINI11.tbl file
{"NoteOff" , __SK_NoteOff_, SK_DBL, SK_DBL},
{"NoteOn" , __SK_NoteOn_, SK_DBL, SK_DBL},
@@ -292,7 +293,7 @@ upon/from which to build and depart.
The first three are basic MIDI messages. The first two would cause the
parser, after recognizing a match of the string "NoteOff" or "NoteOn",
to set the message type to 128 or 144 (__SK_NoteOff_ and __SK_NoteOn_
are #defined in the file SKINI09.msg to be the MIDI byte value, without
are #defined in the file SKINI11.msg to be the MIDI byte value, without
channel, of the actual MIDI messages for NoteOn and NoteOff). The parser
would then set the time or delta time (this is always done and is
therefore not described in the SKINI Message Struct). The next two
@@ -300,11 +301,11 @@ upon/from which to build and depart.
the byteTwo and byteThree variables of the SKINI parser. The remainder
of the line is stashed in the remainderString variable.
The ControlChange line is basically the same as NoteOn and NoteOff, but
The ControlChange spec is basically the same as NoteOn and NoteOff, but
the second data byte is set to an integer (for checking later as to
what MIDI control is being changed).
The Volume line is a MIDI Extension message, which behaves like a
The Volume spec is a MIDI Extension message, which behaves like a
ControlChange message with the controller number set explicitly to
the value for MIDI Volume (7). Thus the following two lines would
accomplish the same changing of MIDI volume on channel 2:
@@ -328,14 +329,15 @@ upon/from which to build and depart.
to read a SKINI file and control a single instrument.
instrument = new Mandolin(50.0);
score = new SKINI09(argv[1]);
score = new SKINI11(argv[1]);
while(score->getType() > 0) {
tempDouble = score->getDelta();
if (tempDouble < 0) {
tempDouble = - tempDouble;
tempDouble = tempDouble - output.getTime();
if (tempDouble < 0) {
printf("Bad News Here!!! Backward Absolute Time Required.\n");
printf("Bad News Here!!! Backward Absolute Time
Required.\n");
tempDouble = 0.0;
}
}
@@ -367,7 +369,7 @@ upon/from which to build and depart.
score->nextMessage();
}
When the score (SKINI09 object) object is created from the
When the score (SKINI11 object) object is created from the
filename in argv[1], the first valid command line is read
from the file and parsed.
@@ -391,7 +393,3 @@ upon/from which to build and depart.
control number, but all other data is treated as double float.
The last line reads and parses the next message in the file.

View File

View File

@@ -2,10 +2,10 @@
/* AgogoBell SubClass of Modal4 Instrument*/
/* by Perry R. Cook, 1995-96 */
/* */
/* Controls: CONTROL1 = stickHardness */
/* CONTROL2 = strikePosition*/
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/* Controls: CONTROL1 = stickHardness */
/* CONTROL2 = strikePosition */
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/*******************************************/
/* Modes measured from my Agogo Bell by FFT: */
@@ -16,15 +16,18 @@
AgogoBel :: AgogoBel() : Modal4()
{
wave = new RawInterp("rawwaves/britestk.raw");
// 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 */
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;

View File

@@ -9,23 +9,33 @@
BeeThree :: BeeThree() : FM4Alg8()
{
this->loadWaves("rawwaves/sinewave.raw",
"rawwaves/sinewave.raw",
"rawwaves/sinewave.raw",
"rawwaves/sinewave.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);
// 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()

View File

@@ -10,7 +10,7 @@
BiQuad :: BiQuad() : Filter()
{
inputs = (MY_FLOAT *) malloc(2 * MY_FLOAT_SIZE);
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;

View File

@@ -3,6 +3,9 @@
/* by Perry R. Cook, 1995-96 */
/***********************************************/
#if !defined(__BowTabl_h)
#define __BowTabl_h
#include "Object.h"
class BowTabl : public Object
@@ -20,3 +23,4 @@ class BowTabl : public Object
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");
}
}

View File

@@ -9,8 +9,8 @@
/* */
/* Controls: CONTROL1 = lipTension */
/* CONTROL2 = slideLength */
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/******************************************/
#if !defined(__Brass_h)
@@ -21,7 +21,7 @@
#include "LipFilt.h"
#include "DCBlock.h"
#include "ADSR.h"
#include "RawLoop.h"
#include "RawWvIn.h"
class Brass: public Instrmnt
{
@@ -30,7 +30,7 @@ class Brass: public Instrmnt
LipFilt *lipFilter;
DCBlock *dcBlock;
ADSR *adsr;
RawLoop *vibr;
RawWvIn *vibr;
long length;
MY_FLOAT lipTarget;
MY_FLOAT slideTarget;

View File

@@ -26,7 +26,11 @@ Clarinet :: Clarinet(MY_FLOAT lowestFreq)
filter = new OneZero;
envelope = new Envelope;
noise = new Noise;
vibr = new RawLoop("rawwaves/sinewave.raw");
// 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;

View File

@@ -22,7 +22,7 @@
#include "OneZero.h"
#include "Envelope.h"
#include "Noise.h"
#include "RawLoop.h"
#include "RawWvIn.h"
class Clarinet : public Instrmnt
{
@@ -32,7 +32,7 @@ class Clarinet : public Instrmnt
OneZero *filter;
Envelope *envelope;
Noise *noise;
RawLoop *vibr;
RawWvIn *vibr;
long length;
MY_FLOAT outputGain;
MY_FLOAT noiseGain;

View File

@@ -12,30 +12,29 @@
DCBlock :: DCBlock()
{
inputs = (MY_FLOAT *) malloc(MY_FLOAT_SIZE);
outputs = (MY_FLOAT *) malloc(MY_FLOAT_SIZE);
this->clear();
inputs = (MY_FLOAT *) malloc(sizeof(MY_FLOAT));
outputs = (MY_FLOAT *) malloc(sizeof(MY_FLOAT));
this->clear();
}
DCBlock :: ~DCBlock()
{
free(inputs);
free(outputs);
free(inputs);
free(outputs);
}
void DCBlock :: clear()
{
outputs[0] = (MY_FLOAT) 0.0;
inputs[0] = (MY_FLOAT) 0.0;
lastOutput = (MY_FLOAT) 0.0;
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;
outputs[0] = sample - inputs[0] + ((MY_FLOAT) 0.99 * outputs[0]);
inputs[0] = sample;
lastOutput = outputs[0];
return lastOutput;
}

View File

@@ -1,6 +1,7 @@
/*******************************************/
/* 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 */
@@ -15,11 +16,11 @@
class DCBlock : public Filter
{
public:
DCBlock();
~DCBlock();
void clear();
MY_FLOAT tick(MY_FLOAT sample);
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
}

View File

@@ -1,7 +1,8 @@
/*******************************************/
/* */
/* AllPass Interpolating Delay Line */
/* Object by Perry R. Cook 1995-96 */
/* 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 */
@@ -31,6 +32,7 @@ class DLineA : public Filter
MY_FLOAT coeff;
MY_FLOAT lastIn;
public:
DLineA();
DLineA(long max_length);
~DLineA();
void clear();

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;
}

View File

@@ -16,18 +16,19 @@
class DLineL : public Filter
{
protected:
long inPoint;
long outPoint;
long length;
MY_FLOAT alpha;
MY_FLOAT omAlpha;
public:
DLineL(long max_length);
~DLineL();
void clear();
void setDelay(MY_FLOAT length);
MY_FLOAT tick(MY_FLOAT sample);
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

View File

@@ -1,20 +1,22 @@
/*******************************************/
/* Master Class for Drum Synthesizer */
/* by Perry R. Cook, 1995-96 */
/* */
/* This instrument contains a bunch of */
/* RawWave objects, run through a bunch */
/* 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 */
/* RawShot objects are used. Otherwise, */
/* RawInterp objects are used. You can */
/* specify the maximum Polyphony (maximum */
/* number of simultaneous voices) in a */
/* #define in the .h file. */
/* 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 RawWave abstract class */
/* by Gary P. Scavone (11/11/98) */
/* Modified for RawWvIn class */
/* by Gary P. Scavone (4/99) */
/*******************************************/
#include "DrumSynt.h"
@@ -78,13 +80,14 @@ DrumSynt :: ~DrumSynt()
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];
RawWave *tempWv;
RawWvIn *tempWv;
OnePole *tempFilt;
/* Yes I know, this is tres kludgey */
@@ -117,12 +120,12 @@ void DrumSynt :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
}
sounding[numSounding-1] = noteNum; /* allocate new wave */
strcpy(tempString,"rawwaves/");
// Concatenate the STK RAWWAVE_PATH to the rawwave file
strcpy(tempString, RAWWAVE_PATH);
strcat(tempString,"rawwaves/");
strcat(tempString,waveNames[genMIDIMap[noteNum]]);
if (SRATE == 22050) {
waves[numSounding-1] = new RawShot(tempString);
} else {
waves[numSounding-1] = new RawInterp(tempString);
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);
@@ -142,6 +145,16 @@ void DrumSynt :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
#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;

View File

@@ -1,29 +1,29 @@
/*******************************************/
/* Master Class for Drum Synthesizer */
/* by Perry R. Cook, 1995-96 */
/* */
/* This instrument contains a bunch of */
/* RawWave objects, run through a bunch */
/* 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 */
/* RawShot objects are used. Otherwise, */
/* RawInterp objects are used. You can */
/* specify the maximum Polyphony (maximum */
/* number of simultaneous voices) in a */
/* #define in the .h file. */
/* 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 RawWave abstract class */
/* by Gary P. Scavone (11/11/98) */
/* Modified for RawWvIn class */
/* by Gary P. Scavone (4/99) */
/*******************************************/
#if !defined(__DrumSynt_h)
#define __DrumSynt_h
#include "Instrmnt.h"
#include "RawWave.h"
#include "RawShot.h"
#include "RawInterp.h"
#include "RawWvIn.h"
#include "OnePole.h"
#define DRUM_NUMWAVES 11
@@ -32,7 +32,7 @@
class DrumSynt : public Instrmnt
{
protected:
RawWave *waves[DRUM_POLYPHONY];
RawWvIn *waves[DRUM_POLYPHONY];
OnePole *filters[DRUM_POLYPHONY];
int sounding[DRUM_POLYPHONY];
int numSounding;
@@ -40,6 +40,7 @@ class DrumSynt : public Instrmnt
DrumSynt();
~DrumSynt();
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
void noteOff(MY_FLOAT amp);
virtual MY_FLOAT tick();
};

View File

@@ -1,5 +1,6 @@
/*******************************************/
/* 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 */
@@ -16,10 +17,10 @@
Envelope :: Envelope() : Object()
{
target = (MY_FLOAT) 0.0;
value = (MY_FLOAT) 0.0;
rate = (MY_FLOAT) 0.001;
state = 0;
target = (MY_FLOAT) 0.0;
value = (MY_FLOAT) 0.0;
rate = (MY_FLOAT) 0.001;
state = 0;
}
Envelope :: ~Envelope()
@@ -28,77 +29,77 @@ Envelope :: ~Envelope()
void Envelope :: keyOn()
{
target = (MY_FLOAT) 1.0;
if (value != target) state = 1;
target = (MY_FLOAT) 1.0;
if (value != target) state = 1;
}
void Envelope :: keyOff()
{
target = (MY_FLOAT) 0.0;
if (value != target) state = 1;
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;
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 ;
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;
target = aTarget;
if (value != target) state = 1;
}
void Envelope :: setValue(MY_FLOAT aValue)
{
state = 0;
target = aValue;
value = 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;
}
}
if (state) {
if (target > value) {
value += rate;
if (value >= target) {
value = target;
state = 0;
}
}
return value;
else {
value -= rate;
if (value <= target) {
value = target;
state = 0;
}
}
}
return value;
}
int Envelope :: informTick()
{
this->tick();
return state;
this->tick();
return state;
}
MY_FLOAT Envelope :: lastOut()
{
return value;
return value;
}
/************ Test Main ************************/

View File

@@ -19,23 +19,23 @@
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();
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

View File

@@ -21,8 +21,8 @@
FM4Alg5 :: FM4Alg5() : FM4Op()
{
/* We still don't make the waves here yet, because */
/* we still don't know what they will be. */
/* We still don't make the waves here yet, because */
/* we still don't know what they will be. */
}
FM4Alg5 :: ~FM4Alg5()
@@ -31,23 +31,23 @@ FM4Alg5 :: ~FM4Alg5()
MY_FLOAT FM4Alg5 :: tick()
{
MY_FLOAT temp,temp2;
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();
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 */
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;
lastOutput = temp * (MY_FLOAT) 0.5;
return lastOutput;
}

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

View File

@@ -10,10 +10,19 @@
FMVoices :: FMVoices() : FM4Alg6()
{
this->loadWaves("rawwaves/sinewave.raw",
"rawwaves/sinewave.raw",
"rawwaves/sinewave.raw",
"rawwaves/sinewave.raw");
// 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);
@@ -52,20 +61,20 @@ void FMVoices :: setFreq(MY_FLOAT frequency)
MY_FLOAT temp,temp2;
int tempi,tempi2;
if (currentVowel < 16) {
if (currentVowel < 32) {
tempi2 = currentVowel;
temp2 = (MY_FLOAT) 0.9;
}
else if (currentVowel < 32) {
tempi2 = currentVowel - 16;
else if (currentVowel < 64) {
tempi2 = currentVowel - 32;
temp2 = (MY_FLOAT) 1.0;
}
else if (currentVowel < 48) {
tempi2 = currentVowel - 32;
else if (currentVowel < 96) {
tempi2 = currentVowel - 64;
temp2 = (MY_FLOAT) 1.1;
}
else if (currentVowel <= 64) {
tempi2 = currentVowel - 48;
else if (currentVowel <= 128) {
tempi2 = currentVowel - 96;
temp2 = (MY_FLOAT) 1.2;
}
baseFreq = frequency;
@@ -106,7 +115,7 @@ void FMVoices :: controlChange(int number, MY_FLOAT value)
if (number == __SK_Breath_)
gains[3] = __FM4Op_gains[(int) (value * 0.78125)];
else if (number == __SK_FootControl_) {
tempi = (int) (value / 2);
tempi = (int) value;
currentVowel = tempi;
this->setFreq(baseFreq);
}

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
}

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