5 Commits
0.99 ... 3.2

Author SHA1 Message Date
Gary Scavone
3f126af4e5 Version 3.2 2013-09-29 22:42:55 +02:00
Gary Scavone
4b6500d3de Version 3.1 2013-09-29 22:42:17 +02:00
Gary Scavone
868787a5f9 Version 3.0 2013-09-29 22:41:42 +02:00
Gary Scavone
7c0ee03d60 Version 2.02 2013-09-29 22:40:37 +02:00
Gary Scavone
ea749b71d2 Version 2.01 2013-09-29 22:39:45 +02:00
494 changed files with 29418 additions and 9066 deletions

173
ADSR.cpp
View File

@@ -1,173 +0,0 @@
/*******************************************/
/* 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());
}
*/

View File

@@ -1,75 +0,0 @@
/*******************************************/
/* 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");
}
}

View File

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

View File

@@ -1,39 +0,0 @@
/*******************************************/
/* 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;
}

View File

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

View File

@@ -1,80 +0,0 @@
/*******************************************/
/* 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;
}

View File

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

View File

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

View File

@@ -1,22 +0,0 @@
/***********************************************/
/* 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
View File

@@ -1,160 +0,0 @@
/******************************************/
/* Bowed String model ala Smith */
/* after McIntyre, Schumacher, Woodhouse */
/* by Perry Cook, 1995-96 */
/* */
/* This is a waveguide model, and thus */
/* relates to various Stanford Univ. */
/* and possibly Yamaha and other patents.*/
/* */
/* Controls: CONTROL1 = bowPressure */
/* CONTROL2 = bowPosition */
/* CONTROL3 = vibrFreq */
/* MOD_WHEEL= vibrGain */
/* */
/******************************************/
#include "Bowed.h"
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
View File

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

129
Brass.cpp
View File

@@ -1,129 +0,0 @@
/******************************************/
/* Waveguide Brass Instrument Model ala */
/* Cook (TBone, HosePlayer) */
/* by Perry R. Cook, 1995-96 */
/* */
/* This is a waveguide model, and thus */
/* relates to various Stanford Univ. */
/* and possibly Yamaha and other patents.*/
/* */
/* Controls: CONTROL1 = lipTension */
/* CONTROL2 = slideLength */
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/******************************************/
#include "Brass.h"
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");
}
}

View File

@@ -1,125 +0,0 @@
/******************************************/
/* 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");
}
}

View File

@@ -1,104 +0,0 @@
/*******************************************/
/* */
/* AllPass Interpolating Delay Line */
/* Object by Perry R. Cook 1995-96 */
/* This one uses a delay line of maximum */
/* length specified on creation, and */
/* interpolates fractional length using */
/* an all-pass filter. This version is */
/* more efficient for computing static */
/* length delay lines (alpha and coeff */
/* are computed only when the length */
/* is set, there probably is a more */
/* efficient computational form if alpha */
/* is changed often (each sample)). */
/* */
/*******************************************/
#include "DLineA.h"
DLineA :: DLineA(long max_length)
{
long i;
length = max_length;
inputs = (MY_FLOAT *) malloc(length * MY_FLOAT_SIZE);
for (i=0;i<length;i++) inputs[i] = 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);
}
*/

View File

@@ -1,90 +0,0 @@
/*******************************************/
/* Linearly Interpolating Delay Line */
/* Object by Perry R. Cook 1995-96 */
/* This one uses a delay line of maximum */
/* length specified on creation, and */
/* linearly interpolates fractional */
/* length. It is designed to be more */
/* efficient if the delay length is not */
/* changed very often. */
/*******************************************/
#include "DLineL.h"
DLineL :: DLineL(long max_length)
{
length = max_length;
inputs = (MY_FLOAT *) malloc(length * MY_FLOAT_SIZE);
this->clear();
outPoint = 0;
inPoint = length >> 1;
}
DLineL :: ~DLineL()
{
free(inputs);
}
void DLineL :: clear()
{
long i;
for (i=0;i<length;i++) inputs[i] = 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);
}
*/

View File

@@ -1,33 +0,0 @@
/*******************************************/
/* Linearly Interpolating Delay Line */
/* Object by Perry R. Cook 1995-96 */
/* This one uses a delay line of maximum */
/* length specified on creation, and */
/* linearly interpolates fractional */
/* length. It is designed to be more */
/* efficient if the delay length is not */
/* changed very often. */
/*******************************************/
#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

View File

@@ -1,80 +0,0 @@
/*******************************************/
/* Non-Interpolating Delay Line */
/* Object by Perry R. Cook 1995-96 */
/* This one uses a delay line of maximum */
/* length specified on creation. A non- */
/* interpolating delay line should be */
/* used in non-time varying (reverb) or */
/* non-critical (????) applications. */
/*******************************************/
#include "DLineN.h"
DLineN :: DLineN(long max_length)
{
length = max_length;
inputs = (MY_FLOAT *) malloc(length * MY_FLOAT_SIZE);
this->clear();
this->setDelay(length * 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);
}
*/

View File

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

View File

@@ -1,164 +0,0 @@
/*******************************************/
/* 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()));
}

View File

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

179
FM4Op.cpp
View File

@@ -1,179 +0,0 @@
/*******************************************/
/* Master Class for 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/* This instrument contains 4 waves, */
/* 4 adsr, and various state vars. */
/* */
/* The basic Chowning/Stanford FM patent */
/* expired April 1995, but there exist */
/* follow-on patents, mostly assigned to */
/* Yamaha. If you are of the type who */
/* should worry about this (making money) */
/* worry away. */
/* */
/*******************************************/
#include "FM4Op.h"
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
View File

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

View File

@@ -1,118 +0,0 @@
/******************************************/
/* 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");
}
}

172
Flute.cpp
View File

@@ -1,172 +0,0 @@
/******************************************/
/* WaveGuide Flute ala Karjalainen, */
/* Smith, Waryznyk, etc. */
/* with polynomial Jet ala Cook */
/* by Perry Cook, 1995-96 */
/* */
/* This is a waveguide model, and thus */
/* relates to various Stanford Univ. */
/* and possibly Yamaha and other patents.*/
/* */
/* Controls: CONTROL1 = jetDelay */
/* CONTROL2 = noiseGain */
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/******************************************/
#include "Flute.h"
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
View File

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

View File

@@ -1,170 +0,0 @@
/*******************************************/
/* Sweepable Formant (2-pole) */
/* Filter Class, by Perry R. Cook, 1995-96*/
/* See books on filters to understand */
/* more about how this works. This drives*/
/* to a target at speed set by rate. */
/*******************************************/
#include "FormSwep.h"
FormSwep :: FormSwep() : Filter()
{
outputs = (MY_FLOAT *) malloc(2 * MY_FLOAT_SIZE);
poleCoeffs[0] = 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);
}
*/

View File

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

View File

@@ -1,125 +0,0 @@
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

View File

@@ -1,60 +0,0 @@
/******************************************/
/* Heavy Metal Synth Subclass */
/* of Algorithm 3 (TX81Z) Subclass of */
/* 3 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/******************************************/
#include "HeavyMtl.h"
HeavyMtl :: HeavyMtl() : FM4Alg3()
{
this->loadWaves("rawwaves/sinewave.raw",
"rawwaves/twopeaks.raw",
"rawwaves/twopeaks.raw",
"rawwaves/sinewave.raw");
this->setRatio(0,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
}

View File

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

View File

@@ -1,66 +0,0 @@
/**********************************************/
/* 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;
}

View File

@@ -1,28 +0,0 @@
/**********************************************/
/* 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();
};

View File

@@ -1,188 +0,0 @@
/******************************************/
/* 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();
}
}
*/

View File

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

View File

@@ -1,133 +0,0 @@
/******************************************/
/* 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) ;
}
*/

View File

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

@@ -1,247 +0,0 @@
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)

View File

@@ -1,116 +0,0 @@
/********************************************/
/* 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");
}
}

View File

@@ -1,111 +0,0 @@
/*******************************************/
/* Marimba SubClass of Modal4 Instrument, */
/* by Perry R. Cook, 1995-96 */
/* */
/* Controls: CONTROL1 = stickHardness */
/* CONTROL2 = strikePosition*/
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/*******************************************/
#include "Marimba.h"
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();
}

View File

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

View File

@@ -1,187 +0,0 @@
/*******************************************/
/* 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;
}

View File

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

View File

@@ -1,84 +0,0 @@
/*******************************************/
/* 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);
}
*/

108
Moog1.cpp
View File

@@ -1,108 +0,0 @@
/******************************************/
/* Test Sampler Subclass of */
/* Sampling Synthesizer Class */
/* by Perry R. Cook, 1995-96 */
/* */
/* Controls: CONTROL1 = filterQ */
/* CONTROL2 = filterRate */
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/******************************************/
#include "Moog1.h"
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;
}

View File

@@ -1,163 +0,0 @@
/*******************************************/
/* 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);
}
*/

View File

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

View File

@@ -1,119 +0,0 @@
/*******************************************/
/* 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);
}
*/

View File

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

View File

@@ -1,52 +0,0 @@
/*******************************************/
/* 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());
}
*/

View File

@@ -1,29 +0,0 @@
/*******************************************/
/* Object Class, by Perry R. Cook, 1995-96*/
/* This is mostly here for compatibility */
/* with Objective C. We'll also stick */
/* global defines here, so everyone will */
/* see them. */
/*******************************************/
#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()
{
}

View File

@@ -1,91 +0,0 @@
/*******************************************/
/* Object Class, by Perry R. Cook, 1995-96*/
/* This is mostly here for compatibility */
/* with Objective C. We'll also stick */
/* global defines here, so everyone will */
/* see them. */
/*******************************************/
#if !defined(__Object_h)
#define __Object_h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
class Object
{
public:
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

View File

@@ -1,81 +0,0 @@
/*******************************************/
/* One Pole Filter Class, */
/* by Perry R. Cook, 1995-96 */
/* The parameter gain is an additional */
/* gain parameter applied to the filter */
/* on top of the normalization that takes */
/* place automatically. So the net max */
/* gain through the system equals the */
/* value of gain. sgain is the combina- */
/* tion of gain and the normalization */
/* parameter, so if you set the poleCoeff */
/* to alpha, sgain is always set to */
/* gain * (1.0 - fabs(alpha)). */
/*******************************************/
#include "OnePole.h"
OnePole :: OnePole() : Filter()
{
poleCoeff = 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");
}
*/

View File

@@ -1,35 +0,0 @@
/*******************************************/
/* One Pole Filter Class, */
/* by Perry R. Cook, 1995-96 */
/* The parameter gain is an additional */
/* gain parameter applied to the filter */
/* on top of the normalization that takes */
/* place automatically. So the net max */
/* gain through the system equals the */
/* value of gain. sgain is the combina- */
/* tion of gain and the normalization */
/* parameter, so if you set the poleCoeff */
/* to alpha, sgain is always set to */
/* gain * (1.0 - fabs(alpha)). */
/*******************************************/
#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

View File

@@ -1,50 +0,0 @@
/******************************************/
/* Percussive Flute Subclass */
/* of Algorithm 4 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/******************************************/
#include "PercFlut.h"
PercFlut :: PercFlut() : FM4Alg4()
{
this->loadWaves("rawwaves/sinewave.raw",
"rawwaves/sinewave.raw",
"rawwaves/sinewave.raw",
"rawwaves/sinewave.raw");
this->setRatio(0,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
}

View File

@@ -1,189 +0,0 @@
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"};

View File

@@ -1,84 +0,0 @@
/******************************************/
/* 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;
}

View File

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

View File

@@ -1,117 +0,0 @@
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.
***********************************************************

View File

@@ -1,155 +0,0 @@
/*******************************************/
/* Raw Looped Soundfile Class, */
/* by Perry R. Cook, 1995-96 */
/* This Object can open a raw 16bit data */
/* (signed integers) file, and play back */
/* the data, looping only, with linear */
/* interpolation on playback. */
/*******************************************/
#include "RawLoop.h"
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);
}
*/

View File

@@ -1,39 +0,0 @@
/*******************************************/
/* Raw Looped Soundfile Class, */
/* by Perry R. Cook, 1995-96 */
/* This Object can open a raw 16bit data */
/* (signed integers) file, and play back */
/* the data, looping only, with linear */
/* interpolation on playback. */
/*******************************************/
#if !defined(__RawLoop_h)
#define __RawLoop_h
#include "Object.h"
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

View File

@@ -1,235 +0,0 @@
/*******************************************/
/* 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);
}
*/

View File

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

View File

@@ -1,163 +0,0 @@
/*******************************************/
/* 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);
}
*/

View File

@@ -1,47 +0,0 @@
/*******************************************/
/* 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(__RawWvIn_h)
#define __RawWvIn_h
#include "Object.h"
class RawWvIn : 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:
RawWvIn(char *fileName);
~RawWvIn();
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

View File

@@ -1,115 +0,0 @@
/*******************************************/
/* Raw Wave File Output Class, */
/* by Perry R. Cook, 1995-96 */
/* This version opens a mono NeXT .snd */
/* file 16bit data at 22KHz, and */
/* pokes buffers of samples into it. */
/*******************************************/
#include "RawWvOut.h"
#if !defined(__SGI_REALTIME)
/******** NeXT Soundfile Header Struct *******/
struct headerform {
char pref[4];
long hdr_length;
long file_length;
long mode;
long samp_rate;
long num_channels;
char comment[1024];
};
RawWvOut :: RawWvOut(char *fileName)
{
struct headerform hdr = {".sn",28,0,3,(long) SRATE,1,"TK"};
hdr.pref[3] = 'd';
fd = fopen(fileName,"wb");
if (!fd) {
printf("Couldn't create soundfile %s !!!!!!!!\n",fileName);
exit(0);
}
fwrite(&hdr,4,7,fd);
counter = 0;
totalCount = 0;
}
RawWvOut :: ~RawWvOut()
{
MY_FLOAT temp;
fwrite(data,2,counter,fd);
fseek(fd,8,SEEK_SET);
fwrite(&totalCount,4,1,fd);
fclose(fd);
temp = (double) totalCount * ONE_OVER_SRATE;
printf("%f Seconds Computed\n",temp);
}
long RawWvOut :: getCounter()
{
return totalCount;
}
void RawWvOut :: tick(MY_FLOAT sample)
{
data[counter++] = (short) (sample * 32000.0);
totalCount += 1;
if (counter == BUFFER_SIZE) {
fwrite(data,2,BUFFER_SIZE,fd);
counter = 0;
}
}
#else
/*******************************************/
/* SGI Real-Time Wave File Output Class, */
/* by Perry R. Cook, 1996 */
/* This Object can opens the SGI soundout */
/* device, and pokes buffers of samples */
/* into it. The real code that does the */
/* is from Doug Scott of SGI. */
/*******************************************/
#include "sgio.C"
RawWvOut :: RawWvOut(char *fileName)
{
int fd;
fd = init_sound(SRATE,1);
if (fd<0) {
printf("Couldn't open SoundOut Device !!!!!!!!\n");
exit(0);
}
counter = 0;
}
RawWvOut :: ~RawWvOut()
{
playbuf(data,counter);
counter = 0;
while (counter<BUFFER_SIZE) {
data[counter++] = 0;
}
playbuf(data,counter);
playbuf(data,counter);
playbuf(data,counter);
shuddup();
}
void RawWvOut :: tick(MY_FLOAT sample)
{
data[counter++] = (short) (sample * 32000.0);
if (counter == BUFFER_SIZE) {
playbuf(data,counter);
counter = 0;
}
}
#endif

View File

@@ -1,60 +0,0 @@
/*******************************************/
/* Raw Wave File Output Class, */
/* by Perry R. Cook, 1995-96 */
/* For now, This Object can open a raw */
/* 16bit data (signed integers) file, and */
/* poke buffers of samples into it. */
/*******************************************/
/*******************************************/
/* SGI Real-Time Wave File Output Class, */
/* by Perry R. Cook, 1995-96 */
/* This Object can opens the SGI soundout */
/* device, and pokes buffers of samples */
/* into it. The real code that does the */
/* is originally from Doug Scott of SGI. */
/*******************************************/
#include "Object.h"
#if !defined(__RawWvOut_h)
#define __RawWvOut_h
#if !defined(__SGI_REALTIME)
#define BUFFER_SIZE 1
class RawWvOut : public Object
{
protected:
FILE *fd;
short data[BUFFER_SIZE];
long counter;
long totalCount;
public:
RawWvOut(char *fileName);
~RawWvOut();
long getCounter();
void tick(MY_FLOAT sample);
};
#else
#define BUFFER_SIZE 256
class RawWvOut : public Object
{
protected:
FILE *fd;
short data[BUFFER_SIZE];
long counter;
public:
RawWvOut(char *fileName);
~RawWvOut();
void tick(MY_FLOAT sample);
};
#endif
#endif

View File

@@ -1,46 +0,0 @@
/**********************************************/
/* One break point linear reed table object */
/* by Perry R. Cook, 1995-96 */
/* Consult McIntyre, Schumacher, & Woodhouse */
/* Smith, Hirschman, Cook, Scavone, */
/* more for information. */
/**********************************************/
#include "ReedTabl.h"
ReedTabl :: ReedTabl() : Object()
{
offSet = 0.6; /* Offset is a bias, related to reed rest position */
slope = -0.8; /* Slope corresponds loosely to reed stiffness */
}
ReedTabl :: ~ReedTabl()
{
}
void ReedTabl :: setOffset(double aValue)
{
offSet = aValue; /* Offset is a bias, related to reed rest position */
}
void ReedTabl :: setSlope(double aValue)
{
slope = aValue; /* Slope corresponds loosely to reed stiffness */
}
MY_FLOAT ReedTabl :: lookup(double deltaP)
/* Perform "Table Lookup" by direct clipped */
/* linear function calculation */
{ /* deltaP is differential reed pressure */
lastOutput = offSet + (slope * deltaP); /* compute basic non-linearity */
if (lastOutput > 1.0) lastOutput = 1.0; /* if other way, reed slams shut */
if (lastOutput < -1.0) lastOutput = -1.0; /* if all the way open, acts like open end */
return lastOutput;
}
MY_FLOAT ReedTabl :: lastOut()
{
return lastOutput;
}

View File

@@ -1,187 +0,0 @@
/******************************************/
/* Reverb Effect Applied to Soundfile */
/* by Perry Cook, 1996 */
/* */
/* This is based on some of the famous */
/* Stanford CCRMA reverbs (NRev, KipRev) */
/* all based on the the Chowning/Moorer/ */
/* Schroeder reverberators, which use */
/* networks of simple allpass and comb */
/* delay filters. */
/******************************************/
#include "Reverb.h"
Reverb :: Reverb(MY_FLOAT longestDelay)
{
delayLine[0] = new DLineN((long) (longestDelay * 0.164631) + 2);
delayLine[1] = new DLineN((long) (longestDelay * 0.513434) + 2);
delayLine[2] = new DLineN((long) (longestDelay * 1.000000) + 2);
delayLine[3] = new DLineN((long) (longestDelay * 0.830484) + 2);
delayLine[0]->setDelay((long) (longestDelay * 0.164631));
delayLine[1]->setDelay((long) (longestDelay * 0.513434));
delayLine[2]->setDelay((long) (longestDelay * 1.000000));
delayLine[3]->setDelay((long) (longestDelay * 0.830484));
allPassCoeff = 0.7;
combCoeff1 = 0.62;
combCoeff2 = -0.71;
effectMix = 0.5;
this->clear();
}
Reverb :: ~Reverb()
{
delete delayLine[0];
delete delayLine[1];
delete delayLine[2];
delete delayLine[3];
}
void Reverb :: clear()
{
delayLine[0]->clear();
delayLine[1]->clear();
delayLine[2]->clear();
delayLine[3]->clear();
lastOutL = 0.0;
lastOutR = 0.0;
}
void Reverb :: setEffectMix(MY_FLOAT mix)
{
effectMix = mix;
}
MY_FLOAT Reverb :: lastOutput()
{
return (lastOutL + lastOutR) * 0.5;
}
MY_FLOAT Reverb :: lastOutputL()
{
return lastOutL;
}
MY_FLOAT Reverb :: lastOutputR()
{
return lastOutR;
}
MY_FLOAT Reverb :: tick(MY_FLOAT input)
{
MY_FLOAT temp,temp0,temp1,temp2,temp3;
temp = delayLine[0]->lastOut();
temp0 = allPassCoeff * temp;
temp0 += input;
delayLine[0]->tick(temp0);
temp0 = -(allPassCoeff * temp0) + temp;
temp = delayLine[1]->lastOut();
temp1 = allPassCoeff * temp;
temp1 += temp0;
delayLine[1]->tick(temp1);
temp1 = -(allPassCoeff * temp1) + temp;
temp2 = temp1 + (combCoeff1 * delayLine[2]->lastOut());
temp3 = temp1 + (combCoeff2 * delayLine[3]->lastOut());
lastOutL = effectMix * (delayLine[2]->tick(temp2));
lastOutR = effectMix * (delayLine[3]->tick(temp3));
temp = (1.0 - effectMix) * input;
lastOutL += temp;
lastOutR += temp;
return (lastOutL + lastOutR) * 0.5;
}
/************** Test Main Program *********************/
struct headerform { /*** NeXT Soundfile Header Struct ***/
char pref[4];
long hdr_length;
long file_length;
long mode;
long samp_rate;
long num_channels;
char comment[1024];
};
/*
int main(int argc, char *argv[])
{
FILE *soundIn,*soundOut;
long i,dLength;
short data[2];
MY_FLOAT temp,efMix;
Reverb *effect;
struct headerform hdr = {".sn",28,0,3,(long) SRATE,1,"TK"};
hdr.pref[3] = 'd';
if (argc==5) {
soundIn = fopen(argv[3],"rb");
soundOut = fopen(argv[4],"wb");
if (soundIn && soundOut) {
dLength = atoi(argv[2]);
efMix = atof(argv[1]);
fread(&hdr,4,2,soundIn);
fread(&hdr.file_length,hdr.hdr_length,1,soundIn);
hdr.file_length += 4 * (2 * dLength * hdr.num_channels);
if (hdr.mode != 3) {
fclose(soundIn);
fclose(soundOut);
printf("Only 16 bit linear data supported in this demo");
exit(0);
}
fwrite(&hdr,1,hdr.hdr_length,soundOut);
effect = new Reverb(dLength);
effect->setEffectMix(1.0);
for (i=0;i<hdr.file_length;i++) {
if (hdr.num_channels==2) {
if (fread(data,2,2,soundIn)) {
temp = (data[0] + data[1]) * 0.5;
temp *= efMix;
temp = effect->tick(temp);
data[0] = (short) (temp + (data[0] * (1.0 - efMix)));
data[1] = (short) (temp + (data[1] * (1.0 - efMix)));
}
else {
temp = effect->tick(0);
data[0] = (short) temp;
data[1] = (short) temp;
}
fwrite(data,2,2,soundOut);
i++;
}
else {
if (fread(data,2,1,soundIn)) {
temp = data[0] * efMix;
temp = effect->tick(temp);
data[0] = (short) (temp + (data[0] * (1.0 - efMix)));
}
else {
temp = effect->tick(0);
data[0] = (short) temp;
}
fwrite(data,2,1,soundOut);
}
}
delete effect;
fclose(soundIn);
fclose(soundOut);
}
else {
printf("Can't open one of the files\n");
}
}
else {
printf("useage: Reverb mix maxDelay soundIn.snd soundOut.snd\n");
printf("0.0 <= mix <= 1.0\n");
printf("maxDelay is in samples\n");
printf("soundfiles are 16 bit linear mono or stereo\n");
}
}
*/

View File

@@ -1,41 +0,0 @@
/******************************************/
/* Reverb Effect Applied to Soundfile */
/* by Perry Cook, 1996 */
/* */
/* This is based on some of the famous */
/* Stanford CCRMA reverbs (NRev, KipRev) */
/* all based on the the Chowning/Moorer/ */
/* Schroeder reverberators, which use */
/* networks of simple allpass and comb */
/* delay filters. */
/******************************************/
#if !defined(__Reverb_h)
#define __Reverb_h
#include "Object.h"
#include "DLineN.h"
class Reverb : public Object
{
protected:
DLineN *delayLine[4];
MY_FLOAT allPassCoeff;
MY_FLOAT combCoeff1;
MY_FLOAT combCoeff2;
MY_FLOAT lastOutL;
MY_FLOAT lastOutR;
MY_FLOAT effectMix;
public:
Reverb(MY_FLOAT longestDelay);
~Reverb();
void clear();
void setEffectMix(MY_FLOAT mix);
MY_FLOAT lastOutput();
MY_FLOAT lastOutputL();
MY_FLOAT lastOutputR();
MY_FLOAT tick(MY_FLOAT input);
};
#endif

View File

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

View File

@@ -1,42 +0,0 @@
/*******************************************/
/* Master Class for Sampling Synthesizer */
/* by Perry R. Cook, 1995-96 */
/* This instrument contains up to 5 */
/* attack waves, 5 looped waves, and */
/* an ADSR envelope. */
/*******************************************/
#if !defined(__Sampler_h)
#define __Sampler_h
#include "Instrmnt.h"
#include "ADSR.h"
#include "RawWave.h"
#include "OnePole.h"
class Sampler : public Instrmnt
{
protected:
ADSR *adsr;
RawWave *attacks[5];
RawWave *loops[5];
OnePole *filter;
MY_FLOAT baseFreq;
MY_FLOAT attackRatios[5];
MY_FLOAT loopRatios[5];
MY_FLOAT attackGain;
MY_FLOAT loopGain;
int whichOne;
public:
Sampler();
~Sampler();
void clear();
virtual void setFreq(MY_FLOAT frequency);
void keyOn();
void keyOff();
virtual void noteOff(MY_FLOAT amplitude);
virtual MY_FLOAT tick();
virtual void controlChange(int number, MY_FLOAT value);
};
#endif

View File

@@ -1,239 +0,0 @@
/*******************************************/
/* "Singing" Looped Soundfile Class, */
/* by Perry R. Cook, 1995-96 */
/* This Object contains all that's needed */
/* to make a pitched musical sound, like */
/* a simple voice or violin. In general, */
/* it will not be used alone (because of */
/* of munchinification effects from pitch */
/* shifting. It will be used as an */
/* excitation source for other instruments*/
/*******************************************/
#include "SingWave.h"
SingWave :: SingWave(char *fileName)
{
long i;
short temp;
FILE *fd;
fd = fopen(fileName,"rb");
if (!fd) {
printf("Couldn't find soundfile %s !!!!!!!!\n",fileName);
}
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);
mytime = 0.0;
rate = 1.0;
sweepRate = 0.001;
modulator = new Modulatr;
modulator->setVibFreq(6.0);
modulator->setVibAmt(0.04);
modulator->setRndAmt(0.005);
envelope = new Envelope;
pitchEnvelope = new Envelope;
this->setFreq(75.0);
pitchEnvelope->setRate(1.0);
this->tick();
this->tick();
pitchEnvelope->setRate(sweepRate * rate);
}
SingWave :: ~SingWave()
{
delete modulator;
delete envelope;
delete pitchEnvelope;
free(data);
}
void SingWave :: reset()
{
mytime = 0.0;
lastOutput = 0.0;
}
void SingWave :: normalize()
{
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;
for (i=0;i<=length;i++)
data[i] *= max;
}
}
void SingWave :: 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 SingWave :: setFreq(MY_FLOAT aFreq)
{
MY_FLOAT temp;
temp = rate;
rate = length * ONE_OVER_SRATE * aFreq;
temp -= rate;
if (temp<0) temp = -temp;
pitchEnvelope->setTarget(rate);
pitchEnvelope->setRate(sweepRate * temp);
}
void SingWave :: setVibFreq(MY_FLOAT vibFreq)
{
modulator->setVibFreq(vibFreq);
}
void SingWave :: setVibAmt(MY_FLOAT vibAmount)
{
modulator->setVibAmt(vibAmount);
}
void SingWave :: setRndAmt(MY_FLOAT rndAmount)
{
modulator->setRndAmt(rndAmount);
}
void SingWave :: setSweepRate(MY_FLOAT swpRate)
{
sweepRate = swpRate;
}
void SingWave :: setGainRate(MY_FLOAT gainRate)
{
envelope->setRate(gainRate);
}
void SingWave :: setGainTarget(MY_FLOAT aTarget)
{
envelope->setTarget(aTarget);
}
void SingWave :: noteOn()
{
envelope->keyOn();
}
void SingWave :: noteOff()
{
envelope->keyOff();
}
MY_FLOAT SingWave :: tick()
{
long temp;
MY_FLOAT alpha, temp_rate;
temp_rate = pitchEnvelope->tick();
mytime += temp_rate; /* Update current time */
mytime += temp_rate *
modulator->tick(); /* Add vibratos */
while (mytime >= length) { /* Check for end of sound */
mytime -= length; /* loop back to beginning */
}
while (mytime < 0.0) { /* Check for end of sound */
mytime += length; /* loop back to beginning */
}
temp = (long) mytime; /* Integer part of time address */
alpha = mytime - (MY_FLOAT) temp; /* fractional part of time address*/
lastOutput = alpha * data[temp+1]; /* Do linear */
lastOutput += (1.0 - alpha) *
data[temp]; /* interpolation */
lastOutput *= envelope->tick();
return lastOutput;
}
MY_FLOAT SingWave :: lastOut()
{
return lastOutput;
}
/************ Test Main Program *****************/
/*
void main()
{
SingWave ahhWave("rawwaves/ahh.raw");
SingWave eeeWave("rawwaves/eee.raw");
SingWave oooWave("rawwaves/ooo.raw");
FILE *fd;
short data;
long i,j;
fd = fopen("test.raw","wb");
ahhWave.normalize();
ahhWave.noteOn();
for (j=0;j<6;j++) {
ahhWave.setFreq(100 * pow(2.0,j*0.25));
for (i=0;i<10000;i++) {
data = ahhWave.tick() * 32000.0;
fwrite(&data,2,1,fd);
}
}
ahhWave.noteOff();
for (i=0;i<5000;i++) {
data = ahhWave.tick() * 32000.0;
fwrite(&data,2,1,fd);
}
eeeWave.normalize();
eeeWave.noteOn();
for (j=0;j<6;j++) {
eeeWave.setFreq(100 * pow(2.0,j*0.25));
for (i=0;i<10000;i++) {
data = eeeWave.tick() * 32000.0;
fwrite(&data,2,1,fd);
}
}
eeeWave.noteOff();
for (i=0;i<5000;i++) {
data = eeeWave.tick() * 32000.0;
fwrite(&data,2,1,fd);
}
oooWave.normalize();
oooWave.noteOn();
for (j=0;j<6;j++) {
oooWave.setFreq(100 * pow(2.0,j*0.25));
for (i=0;i<10000;i++) {
data = oooWave.tick() * 32000.0;
fwrite(&data,2,1,fd);
}
}
oooWave.noteOff();
for (i=0;i<5000;i++) {
data = oooWave.tick() * 32000.0;
fwrite(&data,2,1,fd);
}
fclose(fd);
}
*/

View File

@@ -1,2 +0,0 @@
cd ..
wish < TCLSpecs/TCLPhys.tcl | testTextIn Clarinet

View File

@@ -1,2 +0,0 @@
cd ..
wish < TCLSpecs/TCLStruk.tcl | testTextIn Mandolin

View File

@@ -1,2 +0,0 @@
cd ..
wish < TCLSpecs/TCLVoice.tcl | testTextIn FMVoices

View File

@@ -1,2 +0,0 @@
cd ..
testMIDI | testTextIn Clarinet

View File

@@ -1,2 +0,0 @@
cd ..
testMIDI | testTextIn Mandolin

View File

@@ -1,2 +0,0 @@
cd ..
testMIDI | testTextIn FMVoices

View File

@@ -1,136 +0,0 @@
set pitch 64.0
set press 64.0
button .pretty -bitmap @TCLSpecs/bitmaps/prcFunny.xbm \
-background white -foreground black
.pretty config -bitmap @TCLSpecs/bitmaps/prc.xbm
proc myExit {} {
puts stdout [format "ExitProgram"]
flush stdout
exit
}
proc noteOn {pitchVal pressVal} {
puts stdout [format "NoteOn 0.0 1 %f %f" $pitchVal $pressVal]
flush stdout
}
proc noteOff {pitchVal pressVal} {
puts stdout [format "NoteOff 0.0 1 %f %f" $pitchVal $pressVal]
flush stdout
}
proc patchChange {value} {
global .pretty
puts stdout [format "ProgramChange 0.0 1 %i" $value]
if {$value==0} {
.pretty config -bitmap @TCLSpecs/bitmaps/Klar.xbm
}
if {$value==1} {
.pretty config -bitmap @TCLSpecs/bitmaps/KFloot.xbm
}
if {$value==2} {
.pretty config -bitmap @TCLSpecs/bitmaps/KHose.xbm
}
if {$value==3} {
.pretty config -bitmap @TCLSpecs/bitmaps/KFiddl.xbm
}
flush stdout
}
proc printWhatz {tag value1 value2 } {
puts stdout [format "%s %i %f" $tag $value1 $value2]
flush stdout
}
proc changePress {value} {
global press
set press $value
puts stdout [format "AfterTouch 0.0 1 %f" $press]
flush stdout
}
proc changePitch {value} {
global pitch
set pitch $value
puts stdout [format "PitchBend 0.0 1 %f" $pitch]
flush stdout
}
scale .bPressure -from 0 -to 128 -length 200 \
-command {changePress } \
-activeforeground white -sliderforeground grey80\
-orient horizontal -label "Breath Pressure" \
-tickinterval 32 -showvalue true -bg grey66
scale .pitch -from 0 -to 128 -length 200 \
-command {changePitch } \
-activeforeground white -sliderforeground grey80\
-orient horizontal -label "MIDI Note Number" \
-tickinterval 32 -showvalue true -bg grey66
scale .cont1 -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 2} \
-activeforeground white -sliderforeground grey80\
-orient horizontal -label "Reed, Emb., Lip., Bow Pres." \
-tickinterval 32 -showvalue true -bg grey66
scale .cont2 -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 4} \
-activeforeground white -sliderforeground grey80\
-orient horizontal -label "Noise Amt., Slide Length,Bow Pos." \
-tickinterval 32 -showvalue true -bg grey66
scale .cont3 -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 11} \
-activeforeground white -sliderforeground grey80\
-orient horizontal -label "Vibrato Rate" \
-tickinterval 32 -showvalue true -bg grey66
scale .vibrato -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 1} \
-activeforeground white -sliderforeground grey80\
-orient horizontal -label "Vibrato Amount" \
-tickinterval 32 -showvalue true -bg grey66
. config -bg grey20
frame .instChoice -bg black
radiobutton .instChoice.clar -text Clarinet -bg grey66 \
-command { patchChange 0 }
radiobutton .instChoice.flut -text Flute -bg grey66 \
-command { patchChange 1 }
radiobutton .instChoice.bras -text Brass -bg grey66 \
-command { patchChange 2 }
radiobutton .instChoice.bowd -text Bowed -bg grey66 \
-command { patchChange 3 }
pack .instChoice.clar -side left -padx 5
pack .instChoice.flut -side left -padx 5
pack .instChoice.bras -side left -padx 5
pack .instChoice.bowd -side left -padx 5 -pady 10
pack .instChoice
pack .pretty -padx 5 -pady 10
pack .bPressure -padx 10 -pady 10
pack .pitch -padx 10 -pady 10
pack .vibrato -padx 10 -pady 10
pack .cont1 -padx 10 -pady 10
pack .cont2 -padx 10 -pady 10
pack .cont3 -padx 10 -pady 10
frame .noteOn -bg black
button .noteOn.on -text NoteOn -bg grey66 -command { noteOn $pitch $press }
button .noteOn.off -text NoteOff -bg grey66 -command { noteOff $pitch 127.0 }
button .noteOn.exit -text "Exit Program" -bg grey66 -command myExit
pack .noteOn.on -side left -padx 5
pack .noteOn.off -side left -padx 5 -pady 10
pack .noteOn.exit -side left -padx 5 -pady 10
pack .noteOn

View File

@@ -1,159 +0,0 @@
set pitch 64.0
set press 64.0
button .pretty -bitmap @TCLSpecs/bitmaps/prcFunny.xbm \
-background white -foreground black
.pretty config -bitmap @TCLSpecs/bitmaps/prc.xbm
proc myExit {} {
puts stdout [format "ExitProgram"]
flush stdout
exit
}
proc noteOn {pitchVal pressVal} {
puts stdout [format "NoteOn 0.0 1 %f %f" $pitchVal $pressVal]
flush stdout
}
proc noteOff {pitchVal pressVal} {
puts stdout [format "NoteOff 0.0 1 %f %f" $pitchVal $pressVal]
flush stdout
}
proc patchChange {value} {
global .pretty
puts stdout [format "ProgramChange 0.0 1 %i" $value]
if {$value==4} {
.pretty config -bitmap @TCLSpecs/bitmaps/KPluk.xbm
}
if {$value==5} {
.pretty config -bitmap @TCLSpecs/bitmaps/KModal.xbm
}
if {$value==6} {
.pretty config -bitmap @TCLSpecs/bitmaps/KModal.xbm
}
if {$value==7} {
.pretty config -bitmap @TCLSpecs/bitmaps/KModal.xbm
}
if {$value==8} {
.pretty config -bitmap @TCLSpecs/bitmaps/KFMod.xbm
}
if {$value==9} {
.pretty config -bitmap @TCLSpecs/bitmaps/KFMod.xbm
}
if {$value==10} {
.pretty config -bitmap @TCLSpecs/bitmaps/KFMod.xbm
}
flush stdout
}
proc printWhatz {tag value1 value2 } {
puts stdout [format "%s %i %f" $tag $value1 $value2]
flush stdout
}
proc changePress {value} {
global press
set press $value
puts stdout [format "AfterTouch 0.0 1 %f" $press]
flush stdout
}
proc changePitch {value} {
global pitch
set pitch $value
puts stdout [format "PitchBend 0.0 1 %f" $pitch]
flush stdout
}
scale .bPressure -from 0 -to 128 -length 200 \
-command {changePress } \
-activeforeground white -sliderforeground grey80\
-orient horizontal -label "Breath Pressure" \
-tickinterval 32 -showvalue true -bg grey66
scale .pitch -from 0 -to 128 -length 200 \
-command {changePitch } \
-activeforeground white -sliderforeground grey80\
-orient horizontal -label "MIDI Note Number" \
-tickinterval 32 -showvalue true -bg grey66
scale .cont1 -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 2} \
-activeforeground white -sliderforeground grey80\
-orient horizontal -label "Stick/Pick Hardness" \
-tickinterval 32 -showvalue true -bg grey66
scale .cont2 -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 4} \
-activeforeground white -sliderforeground grey80\
-orient horizontal -label "Strike/Pick Position" \
-tickinterval 32 -showvalue true -bg grey66
scale .cont3 -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 11} \
-activeforeground white -sliderforeground grey80\
-orient horizontal -label "Vibrato Rate" \
-tickinterval 32 -showvalue true -bg grey66
scale .vibrato -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 1} \
-activeforeground white -sliderforeground grey80\
-orient horizontal -label "Vibrato Amount" \
-tickinterval 32 -showvalue true -bg grey66
. config -bg grey20
frame .modal -bg black
frame .fm -bg black
radiobutton .mand -text Mandolin -bg grey66 \
-command { patchChange 4 }
radiobutton .modal.mari -text Marimba -bg grey66 \
-command { patchChange 5 }
radiobutton .modal.vibr -text Vibraphn -bg grey66 \
-command { patchChange 6 }
radiobutton .modal.agog -text AgogoBel -bg grey66 \
-command { patchChange 7 }
radiobutton .fm.rhod -text Rhodey -bg grey66 \
-command { patchChange 8 }
radiobutton .fm.wurl -text Wurley -bg grey66 \
-command { patchChange 9 }
radiobutton .fm.tube -text TubeBell -bg grey66 \
-command { patchChange 10 }
pack .mand -padx 5 -pady 10
pack .modal.mari -side left -padx 5
pack .modal.vibr -side left -padx 5
pack .modal.agog -side left -padx 5 -pady 10
pack .modal
pack .fm.rhod -side left -padx 5
pack .fm.wurl -side left -padx 5
pack .fm.tube -side left -padx 5 -pady 10
pack .fm
pack .pretty -padx 5 -pady 10
pack .bPressure -padx 10 -pady 10
pack .pitch -padx 10 -pady 10
pack .vibrato -padx 10 -pady 10
pack .cont1 -padx 10 -pady 10
pack .cont2 -padx 10 -pady 10
pack .cont3 -padx 10 -pady 10
frame .noteOn -bg black
button .noteOn.on -text NoteOn -bg grey66 -command { noteOn $pitch $press }
button .noteOn.off -text NoteOff -bg grey66 -command { noteOff $pitch 127.0 }
button .noteOn.exit -text "Exit Program" -bg grey66 -command myExit
pack .noteOn.on -side left -padx 5
pack .noteOn.off -side left -padx 5 -pady 10
pack .noteOn.exit -side left -padx 5 -pady 10
bind all <KeyPress> {
noteOn $pitch $press
}
pack .noteOn

View File

@@ -1,124 +0,0 @@
set pitch 64.0
set press 64.0
button .pretty -bitmap @TCLSpecs/bitmaps/prcFunny.xbm \
-background white -foreground black
.pretty config -bitmap @TCLSpecs/bitmaps/prc.xbm
proc myExit {} {
puts stdout [format "ExitProgram"]
flush stdout
exit
}
proc noteOn {pitchVal pressVal} {
puts stdout [format "NoteOn 0.0 1 %f %f" $pitchVal $pressVal]
flush stdout
}
proc noteOff {pitchVal pressVal} {
puts stdout [format "NoteOff 0.0 1 %f %f" $pitchVal $pressVal]
flush stdout
}
proc patchChange {value} {
global .pretty
puts stdout [format "ProgramChange 0.0 1 %i" $value]
if {$value==11} {
.pretty config -bitmap @TCLSpecs/bitmaps/KVoiceFM.xbm
}
if {$value==12} {
.pretty config -bitmap @TCLSpecs/bitmaps/KVoicForm.xbm
}
flush stdout
}
proc printWhatz {tag value1 value2 } {
puts stdout [format "%s %i %f" $tag $value1 $value2]
flush stdout
}
proc changePress {value} {
global press
set press $value
puts stdout [format "AfterTouch 0.0 1 %f" $press]
flush stdout
}
proc changePitch {value} {
global pitch
set pitch $value
puts stdout [format "PitchBend 0.0 1 %f" $pitch]
flush stdout
}
scale .bPressure -from 0 -to 128 -length 200 \
-command {changePress } \
-activeforeground white -sliderforeground grey80\
-orient horizontal -label "Loudness (Spectral Tilt)" \
-tickinterval 32 -showvalue true -bg grey66
scale .pitch -from 0 -to 128 -length 200 \
-command {changePitch } \
-activeforeground white -sliderforeground grey80\
-orient horizontal -label "MIDI Note Number" \
-tickinterval 32 -showvalue true -bg grey66
scale .cont1 -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 2} \
-activeforeground white -sliderforeground grey80\
-orient horizontal -label "Formant Q / Voiced/Un." \
-tickinterval 32 -showvalue true -bg grey66
scale .cont2 -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 4} \
-activeforeground white -sliderforeground grey80\
-orient horizontal -label "Vowel (Bass, Tenor, Alto, Sop.)" \
-tickinterval 32 -showvalue true -bg grey66
scale .cont3 -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 11} \
-activeforeground white -sliderforeground grey80\
-orient horizontal -label "Vibrato Rate" \
-tickinterval 32 -showvalue true -bg grey66
scale .vibrato -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 1} \
-activeforeground white -sliderforeground grey80\
-orient horizontal -label "Vibrato Amount" \
-tickinterval 32 -showvalue true -bg grey66
. config -bg grey20
frame .instChoice -bg black
radiobutton .instChoice.fm -text FMVoice -bg grey66 \
-command { patchChange 11 }
radiobutton .instChoice.form -text Formant -bg grey66 \
-command { patchChange 12 }
pack .instChoice.fm -side left -padx 5
pack .instChoice.form -side left -padx 5 -pady 10
pack .instChoice
pack .pretty -padx 5 -pady 10
pack .bPressure -padx 10 -pady 10
pack .pitch -padx 10 -pady 10
pack .vibrato -padx 10 -pady 10
pack .cont1 -padx 10 -pady 10
pack .cont2 -padx 10 -pady 10
pack .cont3 -padx 10 -pady 10
frame .noteOn -bg black
button .noteOn.on -text NoteOn -bg grey66 -command { noteOn $pitch $press }
button .noteOn.off -text NoteOff -bg grey66 -command { noteOff $pitch 127.0 }
button .noteOn.exit -text "Exit Program" -bg grey66 -command myExit
pack .noteOn.on -side left -padx 5
pack .noteOn.off -side left -padx 5 -pady 10
pack .noteOn.exit -side left -padx 5 -pady 10
pack .noteOn

View File

@@ -1,65 +0,0 @@
testMono Plucked scores/duelingb.ski
sndplay test.snd
mv test.snd Plucked.snd
testMono Mandolin scores/mandtune.ski
sndplay test.snd
mv test.snd MandTune.snd
testMono Mandolin scores/funicula.ski
sndplay test.snd
mv test.snd MandSolo.snd
testMono Clarinet scores/simplgft.ski
sndplay test.snd
mv test.snd Clarinet.snd
testMono Flute scores/simplgft.ski
sndplay test.snd
mv test.snd Flute.snd
testMono Brass scores/pictures.ski
sndplay test.snd
mv test.snd Brass.snd
testMono Bowed scores/fiddle.ski
sndplay test.snd
mv test.snd Bowed.snd
testMono Marimba scores/spain.ski
sndplay test.snd
mv test.snd Marimba.snd
testMono Vibraphn scores/spain.ski
sndplay test.snd
mv test.snd Vibraphn.snd
testMono AgogoBel scores/morazbel.ski
sndplay test.snd
mv test.snd AgogoBel.snd
testMono Rhodey scores/doogie.ski
sndplay test.snd
mv test.snd Rhodey.snd
testMono Wurley scores/riderson.ski
sndplay test.snd
mv test.snd Wurley.snd
testMono TubeBell scores/tubebell.ski
sndplay test.snd
mv test.snd TubeBell.snd
testMono PercFlut scores/misacrio.ski
sndplay test.snd
mv test.snd PercFlut.snd
testMono HeavyMtl scores/streetsf.ski
sndplay test.snd
mv test.snd HeavyMtl.snd
testMult 0.33 BeeThree scores/organs.ski
sndplay test.snd
mv test.snd BeeThree.snd
testMono Moog1 scores/thecars.ski
sndplay test.snd
mv test.snd Moog1.snd
Lacrymosa
mv test.snd Vocaliz.snd
DrumSynt
sndplay test.snd
mv test.snd DrumSynt.snd

View File

@@ -1,30 +0,0 @@
testMono Plucked scores/duelingb.ski
testMult 1.0 Mandolin scores/mandtune.ski
testMono Mandolin scores/funicula.ski
testMono Clarinet scores/simplgft.ski
testMono Flute scores/simplgft.ski
testMono Brass scores/pictures.ski
testMono Bowed scores/fiddle.ski
testMono Marimba scores/spain.ski
testMono Vibraphn scores/spain.ski
testMono AgogoBel scores/morazbel.ski
testMono Rhodey scores/doogie.ski
testMono Wurley scores/riderson.ski
testMono TubeBell scores/tubebell.ski
testMono PercFlut scores/misacrio.ski
testMono HeavyMtl scores/streetsf.ski
testMono BeeThree scores/bookert.ski
testMult 0.33 BeeThree scores/organs.ski
testMono Moog1 scores/thecars.ski
testMono FMVoices scores/lacrymos.ski
testMono VoicForm scores/lacrymos.ski
Vocaliz
Lacrymosa
DrumSynt

116
ToDo.txt
View File

@@ -1,116 +0,0 @@
Need to iron out the differences between RawWvIn, NIWave1S, NIFileIn, etc.
Need to make DrumSyn1 vs. DrumSyn2
One real-time large memory, one non real-time small memory
*****************************************************
Legend:
x = done <1 - 9> = How Good? : = by Inheritance N = Not Applicable
Ex = Exists
Cm = Compiles
On = Note On
Of = Note Off
Pt = Pitch (5 octave range)
Vl = Velocity (0-128)
Bn = Pitch Bend
Md = Mod Wheel
C1 = Controller 1, Algorithm Specific
C2 = Controller 2, Algorithm Specific
Lg = Long/Int/Double verification
Op = Optimization pass 1
Com. = Comments
FILE/CLASS Ex Cm On Of Pt Vl Bn Md C1 C2 C3 Lg Op Com
README.TXT x N N N N N N N N N N N N
OBJECT.H x x N N N N N N N N N x N
FILTER.H x x N N N N N N N N N x N
ONEPOLE.H x x N N N N N N N N N x
ONEZERO.H x x N N N N N N N N N x
DCBLOCK.H x x N N N N N N N N N x
BIQUAD.H x x N N N N N N N N N x
TWOZERO.H x x N N N N N N N N N x
TWOPOLE.H x x N N N N N N N N N x
ALLPASS1.H
FORMSWEP.H x x N N N N N N N N N x
DLINEA.H x x N N N N N N N N N x
DLINEL.H x x N N N N N N N N N x
DLINEN.H x x N N N N N N N N N x
RAWWAVE.H x x N N N N N N N N N x
RAWLOOP.H x x N N N N N N N N N x
NIWAVE1S.H
SINGWAVE.H x x N N N N N N N N N x
RAWWVOUT.H x x N N N N N N N N N x
RAWWVIN.H x x N N N N N N N N N x
REEDTABL.H x x N N N N N N N N N x
JETTABL.H x x N N N N N N N N N x
LIPFILT.H x x N N N N N N N N N x Add Lip Tension Modulation?
BOWTABL.H x x N N N N N N N N N x
ENVELOPE.H x x N N N N N N N N N x
ADSR.H x x N N N N N N N N N x
NOISE.H x x N N N N N N N N N x
SUBNOISE.H x x N N N N N N N N N x Noise each n samples
FILE/CLASS Ex Cm On Of Pt Vl Bn Md C1 C2 C3 Lg Op Com
PLUCKED.H x x x x 7 8 N N N N x tuning funny, allpass approx.
CLARINET.H x x x x 7 5 7 7 7 7 x
FLUTE.H x x x x 7 5 7 7 7 7 x
BRASS.H x x x x 7 5 7 7 7 7 x
BOWED.H x x x x 7 5 7 7 7 7 x Need Better Body Filter
PLUCKED2.H x x N x N N N N N N x
MANDOLIN.H x x x : 8 8 9 9 9 9 x tuning funny, allpass approx.
MODAL4.H x x N x N N 7 N N N x
MARIMBA.H x x x : 7 x : 7 7 7 x Check 4 Clipping Mid Range
VIBRAPHN.H x x x : x x : 7 7 7 x AMDept StickHard Pos AMFreq
AGOGOBEL.H x x x : x x : 7 7 7 x StickHard Position
FM4OP.H x x N x N N N N N x 9 x
FM4ALG8.H x x N : N N N 9 9 | x
BEETHREE.H x x x : x x 9 : : : x
FM4ALG5.H x x N : N N N 9 9 : x
RHODEY.H x x x : 8 x 9 : : : x Minor Aliasing High Range
WURLEY.H x x x : 8 x 9 : : : x " " " "
TUBEBELL.H x x x : x x 9 : : : x
FM4ALG4.H x x N : N N N 9 9 : x
PERCFLUT.H x x x : 8 x 9 : : : x Minor Aliasing High Range
FM4ALG3.H x x N : N N N 9 9 : x
HEAVYMTL.H x x x : x x 9 : : : x Minor Aliasing High Range
SAMPLER.H x x N x N
SAMPLFLT.H x x N : N
MOOG1.H x x x : x x
VOICFORM.H x x ? ? ? ? ? ? ? ? ? x Need much phoneme!!
DRUMSYNT.H x x x N x N N N N N x Need New Drum Samples
FILE/CLASS Ex Cm On Of Pt Vl Bn Md C1 C2 C3 Lg Op Com
Legend:
Es = Exists
Cm = Compiles
On = Note On
Of = Note Off
Pt = Pitch (5 octave range)
Vl = Velocity (0-128)
Bn = Pitch Bend
Md = Mod Wheel
C1 = Controller 1, Algorithm Specific
C2 = Controller 2, Algorithm Specific
Lg = Long/Int/Double verification
Op = Optimization pass 1
Com. = Comments

View File

@@ -1,53 +0,0 @@
/******************************************/
/* Tubular Bell (Orch. Chime) Subclass */
/* of Algorithm 5 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/******************************************/
#include "TubeBell.h"
TubeBell :: TubeBell() : FM4Alg5()
{
this->loadWaves("rawwaves/sinewave.raw",
"rawwaves/sinewave.raw",
"rawwaves/sinewave.raw",
"rawwaves/sinewave.raw");
this->setRatio(0,1.0 * 0.995);
this->setRatio(1,1.414 * 0.995);
this->setRatio(2,1.0 * 1.005);
this->setRatio(3,1.414 );
gains[0] = __FM4Op_gains[94];
gains[1] = __FM4Op_gains[76];
gains[2] = __FM4Op_gains[99];
gains[3] = __FM4Op_gains[71];
adsr[0]->setAll(0.03,0.00001,0.0,0.02);
adsr[1]->setAll(0.03,0.00001,0.0,0.02);
adsr[2]->setAll(0.07,0.00002,0.0,0.02);
adsr[3]->setAll(0.04,0.00001,0.0,0.02);
twozero->setGain(0.5);
vibWave->setFreq(2.0);
}
void TubeBell :: 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 TubeBell :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
gains[0] = amp * __FM4Op_gains[94];
gains[1] = amp * __FM4Op_gains[76];
gains[2] = amp * __FM4Op_gains[99];
gains[3] = amp * __FM4Op_gains[71];
this->setFreq(freq);
this->keyOn();
#if defined(_debug_)
printf("TubeBell : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}

View File

@@ -1,61 +0,0 @@
/*******************************************/
/* Two 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. */
/*******************************************/
#include "TwoPole.h"
TwoPole :: TwoPole() : Filter()
{
outputs = (MY_FLOAT *) malloc(2 * MY_FLOAT_SIZE);
poleCoeffs[0] = 0.0;
poleCoeffs[1] = 0.0;
gain = 1.0;
this->clear();
}
TwoPole :: ~TwoPole()
{
// free(inputs);
free(outputs);
}
void TwoPole :: clear()
{
outputs[0] = 0.0;
outputs[1] = 0.0;
lastOutput = 0.0;
}
void TwoPole :: setPoleCoeffs(MY_FLOAT *coeffs)
{
poleCoeffs[0] = coeffs[0];
poleCoeffs[1] = coeffs[1];
}
void TwoPole :: setFreqAndReson(MY_FLOAT freq, MY_FLOAT reson)
{
poleCoeffs[1] = - (reson * reson);
poleCoeffs[0] = 2.0 * reson * cos(TWO_PI * freq / SRATE);
}
void TwoPole :: setGain(MY_FLOAT aValue)
{
gain = aValue;
}
MY_FLOAT TwoPole :: tick(MY_FLOAT sample) /* Perform Filter Operation */
{ /* TwoPole is a two pole filter (duh!) */
MY_FLOAT temp; /* Look it up in your favorite DSP text */
temp = sample * gain;
temp += poleCoeffs[0] * outputs[0];
temp += poleCoeffs[1] * outputs[1];
outputs[1] = outputs[0];
outputs[0] = temp;
lastOutput = outputs[0];
return lastOutput;
}

View File

@@ -1,53 +0,0 @@
/*******************************************/
/* Two 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 "TwoZero.h"
TwoZero :: TwoZero() : Filter()
{
inputs = (MY_FLOAT *) malloc(2 * MY_FLOAT_SIZE);
zeroCoeffs[0] = 0.0;
zeroCoeffs[1] = 0.0;
gain = 1.0;
this->clear();
}
TwoZero :: ~TwoZero()
{
free(inputs);
}
void TwoZero :: clear()
{
inputs[0] = 0.0;
inputs[1] = 0.0;
lastOutput = 0.0;
}
void TwoZero :: setZeroCoeffs(MY_FLOAT *coeffs)
{
zeroCoeffs[0] = coeffs[0];
zeroCoeffs[1] = coeffs[1];
}
void TwoZero :: setGain(MY_FLOAT aValue)
{
gain = aValue;
}
MY_FLOAT TwoZero :: tick(MY_FLOAT sample) /* Perform Filter Operation */
{ /* TwoZero is a two zero filter (duh!) */
/* Look it up in your favorite DSP text */
lastOutput = zeroCoeffs[0] * inputs[0];
lastOutput += zeroCoeffs[1] * inputs[1];
inputs[1] = inputs[0];
inputs[0] = gain * sample;
lastOutput += inputs[0];
return lastOutput;
}

View File

@@ -1,75 +0,0 @@
/*******************************************/
/* Vibraphone SubClass of Modal4 */
/* Instrument, by Perry R. Cook, 1995-96 */
/* */
/* Controls: CONTROL1 = stickHardness */
/* CONTROL2 = strikePosition*/
/* CONTROL3 = vibFreq */
/* MOD_WHEEL= vibAmt */
/*******************************************/
#include "Vibraphn.h"
Vibraphn :: Vibraphn() : Modal4()
{
wave = new RawWave("rawwaves/marmstk1.raw");
wave->normalize();
wave->setRate(13.33);
vibr->setFreq(4.0);
onepole->setPole(0.2);
this->setRatioAndReson(0, 1.0,0.99995); /* Set */
this->setRatioAndReson(1, 2.01,0.99991); /* our */
this->setRatioAndReson(2, 3.9,0.99992); /* resonance */
this->setRatioAndReson(3,14.37,0.99990); /* values here */
this->setFiltGain(0,0.025);
this->setFiltGain(1,0.015);
this->setFiltGain(2,0.015);
this->setFiltGain(3,0.015);
masterGain = 1.0;
directGain = 0.0;
vibrGain = 0.2;
}
Vibraphn :: ~Vibraphn()
{
}
void Vibraphn :: setStickHardness(MY_FLOAT hardness)
{
wave->setRate(2.0 + (22.66 * hardness));
masterGain = 0.2 + (hardness * 1.6);
}
void Vibraphn :: setStrikePosition(MY_FLOAT position)
{
MY_FLOAT temp,temp2;
temp2 = position * PI;
strikePosition = position; /* Hack only first three modes */
temp = sin(strikePosition * PI);
this->setFiltGain(0,0.025 * temp);
temp = sin(0.1 + (2.01 * temp2));
this->setFiltGain(1,0.015 * temp);
temp = sin(3.95 * temp2);
this->setFiltGain(2,0.015 * temp);
}
void Vibraphn :: controlChange(int number, MY_FLOAT value)
{
#if defined(_debug_)
printf("Vibraphn : 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("Vibraphn : Undefined Control Number!!\n");
}
}

View File

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

View File

@@ -1 +0,0 @@
time textVoic =100.00 eee ahh .... eee + + + + ahh .... eee + + + ahh . eee - - ahh . eee - ahh . eee - - ahh . eee - - ahh ..... =150.0 ...... =200.0 ......

View File

@@ -1,228 +0,0 @@
/*******************************************/
/* 4 Formant Synthesis Instrument */
/* by Perry R. Cook, 1995-96 */
/* This instrument contains an excitation */
/* singing wavetable (looping wave with */
/* random and periodic vibrato, smoothing */
/* on frequency, etc.), excitation noise, */
/* and four sweepable complex resonances. */
/* */
/* Measured Formant data (from me) is */
/* included, and enough data is there to */
/* support either parallel or cascade */
/* synthesis. In the floating point case */
/* cascade synthesis is the most natural */
/* so that's what you'll find here. */
/* */
/* For right now, there's a simple command*/
/* line score interface consisting of 3 */
/* letter symbols for the phonemes, =xx */
/* sets the pitch to x, + and - add and */
/* subtract a half step, and ... makes it */
/* keep doing what it's doing for longer. */
/*******************************************/
#include "VoicForm.h"
VoicForm :: VoicForm() : Instrmnt()
{
voiced = new SingWave("rawwaves/impuls40.raw");
voiced->normalize();
voiced->setGainRate(0.001);
voiced->setGainTarget(0.0);
noise = new Noise;
filters[0] = new FormSwep;
filters[1] = new FormSwep;
filters[2] = new FormSwep;
filters[3] = new FormSwep;
filters[0]->setSweepRate(0.001);
filters[1]->setSweepRate(0.001);
filters[2]->setSweepRate(0.001);
filters[3]->setSweepRate(0.001);
onezero = new OneZero;
onezero->setCoeff(-0.9);
onepole = new OnePole;
onepole->setPole(0.9);
noiseEnv = new Envelope;
noiseEnv->setRate(0.001);
noiseEnv->setTarget(0.0);
this->setPhoneme("eee");
this->clear();
}
VoicForm :: ~VoicForm()
{
delete voiced;
delete noise;
delete filters[0];
delete filters[1];
delete filters[2];
delete filters[3];
delete onezero;
delete onepole;
delete noiseEnv;
}
void VoicForm :: clear()
{
onepole->clear();
filters[0]->clear();
filters[1]->clear();
filters[2]->clear();
filters[3]->clear();
}
void VoicForm :: setFreq(double frequency)
{
voiced->setFreq(frequency);
}
void VoicForm :: setFormantAll(int whichOne, double freq,double reson,double gain)
{
filters[whichOne]->setTargets(freq,reson,gain);
}
extern double phonGains[32][2];
extern double phonParams[32][4][3];
extern char phonemes[32][4];
int VoicForm :: setPhoneme(char *phoneme)
{
int i=0,found=0;
while(i<32 && !found) {
if (!strcmp(phonemes[i],phoneme)) {
found = 1;
this->setFormantAll(0,phonParams[i][0][0],phonParams[i][0][1],pow(10.0,phonParams[i][0][2] / 20.0));
this->setFormantAll(1,phonParams[i][1][0],phonParams[i][1][1],1.0);
this->setFormantAll(2,phonParams[i][2][0],phonParams[i][2][1],1.0);
this->setFormantAll(3,phonParams[i][3][0],phonParams[i][3][1],1.0);
this->setVoicedUnVoiced(phonGains[i][0],phonGains[i][1]);
printf("Found Formant: %s (number %i)\n",phoneme,i);
}
i++;
}
if (!found) printf("Phoneme %s not found\n",phoneme);
return found;
}
void VoicForm :: setVoiced(double vGain)
{
voiced->setGainTarget(vGain);
}
void VoicForm :: setUnVoiced(double nGain)
{
noiseEnv->setTarget(nGain);
}
void VoicForm :: setVoicedUnVoiced(double vGain, double nGain)
{
this->setVoiced(vGain);
this->setUnVoiced(nGain);
}
void VoicForm :: setFiltSweepRate(int whichOne,double rate)
{
filters[whichOne]->setSweepRate(rate);
}
void VoicForm :: setPitchSweepRate(double rate)
{
voiced->setSweepRate(rate);
}
void VoicForm :: speak()
{
voiced->noteOn();
}
void VoicForm :: quiet()
{
voiced->noteOff();
noiseEnv->setTarget(0.0);
}
void VoicForm :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
voiced->setGainTarget(amp);
onepole->setPole(0.95 - (amp * NORM_7 * 0.2));
voiced->setFreq(freq);
}
void VoicForm :: noteOff(MY_FLOAT amp)
{
voiced->noteOff();
}
MY_FLOAT VoicForm :: tick()
{
MY_FLOAT temp;
temp = onepole->tick(onezero->tick(voiced->tick()));
temp += noiseEnv->tick() * noise->tick();
lastOutput = filters[0]->tick(temp);
lastOutput = filters[1]->tick(lastOutput);
lastOutput = filters[2]->tick(lastOutput);
lastOutput = filters[3]->tick(lastOutput);
lastOutput *= 0.02;
return lastOutput;
}
void VoicForm :: controlChange(int number, MY_FLOAT value)
{
MY_FLOAT temp;
int tempi;
#if defined(_debug_)
printf("VoicForm : ControlChange: Number=%i Value=%f\n",number,value);
#endif
if (number == MIDI_control1) {
this->setVoiced(1.0 - (value*NORM_7));
this->setUnVoiced(0.01 * value * NORM_7);
}
else if (number == MIDI_control2) {
tempi = (int) (value / 2);
if (tempi < 16) {
tempi = tempi;
temp = 0.9;
}
else if (tempi < 32) {
tempi = tempi - 16;
temp = 1.0;
}
else if (tempi < 48) {
tempi = tempi - 32;
temp = 1.1;
}
else if (tempi < 64) {
tempi = tempi - 48;
temp = 1.2;
}
this->setFormantAll(0,temp*phonParams[tempi][0][0],
phonParams[tempi][0][1],
pow(10.0,phonParams[tempi][0][2] / 20.0));
this->setFormantAll(1,temp*phonParams[tempi][1][0],
phonParams[tempi][1][1],1.0);
this->setFormantAll(2,temp*phonParams[tempi][2][0],
phonParams[tempi][2][1],1.0);
this->setFormantAll(3,temp*phonParams[tempi][3][0],
phonParams[tempi][3][1],1.0);
}
else if (number == MIDI_control3)
voiced->setVibFreq(value * NORM_7 * 12.0); /* 0 to 12 Hz */
else if (number == MIDI_mod_wheel)
voiced->setVibAmt(value * NORM_7 * 0.2);
else if (number == MIDI_after_touch) {
this->setVoiced(value*NORM_7);
onepole->setPole(0.99 - (value*NORM_7 * 0.2));
}
else {
printf("VoicForm : Undefined Control Number!!\n");
}
}

View File

@@ -1,53 +0,0 @@
/******************************************/
/* Wurlitzer Electric Piano Subclass */
/* of Algorithm 5 (TX81Z) Subclass of */
/* 4 Operator FM Synth */
/* by Perry R. Cook, 1995-96 */
/******************************************/
#include "Wurley.h"
Wurley :: Wurley() : FM4Alg5()
{
this->loadWaves("rawwaves/sinewave.raw",
"rawwaves/sinewave.raw",
"rawwaves/sinewave.raw",
"rawwaves/fwavblnk.raw");
this->setRatio(0,1.0);
this->setRatio(1,4.0);
this->setRatio(2,-510.0);
this->setRatio(3,-510.0);
gains[0] = __FM4Op_gains[99];
gains[1] = __FM4Op_gains[82];
gains[2] = __FM4Op_gains[92];
gains[3] = __FM4Op_gains[68]; /* Originally 78, but sounded stinky */
twozero->setGain(2.0);
adsr[0]->setAll(0.05,0.00003,0.0,0.02);
adsr[1]->setAll(0.05,0.00003,0.0,0.02);
adsr[2]->setAll(0.05,0.0002,0.0,0.02);
adsr[3]->setAll(0.05,0.0003,0.0,0.02);
vibWave->setFreq(8.0);
}
void Wurley :: setFreq(MY_FLOAT frequency)
{
baseFreq = frequency;
waves[0]->setFreq(baseFreq * ratios[0]);
waves[1]->setFreq(baseFreq * ratios[1]);
waves[2]->setFreq(ratios[2]); /* Note here a 'fixed resonance' */
waves[3]->setFreq(ratios[3]);
}
void Wurley :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
{
gains[0] = amp * __FM4Op_gains[99];
gains[1] = amp * __FM4Op_gains[82];
gains[2] = amp * __FM4Op_gains[82]; /* Originally 92 */
gains[3] = amp * __FM4Op_gains[68]; /* Originally 78 */
this->setFreq(freq);
this->keyOn();
#if defined(_debug_)
printf("Wurley : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
#endif
}

156
doc/Hierarchy.txt Normal file
View File

@@ -0,0 +1,156 @@
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
Version 3.2
By Perry R. Cook, 1995-2000
and Gary P. Scavone, 1997-2000.
STK Classes, Version 3.2
Please read README.txt for more information.
<--------Building Blocks---------->|<----------------Instruments------------------>
SourcSink Filters Reverb Non-Lin Modal & FM Physical Sampling PhISM
Formant
Object-----------------------------------Instrmnt----------.
| | | | | | |
Envelope| Filter Reverb BowTabl | .----------------------------------------.
| | | | JetTabl | | | | | | | | |
ADSR | OneZero PRCRev ReedTabl| Modal4 | FM4Op---.| | | | Shakers
| OnePole JCRev | | | | || | | |
._____| TwoZero NRev .____| ModalBar| FM4Alg3 || Plucked Sampler |
| | TwoPole | | | || Clarinet | |
Noise | DCBlock LipFilt | HeavyMtl|| Brass SamplFlt|
| | BiQuad | || Flute | |
SubNoise| DlineL .____| .____|| Bowed Moog1 |
| DLineA | | || BowedBar |
| DLineN VoicForm FM4Alg4 || BlowHole |
| FormSwep | ||____. |
| PoleZero PercFlut| | |
.____| FIR | Plucked2 |
| | .____| | .____|
TablLook| | | Mandolin |
| FM4Alg5 | DrumSynt
|____. | |
| | Rhodey |
| WvIn Wurley |
._____| | TubeBell |
| | WavWvIn .____|
Modulatr| SndWvIn | |
| RawWvIn FM4Alg6 |
._____| MatWvIn | |
| | AifWvIn FMVoices|
SingWave| StrmWvIn |
| .____|
._____|_____. |
| | | FM4Alg8
VoicMang| WvOut |
| | BeeThree
| WavWvOut
._____| SndWvOut
| | RawWvOut
RtMidi | MatWvOut
| AifWvOut
._____| RtWvOut
| StrmWvOut
RtAudio
********** 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,RawWvIn
Clarinet.cpp Pretty Good Clarinet DLineL,ReedTabl,OneZero,Envelope,Noise,RawWvIn
BlowHole.cpp Clarinet w/ tone/reghole DLineL,ReedTabl,OneZero,Envelope,Noise,RawWvIn,PoleZero
Flute.cpp Pretty Good Flute JetTabl,DLineL,OnePole,DCBlock,Noise,ADSR,RawWvIn
BowedBar.cpp Pretty Good Bowed Bar DLineN,BowTabl,ADSR,BiQuad
Modal4.cpp 4 Resonances Envelope,RawWvIn,RawWvIn,BiQuad,OnePole
ModalBar.cpp Various presets <<flavor of MODAL4>>
FM4Op.cpp 4 Operator FM Master ADSR,RawWvIn,TwoZero
FM4Alg3.cpp 3 Cascade w/ FB Mod. <<flavor of FM4OP>>
FM4Alg4.cpp Like Alg3 but diff. <<flavor of FM4OP>>
FM4Alg5.cpp 2 Parallel Simple FMs <<flavor of FM4OP>>
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, RawWvIn (att), RawWvIn (loop), OnePole
SamplFlt.cpp Sampler with Swept Filter <<flavor of Sampler>>
Moog1.cpp Swept filter flavor of <<flavor of SamplFlt>>
VoicForm.cpp Source/Filter Voice Envelope,Noise,SingWave,FormSwep,OnePole,OneZero
DrumSynt.cpp Drum Synthesizer bunch of RawWvIn, and OnePole
Shakers.cpp Stochastic Event Models
*********** BASIC UNIT GENERATORS **************
Master Object: Object.cpp For compatibility with Objective C
Source&Sink: Envelope.cpp Linearly Goes to Target by Rate, + noteOn/Off
ADSR.cpp ADSR Flavor of Envelope
Noise.cpp Random Number Generator
SubNoise.cpp Random Numbers each N samples
Inputs: TablLook.cpp Lookup Table (assumes given data in big-endian format)
WvIn.cpp Input Master Class (Looping, One-Shot,
Interpolating, Non-Interpolating)
RawWvIn.cpp STK Raw-file Input
SndWvIn.cpp .snd Input Class
WavWvIn.cpp .wav Input Class
MatWvIn.cpp Matlab MAT-file Input Class
AifWvIn.cpp AIFF Input Class
RtWvIn.cpp Realtime Input Class
StrmWvIn.cpp Audio Streaming (socket server) Input Class
Outputs: WvOut.cpp Output Master Class
RawWvOut.cpp STK Raw-file Output Class
SndWvOut.cpp .snd Output Class
WavWvOut.cpp .wav Output Class
MatWvOut.cpp Matlab MaT-file Output Class
AifWvOut.cpp AIFF Output Class
RtWvOut.cpp Realtime Output Class
StrmWvOut.cpp Audio Streaming (socket client) Output Class
Duplex: RtDuplex.cpp Realtime Input/Output Class
MIDI: RtMidi.cpp MIDI I/O Class
Audio I/O: RtAudio.cpp Multi-OS Audio I/O Routines
Filters: Filter.cpp Filter Master Class
OneZero.cpp One Zero Filter
OnePole.cpp One Pole Filter
PoleZero.cpp One Pole/One Zero Filter
DCBlock.cpp DC Blocking 1Pole/1Zero Filter
TwoZero.cpp Two Zero Filter
TwoPole.cpp Two Pole Filter
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
Reverb: Reverb.cpp Reverb Master Class
PRCRev.cpp 2 series allpass units, 2 parallel comb filters
JCRev.cpp 3 series allpass units, 4 parallel comb filters
NRev.cpp 6 parallel comb filters, 3 series allpass units, ...
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
Control: Controller.cpp Pipe, Socket, and MIDI control message handling

28
doc/README-Linux.txt Normal file
View File

@@ -0,0 +1,28 @@
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
Version 3.2
By Perry R. Cook, 1995-2000
and Gary P. Scavone, 1997-2000.
Please read the file README.txt for more general STK information.
STK for Linux is currently using either the Open Sound System (OSS) or the Advanced Linux Sound Architecture (ALSA) sound and MIDI APIs. The free version of OSS works as well (and in some cases better than the commercial OSS version ... such as with my Maestro 2e chipset). In general, the ALSA drivers seem to perform well though we have had some problems with them at CCRMA. You can read more about ALSA at http://www.alsa-project.org/. ALSA is open source and holds great promise for audio under Linux. Select (uncomment) the proper API #define statement in Object.h.
STK should compile without much trouble under Linux ... afterall, it is primarily developed on Linux platforms. Since all Linux distributions typically include the GNU makefile utilities, you should be able to use the default Makefile. Typing "make" will initiate the compilation process.
MIDIATOR SERIAL PORT MIDI SUPPORT:
STK now has special support for the MIDIator serial port MIDI interface. This is of primary interest to us laptop users, whose computers usually don't have a gameport. If you want to buy one of these devices, make sure you get the MS-124w model (www.midiator.com). For it to work in STK, make sure you uncomment the MIDIATOR define statement in Object.h. This support currently only works within the OSS API framework, though I should be able to get it to work with ALSA in the future as well.
There are a few things that need to be done on your system to get the MIDIator working. Add the following lines to your bootup sequence in /etc/rc.d/rc.local:
setserial /dev/ttyS0 baud_base 57600
setserial /dev/ttyS0 divisor 1
You may need to specify the full path to the setserial function, depending on how your PATH variable is set up. Also, you may need to modify the permissions of /dev/ttyS0 (chmod a+rwx). And finally, the MIDIator should be set for "single addresssed" mode (the S/A switch on S and the A/B switch on A), which puts identical output on all 4 MIDI output ports. It is possible to use the MIDIator in a "multi-port" mode, though I'm not currently supporting that in STK.
NOTE REGARDING PTHREADS:
There haven't been any problems with threads since the old days of RedHat Linux 5.0. STK uses the MIT pthreads API.

14
doc/README-NeXT.txt Normal file
View File

@@ -0,0 +1,14 @@
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
Version 3.2
By Perry R. Cook, 1995-2000
and Gary P. Scavone, 1997-2000.
Please read the file README.txt for more general STK information.
STK has always worked under NeXTStep without realtime audio or MIDI support. In general, STK should compile in this way using any generic C++ compiler. C++ exception handling was added to STK with release 3.2. I have had some difficulty testing this release under NeXTStep because our NeXTStep compilers at CCRMA are very old. We tried a newer version of gcc-2.7.2.2 and that mostly worked, though it died trying to compile the BowedBar class. Also, I was unable to locate the correct header for the random() function.
In summary, I _think_ STK will compile under NeXTStep with a fairly recent compiler, but you may have to do a little work to make it happen. If you do succeed, please let us know.
Just for clarification, "realtime" support and the use of the __STK_REALTIME_ define statement includes audio and MIDI input/output routines, as well as socket and thread routines for realtime message acquisition (Controller) and internet audio streaming (StrmWvIn, StrmWvOut).

15
doc/README-SGI.txt Normal file
View File

@@ -0,0 +1,15 @@
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
Version 3.2
By Perry R. Cook, 1995-2000
and Gary P. Scavone, 1997-2000.
Please read the file README.txt for more general STK information.
It seems that SGI systems are not distributed with the GNU Makefile utilities. The default Make utility has very limited functionality, so your safest bet is to download the GNU Makefile utilities from the Internet and use STK's default Makefile. If this is not possible, try using Makefile.sgi (make -f Makefile.sgi).
Another issue that has crept up with this release is proper compiler support for C++ error handling. If you experience problems, you probably don't have a recent version of the C++ compiler. Otherwise, STK should compile and run on SGI platforms without any problems.
NOTE REGARDING PTHREADS:
Since release 3.1, STK has used the pthread API under Irix. It appears that pthread functionality is standard on SGI, so this change shouldn't cause any problems. If I'm wrong, let me know!

69
doc/README-Win.txt Normal file
View File

@@ -0,0 +1,69 @@
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
Version 3.2
By Perry R. Cook, 1995-2000
and Gary P. Scavone, 1997-2000.
Please read the file README.txt for more general STK information.
DirectX and WindowsNT Issues:
-----------------------------
STK is currently distributed with Visual C++ 6.0 project and workspace files.
The STK realtime sound input capabilities under Windoze are only supported using the DirectSoundCapture API. The latency is pretty horrendous, but what do you expect? Also, there is a chance you don't have DirectSoundCapture support on your computer. If not, you should download the DirectX 6.0 (or higher) runtime libraries from Microsoft's WWW site (http://www.microsoft.com/directx/download.asp) in order to run the pre-compiled STK executables for Windoze. The last time I checked, there was no DirectSoundCapture support for WindowsNT ... you'll have to switch to Windows 2000. I stopped supporting the WinMM audio output code with this release. So, if you wish to compile STK under WindowsNT (without realtime audio input support), you'll have to download an older version of STK, uncomment the __WINMM_API_ flag (and comment out the __WINDS_API flag) in Object.h and recompile the source code.
Realtime sound output under Windoze is supported using the DirectSound (dsound.lib) API. All new versions of Win95/98/NT come with the DirectSound library, but early versions did not. If you have trouble running the distributed executables, then you probably don't have DirectSound installed on your system. You can download the necessary DirectSound stuff from Microsoft's WWW pages (http://www.microsoft.com/directx/download.asp).
Realtime MIDI input is supported using the winmm.lib API.
Visual C++ 6.0 workspaces have been created for the various STK projects. Everything has already been configured for you. The intermediate .obj files will be written to either the "Release" or "Debug" directories, but the executable files will be written to the main project directories (where they need to be for proper execution). If you should somehow lose or hose the VC++ workspace file (STK.dsw), then you will have to do a LOT of configuring to recreate it ... it's probably easier just to download the distribution again from our WWW sites. Anyway, for your benefit and mine, here is a list of things that need to be added to the various "Project Settings":
1. Under General: Set "Output files:" to <blank> (this will put the executable in the main project directory.
2. Under C/C++ > Code Generation: Set "Use run-time library:" to Multithreaded (use "debug" versions for the debug configuration).
3. Under Link > General: Add winmm.lib, dsound.lib, and Wsock32.lib to the end of the Object/library modules list.
4. Under C/C++ > Preprocessor: Add "../../include" directory to the "extra include" field.
5. Add all the necessary files to the project.
Remember that items 1-3 above need to be done for each project and for each configuration. There might be an easy way to make global changes, but I couldn't figure it out.
To use the Tcl/Tk GUIs, you will have to install Tcl/Tk. I got version 8.0 and it works very well (and installed easily). The distribution is available on the WWW and is free.
In order for socketing to work, it is necessary to have the TCP protocol installed on your computer. This can be done from the "Network" control panel.
Finally, to use it all -
PLAY SKINI SCOREFILES IN REALTIME:
syntmono Clarinet -or < scores/streetsf.ski
USE TCL/TK GUIs FOR REALTIME CONTROL:
1. Open a DOS console window and start syntmono (eg. syntmono Clarinet -or -is).
2. Double click on a Tcl/Tk file in TCLSpecs (eg. TCLPhys.tcl) from the Windows Explorer to start the GUI. Select the "communications" menu item and "Socket" and make the connection.
3. Start moving the sliders to control the instrument.
USE REALTIME MIDI INPUT FOR CONTROL:
1. Open a DOS console window and start syntmono with MIDI input (eg. syntmono Clarinet -or -im).
This assumes you already have MIDI setup correctly for your computer.
WINDOWS NT ONLY:
Realtime piping seems to work under WindowsNT in much the same way as on Unix platforms. Thus, it is possible to pipe realtime control data to syntmono under WindowsNT as well.
WINDOWS 2000:
I don't have Windows 2000 and I doubt I'll get it anytime soon. However, we briefly tested release 3.2 of STK on Perry's Win2000 machine and it worked fine. There is an advantage in using Windows 2000 over 95/98 in that piping works, just as under unix. Also, the scheduler in Win2000 seems to be much better, so socketed messages don't get clumped together like they do in Win 95/98. Since 2000 is supposed to ship with DirectX 7.0, the DirectSoundCapture functionality should work as well.

128
doc/README.txt Normal file
View File

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

90
doc/ReleaseNotes.txt Normal file
View File

@@ -0,0 +1,90 @@
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
Release 3.2
By Perry R. Cook, 1995-2000
and Gary P. Scavone, 1997-2000
v3.2: (13 November 2000)
- new control handling class (Controller)
- added AIFF file input/output support
- stklib.a Makefile in src directory
- added C++ error handling capabilities
- added input/output internet streaming support (StrmWvIn/StrmWvOut)
- added native ALSA support for linux
- added optional "device" argument to all "Rt" classes (audio and MIDI) and printout of devices when argument is invalid
- WvIn classes rewritten to support very big files (incremental load from disk)
- changed WvIn/WvOut classes to work with sample frame buffers
- fixed looping and negative rate calculations in WvIn classes
- fixed interpolation bug in RtWvIn
- windoze RtAudio code rewritten (thanks Dave!)
- simplified byte-swapping functions (in-place swapping)
- new FIR filter class (thanks Julius!)
- "stereo-ized" RagaMatic
- probably a bunch more fixes that I've long since forgotten about
v3.1: (13 March 2000)
- new RagaMatic project!!!
- added "microphone position" to Mandolin in STKdemo
- fixed MIDI system message exclusion under Irix
- added a few bitmaps for the Shaker instruments
- made destructors virtual for Reverb.h, WvIn.h and Simple.h
- fixed bug setting delay length in DLineA when value too big
- fixed bug in WinMM realtime code (RTSoundIO)
- added tick() method to BowTabl, JetTabl, and ReedTabl (same as lookup)
- switched to pthread API on SGI platforms
- added some defines to Object.h for random number generation, FPU overflow checking, etc...
- a lot of minor changes, some bug fixes ... can't remember all of them
v3.0: (10 October 1999)
- new #define flags for OS and realtime dependencies (this will probably cause problems for most everyone, but it was necessary to make future ports easier)
- fixed Linux MIDI input bug
- fixed MIDI status masking problem in Windows
- OS type defines now in Makefile
- new RAWWAVE_PATH define in Object.h
- syntmono pulled out to separate directory and cleaned up
- socketing capabilities under Unix, as well as Windoze
- multiple simultaneous socket client connections to STK servers now possible
- MD2SKINI now can merge MIDI and piped messages under Irix and Linux (for TCL->MD2SKINI->syntmono control)
- defined INT16 and INT32 types and fixed various WvIn and WvOut classes
- updated MatWvIn and MatWvOut for new MAT-file documentation from Matlab
- new demo GUI
- minor fixes to FM behavior
- added record/duplex capabilities to RTSoundIO (Linux, SGI, and Windoze)
- fixed bugs in WavWvOut and MatWvOut header specifications
- added RawWvOut class
- new WvIn class with RawWvIn, SndWvIn, WavWvIn, MatWvIn, and RTWvIn subclasses
- removed RawWave, RawShot, RawInterp, and RawLoop classes (supplanted by RawWvIn)
- multi-channel data support in WvIn and WvOut classes using MY_MULTI data type (pointer to MY_FLOAT) and the methods mtick() and mlastOutput()
- now writing to primary buffer under Windoze when allowed by hardware
- cleaned up Object.h a bit
- pulled various utility and thread functions out of syntmono.cpp (to aid readability of the code)
v2.02: (16 November 1998)
- created RawWave abstract class, with subclasses of RawLoop (looping rawwave oscillator), RawShot (non-looping, non-interpolating rawwave player ... used to be RawWvIn), and RawInterp (looping or non-looping, interpolating rawwave player ... used to be RawWave).
- modified DrumSynt to correctly handle sample rates different than 22050 Hz.
- modified syntmono parsing vs. tick routine so that some ticking occurs between each message. When multiple messages are waiting to be processed, the time between message updates is inversely proportional to the number of messages in the buffer.
- fixed DirectSound playback bug in Win distribution. Sound was being played at 8-bit, 22 kHz in all cases. Playback is now 16-bit and dependent on SRATE.
- fixed bug in MD2SKINI which prevented some NoteOff statements from being output.
v2.01: (27 July 1998)
- Corrected extraneous ^M line return characters that were incompatible with SGI.
v2.0: (20 July 1998)
- The first true release by Gary, with unified capabilities across SGI, Linux, and Win platforms. See WWW pages (http://www-ccrma.stanford.edu/CCRMA/Software/STK/) for more info.
v1.1:
- More linux support and other changes that happened so long ago that I can't remember anymore. Never officially released.
v1.0:
- Linux support added with the help of Tim Stilson. Never officially released.
v0.8:
- One of (if not THE) original distributions for SGI, NeXTStep, and basic Win support. I think this came out in 1996.

395
doc/SKINI11.txt Normal file
View File

@@ -0,0 +1,395 @@
This describes the 1.1 implementation of SKINI,
updated for the 2.x release of STK:
Synthesis toolKit Instrument Network Interface
for the Synthesis Toolkit in C++ by Perry R. Cook
and Gary Scavone, 1999.
*********************************
* Too good to be true? *
* Have control and read it too? *
* A SKINI Haiku. *
*********************************
Profound thanks to Dan Trueman, Brad Garton, and
Gary Scavone for input on this revision. Thanks
also to MIDI, the NeXT MusicKit, ZIPI and all
the creators and modifiers of these for good bases
upon/from which to build and depart.
1) MIDI Compatibility
SKINI was designed to be MIDI compatible wherever possible,
and extend MIDI in incremental, then maybe profound ways.
Differences from MIDI, and motivations, include:
Text-based messages are used, with meaningful names
wherever possible. This allows any language or system
capable of formatted printing to generate SKINI.
Similarly, any system capable of reading in a string
and turning delimited fields into strings, floats,
and ints can consume SKINI for control. More importantly,
humans can actually read, and even write if they want,
SKINI files and streams. Use an editor and search/
replace or macros to change a channel or control number.
Load a SKINI score into a spread sheet to apply
transformations to time, control parameters, MIDI
velocities, etc. Put a monkey on a special typewriter
and get your next great work. Life's too short to debug
bit/nybble packed variable length mumble messages. Disk
space gets cheaper, available bandwidth increases, music
takes up so little space and bandwidth compared to video
and grapics. Live a little.
Floating point numbers are used wherever possible.
Note Numbers, Velocities, Controller Values, and
Delta and Absolute Times are all represented and
scanned as ASCII double-precision floats. MIDI byte
values are preserved, so that incoming MIDI bytes
from an interface can be put directly into SKINI
messages. 60.0 or 60 is middle C, 127.0 or 127 is
maximum velocity etc. But, unlike MIDI, 60.5 can
cause a 50cent sharp middle C to be played. As with
MIDI byte values like velocity, use of the integer and
SKINI-added fractional parts is up to the implementor
of the algorithm being controlled by SKINI messages.
But the extra precision is there to be used or ignored.
2) WHY SKINI?
SKINI was designed to be extensable and hackable for a number
of applications: imbedded synthesis in a game or VR simulation,
scoring and mixing tasks, real-time and non-real time applications
which could benefit from controllable sound synthesis,
JAVA controlled synthesis, or eventually maybe JAVA synthesis,
etc. SKINI is not intended to be "the mother of scorefiles,"
but since the entire system is based on text representations
of names, floats, and ints, converters from one scorefile
language to SKINI, or back, should be easily created.
I am basically a bottom-up designer with an awareness of top-
down design ideas, so SKINI above all reflects the needs of my
particular research and creative projects as they have arisen and
developed. SKINI11 represents a profound advance beyond SKINI08
and SKINI09 (the first versions), future SKINI's might
reflect some changes. Compatibility with prior scorefiles
will be attempted, but there aren't that many scorefiles out
there yet.
3) SKINI MESSAGES
A basic SKINI message is a line of text. There are only three
required fields, the message type (an ASCII name), the time (either
delta or absolute), and the channel number. Don't freak out and
think that this is MIDI channel 0-15 (which is supported), because
the channel number is scanned as a long int. Channels could be socket
numbers, machine IDs, serial numbers, or even unique tags for each
event in a synthesis. Other fields might be used, as specified in the
SKINI11.tbl file. This is described in more detail later.
Fields in a SKINI line are delimited by spaces, commas, or
tabs. The SKINI parser only operates on a line at a time,
so a newline means the message is over. Multiple messages are
NOT allowed directly on a single line (by use of the ; for
example in C). This could be supported, but it isn't in
version 1.1.
Message types include standard MIDI types like NoteOn, NoteOff,
ControlChange, etc. MIDI extension message types (messages
which look better than MIDI but actually get turned into
MIDI-like messages) include LipTension, StringDamping, etc.
NonMIDI message types include SetPath (sets a path for file
use later), and OpenReadFile (for streaming, mixing, and applying
effects to soundfiles along with synthesis, for example).
Other NonMIDI message types include Trilling, HammerOn, etc. (these
translate to gestures, behaviors, and contexts for use by
intellegent players and instruments using SKINI). Where possible
I will still use these as MIDI extension messages, so foot
switches, etc. can be used to control them in real time.
All fields other than type, time, and channel are optional, and the
types and useage of the additional fields is defined in the file
SKINI11.tbl.
The other important file used by SKINI is SKINI11.msg, which is a
set of #defines to make C code more readable, and to allow reasonably
quick re-mapping of control numbers, etc.. All of these defined
symbols are assigned integer values. For JAVA, the #defines could
be replaced by declaration and assignment statements, preserving
the look and behavior of the rest of the code.
4) C Files Used To Implement SKINI11
SKINI11.cpp is an object which can either open a SKINI file, and
successively read and parse lines of text as SKINI strings, or
accept strings from another object and parse them. The latter
functionality would be used by a socket, pipe, or other connection
receiving SKINI messages a line at a time, usually in real time,
but not restricted to real time.
SKINI11.msg should be included by anything wanting to use the
SKINI11.cpp object. This is not mandatory, but use of the __SK_blah_
symbols which are defined in the .msg file will help to ensure
clarity and consistency when messages are added and changed.
SKINI11.tbl is used only by the SKINI parser object (SKINI11.cpp).
In the file SKINI11.tbl, an array of structures is declared and
assigned values which instruct the parser as to what the message
types are, and what the fields mean for those message types.
This table is compiled and linked into applications using SKINI, but
could be dynamically loaded and changed in a future version of
SKINI.
5) SKINI Messages and the SKINI Parser:
The parser isn't all that smart, but neither am I. Here are the
basic rules governing a valid SKINI message:
a) If the first (non-delimiter (see c)) character in a SKINI
string is '/' that line is treated as a comment and echoed
to stdout.
b) If there are no characters on a line, that line is treated
as blank and echoed to stdout. Tabs and spaces are treated
as non-characters.
c) Spaces, commas, and tabs delimit the fields in a SKINI
message line. (We might allow for multiple messages per
line later using the semicolon, but probably not. A series
of lines with deltaTimes of 0.0 denotes simultaneous events.
For Readability, multiple messages per line doesn't help much,
so it's unlikely to be supported later).
d) The first field must be a SKINI message name. (like NoteOn).
These might become case-insensitive in SKINI11+, so don't plan
on exciting clever overloading of names (like noTeOn being
different from NoTeON). There can be a number of leading
spaces or tabs, but don't exceed 32 or so.
e) The second field must be a time specification in seconds.
For real-time applications, this field can be 0.0. A time
field can be either delta-time (most common and the only one
supported in SKINI0.8), or absolute time. Absolute time
messages have an '=' appended to the beginning of the floating
point number with no space. So 0.10000 means delta time of
100ms., while =0.10000 means absolute time of 100 ms. Absolute
time messages make most sense in score files, but could also be
used for (loose) synchronization in a real-time context. Real
time messages should be time-ordered AND time-correct. That is,
if you've sent 100 total delta-time messages of 1.0 seconds, and
then send an absolute time message of =90.0 seconds, or if you
send two absolute time messages of =100.0 and =90.0 in that
order, things will get really fouled up. The SKINI1.1 parser
doesn't know about time, however. The WvOut device is the
master time keeper in the Synthesis Toolkit, so it should be
queried to see if absolute time messages are making sense.
There's an example of how to do that later in this document.
Absolute times are returned by the parser as negative numbers
(since negative deltaTimes are not allowed).
f) The third field must be an integer channel number. Don't go
crazy and think that this is just MIDI channel 0-15 (which is
supported). The channel number is scanned as a long int. Channels
0-15 are in general to be treated as MIDI channels. After that
it's wide open. Channels could be socket numbers, machine IDs,
serial numbers, or even unique tags for each event in a synthesis.
A -1 channel can be used as don't care, omni, or other functions
depending on your needs and taste.
g) All remaining fields are specified in the SKINI11.tbl file.
In general, there are maximum two more fields, which are either
SK_INT (long), SK_DBL (double float), or SK_STR (string). The
latter is the mechanism by which more arguments can be specified
on the line, but the object using SKINI must take that string
apart (retrived by using getRemainderString()) and scan it.
Any excess fields are stashed in remainderString.
6) A Short SKINI File:
/* Howdy!!! Welcome to SKINI11, by P. Cook 1999
NoteOn 0.000082 2 55 82
NoteOff 1.000000 2 55 0
NoteOn 0.000082 2 69 82
StringDetune 0.100000 2 10
StringDetune 0.100000 2 30
StringDetune 0.100000 2 50
NoteOn 0.000000 2 69 82
StringDetune 0.100000 2 40
StringDetune 0.100000 2 22
StringDetune 0.100000 2 12
//
StringDamping 0.000100 2 0.0
NoteOn 0.000082 2 55 82
NoteOn 0.200000 2 62 82
NoteOn 0.100000 2 71 82
NoteOn 0.200000 2 79 82
NoteOff 1.000000 2 55 82
NoteOff 0.000000 2 62 82
NoteOff 0.000000 2 71 82
NoteOff 0.000000 2 79 82
StringDamping =4.000000 2 0.0
NoteOn 0.000082 2 55 82
NoteOn 0.200000 2 62 82
NoteOn 0.100000 2 71 82
NoteOn 0.200000 2 79 82
NoteOff 1.000000 2 55 82
NoteOff 0.000000 2 62 82
NoteOff 0.000000 2 71 82
NoteOff 0.000000 2 79 82
7) The SKINI11.tbl File, How Messages are Parsed
The SKINI11.tbl file contains an array of structures which
are accessed by the parser object SKINI11.cpp. The struct is:
struct SKINISpec { char messageString[32];
long type;
long data2;
long data3;
};
so an assignment of one of these structs looks like:
MessageStr$ ,type, data2, data3,
type is the message type sent back from the SKINI line parser.
data<n> is either
NOPE : field not used, specifically, there aren't going
to be any more fields on this line. So if there
is is NOPE in data2, data3 won't even be checked
SK_INT : byte (actually scanned as 32 bit signed long int)
If it's a MIDI data field which is required to
be an integer, like a controller number, it's
0-127. Otherwise) get creative with SK_INTs
SK_DBL : double precision floating point. SKINI uses these
in the MIDI context for note numbers with micro
tuning, velocities, controller values, etc.
SK_STR : only valid in final field. This allows (nearly)
arbitrary message types to be supported by simply
scanning the string to EndOfLine and then passing
it to a more intellegent handler. For example,
MIDI SYSEX (system exclusive) messages of up to
256bytes can be read as space-delimited integers
into the 1K SK_STR buffer. Longer bulk dumps,
soundfiles, etc. should be handled as a new
message type pointing to a FileName, Socket, or
something else stored in the SK_STR field, or
as a new type of multi-line message.
Here's a couple of lines from the SKINI11.tbl file
{"NoteOff" , __SK_NoteOff_, SK_DBL, SK_DBL},
{"NoteOn" , __SK_NoteOn_, SK_DBL, SK_DBL},
{"ControlChange" , __SK_ControlChange_, SK_INT, SK_DBL},
{"Volume" , __SK_ControlChange_, __SK_Volume_ , SK_DBL},
{"StringDamping" , __SK_ControlChange_, __SK_StringDamping_ , SK_DBL},
{"StringDetune" , __SK_ControlChange_, __SK_StringDetune_ , SK_DBL},
The first three are basic MIDI messages. The first two would cause the
parser, after recognizing a match of the string "NoteOff" or "NoteOn",
to set the message type to 128 or 144 (__SK_NoteOff_ and __SK_NoteOn_
are #defined in the file SKINI11.msg to be the MIDI byte value, without
channel, of the actual MIDI messages for NoteOn and NoteOff). The parser
would then set the time or delta time (this is always done and is
therefore not described in the SKINI Message Struct). The next two
fields would be scanned as double-precision floats and assigned to
the byteTwo and byteThree variables of the SKINI parser. The remainder
of the line is stashed in the remainderString variable.
The ControlChange spec is basically the same as NoteOn and NoteOff, but
the second data byte is set to an integer (for checking later as to
what MIDI control is being changed).
The Volume spec is a MIDI Extension message, which behaves like a
ControlChange message with the controller number set explicitly to
the value for MIDI Volume (7). Thus the following two lines would
accomplish the same changing of MIDI volume on channel 2:
ControlChange 0.000000 2 7 64.1
Volume 0.000000 2 64.1
I like the 2nd line better, thus my motivation for SKINI in the first
place.
The StringDamping and StringDetune messages behave the same as
the Volume message, but use Control Numbers which aren't specifically
nailed-down in MIDI. Note that these Control Numbers are carried
around as long ints, so we're not limited to 0-127. If, however,
you want to use a MIDI controller to play an instrument, using
controller numbers in the 0-127 range might make sense.
8) Objects using SKINI
Here's a simple example of code which uses the SKINI object
to read a SKINI file and control a single instrument.
instrument = new Mandolin(50.0);
score = new SKINI11(argv[1]);
while(score->getType() > 0) {
tempDouble = score->getDelta();
if (tempDouble < 0) {
tempDouble = - tempDouble;
tempDouble = tempDouble - output.getTime();
if (tempDouble < 0) {
printf("Bad News Here!!! Backward Absolute Time
Required.\n");
tempDouble = 0.0;
}
}
tempLong = (long) (tempDouble * SRATE);
for (i=0;i<tempLong;i++) {
output.tick(instrument->tick());
}
tempDouble3 = score->getByteThree();
if (score->getType()== __SK_NoteOn_ ) {
tempDouble3 *= NORM_7;
if (score->getByteThree() == 0) {
tempDouble3 = 0.5;
instrument->noteOff(tempDouble3);
}
else {
tempLong = (int) score->getByteTwo();
tempDouble2 = __MIDI_To_Pitch[tempLong];
instrument->noteOn(tempDouble2,tempDouble3);
}
}
else if (score->getType() == __SK_NoteOff_) {
tempDouble3 *= NORM_7;
instrument->noteOff(tempDouble3);
}
else if (score->getType() == __SK_ControlChange_) {
tempLong = score->getByteTwoInt();
instrument->controlChange(tempLong,temp3.0);
}
score->nextMessage();
}
When the score (SKINI11 object) object is created from the
filename in argv[1], the first valid command line is read
from the file and parsed.
The score->getType() retrieves the messageType. If this is
-1, there are no more valid messages in the file and the
synthesis loop terminates. Otherwise, the message type is
returned.
getDelta() retrieves the deltaTime until the current message
should occur. If this is greater than 0, synthesis occurs
until the deltaTime has elapsed. If deltaTime is less than
zero, the time is interpreted as absolute time and the output
device is queried as to what time it is now. That is used to
form a deltaTime, and if it's positive we synthesize. If
it's negative, we print an error and pretend this never
happened and we hang around hoping to eventually catch up.
The rest of the code sorts out message types NoteOn, NoteOff
(including NoteOn with velocity 0), and ControlChange. The
code implicitly takes into account the integer type of the
control number, but all other data is treated as double float.
The last line reads and parses the next message in the file.

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