Version 0.99

This commit is contained in:
Gary Scavone
2009-03-24 22:41:14 -04:00
committed by Stephen Sinclair
commit 6485746ee9
218 changed files with 13786 additions and 0 deletions

173
ADSR.cpp Normal file
View File

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

43
ADSR.h Normal file
View File

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

75
AgogoBel.cpp Normal file
View File

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

26
AgogoBel.h Normal file
View File

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

39
AllPass1.cpp Normal file
View File

@@ -0,0 +1,39 @@
/*******************************************/
/* 1st order allpass filter. */
/* by Perry R. Cook, 1995-96 */
/* A special case of the one pole */
/* one zero filter. */
/*******************************************/
#include "AllPass1.h"
AllPass1 :: AllPass1()
{
inputs = (MY_FLOAT *) malloc(MY_FLOAT_SIZE);
outputs = (MY_FLOAT *) malloc(MY_FLOAT_SIZE);
this->clear();
}
AllPass1 :: ~AllPass1()
{
free(inputs);
free(outputs);
}
void AllPass1 :: clear()
{
outputs[0] = 0.0;
inputs[0] = 0.0;
lastOutput = 0.0;
}
MY_FLOAT AllPass1 :: tick(MY_FLOAT sample)
{
outputs[0] = sample - inputs[0] + (0.99 * outputs[0]);
inputs[0] = sample;
lastOutput = outputs[0];
return lastOutput;
}

24
AllPass1.h Normal file
View File

@@ -0,0 +1,24 @@
/*******************************************/
/* 1st order allpass filter. */
/* by Perry R. Cook, 1995-96 */
/* A special case of the one pole */
/* one zero filter. */
/*******************************************/
#include "Filter.h"
#if !defined(__AllPass1_h)
#define __AllPass1_h
#include "Filter.h"
class AllPass1 : Filter
{
public:
AllPass1();
~AllPass1();
void clear();
MY_FLOAT tick(MY_FLOAT sample);
};
#endif

71
BeeThree.cpp Normal file
View File

@@ -0,0 +1,71 @@
/******************************************/
/* Hammond(OID) Organ Subclass */
/* of Algorithm 8 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/******************************************/
#include "BeeThree.h"
BeeThree :: BeeThree() : FM4Alg8()
{
this->loadWaves("rawwaves/sinewave.raw",
"rawwaves/sinewave.raw",
"rawwaves/sinewave.raw",
"rawwaves/sinewave.raw");
this->setRatio(0,0.999);
this->setRatio(1,1.997);
this->setRatio(2,3.006);
this->setRatio(3,6.009);
gains[0] = __FM4Op_gains[95];
gains[1] = __FM4Op_gains[95];
gains[2] = __FM4Op_gains[99];
gains[3] = __FM4Op_gains[95];
adsr[0]->setAll(0.05,0.03,1.0,0.04);
adsr[1]->setAll(0.05,0.03,1.0,0.04);
adsr[2]->setAll(0.05,0.03,1.0,0.04);
adsr[3]->setAll(0.05,0.001,0.4,0.06);
twozero->setGain(0.1);
}
BeeThree :: ~BeeThree()
{
}
void BeeThree :: setFreq(MY_FLOAT frequency)
{
baseFreq = frequency;
waves[0]->setFreq(baseFreq * ratios[0]);
waves[1]->setFreq(baseFreq * ratios[1]);
waves[2]->setFreq(baseFreq * ratios[2]);
waves[3]->setFreq(baseFreq * ratios[3]);
}
MY_FLOAT BeeThree :: tick()
{
MY_FLOAT temp;
if (modDepth > 0.0) {
temp = 1.0 + (modDepth * vibWave->tick() * 0.1);
waves[0]->setFreq(baseFreq * ratios[0] * temp);
waves[1]->setFreq(baseFreq * ratios[1] * temp);
waves[2]->setFreq(baseFreq * ratios[2] * temp);
waves[3]->setFreq(baseFreq * ratios[3] * temp);
}
lastOutput = FM4Alg8 :: tick();
return lastOutput;
}
void BeeThree :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
gains[0] = amp * __FM4Op_gains[95];
gains[1] = amp * __FM4Op_gains[95];
gains[2] = amp * __FM4Op_gains[99];
gains[3] = amp * __FM4Op_gains[95];
this->setFreq(freq);
this->keyOn();
#if defined(_debug_)
printf("BeeThree : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}

23
BeeThree.h Normal file
View File

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

80
BiQuad.cpp Normal file
View File

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

31
BiQuad.h Normal file
View File

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

46
BowTabl.cpp Normal file
View File

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

22
BowTabl.h Normal file
View File

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

160
Bowed.cpp Normal file
View File

@@ -0,0 +1,160 @@
/******************************************/
/* 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"
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 = 0.0;
neckDelay->setDelay(100.0);
bridgeDelay->setDelay(29.0);
bowTabl->setSlope(3.0);
reflFilt->setPole(0.6 - (0.1 * RATE_NORM));
reflFilt->setGain(0.95);
bodyFilt->setFreqAndReson(500.0, 0.85);
bodyFilt->setEqualGainZeroes();
bodyFilt->setGain(0.2);
vibr->normalize();
vibr->setFreq(6.12723);
adsr->setAll(0.002,0.01,0.9,0.01);
betaRatio = 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 = (MY_FLOAT) SRATE / frequency - 4.0; /* delay - approx. filter delay */
bridgeDelay->setDelay(baseDelay * betaRatio); /* bow to bridge length */
neckDelay->setDelay(baseDelay * (1.0 - betaRatio)); /* bow to nut (finger) length */
}
void Bowed :: startBowing(MY_FLOAT amplitude, MY_FLOAT rate)
{
adsr->setRate(rate);
adsr->keyOn();
maxVelocity = 0.03 + (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 * 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((1.0 - amp) * 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=0,nutRefl=0;
MY_FLOAT newVel=0,velDiff=0,stringVel=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 * (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 == MIDI_control1)
bowTabl->setSlope(5.0 - (4.0 * value * NORM_7));
else if (number == MIDI_control2) {
betaRatio = 0.027236 + (0.2 * value * NORM_7);
bridgeDelay->setDelay(baseDelay * betaRatio); /* bow to bridge length */
neckDelay->setDelay(baseDelay * (1.0 - betaRatio)); /* bow to nut (finger) length */
}
else if (number == MIDI_control3)
vibr->setFreq((value * NORM_7 * 12.0));
else if (number == MIDI_mod_wheel)
vibrGain = (value * NORM_7 * 0.4);
else if (number == MIDI_after_touch)
adsr->setTarget(value * NORM_7);
else {
printf("Bowed : Undefined Control Number!!\n");
}
}

56
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 "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

129
Brass.cpp Normal file
View File

@@ -0,0 +1,129 @@
/******************************************/
/* 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"
Brass :: Brass(MY_FLOAT lowestFreq)
{
length = (long) (SRATE / lowestFreq + 1);
delayLine = new DLineA(length);
lipFilter = new LipFilt;
dcBlock = new DCBlock;
adsr = new ADSR;
adsr->setAll(0.02, 0.05, 1.0, 0.001);
vibr = new RawLoop("rawwaves/sinewave.raw");
this->clear();
vibr->normalize();
vibr->setFreq(6.137);
vibrGain = 0.05; /* breath periodic vibrato component */
}
Brass :: ~Brass()
{
delete delayLine;
delete lipFilter;
delete dcBlock;
delete adsr;
delete vibr;
}
void Brass :: clear()
{
delayLine->clear();
lipFilter->clear();
dcBlock->clear();
/* adsr->reset(); */
}
void Brass :: setFreq(MY_FLOAT frequency)
{
slideTarget = ((MY_FLOAT) SRATE / frequency * 2.0) + 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 * 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 * 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(0.3 * breathPressure, /* mouth input */
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 == MIDI_control1) {
temp = lipTarget * pow(4.0,(2.0*value*NORM_7) - 1.0);
this->setLip(temp);
}
else if (number == MIDI_control2)
delayLine->setDelay(slideTarget * (0.5 + (value * NORM_7)));
else if (number == MIDI_control3)
vibr->setFreq((value * NORM_7 * 12.0));
else if (number == MIDI_mod_wheel)
vibrGain = (value * NORM_7 * 0.4);
else if (number == MIDI_after_touch)
adsr->setTarget(value * NORM_7);
else {
printf("Brass : Undefined Control Number!!\n");
}
}

53
Brass.h Normal file
View File

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

125
Clarinet.cpp Normal file
View File

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

53
Clarinet.h Normal file
View File

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

41
DCBlock.cpp Normal file
View File

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

25
DCBlock.h Normal file
View File

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

104
DLineA.cpp Normal file
View File

@@ -0,0 +1,104 @@
/*******************************************/
/* */
/* 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] = 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] = 0.0;
lastIn = 0;
lastOutput = 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 = 1.0 + outPoint - outputPointer; /* fractional part of delay */
if (alpha<0.1) {
outputPointer += 1.0; /* Hack to avoid pole/zero */
outPoint += 1; /* cancellation. Keeps allpass */
alpha += 1.0; /* delay in range of .1 to 1.1 */
}
coeff = (1.0 - alpha) / (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);
}
*/

41
DLineA.h Normal file
View File

@@ -0,0 +1,41 @@
/*******************************************/
/* */
/* 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)). */
/* */
/*******************************************/
#if !defined(__DLineA_h)
#define __DLineA_h
#include "Filter.h"
class DLineA : public Filter
{
protected:
long inPoint;
long outPoint;
long length;
MY_FLOAT alpha;
MY_FLOAT coeff;
MY_FLOAT lastIn;
public:
DLineA(long max_length);
~DLineA();
void clear();
void setDelay(MY_FLOAT length);
MY_FLOAT tick(MY_FLOAT sample);
};
#endif

90
DLineL.cpp Normal file
View File

@@ -0,0 +1,90 @@
/*******************************************/
/* 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] = 0.0;
lastOutput = 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 = 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);
}
*/

33
DLineL.h Normal file
View File

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

80
DLineN.cpp Normal file
View File

@@ -0,0 +1,80 @@
/*******************************************/
/* 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 * 0.5);
inPoint = 0;
outPoint = 0;
}
DLineN :: ~DLineN()
{
free(inputs);
}
void DLineN :: clear()
{
long i;
for (i=0;i<length;i++) inputs[i] = 0.0;
lastOutput = 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);
}
*/

30
DLineN.h Normal file
View File

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

164
DrumSynt.cpp Normal file
View File

@@ -0,0 +1,164 @@
/*******************************************/
/* Master Class for Drum Synthesizer */
/* by Perry R. Cook, 1995-96 */
/* This instrument contains a bunch of */
/* RawWvIn objects (Non-Interpolating, */
/* 1 shot players), run through a bunch */
/* of one-pole filters. You can specify */
/* the maximum Polyphony (maximum number */
/* of simultaneous voices) in a #define */
/* in the .h file. */
/*******************************************/
#include "DrumSynt.h"
#include <string.h>
char waveNames[DRUM_NUMWAVES][16] = {
"bass.raw",
"snar.raw",
"tomlow.raw",
"tommid.raw",
"tomhi.raw",
"hat.raw",
"ride.raw",
"crash.raw",
"cowbell.raw",
"tamb.raw"
};
DrumSynt :: DrumSynt() : Object()
{
int i;
/* char temp[64]; */
/* for (i=0;i<DRUM_NUMWAVES;i++) { */
/* strcpy(temp,"rawwaves/drumwavs/"); */
/* strcat(temp,waveNames[i]); */
/* waves[i] = new RawWvIn(temp); */
/* waves[i]->finish(); */
/* waves[i]->normalize(0.2); */
/* } */
for (i=0;i<DRUM_POLYPHONY;i++) {
filters[i] = new OnePole;
sounding[i] = -1;
/* filtSounding[i] = -1; */
}
numSounding = 0; /* This counts the number */
/* of sounding voices */
}
void DrumSynt :: noteOn(int noteNum, int vel)
{
int i,notDone;
char tempString[64];
RawWvIn *tempWv;
OnePole *tempFilt;
printf("NoteOn: %s vel=%i\n",waveNames[noteNum],vel);
notDone = -1;
for (i=0;i<DRUM_POLYPHONY;i++) { /* Check first to see */
if (sounding[i] == noteNum) notDone = i; /* if there's already */
} /* one like this sounding */
if (notDone<0) { /* If not, then */
if (numSounding == DRUM_POLYPHONY) { /* If we're already */
delete waves[0]; /* at max polyphony, */
filters[0]->clear(); /* then */
tempWv = waves[0];
tempFilt = filters[0];
for (i=0;i<DRUM_POLYPHONY-1;i++) { /* preempt oldest */
waves[i] = waves[i+1]; /* oldest voice and */
filters[i] = filters[i+1]; /* ripple all down */
}
waves[DRUM_POLYPHONY-1] = tempWv;
filters[DRUM_POLYPHONY-1] = tempFilt;
}
else {
numSounding += 1; /* otherwise just add one */
}
sounding[numSounding-1] = noteNum; /* allocate new wave */
strcpy(tempString,"rawwaves/drumwavs/");
strcat(tempString,waveNames[noteNum]);
waves[numSounding-1] = new RawWvIn(tempString);
waves[numSounding-1]->normalize(0.2);
filters[numSounding-1]->setPole(0.999 - (vel / 32.0));
filters[numSounding-1]->setGain(vel / 128.0);
}
else {
waves[notDone]->reset();
filters[notDone]->setPole(0.999 - (vel / 32.0));
filters[notDone]->setGain(vel / 128.0);
}
printf("Number Sounding = %i\n",numSounding);
for (i=0;i<numSounding;i++) printf(" %i ",sounding[i]);
printf("\n");
}
MY_FLOAT DrumSynt :: tick()
{
int i, j, notDone;
MY_FLOAT output;
OnePole *tempFilt;
i = 0;
notDone = 1;
output = 0.0;
if (numSounding == 0) notDone = 0;
while (notDone && (i < numSounding)) {
output += waves[i]->lastOut();
if (waves[i]->informTick() == 1) {
printf("Wave %i %i down here\n",i,sounding[i]);
delete waves[i];
tempFilt = filters[i];
for (j=i;j<numSounding-1;j++) {
sounding[j] = sounding[j+1];
waves[j] = waves[j+1];
filters[j] = filters[j+1];
}
filters[j] = tempFilt;
filters[j]->clear();
sounding[j] = -1;
numSounding -= 1;
if (numSounding == 0) notDone = 0;
i -= 1;
}
i++;
}
return output;
}
/************** Test Main Program *********************/
#include "miditabl.h"
#include "RawWvOut.h"
#include "Reverb.h"
#include "Noise.h"
int main()
{
long i,j;
DrumSynt instrument;
RawWvOut output("test.snd");
Reverb reverb(2137);
Noise noise;
for (j=0;j<100;j++) {
i = (int) (fabs(noise.tick()) * DRUM_NUMWAVES);
instrument.noteOn(i,127);
for (i=0;i<2000;i++) output.tick(reverb.tick(instrument.tick()));
}
for (i=0;i<22000;i++) output.tick(reverb.tick(instrument.tick()));
}

37
DrumSynt.h Normal file
View File

@@ -0,0 +1,37 @@
/*******************************************/
/* Master Class for Drum Synthesizer */
/* by Perry R. Cook, 1995-96 */
/* This instrument contains a bunch of */
/* RawWvIn objects (Non-Interpolating, */
/* 1 shot players), run through a bunch */
/* of one-pole filters. You can specify */
/* the maximum Polyphony (maximum number */
/* of simultaneous voices) in a #define */
/* in the .h file. */
/*******************************************/
#if !defined(__DrumSynt_h)
#define __DrumSynt_h
#include "Object.h"
#include "RawWvIn.h"
#include "OnePole.h"
#define DRUM_NUMWAVES 10
#define DRUM_POLYPHONY 4
class DrumSynt : public Object
{
protected:
RawWvIn *waves[DRUM_POLYPHONY];
OnePole *filters[DRUM_POLYPHONY];
int sounding[DRUM_POLYPHONY];
int numSounding;
public:
DrumSynt();
/* ~DrumSynt(); */
void noteOn(int noteNum, int vel);
MY_FLOAT tick();
};
#endif

113
Envelope.cpp Normal file
View File

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

40
Envelope.h Normal file
View File

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

51
FM4Alg3.cpp Normal file
View File

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

29
FM4Alg3.h Normal file
View File

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

48
FM4Alg4.cpp Normal file
View File

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

29
FM4Alg4.h Normal file
View File

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

48
FM4Alg5.cpp Normal file
View File

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

32
FM4Alg5.h Normal file
View File

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

54
FM4Alg6.cpp Normal file
View File

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

35
FM4Alg6.h Normal file
View File

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

43
FM4Alg8.cpp Normal file
View File

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

33
FM4Alg8.h Normal file
View File

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

179
FM4Op.cpp Normal file
View File

@@ -0,0 +1,179 @@
/*******************************************/
/* 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"
FM4Op :: FM4Op()
{
int i;
MY_FLOAT temp;
MY_FLOAT tempCoeffs[2] = {0.0, -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(6.0); /* should make this random?? */
modDepth = 0.0;
/* We don't make the waves here yet, because */
/* we don't know what they will be. */
baseFreq = 440.0;
ratios[0] = 1.0;
ratios[1] = 1.0;
ratios[2] = 1.0;
ratios[3] = 1.0;
gains[0] = 1.0;
gains[1] = 1.0;
gains[2] = 1.0;
gains[3] = 1.0;
twozero->setZeroCoeffs(tempCoeffs);
twozero->setGain(0.0);
control1 = 1.0;
control2 = 1.0;
temp = 1.0;
for (i=99;i>=0;i--) {
__FM4Op_gains[i] = temp;
temp *= 0.933033;
}
temp = 1.0;
for (i=15;i>=0;i--) {
__FM4Op_susLevels[i] = temp;
temp *= 0.707101;
}
temp = 8.498186;
for (i=0;i<32;i++) {
__FM4Op_attTimes[i] = temp;
temp *= 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*2.0;
}
void FM4Op :: setControl2(MY_FLOAT cVal)
{
control2 = cVal*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 == MIDI_control1)
this->setControl1(value * NORM_7);
else if (number == MIDI_control2)
this->setControl2(value * NORM_7);
else if (number == MIDI_control3)
this->setModulationSpeed(value * NORM_7 * 12.0); /* 0 to 12 Hz */
else if (number == MIDI_mod_wheel)
this->setModulationDepth(value * NORM_7);
else if (number == MIDI_after_touch) {
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 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 "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();
~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

118
FMVoices.cpp Normal file
View File

@@ -0,0 +1,118 @@
/******************************************/
/* Singing Voice Synthesis Subclass */
/* of Algorithm 6 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1996 */
/******************************************/
#include "FMVoices.h"
FMVoices :: FMVoices() : FM4Alg6()
{
this->loadWaves("rawwaves/sinewave.raw",
"rawwaves/sinewave.raw",
"rawwaves/sinewave.raw",
"rawwaves/sinewave.raw");
this->setRatio(0,2.00);
this->setRatio(1,4.00);
this->setRatio(2,12.0);
this->setRatio(3,1.00);
gains[3] = __FM4Op_gains[80];
adsr[0]->setAll(0.001,0.001,__FM4Op_susLevels[15],0.001);
adsr[1]->setAll(0.001,0.001,__FM4Op_susLevels[15],0.001);
adsr[2]->setAll(0.001,0.001,__FM4Op_susLevels[15],0.001);
adsr[3]->setAll(0.05,0.05,__FM4Op_susLevels[15],0.0001);
twozero->setGain(0.0);
modDepth = 0.005;
currentVowel = 0;
tilt[0] = 1.0;
tilt[1] = 0.5;
tilt[2] = 0.2;
mods[0] = 1.0;
mods[1] = 1.1;
mods[2] = 1.1;
baseFreq = 110.0;
this->setFreq(110.0);
}
#include "phonTabl.h"
void FMVoices :: setFreq(MY_FLOAT frequency)
{
MY_FLOAT temp,temp2;
int tempi,tempi2;
if (currentVowel < 16) {
tempi2 = currentVowel;
temp2 = 0.9;
}
else if (currentVowel < 32) {
tempi2 = currentVowel - 16;
temp2 = 1.0;
}
else if (currentVowel < 48) {
tempi2 = currentVowel - 32;
temp2 = 1.1;
}
else if (currentVowel < 64) {
tempi2 = currentVowel - 48;
temp2 = 1.2;
}
baseFreq = frequency;
temp = (temp2 * phonParams[tempi2][0][0] / baseFreq) + 0.5;
tempi = (int) temp;
this->setRatio(0,(MY_FLOAT) tempi);
temp = (temp2 * phonParams[tempi2][1][0] / baseFreq) + 0.5;
tempi = (int) temp;
this->setRatio(1,(MY_FLOAT) tempi);
temp = (temp2 * phonParams[tempi2][2][0] / baseFreq) + 0.5;
tempi = (int) temp;
this->setRatio(2,(MY_FLOAT) tempi);
gains[0] = 1.0; // pow(10.0,phonParams[tempi2][0][2] * 0.05);
gains[1] = 1.0; // pow(10.0,phonParams[tempi2][1][2] * 0.05);
gains[2] = 1.0; // pow(10.0,phonParams[tempi2][2][2] * 0.05);
}
void FMVoices :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
this->setFreq(freq);
tilt[0] = amp;
tilt[1] = amp * amp;
tilt[2] = amp * amp * amp;
this->keyOn();
#if defined(_debug_)
printf("FMVoices : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}
void FMVoices :: controlChange(int number, MY_FLOAT value)
{
MY_FLOAT temp;
int tempi;
#if defined(_debug_)
printf("FM4Op : ControlChange: Number=%i Value=%f\n",number,value);
#endif
if (number == MIDI_control1)
gains[3] = __FM4Op_gains[(int) (value * 0.78125)];
else if (number == MIDI_control2) {
tempi = (int) (value / 2);
currentVowel = tempi;
this->setFreq(baseFreq);
}
else if (number == MIDI_control3)
this->setModulationSpeed(value * NORM_7 * 12.0); /* 0 to 12 Hz */
else if (number == MIDI_mod_wheel)
this->setModulationDepth(value * NORM_7);
else if (number == MIDI_after_touch) {
temp = value * NORM_7;
tilt[0] = temp;
tilt[1] = temp * temp;
tilt[2] = temp * temp * temp;
}
else {
printf("FM4Op : Undefined Control Number!!\n");
}
}

24
FMVoices.h Normal file
View File

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

24
Filter.cpp Normal file
View File

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

28
Filter.h Normal file
View File

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

172
Flute.cpp Normal file
View File

@@ -0,0 +1,172 @@
/******************************************/
/* 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"
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(100.0);
jetDelay->setDelay(49.0);
filter->setPole(0.7 - (0.1 * RATE_NORM));
filter->setGain(-1.0);
vibr->normalize();
vibr->setFreq(5.925);
adsr->setAll(0.02, 0.05, 0.8, 0.001);
endRefl = 0.5;
jetRefl = 0.5;
noiseGain = 0.15; /* Breath pressure random component */
vibrGain = 0.05; /* breath periodic vibrato component */
jetRatio = 0.32;
}
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 * 0.66666; /* we're overblowing here */
temp = SRATE / lastFreq - 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 / 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(1.1 + (amp * 0.20),amp * 0.02);
outputGain = amp + 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 * 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 - 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 = 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 == MIDI_control1)
this->setJetDelay(0.08 + (0.48 * value * NORM_7));
else if (number == MIDI_control2)
noiseGain = (value * NORM_7 * 0.4);
else if (number == MIDI_control3)
vibr->setFreq((value * NORM_7 * 12.0));
else if (number == MIDI_mod_wheel)
vibrGain = (value * NORM_7 * 0.4);
else if (number == MIDI_after_touch)
adsr->setTarget(value * NORM_7);
else {
printf("Flute : Undefined Control Number!!\n");
}
}

64
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 "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

170
FormSwep.cpp Normal file
View File

@@ -0,0 +1,170 @@
/*******************************************/
/* 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] = 0.0;
poleCoeffs[1] = 0.0;
gain = 1.0;
freq = 0.0;
reson = 0.0;
currentGain = 1.0;
currentFreq = 0.0;
currentReson = 0.0;
targetGain = 1.0;
targetFreq = 0.0;
targetReson = 0.0;
deltaGain = 0.0;
deltaFreq = 0.0;
deltaReson = 0.0;
sweepState = 0;
sweepRate = 0.002;
dirty = 0;
this->clear();
}
FormSwep :: ~FormSwep()
{
free(outputs);
}
void FormSwep :: clear()
{
outputs[0] = 0.0;
outputs[1] = 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] = 2.0 * reson * 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 = 0.0;
}
void FormSwep :: setSweepRate(MY_FLOAT aRate)
{
sweepRate = aRate;
}
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 = 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] = 2.0 * currentReson * 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);
}
*/

45
FormSwep.h Normal file
View File

@@ -0,0 +1,45 @@
/*******************************************/
/* 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);
MY_FLOAT tick(MY_FLOAT sample);
};
#endif

125
HIERARCH.txt Normal file
View File

@@ -0,0 +1,125 @@
Brief Descriptions of Classes in TK96CPP
A ToolKit of Sound Synthesis Classes
and Instruments in C++
Perry Cook, 1995-96, free distribution for
academic, instructional, tutorial, etc. purposes.
Please read README.txt for more information.
<-----Building Blocks----->|<----------------Instruments------------------>
SourcSink Filters Non-Lin ModalSyn FM Physical Sampling PhISM
& Formant
Object---------------------------Instrmnt----------.
| | | | | |
Envelope| Filter BowTabl | .------------------|---------------------.
| | | JetTabl | | | | | | | | |
ADSR | OneZero ReedTabl| Modal4 | FM4Op---.| | | | PhISEM
| OnePole | | | | || | | | |
._____| TwoZero .____| Marimba | FM4Alg3 || Plucked Sampler | Maracha
| | TwoPole | Vibraphn| | || Clarinet | | Whistle
Noise | DCBlock LipFilt AgogoBel| HeavyMtl|| Brass SamplFlt| VibraSlp
| | BiQuad | || Flute | | Tambourn
SubNoise| AllPass1 .____| .____|| Bowed Moog1 |
| DLineA | | || |
._____| DLineL VoicForm FM4Alg4 ||____. |
| | DLineN | | | |
RawWave | FormSwep PercFlut| Plucked2 |
| | | |
._____| .____| Mandolin .____|
| | | | |
RawLoop | FM4Alg5 | DrumSynt
| | |
._____| Rhodey |
| | Wurley |
NiWave1S| TubeBell |
| .____|
._____| | |
| | FM4Alg6 |
Modulatr| | |
| FMVoices|
._____| |
| | .____|
SingWave| |
| FM4Alg8
._____| |
| | BeeThree
RawWvOut|
|
._____|
| |
RawWvIn |
._____|
|
NIFileIn
********** 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>>
Bowed.cpp Not Hideous Bowed String DlineL,BowTabl,OnePole,BiQuad,RawWave,ADSR
Brass.cpp Not So Bad Brass Inst. DLineA,LipFilt,DCBlock,ADSR,BiQuad
Clarinet.cpp Pretty Good Clarinet DLineL,ReedTabl,OneZero,Envelope,Noise.h
Flute.cpp Pretty Good Flute JetTabl,DLineL,OnePole,DCBlock,Noise,ADSR,RawWave
Modal4.cpp 4 Resonances Envelope,RawWave,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
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>>
FM4Alg6.cpp 3 Carr. with 1 Mod. <<flavor of FM4OP>>
FM4Alg8.cpp 4 Osc. Additive <<flavor of FM4OP>>
HeavyMtl.cpp Distorted Synth <<flavor of FM4Alg3>>
PercFlut.cpp Perc. Flute <<flavor of FM4Alg4>>
Rhodey.cpp Rhodes-Like Elec. Piano <<flavor of FM4Alg5>>
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), RawWave (loop), OnePole
SamplFlt.cpp Sampler with Swept Filt.<<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 NIFileIn, and OnePole
*********** Basic Unit Generators **************
Master Object: Object.cpp for compatibility with Objective C
Source&Sink: RawWave.cpp Lin-Interp Wavetable, Looped or 1 Shot
NIWave1S.cpp Non-Interp Wavetable, 1 Shot
RawLoop.cpp Lin-Interp Wavetable, Looping
RawWvIn.cpp Lin-Interp Wave In streaming 'device'
NIFileIn.cpp Non-Interp Wave In streamer, closes & opens
RawWvOut.cpp Non-Interp Wave Out streaming 'device'
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
Filters: Filter.cpp Filter Master Class
OneZero.cpp One Zero Filter
OnePole.cpp One Pole Filter
AllPass1.cpp 1st Order All-Pass (phase) Filter
DCBlock.cpp DC Blocking 1Pole/1Zero Filter
TwoZero.cpp Two Zero Filter
TwoPole.cpp Two Pole Filter
BiQuad.cpp 2Pole/2Zero Filter
FormSwep.cpp Sweepable 2Pole filter, go to target by rate
DLineL.cpp Linearly Interpolating Delay Line
DLineA.cpp AllPass Interpolating Delay Line
DLineN.cpp Non Interpolating Delay Line
NonLin&Lookup: JetTabl.cpp Cubic Jet NonLinearity
BowTabl.cpp 1/x^3-like Bow 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

60
HeavyMtl.cpp Normal file
View File

@@ -0,0 +1,60 @@
/******************************************/
/* 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,1.00 );
this->setRatio(1,4.00 * 0.999);
this->setRatio(2,3.00 * 1.001);
this->setRatio(3,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]->setAll(0.050,0.0100,1.0,0.001);
adsr[1]->setAll(0.050,0.0010,1.0,0.0001);
adsr[2]->setAll(0.001,0.0020,1.0,0.0002);
adsr[3]->setAll(0.050,0.0010,0.2,0.0002);
twozero->setGain(2.0);
vibWave->setFreq(5.5);
modDepth = 0.00;
}
HeavyMtl :: ~HeavyMtl()
{
}
void HeavyMtl :: setFreq(MY_FLOAT frequency)
{
baseFreq = frequency;
waves[0]->setFreq(baseFreq * ratios[0]);
waves[1]->setFreq(baseFreq * ratios[1]);
waves[2]->setFreq(baseFreq * ratios[2]);
waves[3]->setFreq(baseFreq * ratios[3]);
}
void HeavyMtl :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
gains[0] = amp * __FM4Op_gains[92];
gains[1] = amp * __FM4Op_gains[76];
gains[2] = amp * __FM4Op_gains[91];
gains[3] = amp * __FM4Op_gains[68];
this->setFreq(freq);
this->keyOn();
#if defined(_debug_)
printf("HeavyMtl : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}

22
HeavyMtl.h Normal file
View File

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

35
Instrmnt.cpp Normal file
View File

@@ -0,0 +1,35 @@
/******************************************/
/* Instrument SuperClass for Toolkit96 */
/* Perry R. Cook, Princeton University */
/******************************************/
#include "Instrmnt.h"
Instrmnt :: Instrmnt()
{
}
void Instrmnt :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
}
void Instrmnt :: noteOff(MY_FLOAT amp)
{
}
void Instrmnt :: setFreq(MY_FLOAT freq)
{
}
MY_FLOAT Instrmnt :: tick()
{
}
MY_FLOAT Instrmnt :: lastOut()
{
return lastOutput;
}
void Instrmnt :: controlChange(int number, MY_FLOAT value)
{
}

25
Instrmnt.h Normal file
View File

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

36
JetTabl.cpp Normal file
View File

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

22
JetTabl.h Normal file
View File

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

1
Lacrymosa Executable file
View File

@@ -0,0 +1 @@
time textVoic =100.00 lll ahh ...... =133 .... xxx rrr + + eee .. mmm + ohh ..... sss ahh ..... ddd - eee .. - - ... + + ehh .. + ... sss - - - eee ..... lll =100.0 ahh .......

66
LipFilt.cpp Normal file
View File

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

28
LipFilt.h Normal file
View File

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

188
MIDIInpt.cpp Normal file
View File

@@ -0,0 +1,188 @@
/******************************************/
/* Simple RealTime MIDI Input Object, */
/* by Perry R. Cook, 1996 */
/* */
/* This object takes MIDI from the input */
/* , parses it, turns it into TSIDI */
/* messages, and buffers it up for use by*/
/* any object that asks for it later. */
/* */
/* TSIDI (ToolKit Synthesis Instrument */
/* Digital Interfaceis like MIDI, but */
/* allows for floating point control */
/* changes, note numbers, etc. Example: */
/* noteOn(1,60.01,111.132) plays a sharp */
/* middle C with a velocity of 111.132 */
/* */
/******************************************/
#include "MIDIInpt.h"
int onePending;
MDport inport;
MDevent lastEvent;
// void pollMessage(void *)
// {
// int status;
// while (1) {
// while (onePending == 0) {
// mdReceive(inport, &lastEvent, 1);
// status = mdGetStatus(lastEvent.msg);
// if (status==MD_NOTEON || status==MD_NOTEOFF)
// onePending = 1;
// }
// }
// }
MIDIInpt :: MIDIInpt()
{
int nports;
nports = mdInit();
printf("%d MIDI devices available\n", nports);
inport = mdOpenInPort(0);
if (inport == NULL) {
printf("open failed\n");
exit(0);
}
mdSetStampMode(inport, MD_NOSTAMP);
onePending = 0;
// midi_pid = sproc(pollMessage, PR_SALL);
// if (midi_pid == -1)
// {
// fprintf(stderr, "unable to create midi input thread...aborting.\n");
// exit(-1);
// }
}
#define _BSD_SIGNALS
#include <signal.h>
MIDIInpt :: ~MIDIInpt()
{
mdClosePort(inport);
// kill(midi_pid, SIGKILL);
}
/* MIDI File Code
if (byte > 15) {
if (byte == 248) printf("MIDI Clock,");
else if (byte == 249) printf("Undefined,");
else if (byte == 250) printf("Song Start,");
else if (byte == 251) printf("Continue,");
else if (byte == 252) printf("Song Stop,");
else if (byte == 253) printf("Undefined,");
else if (byte == 254) printf("ActiveSen,");
else if (byte == 255) printf("SystReset,");
else printf("BEATSME");
}
else {
if (byte == 8) printf("NoteOff");
if (byte == 9) printf("NoteOn");
if (byte == 10) printf("Poly Pressure");
if (byte == 11) printf("Control Change");
if (byte == 12) printf("Program Change");
if (byte == 13) printf("Channel Pressure");
if (byte == 14) printf("Pitch Wheel");
}
*/
int MIDIInpt :: nextMessage()
{
int status;
int byte1;
int byte2;
messageType = -1;
mdReceive(inport, &lastEvent, 1);
// if (onePending == 1) {
status = mdGetStatus(lastEvent.msg);
byte1 = mdGetByte1(lastEvent.msg);
byte2 = mdGetByte2(lastEvent.msg);
channel = mdGetChannel(lastEvent.msg);
if (status==MD_NOTEON) {
byteTwo = (float) byte1;
byteThree = (float) byte2;
if (byte2==0)
messageType = 8;
else
messageType = 9;
}
else if (status==MD_NOTEOFF) {
byteTwo = (float) byte1;
byteThree = (float) byte2;
messageType = 8;
}
else if (status==MD_CONTROLCHANGE) {
byteTwo = (float) byte1;
byteThree = (float) byte2;
messageType = 11;
}
else if (status==MD_PROGRAMCHANGE) {
byteTwo = (float) byte1;
messageType = 12;
}
else if (status==MD_CHANNELPRESSURE) {
byteTwo = (float) byte1;
messageType = 13;
}
else if (status==MD_PITCHBENDCHANGE) {
byteTwo = (float) byte1;
byteTwo += (float) byte2 * NORM_7;
messageType = 14;
}
else {
messageType = -1;
}
// onePending = 0;
// }
return messageType;
}
void MIDIInpt :: printMessage()
{
char buffer[128];
mdPrintEvent(buffer,&lastEvent,1);
printf(buffer);
}
int MIDIInpt :: getType()
{
return messageType;
}
int MIDIInpt :: getChannel()
{
return channel;
}
MY_FLOAT MIDIInpt :: getByteTwo()
{
return byteTwo;
}
MY_FLOAT MIDIInpt :: getByteThree()
{
return byteThree;
}
/************ Test Main Program *****************/
/*
void main(int argc,char *argv[])
{
MIDIInpt testMIDI;
while(1) {
if (testMIDI.nextMessage() > 0)
testMIDI.printMessage();
}
}
*/

48
MIDIInpt.h Normal file
View File

@@ -0,0 +1,48 @@
/******************************************/
/* Simple MIDI Text File Reader Class, */
/* by Perry R. Cook, 1996 */
/* This Object can open a MIDI Text File */
/* and parse it. The file spec is mine */
/* and mine alone, but it's all text so */
/* you should be able to figure it out. */
/* */
/* TSIDI (ToolKit Synthesis Instrument */
/* Digital Interfaceis like MIDI, but */
/* allows for floating point control */
/* changes, note numbers, etc. Example: */
/* noteOn(1,60.01,111.132) plays a sharp */
/* middle C with a velocity of 111.132 */
/* */
/* Warning: Obey column spacing in the */
/* text file if you try to edit it or */
/* create your own files. */
/******************************************/
#if !defined(__MIDIInpt_h)
#define __MIDIInpt_h
#include "Object.h"
#include "dmedia/midi.h"
#include <sys/types.h>
#include <sys/prctl.h>
class MIDIInpt : public Object
{
protected:
int midi_pid;
int messageType;
int channel;
float byteTwo;
float byteThree;
public:
MIDIInpt();
~MIDIInpt();
void printMessage();
int nextMessage();
int getType();
int getChannel();
MY_FLOAT getByteTwo();
MY_FLOAT getByteThree();
};
#endif

133
MIDIText.cpp Normal file
View File

@@ -0,0 +1,133 @@
/******************************************/
/* Simple MIDI Text File Reader Class, */
/* by Perry R. Cook, 1996 */
/* This Object can open a MIDI Text File */
/* and parse it. The file spec is mine */
/* and mine alone, but it's all text so */
/* you should be able to figure 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 SKINI.txt for more information */
/* Warning: Obey columns in the text */
/* file if you try to edit it or create */
/* your own files. */
/******************************************/
#include "MIDIText.h"
MIDIText :: MIDIText(char *fileName)
{
myFile = fopen(fileName,"r");
this->nextMessage();
}
MIDIText :: ~MIDIText()
{
}
/* MIDI File Codes
if (byte > 15) {
if (byte == 248) printf("MIDI Clock,");
else if (byte == 249) printf("Undefined,");
else if (byte == 250) printf("Song Start,");
else if (byte == 251) printf("Continue,");
else if (byte == 252) printf("Song Stop,");
else if (byte == 253) printf("Undefined,");
else if (byte == 254) printf("ActiveSen,");
else if (byte == 255) printf("SystReset,");
else printf("BEATSME");
}
else { // these are all nybbles of status bytes //
if (byte == 8) printf("NoteOff");
if (byte == 9) printf("NoteOn");
if (byte == 10) printf("Poly Pressure");
if (byte == 11) printf("Control Change");
if (byte == 12) printf("Program Change");
if (byte == 13) printf("Channel Pressure");
if (byte == 14) printf("Pitch Wheel");
}
*/
int MIDIText :: nextMessage()
{
int notDone = 1,point;
char inputString[1024];
char tempString[32];
while (notDone) {
notDone = 0;
if (fgets(inputString,1000,myFile)) {
sscanf(inputString,"%s %lf %i %f %f",tempString,&deltaTime,&channel,&byteTwo,&byteThree);
point = 5;
if (tempString[0]=='%') point = 1;
if (tempString[point] == 'n') { // NoteO'n'
messageType = 9;
}
else if (inputString[point] == 'f') { // NoteO'f'f
messageType = 8;
}
else if (inputString[point] == 'B') { // Pitch'B'end
byteThree = byteTwo;
messageType = 14;
}
else if (inputString[point] == 'a') { // Progr'a'mChange
messageType = 12;
}
else if (inputString[point] == 'T') { // After'T'ouch
messageType = 11;
}
else if (inputString[point] == 'o') { // Contr'o'lChange
messageType = 11;
}
else if (inputString[0] == '/' || inputString[0] == ' ') {
notDone = 1;
}
}
else {
messageType = -1;
}
}
return messageType;
}
int MIDIText :: getType()
{
return messageType;
}
int MIDIText :: getChannel()
{
return channel;
}
MY_FLOAT MIDIText :: getDelta()
{
return deltaTime;
}
MY_FLOAT MIDIText :: getByteTwo()
{
return byteTwo;
}
MY_FLOAT MIDIText :: getByteThree()
{
return byteThree;
}
/************ Test Main Program *****************/
/*
void main(int argc,char *argv[])
{
MIDIText testFile(argv[1]);
while(testFile.nextMessage() > 0) ;
}
*/

46
MIDIText.h Normal file
View File

@@ -0,0 +1,46 @@
/******************************************/
/* Simple MIDI Text File Reader Class, */
/* by Perry R. Cook, 1996 */
/* This Object can open a MIDI Text File */
/* and parse it. The file spec is mine */
/* and mine alone, but it's all text so */
/* you should be able to figure 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 SKINI.txt for more information */
/* Warning: Obey columns in the text */
/* file if you try to edit it or create */
/* your own files. */
/******************************************/
#if !defined(__MIDIText_h)
#define __MIDIText_h
#include "Object.h"
class MIDIText : public Object
{
protected:
FILE *myFile;
int messageType;
int channel;
MY_FLOAT deltaTime;
float byteTwo;
float byteThree;
public:
MIDIText(char *fileName);
~MIDIText();
int nextMessage();
int getType();
int getChannel();
MY_FLOAT getDelta();
MY_FLOAT getByteTwo();
MY_FLOAT getByteThree();
};
#endif

247
Makefile Normal file
View File

@@ -0,0 +1,247 @@
O_FILES = Object.o Envelope.o ADSR.o Noise.o SubNoise.o RawWave.o RawLoop.o \
NIWave1S.o Modulatr.o SingWave.o RawWvOut.o RawWvIn.o Filter.o \
OneZero.o OnePole.o TwoZero.o TwoPole.o DCBlock.o BiQuad.o AllPass1.o \
DLineA.o DLineL.o DLineN.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 VoicForm.o\
MIDIText.o Reverb.o VoicMang.o \
\
Instrmnt.o Marimba.o Vibraphn.o AgogoBel.o Plucked.o Mandolin.o \
Clarinet.o Flute.o Brass.o Bowed.o Rhodey.o Wurley.o TubeBell.o \
HeavyMtl.o PercFlut.o BeeThree.o FMVoices.o Moog1.o
RM = /bin/rm
# This is for NeXT
# CC = cc -O
# INSTR = testMono testMult DrumSynt textVoic
# These are for SGI
INSTR = testTextIn testMono testMIDI testMult DrumSynt textVoic
CC = gcc -O
MEDIALINK = -lmd
TCLLIB = /usr/local/lib/libtcl.so.7.4 /usr/local/lib/libtk.so.4.0 /usr/lib/libX11.so
LIBRARY = /usr/lib/libmx.so /usr/lib/libaudio.a
# .cpp.o:
# $(CC) -c $*.cpp
all: $(INSTR)
testTextIn: $(LIBRARY) testTextIn.cpp $(O_FILES) MIDIInpt.o
$(CC) $(MEDIALINK) -o testTextIn testTextIn.cpp $(O_FILES) $(LIBRARY)
testMono: $(LIBRARY) testMono.cpp $(O_FILES)
$(CC) $(MEDIALINK) -o testMono testMono.cpp $(O_FILES) $(LIBRARY)
testMIDI: $(LIBRARY) testMIDI.cpp Object.o MIDIInpt.o
$(CC) $(MEDIALINK) -o testMIDI testMIDI.cpp Object.o MIDIInpt.o $(LIBRARY) /usr/lib/libmidi.so
testMult: $(LIBRARY) testMult.cpp $(O_FILES)
$(CC) $(MEDIALINK) -o testMult testMult.cpp $(O_FILES) $(LIBRARY)
textVoic: $(LIBRARY) textVoic.cpp $(O_FILES)
$(CC) $(MEDIALINK) -o textVoic textVoic.cpp $(O_FILES) $(LIBRARY)
Instrmnt.o: Instrmnt.cpp
$(CC) -c Instrmnt.cpp
Marimba.o: Marimba.cpp
$(CC) -c Marimba.cpp
Vibraphn.o: Vibraphn.cpp
$(CC) -c Vibraphn.cpp
AgogoBel.o: AgogoBel.cpp
$(CC) -c AgogoBel.cpp
Plucked.o: Plucked.cpp
$(CC) -c Plucked.cpp
Mandolin.o: Mandolin.cpp
$(CC) -c Mandolin.cpp
Clarinet.o: Clarinet.cpp
$(CC) -c Clarinet.cpp
Flute.o: Flute.cpp
$(CC) -c Flute.cpp
Brass.o: Brass.cpp
$(CC) -c Brass.cpp
Bowed.o: Bowed.cpp
$(CC) -c Bowed.cpp
Rhodey.o: Rhodey.cpp
$(CC) -c Rhodey.cpp
Wurley.o: Wurley.cpp
$(CC) -c Wurley.cpp
TubeBell.o: TubeBell.cpp
$(CC) -c TubeBell.cpp
HeavyMtl.o: HeavyMtl.cpp
$(CC) -c HeavyMtl.cpp
PercFlut.o: PercFlut.cpp
$(CC) -c PercFlut.cpp
BeeThree.o: BeeThree.cpp
$(CC) -c BeeThree.cpp
FMVoices.o: FMVoices.cpp
$(CC) -c FMVoices.cpp
Moog1.o: Moog1.cpp
$(CC) -c Moog1.cpp
DrumSynt: $(LIBRARY) DrumSynt.cpp $(O_FILES)
$(CC) -o DrumSynt DrumSynt.cpp $(O_FILES) $(LIBRARY)
testVoic: $(LIBRARY) testVoic.cpp $(O_FILES)
$(CC) -o testVoic testVoic.cpp $(O_FILES) $(LIBRARY)
# $(O_FILES) :
# $(CC) -c -o $@ $*.cpp
Object.o : Object.cpp
$(CC) -c Object.cpp
Envelope.o : Envelope.cpp
$(CC) -c Envelope.cpp
ADSR.o : ADSR.cpp
$(CC) -c ADSR.cpp
Noise.o : Noise.cpp
$(CC) -c Noise.cpp
SubNoise.o : SubNoise.cpp
$(CC) -c SubNoise.cpp
RawWave.o : RawWave.cpp
$(CC) -c RawWave.cpp
RawLoop.o : RawLoop.cpp
$(CC) -c RawLoop.cpp
NIWave1S.o : NIWave1S.cpp
$(CC) -c NIWave1S.cpp
Modulatr.o : Modulatr.cpp
$(CC) -c Modulatr.cpp
SingWave.o : SingWave.cpp
$(CC) -c SingWave.cpp
RawWvOut.o : RawWvOut.cpp
$(CC) -c RawWvOut.cpp
RawWvIn.o : RawWvIn.cpp
$(CC) -c RawWvIn.cpp
Filter.o : Filter.cpp
$(CC) -c Filter.cpp
OneZero.o : OneZero.cpp
$(CC) -c OneZero.cpp
OnePole.o : OnePole.cpp
$(CC) -c OnePole.cpp
TwoZero.o : TwoZero.cpp
$(CC) -c TwoZero.cpp
TwoPole.o : TwoPole.cpp
$(CC) -c TwoPole.cpp
DCBlock.o : DCBlock.cpp
$(CC) -c DCBlock.cpp
BiQuad.o : BiQuad.cpp
$(CC) -c BiQuad.cpp
AllPass1.o : AllPass1.cpp
$(CC) -c AllPass1.cpp
DLineA.o : DLineA.cpp
$(CC) -c DLineA.cpp
DLineL.o : DLineL.cpp
$(CC) -c DLineL.cpp
DLineN.o : DLineN.cpp
$(CC) -c DLineN.cpp
FormSwep.o : FormSwep.cpp
$(CC) -c FormSwep.cpp
BowTabl.o : BowTabl.cpp
$(CC) -c BowTabl.cpp
JetTabl.o : JetTabl.cpp
$(CC) -c JetTabl.cpp
ReedTabl.o : ReedTabl.cpp
$(CC) -c ReedTabl.cpp
LipFilt.o : LipFilt.cpp
$(CC) -c LipFilt.cpp
Modal4.o : Modal4.cpp
$(CC) -c Modal4.cpp
FM4Op.o : FM4Op.cpp
$(CC) -c FM4Op.cpp
FM4Alg3.o : FM4Alg3.cpp
$(CC) -c FM4Alg3.cpp
FM4Alg4.o : FM4Alg4.cpp
$(CC) -c FM4Alg4.cpp
FM4Alg5.o : FM4Alg5.cpp
$(CC) -c FM4Alg5.cpp
FM4Alg6.o : FM4Alg6.cpp
$(CC) -c FM4Alg6.cpp
FM4Alg8.o : FM4Alg8.cpp
$(CC) -c FM4Alg8.cpp
Plucked2.o : Plucked2.cpp
$(CC) -c Plucked2.cpp
SamplFlt.o : SamplFlt.cpp
$(CC) -c SamplFlt.cpp
Sampler.o : Sampler.cpp
$(CC) -c Sampler.cpp
VoicForm.o : VoicForm.cpp
$(CC) -c VoicForm.cpp
MIDIText.o : MIDIText.cpp
$(CC) -c MIDIText.cpp
MIDIInpt.o : MIDIInpt.cpp
$(CC) -c MIDIInpt.cpp
VoicMang.o : VoicMang.cpp
$(CC) -c VoicMang.cpp
Reverb.o : Reverb.cpp
$(CC) -c Reverb.cpp
clean :
rm $(INSTR)
rm *.o
cleanIns :
rm $(INSTR)
strip :
strip $(INSTR)

116
Mandolin.cpp Normal file
View File

@@ -0,0 +1,116 @@
/********************************************/
/* Commuted Mandolin Subclass of enhanced */
/* dual plucked-string model */
/* by Perry Cook, 1995-96 */
/* Controls: CONTROL1 = bodySize */
/* CONTROL2 = pluckPosition */
/* CONTROL3 = loopGain */
/* MOD_WHEEL= deTuning */
/* */
/* Note: Commuted Synthesis, as with many */
/* other WaveGuide techniques, is covered */
/* by patents, granted, pending, and/or */
/* applied-for. Many are assigned to the */
/* Board of Trustees, Stanford University. */
/* For information, contact the Office of */
/* Technology Licensing, Stanford U. */
/********************************************/
#include "Mandolin.h"
Mandolin :: Mandolin(MY_FLOAT lowestFreq) : Plucked2(lowestFreq)
{
soundfile = new RawWave("rawwaves/mandpluk.raw");
soundfile->normalize(0.05); /* Empirical hack here */
soundfile->setLooping(0);
dampTime = 0;
waveDone = 1;
}
void Mandolin :: pluck(MY_FLOAT amplitude)
{ /* this function gets interesting here, */
soundfile->reset(); /* because pluck may be longer than */
pluckAmp = amplitude; /* string length, so we just reset the */
/* soundfile and add in the pluck in */
/* the tick method. */
combDelay->setDelay(
0.5 * pluckPos * lastLength); /* Set Pick Position */
/* which puts zeroes at pos*length */
dampTime = (long) lastLength; /* See tick method below */
waveDone = 0;
}
void Mandolin :: pluck(MY_FLOAT amplitude, MY_FLOAT position)
{
pluckPos = position; /* pluck position is zeroes at pos*length */
this->pluck(amplitude);
}
void Mandolin :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
this->setFreq(freq);
this->pluck(amp);
#if defined(_debug_)
printf("Mandolin : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}
void Mandolin :: setBodySize(MY_FLOAT size)
{
soundfile->setRate(size);
}
MY_FLOAT Mandolin :: tick()
{
MY_FLOAT temp = 0;
if (!waveDone) {
waveDone = soundfile->informTick(); /* as long as it goes . . . */
temp = soundfile->lastOut() * pluckAmp; /* scaled pluck excitation */
temp = temp - combDelay->tick(temp); /* with comb filtering */
}
if (dampTime>=0) { /* Damping hack to help avoid */
dampTime -= 1; /* overflow on replucking */
lastOutput = delayLine->tick( /* Calculate 1st delay */
filter->tick( /* filterered reflection */
temp + /* plus pluck excitation */
(delayLine->lastOut() * 0.7)));
lastOutput += delayLine2->tick( /* and 2nd delay */
filter2->tick( /* just like the 1st */
temp +
(delayLine2->lastOut() * 0.7))); /* that's the whole thing!! */
}
else { /* No damping hack after 1 period */
lastOutput = delayLine->tick( /* Calculate 1st delay */
filter->tick( /* filtered reflection */
temp + /* plus pluck excitation */
(delayLine->lastOut()
* loopGain)));
lastOutput += delayLine2->tick( /* and 2nd delay */
filter2->tick( /* just like the 1st */
temp +
(delayLine2->lastOut()
* loopGain)));
}
lastOutput *= 2.0;
return lastOutput;
}
void Mandolin :: controlChange(int number, MY_FLOAT value)
{
#if defined(_debug_)
printf("Mandolin : ControlChange: Number=%i Value=%f\n",number,value);
#endif
if (number == MIDI_control1)
this->setBodySize(value * NORM_7 * 2.0);
else if (number == MIDI_control2)
this->setPluckPos(value * NORM_7);
else if (number == MIDI_control3)
this->setBaseLoopGain(0.97 + (value * NORM_7 * 0.03));
else if (number == MIDI_mod_wheel)
this->setDetune(1.0 - (value * NORM_7 * 0.1));
else if (number == MIDI_after_touch)
this->pluck(value * NORM_7);
else {
printf("Mandolin : Undefined Control Number!!\n");
}
}

41
Mandolin.h Normal file
View File

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

111
Marimba.cpp Normal file
View File

@@ -0,0 +1,111 @@
/*******************************************/
/* Marimba SubClass of Modal4 Instrument, */
/* by Perry R. Cook, 1995-96 */
/* */
/* Controls: CONTROL1 = stickHardness */
/* CONTROL2 = strikePosition*/
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/*******************************************/
#include "Marimba.h"
Marimba :: Marimba() : Modal4()
{
wave = new RawWave("rawwaves/marmstk1.raw");
wave->normalize();
wave->setRate(0.5); /* normal stick */
this->setRatioAndReson(0, 1.00,0.9996); /* Set all 132.0 */
this->setRatioAndReson(1, 3.99,0.9994); /* of our 523.0 */
this->setRatioAndReson(2,10.65,0.9994); /* default 1405.0 */
this->setRatioAndReson(3,-18.50,0.999); /* resonances 2443.0 */
this->setFiltGain(0,0.08); /* and */
this->setFiltGain(1,0.02); /* gains */
this->setFiltGain(2,0.02); /* for each */
this->setFiltGain(3,0.015); /* resonance */
directGain = 0.1;
multiStrike = 0;
}
Marimba :: ~Marimba()
{
}
void Marimba :: setStickHardness(MY_FLOAT hardness)
{
stickHardness = hardness;
wave->setRate(0.25 * pow(4.0,stickHardness));
masterGain = 0.1 + (1.8 * stickHardness);
}
void Marimba :: setStrikePosition(MY_FLOAT position)
{
MY_FLOAT temp,temp2;
temp2 = position * PI;
strikePosition = position; /* Hack only first three modes */
temp = sin(temp2);
this->setFiltGain(0,0.12 * temp); /* 1st mode function of pos. */
temp = sin(0.05 + (3.9 * temp2));
this->setFiltGain(1,-0.03 * temp); /* 2nd mode function of pos. */
temp = sin(-0.05 + (11 * temp2));
this->setFiltGain(2,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 = random() >> 26;
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 == MIDI_control1)
this->setStickHardness(value * NORM_7);
else if (number == MIDI_control2)
this->setStrikePosition(value * NORM_7);
else if (number == MIDI_control3)
vibr->setFreq((value * NORM_7 * 12.0));
else if (number == MIDI_mod_wheel)
vibrGain = (value * NORM_7);
else if (number == MIDI_after_touch)
this->strike(value * NORM_7);
else {
printf("Marimba : Undefined Control Number!!\n");
}
}
MY_FLOAT Marimba :: tick()
{
if (multiStrike>0)
if (wave->isAllDone()) {
wave->reset();
multiStrike -= 1;
}
return Modal4::tick();
}

32
Marimba.h Normal file
View File

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

187
Modal4.cpp Normal file
View File

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

52
Modal4.h Normal file
View File

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

84
Modulatr.cpp Normal file
View File

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

36
Modulatr.h Normal file
View File

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

108
Moog1.cpp Normal file
View File

@@ -0,0 +1,108 @@
/******************************************/
/* 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"
Moog1 :: Moog1() : SamplFlt()
{
attacks[0] = new RawWave("rawwaves/mandpluk.raw");
loops[0] = new RawWave("rawwaves/impuls20.raw");
loops[1] = new RawWave("rawwaves/sinewave.raw"); /* Steal one for vibrato */
attacks[0]->normalize();
loops[0]->normalize();
loops[0]->setLooping(1);
loops[1]->normalize();
loops[1]->setLooping(1);
loops[1]->setFreq(6.122);
adsr->setAll(0.05,0.00003,0.6,0.0002);
filterQ = 0.85;
filterRate = 0.0001;
modDepth = 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 * 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 * 0.5;
loopGain = amp;
temp = filterQ+0.05;
filters[0]->setStates(2000,temp,2.0 * (1.0 - temp));
filters[1]->setStates(2000,temp,2.0 * (1.0 - temp));
temp = filterQ+0.099;
filters[0]->setTargets( 0,temp,2.0 * (1.0 - temp));
filters[1]->setTargets( 0,temp,2.0 * (1.0 - temp));
filters[0]->setSweepRate(filterRate * RATE_NORM);
filters[1]->setSweepRate(filterRate * RATE_NORM);
#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 * 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 == MIDI_control1)
filterQ = 0.80 + (0.1 * value * NORM_7);
else if (number == MIDI_control2)
filterRate = (value * NORM_7 * 0.0002);
else if (number == MIDI_control3)
this->setModulationSpeed(value * NORM_7 * 12.0);
else if (number == MIDI_mod_wheel)
this->setModulationDepth(value * NORM_7);
else if (number == MIDI_after_touch)
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 * (1.0 + temp));
}
lastOutput = SamplFlt :: tick();
return lastOutput;
}

34
Moog1.h Normal file
View File

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

163
NIFileIn.cpp Normal file
View File

@@ -0,0 +1,163 @@
/*******************************************/
/* NonInterpolating 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 "NIFileIn.h"
NIFileIn :: NIFileIn(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 = 0.0;
rate = 1.0;
lastTime = 0;
finished = 0;
gain = 1.0;
lastOutput = 0.0;
}
NIFileIn :: ~NIFileIn()
{
this->finish();
}
void NIFileIn :: reset()
{
if (finished) {
myFile = fopen(fileNm,"rb");
}
fseek(myFile,0,0);
printf("Resetting\n");
time = 0.0;
lastTime = 0;
finished = 0;
lastOutput = 0.0;
}
void NIFileIn :: normalize()
{
this->normalize(1.0);
}
void NIFileIn :: normalize(MY_FLOAT newPeak)
{
long i;
FILE *fd;
gain = 0.0;
fd = fopen(fileNm,"rb");
for (i=0;i<length;i++) {
fread(&data,2,1,fd);
if (fabs(data) > gain)
gain = fabs(data);
}
if (gain > 0.0) {
gain = newPeak / gain;
}
fclose(fd);
}
void NIFileIn :: setRate(MY_FLOAT aRate)
{
rate = aRate;
}
void NIFileIn :: finish()
{
finished = 1;
lastOutput = 0.0;
if (myFile) {
fclose(myFile);
myFile = 0;
}
}
MY_FLOAT NIFileIn :: tick()
{
this->informTick();
return lastOutput;
}
int NIFileIn :: informTick()
{
long temp;
if (!finished) {
time += rate; /* Update current time */
if (time >= length) { /* Check for end of sound */
time = 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 */
lastOutput = data * gain; /* And save as non-interpolated data */
}
}
}
return finished;
}
MY_FLOAT NIFileIn :: lastOut()
{
return lastOutput;
}
/************ Test Main Program *****************/
/*
void main()
{
NIFileIn 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);
}
*/

47
NIFileIn.h Normal file
View File

@@ -0,0 +1,47 @@
/*******************************************/
/* NonInterpolating 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(__NIFileIn_h)
#define __NIFileIn_h
#include "Object.h"
class NIFileIn : public Object
{
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:
NIFileIn(char *fileName);
~NIFileIn();
void reset();
void normalize();
void normalize(MY_FLOAT newPeak);
void setRate(MY_FLOAT aRate);
void finish();
MY_FLOAT tick();
int informTick();
MY_FLOAT lastOut();
};
#endif

119
NIWave1S.cpp Normal file
View File

@@ -0,0 +1,119 @@
/*******************************************/
/* NonInterpolating 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 (again when reset), with */
/* no interpolation on playback. */
/*******************************************/
#include "NIWave1S.h"
NIWave1S :: NIWave1S(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)) {
data[i] = temp;
i++;
}
data[length] = data[length-1];
fclose(fd);
time = 0.0;
rate = 1.0;
}
void NIWave1S :: reset()
{
time = 0.0;
lastOutput = 0.0;
}
void NIWave1S :: normalize()
{
this->normalize(1.0);
}
void NIWave1S :: normalize(MY_FLOAT newPeak)
{
long i;
MY_FLOAT max = 0.0;
for (i=0;i<=length;i++)
if (fabs(data[i]) > max)
max = fabs(data[i]);
if (max > 0.0) {
max = 1.0 / max;
max *= newPeak;
for (i=0;i<=length;i++)
data[i] *= max;
}
}
void NIWave1S :: setRate(MY_FLOAT aRate)
{
rate = aRate;
}
MY_FLOAT NIWave1S :: tick()
{
this->informTick();
return lastOutput;
}
int NIWave1S :: informTick()
{
int allDone = 0;
long temp;
time += rate; /* Update current time */
if (time >= length) { /* Check for end of sound */
time = length-1; /* stick at end */
allDone = 1; /* Information for one-shot use */
}
temp = (long) time; /* Integer part of time address */
lastOutput = data[temp]; /* Get non-interpolated data */
return allDone;
}
MY_FLOAT NIWave1S :: lastOut()
{
return lastOutput;
}
/************ Test Main Program *****************/
/*
void main()
{
NIWave1S oneShot("rawwaves/mandpluk.raw");
FILE *fd;
short data;
long i;
fd = fopen("test.raw","wb");
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);
}
*/

34
NIWave1S.h Normal file
View File

@@ -0,0 +1,34 @@
/*******************************************/
/* NonInterpolating 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 (again when reset), with */
/* no interpolation on playback. */
/*******************************************/
#if !defined(__NIWave1S_h)
#define __NIWave1S_h
#include "Object.h"
class NIWave1S : public Object
{
protected:
long length;
MY_FLOAT *data;
MY_FLOAT rate;
MY_FLOAT time;
MY_FLOAT lastOutput;
public:
NIWave1S(char *fileName);
void reset();
void normalize();
void normalize(MY_FLOAT newPeak);
void setRate(MY_FLOAT aRate);
MY_FLOAT tick();
int informTick();
MY_FLOAT lastOut();
};
#endif

52
Noise.cpp Normal file
View File

@@ -0,0 +1,52 @@
/*******************************************/
/* Noise Generator Class, */
/* by Perry R. Cook, 1995-96 */
/* White noise as often as you like. */
/*******************************************/
#include "Noise.h"
Noise :: Noise() : Object()
{
lastOutput = 0.0;
}
Noise :: ~Noise()
{
}
/* THIS IS FOR TURBO C */
/* Constant = 1.0 / 16384.0 */
/* #define ONE_OVER_RANDLIMIT 0.00006103516 */
/* THIS IS FOR UNIX, NeXT and SGI */
#define ONE_OVER_RANDLIMIT 0.00000000093132258
MY_FLOAT Noise :: tick()
{
/* THIS ONE IS TURBO C */
/* lastOutput = (MY_FLOAT) random(32767) - 16384.0; */
/* THIS IS FOR UNIX, NeXT and SGI */
lastOutput = (MY_FLOAT) random() - 1073741823.0;
lastOutput *= ONE_OVER_RANDLIMIT;
return lastOutput;
}
MY_FLOAT Noise :: lastOut()
{
return lastOutput;
}
/************ Test Main ************************/
/*
void main()
{
long i;
Noise test;
for (i=0;i<20;i++) printf("%lf\n",test.tick());
}
*/

23
Noise.h Normal file
View File

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

29
Object.cpp Normal file
View File

@@ -0,0 +1,29 @@
/*******************************************/
/* Object Class, by Perry R. Cook, 1995-96*/
/* This is mostly here for compatibility */
/* with Objective C. We'll also stick */
/* global defines here, so everyone will */
/* see them. */
/*******************************************/
#include "Object.h"
/* This is just here for compatibility and convenience,
so there's no need to do any real calculations.
I do set up some redefinable variables here. */
Object :: Object()
{
MIDI_mod_wheel = 1; /* Controller # 1 */
MIDI_control1 = 2; /* Breath Pressure */
MIDI_control2 = 4; /* Foot Control */
MIDI_control3 = 11; /* Expression Pedal */
MIDI_after_touch = 128; /* Channel Pressure -> new controller */
}
Object :: ~Object()
{
}

91
Object.h Normal file
View File

@@ -0,0 +1,91 @@
/*******************************************/
/* 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:
int MIDI_control1;
int MIDI_control2;
int MIDI_control3;
int MIDI_mod_wheel;
int MIDI_after_touch;
protected:
Object();
~Object();
};
/* Only use one of __SGI_ __NeXT_ __DOS_ */
/* And choice of __SGI_REALTIME or not */
#define __SGI_
#define __SGI_REALTIME
/* #define __NeXT_ */
/* SRATE here is 44100, others are derived accordingly */
/* #define SRATE 44100.0
#define SRATE_OVER_TWO 22050.0
#define ONE_OVER_SRATE 0.00002267573696
#define RATE_NORM 0.5
*/
/* SRATE here is 22050, others are derived accordingly */
#define SRATE 22050.0
#define SRATE_OVER_TWO 11025.0
#define ONE_OVER_SRATE 0.00004535147392
#define RATE_NORM 1.0
/* SRATE here is 8k, others are derived accordingly */
/* #define SRATE 8000.0
#define SRATE_OVER_TWO 4000
#define ONE_OVER_SRATE 0.00012500000000
#define RATE_NORM 2.75625
*/
/* RATE_NORM is 22050 / 8000 */
/* Yer Basic Trigonometric constants */
#define PI 3.14159265359
#define TWO_PI 6.28318530718
#define ONE_OVER_TWO_PI 0.15915494309
/* States for Envelopes, etc. */
#define ATTACK 0
#define DECAY 1
#define SUSTAIN 2
#define RELEASE 3
/* Machine dependent stuff, possibly useful for optimization */
/* for example, changing double to float here increases */
/* performance (speed) by a whopping 4-6% on 486-flavor machines */
/* BUT!! a change from float to double here increases speed by */
/* 30% or so on SGI machines */
/* #define MY_FLOAT float */
/* #define MY_FLOAT_SIZE 4 */
#define MY_FLOAT double
#define MY_FLOAT_SIZE 8
/* Debugging define, causes massive printf's to come out. */
/* Also enables timing calculations in WaveOut class, other stuff. */
/* #define _debug_ 1 */
#include <stdio.h>
#define NORM_7 0.0078125
/* this is 1/128 for MIDI normalization*/
#endif

81
OnePole.cpp Normal file
View File

@@ -0,0 +1,81 @@
/*******************************************/
/* 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 = 0.9;
gain = 1.0;
sgain = 0.1;
outputs = (MY_FLOAT *) malloc(MY_FLOAT_SIZE);
outputs[0] = 0.0;
}
OnePole :: ~OnePole()
{
free(outputs);
}
void OnePole :: clear()
{
outputs[0] = 0.0;
lastOutput = 0.0;
}
void OnePole :: setPole(MY_FLOAT aValue)
{
poleCoeff = aValue;
if (poleCoeff > 0.0) /* Normalize gain to 1.0 max */
sgain = gain * (1.0 - poleCoeff);
else
sgain = gain * (1.0 + poleCoeff);
}
void OnePole :: setGain(MY_FLOAT aValue)
{
gain = aValue;
if (poleCoeff > 0.0)
sgain = gain * (1.0 - poleCoeff); /* Normalize gain to 1.0 max */
else
sgain = gain * (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");
}
*/

35
OnePole.h Normal file
View File

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

64
OneZero.cpp Normal file
View File

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

35
OneZero.h Normal file
View File

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

50
PercFlut.cpp Normal file
View File

@@ -0,0 +1,50 @@
/******************************************/
/* 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,1.50 );
this->setRatio(1,3.00 * 0.995);
this->setRatio(2,2.99 * 1.005);
this->setRatio(3,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]->setAll(0.001,0.001,__FM4Op_susLevels[14],0.001);
adsr[1]->setAll(0.05,0.0001,__FM4Op_susLevels[13],0.0001);
adsr[2]->setAll(0.05,0.0020,__FM4Op_susLevels[11],0.001);
adsr[3]->setAll(0.05,0.0010,__FM4Op_susLevels[13],0.005);
twozero->setGain(0.0);
modDepth = 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];
gains[1] = amp * __FM4Op_gains[71];
gains[2] = amp * __FM4Op_gains[93];
gains[3] = amp * __FM4Op_gains[85];
this->setFreq(freq);
this->keyOn();
#if defined(_debug_)
printf("PercFlut : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}

21
PercFlut.h Normal file
View File

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

189
PhonTabl.h Normal file
View File

@@ -0,0 +1,189 @@
double phonGains[32][2] =
{{1.0,0.0}, // eee
{1.0,0.0}, // ihh
{1.5,0.0}, // ehh
{1.0,0.0}, // aaa
{0.5,0.0}, // ahh
{0.5,0.0}, // aww
{0.5,0.0}, // ohh
{0.5,0.0}, // uhh
{0.5,0.0}, // uuu
{0.15,0.0}, // ooo
{0.15,0.0}, // rrr
{6.0,0.0}, // lll
{1.0,0.0}, // mmm
{1.0,0.0}, // nnn
{1.0,0.0}, // nng
{1.0,0.0}, // ngg
{0.0,1.0}, // fff
{0.0,1.0}, // sss
{0.0,1.0}, // thh
{0.0,1.0}, // shh
{0.0,0.2}, // xxx
{0.0,0.003}, // hee
{0.0,0.001}, // hoo
{0.0,0.002}, // hah
{1.0,0.4}, // bbb
{4.0,0.1}, // ddd
{1.0,0.4}, // jjj
{1.0,0.4}, // ggg
{1.0,0.1}, // vvv
{1.0,0.1}, // zzz
{1.0,0.1}, // thz
{1.0,0.1} // zhh
};
double phonParams[32][4][3] =
{{ { 273,0.996, 0}, // eee (beet)
{2086,0.945, -16},
{2754,0.979, -12},
{3270,0.440, -17}},
{ { 385,0.987, 0}, // ihh (bit)
{2056,0.930, -20},
{2587,0.890, -20},
{3150,0.400, -20}},
{ { 515,0.977, 0}, // ehh (bet)
{1805,0.810, -10},
{2526,0.875, -10},
{3103,0.400, -13}},
{ { 773,0.950, 0}, // aaa (bat)
{1676,0.830, -6},
{2380,0.880, -20},
{3027,0.600, -20}},
{ { 770,0.950, 0}, // ahh (father)
{1153,0.970, -3},
{2450,0.780, -20},
{3140,0.800, -32}},
{ { 637,0.910, 0}, // aww (bought)
{ 895,0.900, -3},
{2556,0.950, -17},
{3070,0.910, -20}},
{ { 637,0.910, 0}, // ohh (bone) NOTE:: same as aww (bought)
{ 895,0.900, -3},
{2556,0.950, -17},
{3070,0.910, -20}},
{ { 561,0.965, 0}, // uhh (but)
{1084,0.930, -10},
{2541,0.930, -15},
{3345,0.900, -20}},
{ { 515,0.976, 0}, // uuu (foot)
{1031,0.950, -3},
{2572,0.960, -11},
{3345,0.960, -20}},
{ { 349,0.986, 0}, // ooo (boot)
{ 918,0.940, -10},
{2350,0.960, -17},
{2731,0.950, -23}},
{ { 394,0.959, 0}, // rrr (bird)
{1297,0.780, -6},
{1441,0.980, -6},
{2754,0.950, -30}},
{ { 462,0.940, 0}, // lll (lull)
{2754,0.900, -30},
{3406,0.100, -30},
{3755,0.100, -30}},
{ { 265,0.987, 0}, // mmm (mom)
{1176,0.940, -22},
{2352,0.970, -20},
{3277,0.940, -31}},
{ { 204,0.980, 0}, // nnn (nun)
{1570,0.940, -15},
{2481,0.980, -12},
{3133,0.800, -30}},
{ { 204,0.980, 0}, // nng (sang) NOTE:: same as nnn
{1570,0.940, -15},
{2481,0.980, -12},
{3133,0.800, -30}},
{ { 204,0.980, 0}, // ngg (bong) NOTE:: same as nnn
{1570,0.940, -15},
{2481,0.980, -12},
{3133,0.800, -30}},
{ {1000,0.300, -10}, // fff
{2800,0.860, -10},
{7425,0.740, 0},
{8140,0.860, 0}},
{ {2000,0.700, -20}, // sss
{5257,0.750, -15},
{7171,0.840, -3},
{9000,0.900, 0}},
{ { 100,0.900, 0}, // thh
{4000,0.500, -20},
{5500,0.500, -15},
{8000,0.400, -20}},
{ {2693,0.940, 0}, // shh
{4000,0.720, -10},
{6123,0.870, -10},
{7755,0.750, -18}},
{ {1000,0.300, -10}, // xxx NOTE:: Not Really Done Yet
{2800,0.860, -10},
{7425,0.740, 0},
{8140,0.860, 0}},
{ { 273,0.996, 0}, // hee (beet) (noisy eee)
{2086,0.945, -16},
{2754,0.979, -12},
{3270,0.440, -17}},
{ { 349,0.986, 0}, // hoo (boot) (noisy ooo)
{ 918,0.940, -10},
{2350,0.960, -17},
{2731,0.950, -23}},
{ { 770,0.950, 0}, // hah (father) (noisy ahh)
{1153,0.970, -3},
{2450,0.780, -20},
{3140,0.800, -32}},
{ {2000,0.700, -20}, // bbb NOTE:: Not Really Done Yet
{5257,0.750, -15},
{7171,0.840, -3},
{9000,0.900, 0}},
{ { 100,0.900, 0}, // ddd NOTE:: Not Really Done Yet
{4000,0.500, -20},
{5500,0.500, -15},
{8000,0.400, -20}},
{ {2693,0.940, 0}, // jjj NOTE:: Not Really Done Yet
{4000,0.720, -10},
{6123,0.870, -10},
{7755,0.750, -18}},
{ {2693,0.940, 0}, // ggg NOTE:: Not Really Done Yet
{4000,0.720, -10},
{6123,0.870, -10},
{7755,0.750, -18}},
{ {2000,0.700, -20}, // vvv NOTE:: Not Really Done Yet
{5257,0.750, -15},
{7171,0.840, -3},
{9000,0.900, 0}},
{ { 100,0.900, 0}, // zzz NOTE:: Not Really Done Yet
{4000,0.500, -20},
{5500,0.500, -15},
{8000,0.400, -20}},
{ {2693,0.940, 0}, // thz NOTE:: Not Really Done Yet
{4000,0.720, -10},
{6123,0.870, -10},
{7755,0.750, -18}},
{ {2693,0.940, 0}, // zhh NOTE:: Not Really Done Yet
{4000,0.720, -10},
{6123,0.870, -10},
{7755,0.750, -18}}
};
char phonemes[32][4] =
{"eee","ihh","ehh","aaa",
"ahh","aww","ohh","uhh",
"uuu","ooo","rrr","lll",
"mmm","nnn","nng","ngg",
"fff","sss","thh","shh",
"xxx","hee","hoo","hah",
"bbb","ddd","jjj","ggg",
"vvv","zzz","thz","zhh"};

84
Plucked.cpp Normal file
View File

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

40
Plucked.h Normal file
View File

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

90
Plucked2.cpp Normal file
View File

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

46
Plucked2.h Normal file
View File

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

117
README.txt Normal file
View File

@@ -0,0 +1,117 @@
TK96CPP
A ToolKit of Audio Synthesis Classes
and Instruments in C++
Perry Cook, 1995-96
Please read the Legal and Ethical notes at the
bottom of this document.
For instant fun, if you get it to compile (see
below) type TestAllNext or TestAllSGIRT. The
former makes sound files of each instrument and
saves them under the instrument name. The latter
plays in real time from a SKINI scorefile.
For even more potential fun, try the GUI and MIDI
interface demos in the directory TCLSpecs. MIDI
is SGI specific for today, look for more support
later. TCL works on SGI, maybe elsewhere, but
you must have and install Tcl/TK.
For more documentation on this ToolKit, the classes,
etc, read the file HIERARCH.txt and the individual
class definitions.
SGI vs. NeXT vs. Intel vs. the world:
See Object.h and Makefile for machine-specific
items.
Initial public release. Some objects still beta.
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 (see Adrian Freed's home page for some
nice experience-based thoughts on that topic).
Your question at this point might be, "But Perry,
with CMix, CMusic, CSound, CShells, CMonkeys, etc.
already cluttering the landscape, why a new set
of stupid C functions for music synthesis and
processing?" The answers lie below.
1) I needed to port many of the things I've done
into something which is generic enough to port
further to different machines.
2) I really plan to document this stuff, so that
you don't have to be me to figure out what's
going on. (I'll probably be sorry I said this
in a couple of years, when even I can't figure
out what I was thinking.)
3) The classic difficulties most people have in
trying to implement physical models are:
A) They have trouble understanding the papers,
and/or in turning the theory into practice.
B) The Physical Model instruments are a pain to get
to oscillate, and coming up with stable and
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
get asking what to do with those block diagrams
I put in my papers.
4) I wanted to try some new stuff with modal synthesis,
and implement some classic FM patches as well.
5) I wanted to reimplement, and newly implement
more of the intelligent and physical performer
models I've talked about in some of my papers.
But I wanted to do it in a portable way, and in
such a way that I can hook up modules quickly.
I also wanted to make these instruments connectable
to such player objects, so folks like Brad Garton
who really think a lot about the players can connect
them to my instruments, a lot about which I think.
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.
***********************************************************

155
RawLoop.cpp Normal file
View File

@@ -0,0 +1,155 @@
/*******************************************/
/* 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"
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)) {
data[i] = temp;
i++;
}
data[length] = data[0];
fclose(fd);
time = 0.0;
phaseOffset = 0.0;
rate = 1.0;
}
RawLoop :: ~RawLoop()
{
free(data);
}
void RawLoop :: reset()
{
time = 0.0;
lastOutput = 0.0;
}
void RawLoop :: normalize()
{
this->normalize(1.0);
}
void RawLoop :: normalize(MY_FLOAT newPeak)
{
long i;
MY_FLOAT max = 0.0;
for (i=0;i<=length;i++)
if (fabs(data[i]) > max)
max = fabs(data[i]);
if (max > 0.0) {
max = 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);
}
*/

39
RawLoop.h Normal file
View File

@@ -0,0 +1,39 @@
/*******************************************/
/* 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"
class RawLoop : public Object
{
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

235
RawWave.cpp Normal file
View File

@@ -0,0 +1,235 @@
/*******************************************/
/* Raw Soundfile 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. */
/*******************************************/
#include "RawWave.h"
RawWave :: RawWave(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)) {
data[i] = temp;
i++;
}
data[length] = data[length-1];
fclose(fd);
looping = 0;
time = length;
phaseOffset = 0.0;
rate = 1.0;
allDone = 0;
}
RawWave :: RawWave(MY_FLOAT *someData, long aLength)
{
length = aLength;
data = someData;
myData = 0;
looping = 0;
time = 0.0;
phaseOffset = 0.0;
rate = 1.0;
}
RawWave :: ~RawWave()
{
if (myData) {
free(data);
data = 0;
}
}
void RawWave :: reset()
{
time = 0.0;
lastOutput = 0.0;
allDone = 0;
}
void RawWave :: normalize()
{
this->normalize(1.0);
}
void RawWave :: normalize(MY_FLOAT newPeak)
{
long i;
MY_FLOAT max = 0.0;
for (i=0;i<=length;i++)
if (fabs(data[i]) > max)
max = fabs(data[i]);
if (max > 0.0) {
max = 1.0 / max;
max *= newPeak;
for (i=0;i<=length;i++)
data[i] *= max;
}
}
void RawWave :: setRate(MY_FLOAT aRate)
{
rate = aRate;
}
void RawWave :: setFreq(MY_FLOAT aFreq)
{
rate = length * ONE_OVER_SRATE * aFreq;
}
void RawWave :: addTime(MY_FLOAT aTime) /* Add an absolute time */
{ /* in samples */
time += aTime;
}
void RawWave :: addPhase(MY_FLOAT anAngle) /* Add a time in cycles */
{ /* Cycles here means */
time += length * anAngle; /* 1.0 = length */
}
void RawWave :: addPhaseOffset(MY_FLOAT anAngle)
{ /* Add a phase offset */
phaseOffset = length * anAngle; /* in cycles, where */
} /* 1.0 = length */
void RawWave :: setLooping(int aLoopStatus)
{
time = 0;
looping = aLoopStatus;
if (looping) data[length] = data[0];
}
long RawWave :: getLength()
{
return length;
}
MY_FLOAT* RawWave :: getData()
{
return data;
}
MY_FLOAT RawWave :: tick()
{
this->informTick();
return lastOutput;
}
int RawWave :: isAllDone()
{
return allDone;
}
int RawWave :: 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-1; /* stick at end */
allDone = 1; /* Information for one-shot use */
}
else if (time < 0.0) /* Check for end of sound */
time = 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-1; /* stick at end */
else if (temp_time < 0.0) /* check for end of sound */
temp_time = 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 allDone;
}
MY_FLOAT RawWave :: lastOut()
{
return lastOutput;
}
/************ Test Main Program *****************/
/*
void main()
{
RawWave loopWave("rawwaves/sinewave.raw");
RawWave 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);
}
*/

48
RawWave.h Normal file
View File

@@ -0,0 +1,48 @@
/*******************************************/
/* Raw Soundfile 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. */
/*******************************************/
#if !defined(__RawWave_h)
#define __RawWave_h
#include "Object.h"
class RawWave : public Object
{
protected:
int looping;
int myData;
int allDone;
long length;
MY_FLOAT *data;
MY_FLOAT rate;
MY_FLOAT time;
MY_FLOAT phaseOffset;
MY_FLOAT lastOutput;
public:
RawWave(char *fileName);
RawWave(MY_FLOAT *someData,long aLength);
~RawWave();
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 isAllDone();
long getLength();
MY_FLOAT* getData();
MY_FLOAT tick();
int informTick();
MY_FLOAT lastOut();
};
#endif

163
RawWvIn.cpp Normal file
View File

@@ -0,0 +1,163 @@
/*******************************************/
/* NonInterpolating 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 "RawWvIn.h"
RawWvIn :: RawWvIn(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 = 0.0;
rate = 1.0;
lastTime = 0;
finished = 0;
gain = 1.0;
lastOutput = 0.0;
}
RawWvIn :: ~RawWvIn()
{
this->finish();
}
void RawWvIn :: reset()
{
if (finished) {
myFile = fopen(fileNm,"rb");
}
fseek(myFile,0,0);
printf("Resetting\n");
time = 0.0;
lastTime = 0;
finished = 0;
lastOutput = 0.0;
}
void RawWvIn :: normalize()
{
this->normalize(1.0);
}
void RawWvIn :: normalize(MY_FLOAT newPeak)
{
long i;
FILE *fd;
gain = 0.0;
fd = fopen(fileNm,"rb");
for (i=0;i<length;i++) {
fread(&data,2,1,fd);
if (fabs(data) > gain)
gain = fabs(data);
}
if (gain > 0.0) {
gain = newPeak / gain;
}
fclose(fd);
}
void RawWvIn :: setRate(MY_FLOAT aRate)
{
rate = aRate;
}
void RawWvIn :: finish()
{
finished = 1;
lastOutput = 0.0;
if (myFile) {
fclose(myFile);
myFile = 0;
}
}
MY_FLOAT RawWvIn :: tick()
{
this->informTick();
return lastOutput;
}
int RawWvIn :: informTick()
{
long temp;
if (!finished) {
time += rate; /* Update current time */
if (time >= length) { /* Check for end of sound */
time = 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 */
lastOutput = data * gain; /* And save as non-interpolated data */
}
}
}
return finished;
}
MY_FLOAT RawWvIn :: lastOut()
{
return lastOutput;
}
/************ Test Main Program *****************/
/*
void main()
{
RawWvIn 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);
}
*/

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