mirror of
https://github.com/thestk/stk
synced 2026-01-14 13:31:53 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f126af4e5 | ||
|
|
4b6500d3de | ||
|
|
868787a5f9 |
76
AgogoBel.cpp
76
AgogoBel.cpp
@@ -1,76 +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"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
AgogoBel :: AgogoBel() : Modal4()
|
||||
{
|
||||
wave = new RawInterp("rawwaves/britestk.raw");
|
||||
wave->normalize();
|
||||
wave->setRate((MY_FLOAT) 7.0); /* hardstick */
|
||||
this->setRatioAndReson(0, (MY_FLOAT) 1.00,(MY_FLOAT) 0.999); /* Set our */
|
||||
this->setRatioAndReson(1, (MY_FLOAT) 4.08,(MY_FLOAT) 0.999); /* resonances */
|
||||
this->setRatioAndReson(2,(MY_FLOAT) 6.669,(MY_FLOAT) 0.999); /* here */
|
||||
this->setRatioAndReson(3,(MY_FLOAT) -3725.0, (MY_FLOAT)0.999); /* (One fixed) */
|
||||
this->setFiltGain(0,(MY_FLOAT) 0.06); /* And filter */
|
||||
this->setFiltGain(1,(MY_FLOAT) 0.05); /* gains too */
|
||||
this->setFiltGain(2,(MY_FLOAT) 0.03);
|
||||
this->setFiltGain(3,(MY_FLOAT) 0.02);
|
||||
directGain = (MY_FLOAT) 0.25;
|
||||
}
|
||||
|
||||
AgogoBel :: ~AgogoBel()
|
||||
{
|
||||
delete wave;
|
||||
}
|
||||
|
||||
void AgogoBel :: setStickHardness(MY_FLOAT hardness)
|
||||
{
|
||||
stickHardness = hardness; /* To an approximation, */
|
||||
wave->setRate((MY_FLOAT) 3.0 + ((MY_FLOAT) 8.0 * stickHardness)); /* hardness <-> center */
|
||||
masterGain = (MY_FLOAT) 1.0; /* freq and amplitude */
|
||||
}
|
||||
|
||||
void AgogoBel :: setStrikePosition(MY_FLOAT position)
|
||||
{
|
||||
MY_FLOAT temp,temp2;
|
||||
temp2 = position * PI;
|
||||
strikePosition = position; /* Hack only first */
|
||||
temp = (MY_FLOAT) sin(0.7 * temp2); /* three modes, */
|
||||
this->setFiltGain(0,(MY_FLOAT) 0.08 * temp); /* leave the other */
|
||||
temp = (MY_FLOAT) sin(0.1 + (5.0 * temp2)); /* fixed. Why? */
|
||||
this->setFiltGain(1,(MY_FLOAT) 0.07 * temp); /* So it doesn't */
|
||||
temp = (MY_FLOAT) sin(0.2 + (7.0 * temp2)); /* sound like a */
|
||||
this->setFiltGain(2,(MY_FLOAT) 0.04 * temp); /* sample! */
|
||||
}
|
||||
|
||||
void AgogoBel :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("AgogoBel : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_StickHardness_)
|
||||
this->setStickHardness(value * NORM_7);
|
||||
else if (number == __SK_StrikePosition_)
|
||||
this->setStrikePosition(value * NORM_7);
|
||||
else if (number == __SK_ModFrequency_)
|
||||
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
|
||||
else if (number == __SK_ModWheel_)
|
||||
vibrGain = (value * NORM_7);
|
||||
else if (number == __SK_AfterTouch_Cont_)
|
||||
this->strike(value * NORM_7);
|
||||
else {
|
||||
printf("AgogoBel : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
26
AgogoBel.h
26
AgogoBel.h
@@ -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
|
||||
80
BiQuad.cpp
80
BiQuad.cpp
@@ -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] = (MY_FLOAT) 0.0;
|
||||
zeroCoeffs[1] = (MY_FLOAT) 0.0;
|
||||
poleCoeffs[0] = (MY_FLOAT) 0.0;
|
||||
poleCoeffs[1] = (MY_FLOAT) 0.0;
|
||||
gain = (MY_FLOAT) 1.0;
|
||||
this->clear();
|
||||
}
|
||||
|
||||
BiQuad :: ~BiQuad()
|
||||
{
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
void BiQuad :: clear()
|
||||
{
|
||||
inputs[0] = (MY_FLOAT) 0.0;
|
||||
inputs[1] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void BiQuad :: setPoleCoeffs(MY_FLOAT *coeffs)
|
||||
{
|
||||
poleCoeffs[0] = coeffs[0];
|
||||
poleCoeffs[1] = coeffs[1];
|
||||
}
|
||||
|
||||
void BiQuad :: setZeroCoeffs(MY_FLOAT *coeffs)
|
||||
{
|
||||
zeroCoeffs[0] = coeffs[0];
|
||||
zeroCoeffs[1] = coeffs[1];
|
||||
}
|
||||
|
||||
void BiQuad :: setFreqAndReson(MY_FLOAT freq, MY_FLOAT reson)
|
||||
{
|
||||
poleCoeffs[1] = - (reson * reson);
|
||||
poleCoeffs[0] = (MY_FLOAT) 2.0 * reson * (MY_FLOAT) cos(TWO_PI * freq / SRATE);
|
||||
}
|
||||
|
||||
void BiQuad :: setEqualGainZeroes()
|
||||
{
|
||||
zeroCoeffs[1] = (MY_FLOAT) -1.0;
|
||||
zeroCoeffs[0] = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void BiQuad :: setGain(MY_FLOAT aValue)
|
||||
{
|
||||
gain = aValue;
|
||||
}
|
||||
|
||||
MY_FLOAT BiQuad :: tick(MY_FLOAT sample) /* Perform Filter Operation */
|
||||
{ /* Biquad is two pole, two zero filter */
|
||||
MY_FLOAT temp; /* Look it up in your favorite DSP text */
|
||||
|
||||
temp = sample * gain; /* Here's the math for the */
|
||||
temp += inputs[0] * poleCoeffs[0]; /* version which implements */
|
||||
temp += inputs[1] * poleCoeffs[1]; /* only 2 state variables. */
|
||||
|
||||
lastOutput = temp; /* This form takes */
|
||||
lastOutput += (inputs[0] * zeroCoeffs[0]); /* 5 multiplies and */
|
||||
lastOutput += (inputs[1] * zeroCoeffs[1]); /* 4 adds */
|
||||
inputs[1] = inputs[0]; /* and 3 moves */
|
||||
inputs[0] = temp; /* like the 2 state-var form*/
|
||||
|
||||
return lastOutput;
|
||||
|
||||
}
|
||||
|
||||
31
BiQuad.h
31
BiQuad.h
@@ -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
|
||||
46
BowTabl.cpp
46
BowTabl.cpp
@@ -1,46 +0,0 @@
|
||||
/***********************************************/
|
||||
/* Simple Bow Table Object, after Smith */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/***********************************************/
|
||||
|
||||
#include "BowTabl.h"
|
||||
|
||||
BowTabl :: BowTabl()
|
||||
{
|
||||
offSet = (MY_FLOAT) 0.0; /* offset is a bias, really not needed unless */
|
||||
/* friction is different in each direction */
|
||||
slope = (MY_FLOAT) 0.1; /* controls width of friction pulse, */
|
||||
/* related to bowForce */
|
||||
}
|
||||
|
||||
BowTabl :: ~BowTabl()
|
||||
{
|
||||
}
|
||||
|
||||
void BowTabl :: setOffset(MY_FLOAT aValue)
|
||||
{
|
||||
offSet = aValue;
|
||||
}
|
||||
|
||||
void BowTabl :: setSlope(MY_FLOAT aValue)
|
||||
{
|
||||
slope = aValue;
|
||||
}
|
||||
|
||||
MY_FLOAT BowTabl :: lookup(MY_FLOAT sample) /* Perform Table Lookup */
|
||||
{ /* sample is differential */
|
||||
/* string vs. bow velocity */
|
||||
MY_FLOAT input;
|
||||
input = sample + offSet; /* add bias to sample */
|
||||
input *= slope; /* scale it */
|
||||
lastOutput = (MY_FLOAT) fabs((double) input) + (MY_FLOAT) 0.75; /* below min delta, friction = 1 */
|
||||
lastOutput = (MY_FLOAT) pow(lastOutput,(MY_FLOAT) -4.0);
|
||||
// if (lastOutput < 0.0 ) lastOutput = 0.0; /* minimum friction is 0.0 */
|
||||
if (lastOutput > 1.0 ) lastOutput = (MY_FLOAT) 1.0; /* maximum friction is 1.0 */
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT BowTabl :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
22
BowTabl.h
22
BowTabl.h
@@ -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();
|
||||
};
|
||||
|
||||
161
Bowed.cpp
161
Bowed.cpp
@@ -1,161 +0,0 @@
|
||||
/******************************************/
|
||||
/* Bowed String model ala Smith */
|
||||
/* after McIntyre, Schumacher, Woodhouse */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* */
|
||||
/* This is a waveguide model, and thus */
|
||||
/* relates to various Stanford Univ. */
|
||||
/* and possibly Yamaha and other patents.*/
|
||||
/* */
|
||||
/* Controls: CONTROL1 = bowPressure */
|
||||
/* CONTROL2 = bowPosition */
|
||||
/* CONTROL3 = vibrFreq */
|
||||
/* MOD_WHEEL= vibrGain */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#include "Bowed.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
Bowed :: Bowed(MY_FLOAT lowestFreq)
|
||||
{
|
||||
long length;
|
||||
length = (long) (SRATE / lowestFreq + 1);
|
||||
neckDelay = new DLineL(length);
|
||||
length >>= 1;
|
||||
bridgeDelay = new DLineL(length);
|
||||
bowTabl = new BowTabl;
|
||||
reflFilt = new OnePole;
|
||||
bodyFilt = new BiQuad;
|
||||
vibr = new RawLoop("rawwaves/sinewave.raw");
|
||||
adsr = new ADSR;
|
||||
vibrGain = (MY_FLOAT) 0.0;
|
||||
|
||||
neckDelay->setDelay((MY_FLOAT) 100.0);
|
||||
bridgeDelay->setDelay((MY_FLOAT) 29.0);
|
||||
|
||||
bowTabl->setSlope((MY_FLOAT) 3.0);
|
||||
|
||||
reflFilt->setPole((MY_FLOAT) (0.6 - (0.1 * 22050.0 / SRATE)));
|
||||
reflFilt->setGain((MY_FLOAT) 0.95);
|
||||
|
||||
bodyFilt->setFreqAndReson((MY_FLOAT) 500.0, (MY_FLOAT) 0.85);
|
||||
bodyFilt->setEqualGainZeroes();
|
||||
bodyFilt->setGain((MY_FLOAT) 0.2);
|
||||
|
||||
vibr->normalize();
|
||||
vibr->setFreq((MY_FLOAT) 6.12723);
|
||||
|
||||
adsr->setAllTimes((MY_FLOAT) 0.02,(MY_FLOAT) 0.005,(MY_FLOAT) 0.9,(MY_FLOAT) 0.01);
|
||||
|
||||
betaRatio = (MY_FLOAT) 0.127236;
|
||||
}
|
||||
|
||||
Bowed :: ~Bowed()
|
||||
{
|
||||
delete neckDelay;
|
||||
delete bridgeDelay;
|
||||
delete bowTabl;
|
||||
delete reflFilt;
|
||||
delete bodyFilt;
|
||||
delete vibr;
|
||||
delete adsr;
|
||||
}
|
||||
|
||||
void Bowed :: clear()
|
||||
{
|
||||
neckDelay->clear();
|
||||
bridgeDelay->clear();
|
||||
}
|
||||
|
||||
void Bowed :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseDelay = SRATE / frequency - (MY_FLOAT) 4.0; /* delay - approx. filter delay */
|
||||
bridgeDelay->setDelay(baseDelay * betaRatio); /* bow to bridge length */
|
||||
neckDelay->setDelay(baseDelay * ((MY_FLOAT) 1.0 - betaRatio)); /* bow to nut (finger) length */
|
||||
}
|
||||
|
||||
void Bowed :: startBowing(MY_FLOAT amplitude, MY_FLOAT rate)
|
||||
{
|
||||
adsr->setRate(rate);
|
||||
adsr->keyOn();
|
||||
maxVelocity = (MY_FLOAT) 0.03 + ((MY_FLOAT) 0.2 * amplitude);
|
||||
}
|
||||
|
||||
void Bowed :: stopBowing(MY_FLOAT rate)
|
||||
{
|
||||
adsr->setRate(rate);
|
||||
adsr->keyOff();
|
||||
}
|
||||
|
||||
void Bowed :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->startBowing(amp,amp * (MY_FLOAT) 0.001);
|
||||
this->setFreq(freq);
|
||||
#if defined(_debug_)
|
||||
printf("Bowed : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Bowed :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
this->stopBowing(((MY_FLOAT) 1.0 - amp) * (MY_FLOAT) 0.005);
|
||||
#if defined(_debug_)
|
||||
printf("Bowed : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Bowed :: setVibrato(MY_FLOAT amount)
|
||||
{
|
||||
vibrGain = amount;
|
||||
}
|
||||
|
||||
MY_FLOAT Bowed :: tick()
|
||||
{
|
||||
MY_FLOAT bowVelocity;
|
||||
MY_FLOAT bridgeRefl=(MY_FLOAT) 0,nutRefl=(MY_FLOAT) 0;
|
||||
MY_FLOAT newVel=(MY_FLOAT) 0,velDiff=(MY_FLOAT) 0,stringVel=(MY_FLOAT) 0;
|
||||
|
||||
bowVelocity = maxVelocity * adsr->tick();
|
||||
|
||||
bridgeRefl = -reflFilt->tick(
|
||||
bridgeDelay->lastOut()); /* Bridge Reflection */
|
||||
nutRefl = -neckDelay->lastOut(); /* Nut Reflection */
|
||||
stringVel = bridgeRefl + nutRefl; /* Sum is String Velocity */
|
||||
velDiff = bowVelocity - stringVel; /* Differential Velocity */
|
||||
newVel = velDiff * bowTabl->lookup(velDiff); /* Non-Lin Bow Function */
|
||||
neckDelay->tick(bridgeRefl + newVel); /* Do string */
|
||||
bridgeDelay->tick(nutRefl + newVel); /* propagations */
|
||||
|
||||
if (vibrGain > 0.0) {
|
||||
neckDelay->setDelay((baseDelay * ((MY_FLOAT) 1.0 - betaRatio)) +
|
||||
(baseDelay * vibrGain*vibr->tick()));
|
||||
}
|
||||
|
||||
lastOutput = bodyFilt->tick(bridgeDelay->lastOut());
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void Bowed :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Bowed : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_BowPressure_)
|
||||
bowTabl->setSlope((MY_FLOAT) 5.0 - ((MY_FLOAT) 4.0 * value * NORM_7));
|
||||
else if (number == __SK_BowPosition_) {
|
||||
betaRatio = (MY_FLOAT) 0.027236 + ((MY_FLOAT) 0.2 * value * NORM_7);
|
||||
bridgeDelay->setDelay(baseDelay * betaRatio); /* bow to bridge length */
|
||||
neckDelay->setDelay(baseDelay * ((MY_FLOAT) 1.0 - betaRatio)); /* bow to nut (finger) length */
|
||||
}
|
||||
else if (number == __SK_ModFrequency_)
|
||||
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
|
||||
else if (number == __SK_ModWheel_)
|
||||
vibrGain = (value * NORM_7 * (MY_FLOAT) 0.4);
|
||||
else if (number == __SK_AfterTouch_Cont_)
|
||||
adsr->setTarget(value * NORM_7);
|
||||
else {
|
||||
printf("Bowed : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
56
Bowed.h
56
Bowed.h
@@ -1,56 +0,0 @@
|
||||
/******************************************/
|
||||
/* Bowed String model ala Smith */
|
||||
/* after McIntyre, Schumacher, Woodhouse */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* */
|
||||
/* This is a waveguide model, and thus */
|
||||
/* relates to various Stanford Univ. */
|
||||
/* and possibly Yamaha and other patents.*/
|
||||
/* */
|
||||
/* Controls: CONTROL1 = bowPressure */
|
||||
/* CONTROL2 = bowPosition */
|
||||
/* CONTROL3 = vibrFreq */
|
||||
/* MOD_WHEEL= vibrGain */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__Bowed_h)
|
||||
#define __Bowed_h
|
||||
|
||||
#include "Instrmnt.h"
|
||||
#include "DLineL.h"
|
||||
#include "BowTabl.h"
|
||||
#include "OnePole.h"
|
||||
#include "BiQuad.h"
|
||||
#include "RawLoop.h"
|
||||
#include "ADSR.h"
|
||||
|
||||
class Bowed : public Instrmnt
|
||||
{
|
||||
protected:
|
||||
DLineL *neckDelay;
|
||||
DLineL *bridgeDelay;
|
||||
BowTabl *bowTabl;
|
||||
OnePole *reflFilt;
|
||||
BiQuad *bodyFilt;
|
||||
RawLoop *vibr;
|
||||
ADSR *adsr;
|
||||
MY_FLOAT maxVelocity;
|
||||
MY_FLOAT baseDelay;
|
||||
MY_FLOAT vibrGain;
|
||||
MY_FLOAT betaRatio;
|
||||
public:
|
||||
Bowed(MY_FLOAT lowestFreq);
|
||||
~Bowed();
|
||||
void clear();
|
||||
void startBowing(MY_FLOAT amplitude,MY_FLOAT rate);
|
||||
void stopBowing(MY_FLOAT rate);
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
virtual void noteOff(MY_FLOAT amp);
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
void setVibrato(MY_FLOAT amount);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
virtual MY_FLOAT tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
131
Brass.cpp
131
Brass.cpp
@@ -1,131 +0,0 @@
|
||||
/******************************************/
|
||||
/* Waveguide Brass Instrument Model ala */
|
||||
/* Cook (TBone, HosePlayer) */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* This is a waveguide model, and thus */
|
||||
/* relates to various Stanford Univ. */
|
||||
/* and possibly Yamaha and other patents.*/
|
||||
/* */
|
||||
/* Controls: CONTROL1 = lipTension */
|
||||
/* CONTROL2 = slideLength */
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/******************************************/
|
||||
|
||||
#include "Brass.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
Brass :: Brass(MY_FLOAT lowestFreq)
|
||||
{
|
||||
length = (long) (SRATE / lowestFreq + 1);
|
||||
delayLine = new DLineA(length);
|
||||
lipFilter = new LipFilt;
|
||||
dcBlock = new DCBlock;
|
||||
adsr = new ADSR;
|
||||
adsr->setAllTimes((MY_FLOAT) 0.005, (MY_FLOAT) 0.001, (MY_FLOAT) 1.0, (MY_FLOAT) 0.010);
|
||||
vibr = new RawLoop("rawwaves/sinewave.raw");
|
||||
this->clear();
|
||||
|
||||
vibr->normalize();
|
||||
vibr->setFreq((MY_FLOAT) 6.137);
|
||||
vibrGain = (MY_FLOAT) 0.05; /* breath periodic vibrato component */
|
||||
|
||||
maxPressure = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
Brass :: ~Brass()
|
||||
{
|
||||
delete delayLine;
|
||||
delete lipFilter;
|
||||
delete dcBlock;
|
||||
delete adsr;
|
||||
delete vibr;
|
||||
}
|
||||
|
||||
void Brass :: clear()
|
||||
{
|
||||
delayLine->clear();
|
||||
lipFilter->clear();
|
||||
dcBlock->clear();
|
||||
}
|
||||
|
||||
void Brass :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
slideTarget = (SRATE / frequency * (MY_FLOAT) 2.0) + (MY_FLOAT) 3.0;
|
||||
/* fudge correction for filter delays */
|
||||
delayLine->setDelay(slideTarget); /* we'll play a harmonic */
|
||||
lipTarget = frequency;
|
||||
lipFilter->setFreq(frequency);
|
||||
}
|
||||
|
||||
void Brass :: setLip(MY_FLOAT frequency)
|
||||
{
|
||||
lipFilter->setFreq(frequency);
|
||||
}
|
||||
|
||||
void Brass :: startBlowing(MY_FLOAT amplitude,MY_FLOAT rate)
|
||||
{
|
||||
adsr->setAttackRate(rate);
|
||||
maxPressure = amplitude;
|
||||
adsr->keyOn();
|
||||
}
|
||||
|
||||
void Brass :: stopBlowing(MY_FLOAT rate)
|
||||
{
|
||||
adsr->setReleaseRate(rate);
|
||||
adsr->keyOff();
|
||||
}
|
||||
|
||||
void Brass :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->setFreq(freq);
|
||||
this->startBlowing(amp, amp * (MY_FLOAT) 0.001);
|
||||
#if defined(_debug_)
|
||||
printf("Brass : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Brass :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
this->stopBlowing(amp * (MY_FLOAT) 0.005);
|
||||
#if defined(_debug_)
|
||||
printf("Brass : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
MY_FLOAT Brass :: tick()
|
||||
{
|
||||
MY_FLOAT breathPressure;
|
||||
|
||||
breathPressure = maxPressure * adsr->tick();
|
||||
breathPressure += vibrGain * vibr->tick();
|
||||
lastOutput = delayLine->tick( /* bore delay */
|
||||
dcBlock->tick( /* block DC */
|
||||
lipFilter->tick((MY_FLOAT) 0.3 * breathPressure, /* mouth input */
|
||||
(MY_FLOAT) 0.85 * delayLine->lastOut()))); /* and bore reflection */
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void Brass :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
#if defined(_debug_)
|
||||
printf("Brass : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_LipTension_) {
|
||||
temp = lipTarget * (MY_FLOAT) pow(4.0,(2.0*value*NORM_7) - 1.0);
|
||||
this->setLip(temp);
|
||||
}
|
||||
else if (number == __SK_SlideLength_)
|
||||
delayLine->setDelay(slideTarget * ((MY_FLOAT) 0.5 + (value * NORM_7)));
|
||||
else if (number == __SK_ModFrequency_)
|
||||
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
|
||||
else if (number == __SK_ModWheel_ )
|
||||
vibrGain = (value * NORM_7 * (MY_FLOAT) 0.4);
|
||||
else if (number == __SK_AfterTouch_Cont_)
|
||||
adsr->setTarget(value * NORM_7);
|
||||
else {
|
||||
printf("Brass : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
105
DLineA.cpp
105
DLineA.cpp
@@ -1,105 +0,0 @@
|
||||
/*******************************************/
|
||||
/* */
|
||||
/* AllPass Interpolating Delay Line */
|
||||
/* Object by Perry R. Cook 1995-96 */
|
||||
/* This one uses a delay line of maximum */
|
||||
/* length specified on creation, and */
|
||||
/* interpolates fractional length using */
|
||||
/* an all-pass filter. This version is */
|
||||
/* more efficient for computing static */
|
||||
/* length delay lines (alpha and coeff */
|
||||
/* are computed only when the length */
|
||||
/* is set, there probably is a more */
|
||||
/* efficient computational form if alpha */
|
||||
/* is changed often (each sample)). */
|
||||
/* */
|
||||
/*******************************************/
|
||||
|
||||
#include "DLineA.h"
|
||||
|
||||
DLineA :: DLineA(long max_length)
|
||||
{
|
||||
long i;
|
||||
length = max_length;
|
||||
inputs = (MY_FLOAT *) malloc(length * MY_FLOAT_SIZE);
|
||||
for (i=0;i<length;i++) inputs[i] = (MY_FLOAT) 0;
|
||||
this->clear();
|
||||
inPoint = 0;
|
||||
outPoint = length >> 1;
|
||||
}
|
||||
|
||||
DLineA :: ~DLineA()
|
||||
{
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
void DLineA :: clear()
|
||||
{
|
||||
long i;
|
||||
for (i=0;i<length;i++) inputs[i] = (MY_FLOAT) 0.0;
|
||||
lastIn = (MY_FLOAT) 0;
|
||||
lastOutput = (MY_FLOAT) 0;
|
||||
}
|
||||
|
||||
void DLineA :: setDelay(MY_FLOAT lag)
|
||||
{
|
||||
MY_FLOAT outputPointer;
|
||||
outputPointer = inPoint - lag + 2; /* outPoint chases inpoint */
|
||||
/* + 2 for interp and other */
|
||||
while (outputPointer<0)
|
||||
outputPointer += length; /* modulo table length */
|
||||
outPoint = (long) outputPointer; /* Integer part of delay */
|
||||
alpha = (MY_FLOAT) 1.0 + outPoint - outputPointer; /* fractional part of delay */
|
||||
if (alpha<0.1) {
|
||||
outputPointer += (MY_FLOAT) 1.0;/* Hack to avoid pole/zero */
|
||||
outPoint += 1; /* cancellation. Keeps allpass */
|
||||
alpha += (MY_FLOAT) 1.0; /* delay in range of .1 to 1.1 */
|
||||
}
|
||||
coeff = ((MY_FLOAT) 1.0 - alpha) /
|
||||
((MY_FLOAT) 1.0 + alpha); /* coefficient for all pass */
|
||||
}
|
||||
|
||||
MY_FLOAT DLineA :: tick(MY_FLOAT sample) /* Take sample, yield sample */
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
inputs[inPoint++] = sample; /* Write input sample */
|
||||
if (inPoint == length) /* Increment input pointer */
|
||||
inPoint -= length; /* modulo length */
|
||||
temp = inputs[outPoint++]; /* filter input */
|
||||
if (outPoint == length) /* Increment output pointer */
|
||||
outPoint -= length; /* modulo length */
|
||||
lastOutput = -coeff * lastOutput; /* delayed output */
|
||||
lastOutput += lastIn + (coeff * temp); /* input + delayed Input */
|
||||
lastIn = temp;
|
||||
return lastOutput; /* save output and return */
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
|
||||
void main()
|
||||
{
|
||||
DLineA delay(140);
|
||||
FILE *fd;
|
||||
MY_FLOAT temp;
|
||||
short data;
|
||||
long i;
|
||||
|
||||
fd = fopen("test.raw","wb");
|
||||
|
||||
delay.setDelay(128);
|
||||
for (i=0;i<4096;i++) {
|
||||
if (i%256 != 0) temp = 0.0; else temp = 1.0;
|
||||
data = (temp + delay.tick(temp)) * 16000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
delay.setDelay(64.5);
|
||||
for (i=0;i<4096;i++) {
|
||||
if (i%256 != 0) temp = 0.0; else temp = 1.0;
|
||||
data = (temp + delay.tick(temp)) * 16000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
90
DLineL.cpp
90
DLineL.cpp
@@ -1,90 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Linearly Interpolating Delay Line */
|
||||
/* Object by Perry R. Cook 1995-96 */
|
||||
/* This one uses a delay line of maximum */
|
||||
/* length specified on creation, and */
|
||||
/* linearly interpolates fractional */
|
||||
/* length. It is designed to be more */
|
||||
/* efficient if the delay length is not */
|
||||
/* changed very often. */
|
||||
/*******************************************/
|
||||
|
||||
#include "DLineL.h"
|
||||
|
||||
DLineL :: DLineL(long max_length)
|
||||
{
|
||||
length = max_length;
|
||||
inputs = (MY_FLOAT *) malloc(length * MY_FLOAT_SIZE);
|
||||
this->clear();
|
||||
outPoint = 0;
|
||||
inPoint = length >> 1;
|
||||
}
|
||||
|
||||
DLineL :: ~DLineL()
|
||||
{
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
void DLineL :: clear()
|
||||
{
|
||||
long i;
|
||||
for (i=0;i<length;i++) inputs[i] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0;
|
||||
}
|
||||
|
||||
void DLineL :: setDelay(MY_FLOAT lag)
|
||||
{
|
||||
MY_FLOAT outputPointer;
|
||||
outputPointer = inPoint - lag; /* read chases write, add 1 for interp. */
|
||||
while (outputPointer<0)
|
||||
outputPointer += length; /* modulo maximum length */
|
||||
outPoint = (long) outputPointer; /* integer part */
|
||||
alpha = outputPointer - outPoint; /* fractional part */
|
||||
omAlpha = (MY_FLOAT) 1.0 - alpha; /* 1.0 - fractional part (more efficient) */
|
||||
}
|
||||
|
||||
MY_FLOAT DLineL :: tick(MY_FLOAT sample) /* Take one, yield one */
|
||||
{
|
||||
inputs[inPoint++] = sample; /* Input next sample */
|
||||
if (inPoint == length) /* Check for end condition */
|
||||
inPoint -= length;
|
||||
lastOutput = inputs[outPoint++] * omAlpha; /* first 1/2 of interpolation */
|
||||
if (outPoint<length) { /* Check for end condition */
|
||||
lastOutput += inputs[outPoint] * alpha; /* second 1/2 of interpolation */
|
||||
}
|
||||
else { /* if at end . . . */
|
||||
lastOutput += inputs[0] * alpha; /* second 1/2 of interpolation */
|
||||
outPoint -= length;
|
||||
}
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
|
||||
void main()
|
||||
{
|
||||
DLineL delay(140);
|
||||
FILE *fd;
|
||||
MY_FLOAT temp;
|
||||
short data;
|
||||
long i;
|
||||
|
||||
fd = fopen("test.raw","wb");
|
||||
|
||||
delay.setDelay(128);
|
||||
for (i=0;i<4096;i++) {
|
||||
if (i%256 != 0) temp = 0.0; else temp = 1.0;
|
||||
data = (temp + delay.tick(temp)) * 16000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
delay.setDelay(64.5);
|
||||
for (i=0;i<4096;i++) {
|
||||
if (i%256 != 0) temp = 0.0; else temp = 1.0;
|
||||
data = (temp + delay.tick(temp)) * 16000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
33
DLineL.h
33
DLineL.h
@@ -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
|
||||
80
DLineN.cpp
80
DLineN.cpp
@@ -1,80 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Non-Interpolating Delay Line */
|
||||
/* Object by Perry R. Cook 1995-96 */
|
||||
/* This one uses a delay line of maximum */
|
||||
/* length specified on creation. A non- */
|
||||
/* interpolating delay line should be */
|
||||
/* used in non-time varying (reverb) or */
|
||||
/* non-critical (????) applications. */
|
||||
/*******************************************/
|
||||
|
||||
#include "DLineN.h"
|
||||
|
||||
DLineN :: DLineN(long max_length)
|
||||
{
|
||||
length = max_length;
|
||||
inputs = (MY_FLOAT *) malloc(length * MY_FLOAT_SIZE);
|
||||
this->clear();
|
||||
this->setDelay(length * (MY_FLOAT) 0.5);
|
||||
inPoint = 0;
|
||||
outPoint = 0;
|
||||
}
|
||||
|
||||
DLineN :: ~DLineN()
|
||||
{
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
void DLineN :: clear()
|
||||
{
|
||||
long i;
|
||||
for (i=0;i<length;i++) inputs[i] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0;
|
||||
}
|
||||
|
||||
void DLineN :: setDelay(MY_FLOAT lag)
|
||||
{
|
||||
outPoint = inPoint - (long) lag; /* read chases write */
|
||||
while (outPoint<0) outPoint += length; /* modulo maximum length */
|
||||
}
|
||||
|
||||
MY_FLOAT DLineN :: tick(MY_FLOAT sample) /* Take one, yield one */
|
||||
{
|
||||
inputs[inPoint++] = sample; /* Input next sample */
|
||||
if (inPoint == length) /* Check for end condition */
|
||||
inPoint -= length;
|
||||
lastOutput = inputs[outPoint++]; // first 1/2 of interpolation */
|
||||
if (outPoint>=length) { // Check for end condition */
|
||||
outPoint -= length;
|
||||
}
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
void main()
|
||||
{
|
||||
DLineN delay(140);
|
||||
FILE *fd;
|
||||
MY_FLOAT temp;
|
||||
short data;
|
||||
long i;
|
||||
|
||||
fd = fopen("test.raw","wb");
|
||||
|
||||
delay.setDelay(128);
|
||||
for (i=0;i<4096;i++) {
|
||||
if (i%256 != 0) temp = 0.0; else temp = 1.0;
|
||||
data = (temp + delay.tick(temp)) * 16000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
delay.setDelay(64.5);
|
||||
for (i=0;i<4096;i++) {
|
||||
if (i%256 != 0) temp = 0.0; else temp = 1.0;
|
||||
data = (temp + delay.tick(temp)) * 16000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
31
DLineN.h
31
DLineN.h
@@ -1,31 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Non-Interpolating Delay Line */
|
||||
/* Object by Perry R. Cook 1995-96 */
|
||||
/* This one uses a delay line of maximum */
|
||||
/* length specified on creation. A non- */
|
||||
/* interpolating delay line should be */
|
||||
/* used in non-time varying (reverb) or */
|
||||
/* non-critical (????) applications. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__DLineN_h)
|
||||
#define __DLineN_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class DLineN : public Filter
|
||||
{
|
||||
protected:
|
||||
long inPoint;
|
||||
long outPoint;
|
||||
long length;
|
||||
public:
|
||||
DLineN(long max_length);
|
||||
~DLineN();
|
||||
void clear();
|
||||
void setDelay(MY_FLOAT length);
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
180
FM4Op.cpp
180
FM4Op.cpp
@@ -1,180 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Master Class for 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This instrument contains 4 waves, */
|
||||
/* 4 adsr, and various state vars. */
|
||||
/* */
|
||||
/* The basic Chowning/Stanford FM patent */
|
||||
/* expired April 1995, but there exist */
|
||||
/* follow-on patents, mostly assigned to */
|
||||
/* Yamaha. If you are of the type who */
|
||||
/* should worry about this (making money) */
|
||||
/* worry away. */
|
||||
/* */
|
||||
/*******************************************/
|
||||
|
||||
#include "FM4Op.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
FM4Op :: FM4Op()
|
||||
{
|
||||
int i;
|
||||
MY_FLOAT temp;
|
||||
MY_FLOAT tempCoeffs[2] = {(MY_FLOAT) 0.0, (MY_FLOAT) -1.0};
|
||||
adsr[0] = new ADSR;
|
||||
adsr[1] = new ADSR;
|
||||
adsr[2] = new ADSR;
|
||||
adsr[3] = new ADSR;
|
||||
twozero = new TwoZero;
|
||||
vibWave = new RawLoop("rawwaves/sinewave.raw");
|
||||
vibWave->normalize();
|
||||
vibWave->setFreq((MY_FLOAT) 6.0); /* should make this random?? */
|
||||
modDepth = (MY_FLOAT) 0.0;
|
||||
/* We don't make the waves here yet, because */
|
||||
/* we don't know what they will be. */
|
||||
baseFreq = (MY_FLOAT) 440.0;
|
||||
ratios[0] = (MY_FLOAT) 1.0;
|
||||
ratios[1] = (MY_FLOAT) 1.0;
|
||||
ratios[2] = (MY_FLOAT) 1.0;
|
||||
ratios[3] = (MY_FLOAT) 1.0;
|
||||
gains[0] = (MY_FLOAT) 1.0;
|
||||
gains[1] = (MY_FLOAT) 1.0;
|
||||
gains[2] = (MY_FLOAT) 1.0;
|
||||
gains[3] = (MY_FLOAT) 1.0;
|
||||
twozero->setZeroCoeffs(tempCoeffs);
|
||||
twozero->setGain((MY_FLOAT) 0.0);
|
||||
control1 = (MY_FLOAT) 1.0;
|
||||
control2 = (MY_FLOAT) 1.0;
|
||||
temp = (MY_FLOAT) 1.0;
|
||||
for (i=99;i>=0;i--) {
|
||||
__FM4Op_gains[i] = temp;
|
||||
temp *= (MY_FLOAT) 0.933033;
|
||||
}
|
||||
temp = (MY_FLOAT) 1.0;
|
||||
for (i=15;i>=0;i--) {
|
||||
__FM4Op_susLevels[i] = temp;
|
||||
temp *= (MY_FLOAT) 0.707101;
|
||||
}
|
||||
temp = (MY_FLOAT) 8.498186;
|
||||
for (i=0;i<32;i++) {
|
||||
__FM4Op_attTimes[i] = temp;
|
||||
temp *= (MY_FLOAT) 0.707101;
|
||||
}
|
||||
}
|
||||
|
||||
FM4Op :: ~FM4Op()
|
||||
{
|
||||
delete adsr[0];
|
||||
delete adsr[1];
|
||||
delete adsr[2];
|
||||
delete adsr[3];
|
||||
delete waves[0];
|
||||
delete waves[1];
|
||||
delete waves[2];
|
||||
delete waves[3];
|
||||
delete vibWave;
|
||||
delete twozero;
|
||||
}
|
||||
|
||||
void FM4Op :: loadWaves(char* wave1, char* wave2, char* wave3, char* wave4)
|
||||
{
|
||||
int i;
|
||||
waves[0] = new RawLoop(wave1);
|
||||
waves[1] = new RawLoop(wave2);
|
||||
waves[2] = new RawLoop(wave3);
|
||||
waves[3] = new RawLoop(wave4);
|
||||
for (i=0;i<4;i++) {
|
||||
waves[i]->normalize();
|
||||
}
|
||||
}
|
||||
void FM4Op :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
waves[0]->setFreq(baseFreq * ratios[0]);
|
||||
waves[1]->setFreq(baseFreq * ratios[1]);
|
||||
waves[2]->setFreq(baseFreq * ratios[2]);
|
||||
waves[3]->setFreq(baseFreq * ratios[3]);
|
||||
}
|
||||
|
||||
void FM4Op :: setRatio(int whichOne, MY_FLOAT ratio)
|
||||
{
|
||||
ratios[whichOne] = ratio;
|
||||
if (ratio>0.0)
|
||||
waves[whichOne]->setFreq(baseFreq * ratio);
|
||||
else
|
||||
waves[whichOne]->setFreq(ratio);
|
||||
}
|
||||
|
||||
void FM4Op :: setGain(int whichOne, MY_FLOAT gain)
|
||||
{
|
||||
gains[whichOne]=gain;
|
||||
}
|
||||
|
||||
void FM4Op :: keyOn()
|
||||
{
|
||||
adsr[0]->keyOn();
|
||||
adsr[1]->keyOn();
|
||||
adsr[2]->keyOn();
|
||||
adsr[3]->keyOn();
|
||||
}
|
||||
|
||||
void FM4Op :: keyOff()
|
||||
{
|
||||
adsr[0]->keyOff();
|
||||
adsr[1]->keyOff();
|
||||
adsr[2]->keyOff();
|
||||
adsr[3]->keyOff();
|
||||
}
|
||||
|
||||
void FM4Op :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
this->keyOff();
|
||||
#if defined(_debug_)
|
||||
printf("FM4Op : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FM4Op :: setModulationSpeed(MY_FLOAT mSpeed)
|
||||
{
|
||||
vibWave->setFreq(mSpeed);
|
||||
}
|
||||
|
||||
void FM4Op :: setModulationDepth(MY_FLOAT mDepth)
|
||||
{
|
||||
modDepth = mDepth;
|
||||
}
|
||||
|
||||
void FM4Op :: setControl1(MY_FLOAT cVal)
|
||||
{
|
||||
control1 = cVal * (MY_FLOAT) 2.0;
|
||||
}
|
||||
|
||||
void FM4Op :: setControl2(MY_FLOAT cVal)
|
||||
{
|
||||
control2 = cVal * (MY_FLOAT) 2.0;
|
||||
}
|
||||
|
||||
void FM4Op :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("FM4Op : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_Breath_)
|
||||
this->setControl1(value * NORM_7);
|
||||
else if (number == __SK_FootControl_)
|
||||
this->setControl2(value * NORM_7);
|
||||
else if (number == __SK_ModFrequency_)
|
||||
this->setModulationSpeed(value * NORM_7 * (MY_FLOAT) 12.0); /* 0 to 12 Hz */
|
||||
else if (number == __SK_ModWheel_)
|
||||
this->setModulationDepth(value * NORM_7);
|
||||
else if (number == __SK_AfterTouch_Cont_) {
|
||||
adsr[0]->setTarget(value * NORM_7);
|
||||
adsr[1]->setTarget(value * NORM_7);
|
||||
adsr[2]->setTarget(value * NORM_7);
|
||||
adsr[3]->setTarget(value * NORM_7);
|
||||
}
|
||||
else {
|
||||
printf("FM4Op : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
59
FM4Op.h
59
FM4Op.h
@@ -1,59 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Master Class for 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This instrument contains an 4 waves, */
|
||||
/* 4 envelopes, and various state vars. */
|
||||
/* */
|
||||
/* The basic Chowning/Stanford FM patent */
|
||||
/* expired April 1995, but there exist */
|
||||
/* follow-on patents, mostly assigned to */
|
||||
/* Yamaha. If you are of the type who */
|
||||
/* should worry about this (making money) */
|
||||
/* worry away. */
|
||||
/* */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__FM4Op_h)
|
||||
#define __FM4Op_h
|
||||
|
||||
#include "Instrmnt.h"
|
||||
#include "ADSR.h"
|
||||
#include "RawLoop.h"
|
||||
#include "TwoZero.h"
|
||||
|
||||
class FM4Op : public Instrmnt
|
||||
{
|
||||
protected:
|
||||
ADSR *adsr[4];
|
||||
RawLoop *waves[4];
|
||||
RawLoop *vibWave;
|
||||
TwoZero *twozero;
|
||||
MY_FLOAT baseFreq;
|
||||
MY_FLOAT ratios[4];
|
||||
MY_FLOAT gains[4];
|
||||
MY_FLOAT modDepth;
|
||||
MY_FLOAT control1;
|
||||
MY_FLOAT control2;
|
||||
MY_FLOAT __FM4Op_gains[100];
|
||||
MY_FLOAT __FM4Op_susLevels[16];
|
||||
MY_FLOAT __FM4Op_attTimes[32];
|
||||
public:
|
||||
FM4Op();
|
||||
virtual ~FM4Op();
|
||||
void loadWaves(char* wave1, char* wave2, char* wave3, char* wave4);
|
||||
void clear();
|
||||
void setFreq(MY_FLOAT frequency);
|
||||
void setRatio(int whichOne, MY_FLOAT ratio);
|
||||
void setGain(int whichOne, MY_FLOAT gain);
|
||||
void keyOn();
|
||||
void keyOff();
|
||||
void noteOff(MY_FLOAT amp);
|
||||
/* There's no tick() method here, because that depends on the algorithm */
|
||||
void setModulationSpeed(MY_FLOAT mSpeed);
|
||||
void setModulationDepth(MY_FLOAT mDepth);
|
||||
void setControl1(MY_FLOAT cVal);
|
||||
void setControl2(MY_FLOAT cVal);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
};
|
||||
|
||||
#endif
|
||||
175
Flute.cpp
175
Flute.cpp
@@ -1,175 +0,0 @@
|
||||
/******************************************/
|
||||
/* WaveGuide Flute ala Karjalainen, */
|
||||
/* Smith, Waryznyk, etc. */
|
||||
/* with polynomial Jet ala Cook */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* */
|
||||
/* This is a waveguide model, and thus */
|
||||
/* relates to various Stanford Univ. */
|
||||
/* and possibly Yamaha and other patents.*/
|
||||
/* */
|
||||
/* Controls: CONTROL1 = jetDelay */
|
||||
/* CONTROL2 = noiseGain */
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/******************************************/
|
||||
|
||||
#include "Flute.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
Flute :: Flute(MY_FLOAT lowestFreq)
|
||||
{
|
||||
long length;
|
||||
length = (long) (SRATE / lowestFreq + 1);
|
||||
boreDelay = new DLineL(length);
|
||||
length >>= 1;
|
||||
jetDelay = new DLineL(length);
|
||||
jetTable = new JetTabl;
|
||||
filter = new OnePole;
|
||||
dcBlock = new DCBlock;
|
||||
noise = new Noise;
|
||||
adsr = new ADSR;
|
||||
vibr = new RawLoop("rawwaves/sinewave.raw");
|
||||
this->clear();
|
||||
|
||||
boreDelay->setDelay((MY_FLOAT) 100.0);
|
||||
jetDelay->setDelay((MY_FLOAT) 49.0);
|
||||
|
||||
filter->setPole((MY_FLOAT) 0.7 - ((MY_FLOAT) 0.1 * (MY_FLOAT) 22050.0 / SRATE));
|
||||
filter->setGain((MY_FLOAT) -1.0);
|
||||
vibr->normalize();
|
||||
vibr->setFreq((MY_FLOAT) 5.925);
|
||||
adsr->setAllTimes((MY_FLOAT) 0.005, (MY_FLOAT) 0.01, (MY_FLOAT) 0.8, (MY_FLOAT) 0.010);
|
||||
endRefl = (MY_FLOAT) 0.5;
|
||||
jetRefl = (MY_FLOAT) 0.5;
|
||||
noiseGain = (MY_FLOAT) 0.15; /* Breath pressure random component */
|
||||
vibrGain = (MY_FLOAT) 0.05; /* breath periodic vibrato component */
|
||||
jetRatio = (MY_FLOAT) 0.32;
|
||||
|
||||
maxPressure = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
Flute :: ~Flute()
|
||||
{
|
||||
delete jetDelay;
|
||||
delete boreDelay;
|
||||
delete jetTable;
|
||||
delete filter;
|
||||
delete dcBlock;
|
||||
delete noise;
|
||||
delete adsr;
|
||||
delete vibr;
|
||||
}
|
||||
|
||||
void Flute :: clear()
|
||||
{
|
||||
jetDelay->clear();
|
||||
boreDelay->clear();
|
||||
filter->clear();
|
||||
dcBlock->clear();
|
||||
/* adsr->reset(); */
|
||||
}
|
||||
|
||||
void Flute :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
lastFreq = frequency * (MY_FLOAT) 0.66666; /* we're overblowing here */
|
||||
temp = SRATE / lastFreq - (MY_FLOAT) 2.0; /* Length - approx. filter delay */
|
||||
boreDelay->setDelay(temp); /* Length of bore tube */
|
||||
jetDelay->setDelay(temp * jetRatio); /* jet delay shorter */
|
||||
}
|
||||
|
||||
void Flute :: startBlowing(MY_FLOAT amplitude, MY_FLOAT rate)
|
||||
{
|
||||
adsr->setAttackRate(rate);
|
||||
maxPressure = amplitude / (MY_FLOAT) 0.8;
|
||||
adsr->keyOn();
|
||||
}
|
||||
|
||||
void Flute :: stopBlowing(MY_FLOAT rate)
|
||||
{
|
||||
adsr->setReleaseRate(rate);
|
||||
adsr->keyOff();
|
||||
}
|
||||
|
||||
void Flute :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->setFreq(freq);
|
||||
this->startBlowing((MY_FLOAT) 1.1 + (amp * (MY_FLOAT) 0.20),amp * (MY_FLOAT) 0.02);
|
||||
outputGain = amp + (MY_FLOAT) 0.001;
|
||||
#if defined(_debug_)
|
||||
printf("Flute : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Flute :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
this->stopBlowing(amp * (MY_FLOAT) 0.02);
|
||||
#if defined(_debug_)
|
||||
printf("Flute : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Flute :: setJetRefl(MY_FLOAT refl)
|
||||
{
|
||||
jetRefl = refl;
|
||||
}
|
||||
|
||||
void Flute :: setEndRefl(MY_FLOAT refl)
|
||||
{
|
||||
endRefl = refl;
|
||||
}
|
||||
|
||||
void Flute :: setJetDelay(MY_FLOAT aRatio)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
temp = SRATE / lastFreq - (MY_FLOAT) 2.0; /* Length - approx. filter delay */
|
||||
jetRatio = aRatio;
|
||||
jetDelay->setDelay(temp * aRatio); /* Scaled by ratio */
|
||||
}
|
||||
|
||||
MY_FLOAT Flute :: tick()
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
MY_FLOAT pressureDiff;
|
||||
MY_FLOAT randPressure;
|
||||
MY_FLOAT breathPressure;
|
||||
|
||||
breathPressure = maxPressure * adsr->tick(); /* Breath Pressure */
|
||||
randPressure = noiseGain * noise->tick(); /* Random Deviation */
|
||||
randPressure += vibrGain * vibr->tick(); /* + breath vibrato */
|
||||
randPressure *= breathPressure; /* All scaled by Breath Pressure */
|
||||
|
||||
temp = filter->tick(boreDelay->lastOut());
|
||||
temp = dcBlock->tick(temp); /* Block DC on reflection */
|
||||
pressureDiff = breathPressure + randPressure - /* Breath Pressure */
|
||||
(jetRefl * temp); /* - reflected */
|
||||
pressureDiff = jetDelay->tick(pressureDiff); /* Jet Delay Line */
|
||||
pressureDiff = jetTable->lookup(pressureDiff) /* Non-Lin Jet + reflected */
|
||||
+ (endRefl * temp);
|
||||
lastOutput = (MY_FLOAT) 0.3 * boreDelay->tick(pressureDiff); /* Bore Delay and "bell" filter */
|
||||
|
||||
lastOutput *= outputGain;
|
||||
return lastOutput;
|
||||
|
||||
}
|
||||
|
||||
void Flute :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Flute : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_JetDelay_)
|
||||
this->setJetDelay((MY_FLOAT) 0.08 + ((MY_FLOAT) 0.48 * value * NORM_7));
|
||||
else if (number == __SK_NoiseLevel_)
|
||||
noiseGain = (value * NORM_7 * (MY_FLOAT) 0.4);
|
||||
else if (number == __SK_ModFrequency_)
|
||||
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
|
||||
else if (number == __SK_ModWheel_)
|
||||
vibrGain = (value * NORM_7 * (MY_FLOAT) 0.4);
|
||||
else if (number == __SK_AfterTouch_Cont_)
|
||||
adsr->setTarget(value * NORM_7);
|
||||
else {
|
||||
printf("Flute : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
64
Flute.h
64
Flute.h
@@ -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
|
||||
176
FormSwep.cpp
176
FormSwep.cpp
@@ -1,176 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Sweepable Formant (2-pole) */
|
||||
/* Filter Class, by Perry R. Cook, 1995-96*/
|
||||
/* See books on filters to understand */
|
||||
/* more about how this works. This drives*/
|
||||
/* to a target at speed set by rate. */
|
||||
/*******************************************/
|
||||
|
||||
#include "FormSwep.h"
|
||||
|
||||
FormSwep :: FormSwep() : Filter()
|
||||
{
|
||||
outputs = (MY_FLOAT *) malloc(2 * MY_FLOAT_SIZE);
|
||||
poleCoeffs[0] = (MY_FLOAT) 0.0;
|
||||
poleCoeffs[1] = (MY_FLOAT) 0.0;
|
||||
gain = (MY_FLOAT) 1.0;
|
||||
freq = (MY_FLOAT) 0.0;
|
||||
reson = (MY_FLOAT) 0.0;
|
||||
currentGain = (MY_FLOAT) 1.0;
|
||||
currentFreq = (MY_FLOAT) 0.0;
|
||||
currentReson = (MY_FLOAT) 0.0;
|
||||
targetGain = (MY_FLOAT) 1.0;
|
||||
targetFreq = (MY_FLOAT) 0.0;
|
||||
targetReson = (MY_FLOAT) 0.0;
|
||||
deltaGain = (MY_FLOAT) 0.0;
|
||||
deltaFreq = (MY_FLOAT) 0.0;
|
||||
deltaReson = (MY_FLOAT) 0.0;
|
||||
sweepState = (MY_FLOAT) 0.0;
|
||||
sweepRate = (MY_FLOAT) 0.002;
|
||||
dirty = 0;
|
||||
this->clear();
|
||||
}
|
||||
|
||||
FormSwep :: ~FormSwep()
|
||||
{
|
||||
free(outputs);
|
||||
}
|
||||
|
||||
void FormSwep :: clear()
|
||||
{
|
||||
outputs[0] = (MY_FLOAT) 0.0;
|
||||
outputs[1] = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void FormSwep :: setPoleCoeffs(MY_FLOAT *coeffs)
|
||||
{
|
||||
dirty = 0;
|
||||
poleCoeffs[0] = coeffs[0];
|
||||
poleCoeffs[1] = coeffs[1];
|
||||
}
|
||||
|
||||
void FormSwep :: setFreqAndReson(MY_FLOAT aFreq, MY_FLOAT aReson)
|
||||
{
|
||||
dirty = 0;
|
||||
reson = aReson;
|
||||
freq = aFreq;
|
||||
currentReson = aReson;
|
||||
currentFreq = aFreq;
|
||||
poleCoeffs[1] = - (reson * reson);
|
||||
poleCoeffs[0] = (MY_FLOAT) 2.0 * reson * (MY_FLOAT) cos(TWO_PI * freq / SRATE);
|
||||
}
|
||||
|
||||
void FormSwep :: setStates(MY_FLOAT aFreq, MY_FLOAT aReson, MY_FLOAT aGain)
|
||||
{
|
||||
dirty = 0;
|
||||
freq = aFreq;
|
||||
reson = aReson;
|
||||
gain = aGain;
|
||||
targetFreq = aFreq;
|
||||
targetReson = aReson;
|
||||
targetGain = aGain;
|
||||
currentFreq = aFreq;
|
||||
currentReson = aReson;
|
||||
currentGain = aGain;
|
||||
}
|
||||
|
||||
void FormSwep :: setTargets(MY_FLOAT aFreq, MY_FLOAT aReson, MY_FLOAT aGain)
|
||||
{
|
||||
dirty = 1;
|
||||
targetFreq = aFreq;
|
||||
targetReson = aReson;
|
||||
targetGain = aGain;
|
||||
deltaFreq = aFreq - currentFreq;
|
||||
deltaReson = aReson - currentReson;
|
||||
deltaGain = aGain - currentGain;
|
||||
sweepState = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void FormSwep :: setSweepRate(MY_FLOAT aRate)
|
||||
{
|
||||
sweepRate = aRate;
|
||||
}
|
||||
|
||||
void FormSwep :: setSweepTime(MY_FLOAT aTime)
|
||||
{
|
||||
sweepRate = ONE_OVER_SRATE / aTime;
|
||||
}
|
||||
|
||||
void FormSwep :: setGain(MY_FLOAT aValue)
|
||||
{
|
||||
gain = aValue;
|
||||
}
|
||||
|
||||
MY_FLOAT FormSwep :: tick(MY_FLOAT sample) /* Perform Filter Operation */
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
|
||||
if (dirty) {
|
||||
sweepState += sweepRate;
|
||||
if (sweepState>= 1.0) {
|
||||
sweepState = (MY_FLOAT) 1.0;
|
||||
dirty = 0;
|
||||
currentReson = targetReson;
|
||||
reson = targetReson;
|
||||
currentFreq = targetFreq;
|
||||
freq = targetFreq;
|
||||
currentGain = targetGain;
|
||||
gain = targetGain;
|
||||
}
|
||||
else {
|
||||
currentReson = reson + (deltaReson * sweepState);
|
||||
currentFreq = freq + (deltaFreq * sweepState);
|
||||
currentGain = gain + (deltaGain * sweepState);
|
||||
}
|
||||
poleCoeffs[1] = - (currentReson * currentReson);
|
||||
poleCoeffs[0] = (MY_FLOAT) 2.0 * currentReson *
|
||||
(MY_FLOAT) cos(TWO_PI * currentFreq / SRATE);
|
||||
}
|
||||
|
||||
temp = currentGain * sample;
|
||||
temp += poleCoeffs[0] * outputs[0];
|
||||
temp += poleCoeffs[1] * outputs[1];
|
||||
outputs[1] = outputs[0];
|
||||
outputs[0] = temp;
|
||||
lastOutput = outputs[0];
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
|
||||
void main()
|
||||
{
|
||||
FormSwep filter;
|
||||
FILE *fd;
|
||||
MY_FLOAT temp;
|
||||
short data;
|
||||
long i;
|
||||
|
||||
fd = fopen("test.raw","wb");
|
||||
|
||||
filter.setTargets(100.0,0.99,0.01);
|
||||
for (i=0;i<20000;i++) {
|
||||
if (i%100 != 0) temp = 0.0; else temp = 1.0;
|
||||
data = filter.tick(temp) * 32000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
filter.setTargets(1000.0,0.99,0.01);
|
||||
for (i=0;i<20000;i++) {
|
||||
if (i%100 != 0) temp = 0.0; else temp = 1.0;
|
||||
data = filter.tick(temp) * 32000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
filter.setTargets(500.0,0.9999,0.001);
|
||||
for (i=0;i<20000;i++) {
|
||||
if (i%100 != 0) temp = 0.0; else temp = 1.0;
|
||||
data = filter.tick(temp) * 32000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
|
||||
46
FormSwep.h
46
FormSwep.h
@@ -1,46 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Sweepable Formant (2-pole) */
|
||||
/* Filter Class, by Perry R. Cook, 1995-96*/
|
||||
/* See books on filters to understand */
|
||||
/* more about how this works. Nothing */
|
||||
/* out of the ordinary in this version. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__FormSwep_h)
|
||||
#define __FormSwep_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class FormSwep : public Filter
|
||||
{
|
||||
protected:
|
||||
MY_FLOAT poleCoeffs[2];
|
||||
MY_FLOAT freq;
|
||||
MY_FLOAT reson;
|
||||
int dirty;
|
||||
MY_FLOAT targetFreq;
|
||||
MY_FLOAT targetReson;
|
||||
MY_FLOAT targetGain;
|
||||
MY_FLOAT currentFreq;
|
||||
MY_FLOAT currentReson;
|
||||
MY_FLOAT currentGain;
|
||||
MY_FLOAT deltaFreq;
|
||||
MY_FLOAT deltaReson;
|
||||
MY_FLOAT deltaGain;
|
||||
MY_FLOAT sweepState;
|
||||
MY_FLOAT sweepRate;
|
||||
public:
|
||||
FormSwep();
|
||||
~FormSwep();
|
||||
void clear();
|
||||
void setPoleCoeffs(MY_FLOAT *coeffs);
|
||||
void setGain(MY_FLOAT aValue);
|
||||
void setFreqAndReson(MY_FLOAT aFreq, MY_FLOAT aReson);
|
||||
void setStates(MY_FLOAT aFreq, MY_FLOAT aReson, MY_FLOAT aGain);
|
||||
void setTargets(MY_FLOAT aFreq, MY_FLOAT aReson, MY_FLOAT aGain);
|
||||
void setSweepRate(MY_FLOAT aRate);
|
||||
void setSweepTime(MY_FLOAT aTime);
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
60
HeavyMtl.cpp
60
HeavyMtl.cpp
@@ -1,60 +0,0 @@
|
||||
/******************************************/
|
||||
/* Heavy Metal Synth Subclass */
|
||||
/* of Algorithm 3 (TX81Z) Subclass of */
|
||||
/* 3 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/******************************************/
|
||||
|
||||
#include "HeavyMtl.h"
|
||||
|
||||
HeavyMtl :: HeavyMtl() : FM4Alg3()
|
||||
{
|
||||
this->loadWaves("rawwaves/sinewave.raw",
|
||||
"rawwaves/twopeaks.raw",
|
||||
"rawwaves/twopeaks.raw",
|
||||
"rawwaves/sinewave.raw");
|
||||
|
||||
this->setRatio(0,(MY_FLOAT) (1.00 * 1.000));
|
||||
this->setRatio(1,(MY_FLOAT) (4.00 * 0.999));
|
||||
this->setRatio(2,(MY_FLOAT) (3.00 * 1.001));
|
||||
this->setRatio(3,(MY_FLOAT) (0.50 * 1.002));
|
||||
gains[0] = __FM4Op_gains[92];
|
||||
gains[1] = __FM4Op_gains[76];
|
||||
gains[2] = __FM4Op_gains[91];
|
||||
gains[3] = __FM4Op_gains[68];
|
||||
adsr[0]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 0.001,(MY_FLOAT) 1.0,(MY_FLOAT) 0.01);
|
||||
adsr[1]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 0.010,(MY_FLOAT) 1.0,(MY_FLOAT) 0.50);
|
||||
adsr[2]->setAllTimes((MY_FLOAT) 0.010,(MY_FLOAT) 0.005,(MY_FLOAT) 1.0,(MY_FLOAT) 0.20);
|
||||
adsr[3]->setAllTimes((MY_FLOAT) 0.030,(MY_FLOAT) 0.010,(MY_FLOAT) 0.2,(MY_FLOAT) 0.20);
|
||||
twozero->setGain((MY_FLOAT) 2.0);
|
||||
vibWave->setFreq((MY_FLOAT) 5.5);
|
||||
modDepth = (MY_FLOAT) 0.00;
|
||||
}
|
||||
|
||||
HeavyMtl :: ~HeavyMtl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void HeavyMtl :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
waves[0]->setFreq(baseFreq * ratios[0]);
|
||||
waves[1]->setFreq(baseFreq * ratios[1]);
|
||||
waves[2]->setFreq(baseFreq * ratios[2]);
|
||||
waves[3]->setFreq(baseFreq * ratios[3]);
|
||||
}
|
||||
|
||||
void HeavyMtl :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
gains[0] = amp * __FM4Op_gains[92];
|
||||
gains[1] = amp * __FM4Op_gains[76];
|
||||
gains[2] = amp * __FM4Op_gains[91];
|
||||
gains[3] = amp * __FM4Op_gains[68];
|
||||
this->setFreq(freq);
|
||||
this->keyOn();
|
||||
#if defined(_debug_)
|
||||
printf("HeavyMtl : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
36
JetTabl.cpp
36
JetTabl.cpp
@@ -1,36 +0,0 @@
|
||||
/**********************************************/
|
||||
/* Jet Table Object by Perry R. Cook, 1995-96 */
|
||||
/* Consult Fletcher and Rossing, Karjalainen, */
|
||||
/* Cook, more, for information. */
|
||||
/* This, as with many other of my "tables", */
|
||||
/* is not a table, but is computed by poly- */
|
||||
/* nomial calculation. */
|
||||
/**********************************************/
|
||||
|
||||
#include "JetTabl.h"
|
||||
|
||||
JetTabl :: JetTabl()
|
||||
{
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
JetTabl :: ~JetTabl()
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT JetTabl :: lookup(MY_FLOAT sample) /* Perform "Table Lookup" */
|
||||
{ /* By Polynomial Calculation */
|
||||
lastOutput = sample *
|
||||
(sample*sample - (MY_FLOAT) 1.0); /* (x^3 - x) approximates sigmoid of jet */
|
||||
if (lastOutput > 1.0)
|
||||
lastOutput = (MY_FLOAT) 1.0; /* Saturation at +/- 1.0 */
|
||||
if (lastOutput < -1.0)
|
||||
lastOutput = (MY_FLOAT) -1.0;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT JetTabl :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
67
LipFilt.cpp
67
LipFilt.cpp
@@ -1,67 +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] = (MY_FLOAT) 0.0;
|
||||
coeffs[1] = (MY_FLOAT) 0.0;
|
||||
filter->setZeroCoeffs(coeffs);
|
||||
this->clear();
|
||||
}
|
||||
|
||||
LipFilt :: ~LipFilt()
|
||||
{
|
||||
delete filter;
|
||||
}
|
||||
|
||||
void LipFilt :: clear()
|
||||
{
|
||||
filter->clear();
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void LipFilt :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT coeffs[2];
|
||||
coeffs[0] = (MY_FLOAT) 2.0 * (MY_FLOAT) 0.997 *
|
||||
(MY_FLOAT) cos(TWO_PI * frequency / SRATE); /* damping should change with */
|
||||
coeffs[1] = (MY_FLOAT) (-0.997 * 0.997); /* lip parameters, but not yet.*/
|
||||
filter->setPoleCoeffs(coeffs);
|
||||
filter->setGain((MY_FLOAT) 0.03);
|
||||
}
|
||||
|
||||
/* NOTE: Here we should add lip tension */
|
||||
/* settings based on Mass/Spring/Damping */
|
||||
/* Maybe in TookKit97 */
|
||||
|
||||
MY_FLOAT LipFilt :: tick(MY_FLOAT mouthSample,MY_FLOAT boreSample)
|
||||
/* Perform "Table Lookup" By Polynomial Calculation */
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
temp = mouthSample - boreSample; /* Differential pressure */
|
||||
temp = filter->tick(temp); /* Force -> position */
|
||||
temp = temp*temp; /* Simple position to area mapping */
|
||||
if (temp > 1.0) temp = (MY_FLOAT) 1.0; /* Saturation at + 1.0 */
|
||||
lastOutput = temp * mouthSample; /* Assume mouth input = area */
|
||||
lastOutput += ((MY_FLOAT) 1.0 - temp)
|
||||
* boreSample; /* and Bore reflection is compliment. */
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT LipFilt :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
28
LipFilt.h
28
LipFilt.h
@@ -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();
|
||||
};
|
||||
|
||||
575
MIDIIO.cpp
575
MIDIIO.cpp
@@ -1,575 +0,0 @@
|
||||
/******************************************/
|
||||
/* MIDIIO.cpp */
|
||||
/* Realtime MIDI I/O Object for STK, */
|
||||
/* by Gary P. Scavone, 1998. */
|
||||
/* Based in part on code by Perry */
|
||||
/* Cook (SGI), Paul Leonard (Linux), */
|
||||
/* the RoseGarden team (Linux), and */
|
||||
/* Bill Putnam (Win95/NT). */
|
||||
/* */
|
||||
/* At the moment, this object only */
|
||||
/* handles MIDI Input, though MIDI */
|
||||
/* Output code can go here when someone */
|
||||
/* decides they need it (and writes it). */
|
||||
/* */
|
||||
/* This object opens a MIDI Input device */
|
||||
/* and parses MIDI messages into a MIDI */
|
||||
/* buffer. Time stamp info is converted */
|
||||
/* to deltaTime. MIDI data is stored as */
|
||||
/* MY_FLOAT to conform with SKINI. */
|
||||
/******************************************/
|
||||
|
||||
#include "MIDIIO.h"
|
||||
|
||||
#define MIDI_BUFFER_SIZE 1024
|
||||
int writeOffset;
|
||||
int readOffset;
|
||||
|
||||
|
||||
#if defined(__SGI_REALTIME_)
|
||||
|
||||
/*************************************/
|
||||
/* __SGI_REALTIME_ */
|
||||
/*************************************/
|
||||
|
||||
#include <dmedia/midi.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <signal.h>
|
||||
|
||||
MDport inport;
|
||||
|
||||
MDevent *midiBuffer;
|
||||
|
||||
pid_t midi_input_pid;
|
||||
|
||||
void midiInputThread(void *)
|
||||
{
|
||||
MDevent newMessage;
|
||||
int status;
|
||||
|
||||
while (1) {
|
||||
mdReceive(inport, &newMessage, 1);
|
||||
status = (newMessage.msg[0] & MD_STATUSMASK);
|
||||
|
||||
// Ignore Active Sensing messages
|
||||
if (!((status & 0xff) == 0xfe || (status & 0xff) == 0xf8)) {
|
||||
midiBuffer[writeOffset] = newMessage;
|
||||
writeOffset++;
|
||||
|
||||
if( writeOffset >= MIDI_BUFFER_SIZE )
|
||||
writeOffset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MIDIIO :: MIDIIO()
|
||||
{
|
||||
int nports;
|
||||
|
||||
nports = mdInit();
|
||||
printf("%d MIDI devices available\n", nports);
|
||||
inport = mdOpenInPort(NULL);
|
||||
if (inport == NULL) {
|
||||
fprintf(stderr,"Cannot open MIDI device.\n");
|
||||
printf("Exiting MIDIIO Process.\n");
|
||||
exit(0);
|
||||
}
|
||||
mdSetStampMode(inport, MD_NOSTAMP);
|
||||
|
||||
// Set up the circular buffer for the Midi Input Messages
|
||||
midiBuffer = new MDevent[MIDI_BUFFER_SIZE];
|
||||
readOffset = 0;
|
||||
writeOffset = 0;
|
||||
|
||||
midi_input_pid = sproc(midiInputThread, PR_SALL);
|
||||
if (midi_input_pid == -1) {
|
||||
fprintf(stderr, "unable to create MIDI input thread...aborting.\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
MIDIIO :: ~MIDIIO()
|
||||
{
|
||||
kill (midi_input_pid, SIGKILL);
|
||||
mdClosePort(inport);
|
||||
delete [] midiBuffer;
|
||||
}
|
||||
|
||||
int MIDIIO :: nextMessage()
|
||||
{
|
||||
int status;
|
||||
int byte1;
|
||||
int byte2;
|
||||
MDevent lastEvent;
|
||||
static unsigned long long lastTimeStamp = 0;
|
||||
|
||||
if ( readOffset == writeOffset ) return 0;
|
||||
|
||||
lastEvent = midiBuffer[readOffset];
|
||||
|
||||
readOffset++;
|
||||
if ( readOffset >= MIDI_BUFFER_SIZE ) readOffset = 0;
|
||||
|
||||
status = (lastEvent.msg[0] & MD_STATUSMASK);
|
||||
byte1 = lastEvent.msg[1];
|
||||
byte2 = lastEvent.msg[2];
|
||||
channel = (lastEvent.msg[0] & MD_CHANNELMASK);
|
||||
|
||||
if ((status == MD_PROGRAMCHANGE) ||
|
||||
(status == MD_CHANNELPRESSURE))
|
||||
{
|
||||
messageType = status;
|
||||
byteTwo = (float) byte1;
|
||||
deltaTime = (MY_FLOAT) ((lastEvent.stamp - lastTimeStamp) * 0.000000001);
|
||||
lastTimeStamp = lastEvent.stamp;
|
||||
}
|
||||
else if ((status == MD_NOTEON) || (status == MD_NOTEOFF) ||
|
||||
(status == MD_CONTROLCHANGE) || (status == MD_POLYKEYPRESSURE))
|
||||
{
|
||||
messageType = status;
|
||||
byteTwo = (float) byte1;
|
||||
byteThree = (float) byte2;
|
||||
deltaTime = (MY_FLOAT) ((lastEvent.stamp - lastTimeStamp) * 0.000000001);
|
||||
lastTimeStamp = lastEvent.stamp;
|
||||
}
|
||||
else if (status == MD_PITCHBENDCHANGE)
|
||||
{
|
||||
messageType = status;
|
||||
byteTwo = (float) byte1 * NORM_7;
|
||||
byteTwo += (float) byte2;
|
||||
deltaTime = (MY_FLOAT) ((lastEvent.stamp - lastTimeStamp) * 0.000000001);
|
||||
lastTimeStamp = lastEvent.stamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
messageType = -1;
|
||||
}
|
||||
|
||||
return messageType;
|
||||
}
|
||||
|
||||
|
||||
#elif defined(__USS_REALTIME_)
|
||||
|
||||
/*************************************/
|
||||
/* __USS_REALTIME_ */
|
||||
/*************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/soundcard.h>
|
||||
#include <pthread.h>
|
||||
//#include <pthread/mit/pthread.h>
|
||||
|
||||
int _seqfd;
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
||||
typedef struct {
|
||||
byte data[4];
|
||||
unsigned long time;
|
||||
} MIDIMESSAGE;
|
||||
|
||||
MIDIMESSAGE *midiBuffer;
|
||||
|
||||
/* System Messages */
|
||||
#define MIDI_SYSTEM_MSG ((byte)0xF0)
|
||||
#define MessageType(MSG) (byte)((MSG) & ((byte)0xF0))
|
||||
|
||||
#define SEQUENCER_PATH "/dev/sequencer"
|
||||
|
||||
/* MIDI time code at 100 ticks per second. */
|
||||
#define OSS_MIDI_CLOCK_RATE 100
|
||||
|
||||
pthread_t midi_input_thread;
|
||||
|
||||
void *midiInputThread(void *)
|
||||
{
|
||||
byte NumArgs = 0;
|
||||
byte ArgsLeft = 0;
|
||||
unsigned long lastTime = 0;
|
||||
unsigned long newTime = 0;
|
||||
byte InBytes[4];
|
||||
static MIDIMESSAGE newMessage;
|
||||
int n;
|
||||
|
||||
while (1) {
|
||||
if ((n = read(_seqfd, &InBytes, sizeof(InBytes))) == -1) {
|
||||
fprintf(stderr,"Error reading " SEQUENCER_PATH "\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
switch ( InBytes[0] )
|
||||
{
|
||||
case SEQ_WAIT:
|
||||
/* MIDI clock ticks ... the first MIDI message deltaTime is calculated
|
||||
* with respect to the start of the MIDI clock.
|
||||
*/
|
||||
newTime = ((InBytes[3]<<16)|(InBytes[2]<<8)| InBytes[1]);
|
||||
break;
|
||||
|
||||
case SEQ_ECHO:
|
||||
/* no echo events yet defined */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"ECHO EVENT\n");
|
||||
#endif
|
||||
break;
|
||||
|
||||
case SEQ_MIDIPUTC:
|
||||
/* Determination of a full MIDI message from the input MIDI stream is based
|
||||
here on the observation that MIDI status bytes and subsequent data bytes
|
||||
are NOT returned in the same read() call. Rather, they are spread out
|
||||
over multiple read() returns, with only a single value per return. So,
|
||||
if we find a status byte, we then determine the number of expected
|
||||
operands and process that number of subsequent read()s to determine the
|
||||
complete MIDI message.
|
||||
*/
|
||||
if (InBytes[1] & 0x80) { /* Status Byte */
|
||||
if (MessageType(InBytes[1]) == MIDI_SYSTEM_MSG)
|
||||
{
|
||||
NumArgs = 0; /* no timing info */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "SYSTEM MESSAGE\n");
|
||||
#endif
|
||||
}
|
||||
else if (MessageType(InBytes[1]) == MIDI_PGM_CHANGE ||
|
||||
MessageType(InBytes[1]) == MIDI_CHN_PRESSURE)
|
||||
{
|
||||
NumArgs = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
NumArgs = 2;
|
||||
}
|
||||
newMessage.data[0] = InBytes[1];
|
||||
ArgsLeft = NumArgs;
|
||||
newMessage.data[1] = 0;
|
||||
newMessage.data[2] = 0;
|
||||
}
|
||||
|
||||
if (ArgsLeft && !(InBytes[1] & 0x80)) { /* not a status byte */
|
||||
if (ArgsLeft == NumArgs)
|
||||
newMessage.data[1] = InBytes[1];
|
||||
else
|
||||
{
|
||||
newMessage.data[2] = InBytes[1];
|
||||
}
|
||||
|
||||
--ArgsLeft;
|
||||
|
||||
/* If MIDI message complete, then setup for running status mode
|
||||
(another event of the same type without status byte).
|
||||
*/
|
||||
if ( !ArgsLeft ) {
|
||||
if (MessageType(newMessage.data[0]) == (int) MIDI_PGM_CHANGE ||
|
||||
MessageType(newMessage.data[0]) == (int) MIDI_CHN_PRESSURE)
|
||||
{
|
||||
ArgsLeft = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ArgsLeft = 2;
|
||||
}
|
||||
newMessage.time = newTime - lastTime;
|
||||
lastTime = newTime;
|
||||
|
||||
// Put newMessage in the circular buffer
|
||||
midiBuffer[writeOffset] = newMessage;
|
||||
writeOffset++;
|
||||
|
||||
if( writeOffset >= MIDI_BUFFER_SIZE )
|
||||
writeOffset = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MIDIIO :: MIDIIO()
|
||||
{
|
||||
int err = 0;
|
||||
_seqfd = 0;
|
||||
|
||||
#ifdef NONBLOCKING_MIDI
|
||||
if((_seqfd = open(SEQUENCER_PATH, O_RDONLY+O_NONBLOCK, 0)) == -1) {
|
||||
#else
|
||||
if((_seqfd = open(SEQUENCER_PATH, O_RDONLY, 0)) == -1) {
|
||||
#endif
|
||||
fprintf(stderr,"Cannot open " SEQUENCER_PATH ". \n");
|
||||
printf("Exiting MIDIIO Process.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Set up the circular buffer for the Midi Input Messages
|
||||
midiBuffer = new MIDIMESSAGE[MIDI_BUFFER_SIZE];
|
||||
readOffset = 0;
|
||||
writeOffset = 0;
|
||||
|
||||
err = pthread_create(&midi_input_thread, NULL, midiInputThread, NULL);
|
||||
if (err)
|
||||
{
|
||||
fprintf(stderr, "Unable to create MIDI input thread.\n");
|
||||
printf("Exiting MIDIIO Process.\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
MIDIIO :: ~MIDIIO()
|
||||
{
|
||||
if (_seqfd != 0) close(_seqfd);
|
||||
delete [] midiBuffer;
|
||||
}
|
||||
|
||||
int MIDIIO::nextMessage()
|
||||
{
|
||||
MIDIMESSAGE lastEvent;
|
||||
unsigned long micros = 2000;
|
||||
|
||||
if ( readOffset == writeOffset ) return 0;
|
||||
|
||||
lastEvent = midiBuffer[readOffset];
|
||||
|
||||
readOffset++;
|
||||
if ( readOffset >= MIDI_BUFFER_SIZE ) readOffset = 0;
|
||||
|
||||
messageType = (int) (lastEvent.data[0] & 0xf0);
|
||||
channel = (int) (lastEvent.data[0] & 0x0f);
|
||||
byteTwo = (float) lastEvent.data[1];
|
||||
if (messageType == (int) MIDI_PITCH_BEND)
|
||||
byteTwo = (float) lastEvent.data[2] + (byteTwo * NORM_7);
|
||||
else
|
||||
byteThree = (float) lastEvent.data[2];
|
||||
deltaTime = (float) lastEvent.time / OSS_MIDI_CLOCK_RATE;
|
||||
|
||||
return messageType;
|
||||
}
|
||||
|
||||
|
||||
#elif (defined(__WINDS_REALTIME_) || defined(__WINMM_REALTIME_) )
|
||||
|
||||
/*************************************/
|
||||
/* __WIN_REALTIME_ */
|
||||
/*************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "MIDIIO.h"
|
||||
|
||||
#define MIDI_NOTEON 0x90
|
||||
#define MIDI_NOTEOFF 0x80
|
||||
#define MIDI_POLYKEYPRESSURE 0xA0
|
||||
#define MIDI_CHANNELPRESSURE 0xD0
|
||||
#define MIDI_PROGRAMCHANGE 0xC0
|
||||
#define MIDI_CONTROLCHANGE 0xB0
|
||||
#define MIDI_PITCHBEND 0xE0
|
||||
|
||||
typedef struct {
|
||||
DWORD data;
|
||||
DWORD time;
|
||||
} MIDIMESSAGE;
|
||||
|
||||
MIDIMESSAGE *midiBuffer;
|
||||
|
||||
static void CALLBACK midiInputCallback( HMIDIOUT hmin, UINT inputStatus,
|
||||
DWORD instancePtr, DWORD midiMessage, DWORD timestamp)
|
||||
{
|
||||
MIDIMESSAGE newMessage;
|
||||
|
||||
switch (inputStatus) {
|
||||
case MIM_OPEN:
|
||||
#ifdef TESTING_MIDI_IN
|
||||
printf("MIM_OPEN\n");
|
||||
#endif
|
||||
break;
|
||||
|
||||
case MIM_CLOSE:
|
||||
#ifdef TESTING_MIDI_IN
|
||||
printf("MIM_CLOSE\n");
|
||||
#endif
|
||||
break;
|
||||
|
||||
case MIM_DATA:
|
||||
#ifdef TESTING_MIDI_IN
|
||||
printf("MIM_DATA\n");
|
||||
#endif
|
||||
// Ignore Active Sensing messages
|
||||
if ((midiMessage & 0xff) == 0xfe || (midiMessage & 0xff) == 0xf8) {
|
||||
break;
|
||||
}
|
||||
newMessage.data = midiMessage;
|
||||
newMessage.time = timestamp;
|
||||
|
||||
// Put newMessage in the circular buffer
|
||||
midiBuffer[writeOffset] = newMessage;
|
||||
writeOffset++;
|
||||
|
||||
if( writeOffset >= MIDI_BUFFER_SIZE )
|
||||
writeOffset = 0;
|
||||
break;
|
||||
|
||||
case MIM_ERROR:
|
||||
fprintf(stderr,"Invalid MIDI message received!\n");
|
||||
#ifdef TESTING_MIDI_IN
|
||||
printf("MIM_ERROR\n");
|
||||
#endif
|
||||
break;
|
||||
|
||||
case MIM_LONGDATA:
|
||||
/* System exclusive buffer is returned */
|
||||
break;
|
||||
|
||||
case MIM_LONGERROR:
|
||||
#ifdef TESTING_MIDI_IN
|
||||
printf("MIM_LONGERROR\n");
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
HMIDIIN hMidiIn ; // Handle to Midi Output Device
|
||||
|
||||
MIDIIO :: MIDIIO()
|
||||
{
|
||||
MMRESULT result;
|
||||
UINT uDeviceID;
|
||||
MIDIINCAPS deviceCaps;
|
||||
UINT i;
|
||||
char inputString[128];
|
||||
|
||||
uDeviceID = midiInGetNumDevs();
|
||||
printf("%i MIDI Input Devices Available.\n",uDeviceID);
|
||||
if (uDeviceID == 0) {
|
||||
printf("Exiting MIDIIO Process.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for (i=0; i<uDeviceID; i++) {
|
||||
result = midiInGetDevCaps(i, &deviceCaps, sizeof(MIDIINCAPS));
|
||||
printf("MIDI Device %d is %s.\n", i, deviceCaps.szPname);
|
||||
}
|
||||
|
||||
if (uDeviceID > 1) {
|
||||
printf("\nType the MIDI Device to open: ");
|
||||
fgets(inputString, 128, stdin);
|
||||
uDeviceID = (UINT) atoi(inputString);
|
||||
}
|
||||
else uDeviceID -= 1;
|
||||
|
||||
// Open the port and return any errors
|
||||
result = midiInOpen(&hMidiIn, uDeviceID, (DWORD)&midiInputCallback, (DWORD)NULL, CALLBACK_FUNCTION);
|
||||
if (result != MMSYSERR_NOERROR) {
|
||||
fprintf(stderr,"Cannot open MIDI Input Device %d!\n", uDeviceID);
|
||||
printf("Exiting MIDIIO Process.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Set up the circular buffer for the Midi Input Messages
|
||||
midiBuffer = new MIDIMESSAGE[MIDI_BUFFER_SIZE];
|
||||
readOffset = 0;
|
||||
writeOffset = 0;
|
||||
|
||||
midiInStart( hMidiIn );
|
||||
}
|
||||
|
||||
MIDIIO :: ~MIDIIO()
|
||||
{
|
||||
midiInReset( hMidiIn );
|
||||
midiInStop( hMidiIn );
|
||||
midiInClose( hMidiIn );
|
||||
delete [] midiBuffer;
|
||||
}
|
||||
|
||||
int MIDIIO :: nextMessage()
|
||||
{
|
||||
int status;
|
||||
int byte1;
|
||||
int byte2;
|
||||
MIDIMESSAGE lastEvent;
|
||||
static DWORD lastTime = 0;
|
||||
static DWORD newTime = 0;
|
||||
|
||||
if ( readOffset == writeOffset ) return 0;
|
||||
|
||||
lastEvent = midiBuffer[readOffset];
|
||||
|
||||
readOffset++;
|
||||
if ( readOffset >= MIDI_BUFFER_SIZE ) readOffset = 0;
|
||||
|
||||
status = (int) (lastEvent.data & 0xff);
|
||||
byte1 = (int) (lastEvent.data & 0xff00) >> 8;
|
||||
byte2 = (int) (lastEvent.data & 0xff0000) >> 16;
|
||||
channel = (int) (status & 0x0f);
|
||||
newTime = lastEvent.time;
|
||||
deltaTime = (float) (newTime - lastTime) * 0.001;
|
||||
lastTime = newTime;
|
||||
|
||||
if ((status == MIDI_PROGRAMCHANGE) ||
|
||||
(status == MIDI_CHANNELPRESSURE))
|
||||
{
|
||||
messageType = status;
|
||||
byteTwo = (float) byte1;
|
||||
}
|
||||
else if ((status == MIDI_NOTEON) || (status == MIDI_NOTEOFF) ||
|
||||
(status == MIDI_CONTROLCHANGE) || (status == MIDI_POLYKEYPRESSURE))
|
||||
{
|
||||
messageType = status;
|
||||
byteTwo = (float) byte1;
|
||||
byteThree = (float) byte2;
|
||||
}
|
||||
else if (status == MIDI_PITCHBEND)
|
||||
{
|
||||
messageType = status;
|
||||
byteTwo = (float) (byte1 * NORM_7);
|
||||
byteTwo += (float) byte2;
|
||||
}
|
||||
else
|
||||
{
|
||||
messageType = -1;
|
||||
}
|
||||
|
||||
return messageType;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void MIDIIO :: printMessage()
|
||||
{
|
||||
printf("type = %d, channel = %d, byte2 = %f, byte3 = %f\n",
|
||||
this->getType(), this->getChannel(), this->getByteTwo(),
|
||||
this->getByteThree());
|
||||
}
|
||||
|
||||
int MIDIIO :: getType()
|
||||
{
|
||||
return messageType;
|
||||
}
|
||||
|
||||
int MIDIIO :: getChannel()
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
|
||||
MY_FLOAT MIDIIO :: getByteTwo()
|
||||
{
|
||||
return byteTwo;
|
||||
}
|
||||
|
||||
MY_FLOAT MIDIIO :: getByteThree()
|
||||
{
|
||||
return byteThree;
|
||||
}
|
||||
|
||||
MY_FLOAT MIDIIO :: getDeltaTime()
|
||||
{
|
||||
return deltaTime;
|
||||
}
|
||||
56
MIDIIO.h
56
MIDIIO.h
@@ -1,56 +0,0 @@
|
||||
/******************************************/
|
||||
/* MIDIIO.h */
|
||||
/* Realtime MIDI I/O Object for STK, */
|
||||
/* by Gary P. Scavone, 1998. */
|
||||
/* Based in part on code by Perry */
|
||||
/* Cook (SGI), Paul Leonard (Linux), */
|
||||
/* the RoseGarden team (Linux), and */
|
||||
/* Bill Putnam (Win95/NT). */
|
||||
/* */
|
||||
/* At the moment, this object only */
|
||||
/* handles MIDI Input, though MIDI */
|
||||
/* Output code can go here when someone */
|
||||
/* decides they need it (and writes it). */
|
||||
/* */
|
||||
/* This object opens a MIDI Input device */
|
||||
/* and parses MIDI data. Time stamp */
|
||||
/* info is converted to deltaTime. */
|
||||
/* MIDI data is stored as MY_FLOAT to */
|
||||
/* conform with SKINI. */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__MIDIIO_h)
|
||||
#define __MIDIIO_h
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class MIDIIO : public Object
|
||||
{
|
||||
protected:
|
||||
int messageType;
|
||||
int channel;
|
||||
float byteTwo;
|
||||
float byteThree;
|
||||
MY_FLOAT deltaTime;
|
||||
public:
|
||||
MIDIIO();
|
||||
~MIDIIO();
|
||||
void printMessage();
|
||||
int nextMessage();
|
||||
int getType();
|
||||
int getChannel();
|
||||
MY_FLOAT getByteTwo();
|
||||
MY_FLOAT getByteThree();
|
||||
MY_FLOAT getDeltaTime();
|
||||
};
|
||||
|
||||
#if (defined(__WINDS_REALTIME_) || defined(__WINMM_REALTIME_) )
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
static void CALLBACK midiInputCallback( HMIDIOUT hmin, UINT inputStatus,
|
||||
DWORD instancePtr, DWORD midiMessage, DWORD timestamp);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
69
Makefile
69
Makefile
@@ -1,69 +0,0 @@
|
||||
# STK98 Makefile - Global version for Unix systems which have GNU
|
||||
# Makefile utilities installed. If this Makefile does not work on
|
||||
# your system, try using the platform specific Makefiles (.sgi,
|
||||
# .next, and .linux).
|
||||
|
||||
OS = $(shell uname)
|
||||
|
||||
O_FILES = Object.o Envelope.o ADSR.o Noise.o SubNoise.o \
|
||||
RawWave.o RawShot.o RawLoop.o RawInterp.o \
|
||||
Modulatr.o Filter.o OneZero.o \
|
||||
OnePole.o TwoZero.o TwoPole.o DCBlock.o \
|
||||
BiQuad.o DLineA.o DLineL.o DLineN.o VoicMang.o \
|
||||
FormSwep.o BowTabl.o JetTabl.o ReedTabl.o \
|
||||
LipFilt.o Modal4.o FM4Op.o FM4Alg3.o FM4Alg4.o \
|
||||
FM4Alg5.o FM4Alg6.o FM4Alg8.o Plucked2.o \
|
||||
SamplFlt.o Sampler.o SKINI11.o Simple.o \
|
||||
SingWave.o VoicForm.o FMVoices.o swapstuf.o \
|
||||
\
|
||||
Instrmnt.o Marimba.o Vibraphn.o AgogoBel.o Shakers.o \
|
||||
Plucked.o Mandolin.o Clarinet.o Flute.o Moog1.o \
|
||||
Brass.o Bowed.o Rhodey.o Wurley.o TubeBell.o \
|
||||
HeavyMtl.o PercFlut.o BeeThree.o DrumSynt.o \
|
||||
\
|
||||
WvOut.o SndWvOut.o WavWvOut.o MatWvOut.o \
|
||||
Reverb.o PRCRev.o JCRev.o NRev.o
|
||||
|
||||
RM = /bin/rm
|
||||
|
||||
ifeq ($(OS),NEXTSTEP) # These are for NeXT
|
||||
CC = cc -arch m68k -arch i386 -Wall
|
||||
INSTR = syntmono
|
||||
endif
|
||||
|
||||
ifeq ($(OS),IRIX) # These are for SGI
|
||||
INSTR = MD2SKINI syntmono
|
||||
CC = CC -O # -g -fullwarn -D__SGI_CC__
|
||||
O_FILES += RTWvOut.o RTSoundIO.o MIDIIO.o
|
||||
LIBRARY = -L/usr/sgitcl/lib -laudio -lmd -lm
|
||||
endif
|
||||
|
||||
ifeq ($(OS),Linux) # These are for Linux
|
||||
INSTR = syntmono MD2SKINI
|
||||
CC = gcc -O3 # -g -pg -O3
|
||||
O_FILES += RTWvOut.o RTSoundIO.o MIDIIO.o
|
||||
LIBRARY = -lpthread -lm
|
||||
# LIBRARY = /lib/libpthread.so.0 -lm
|
||||
endif
|
||||
|
||||
.SUFFIXES: .cpp
|
||||
.cpp.o: Object.h
|
||||
$(CC) -c $*.cpp
|
||||
|
||||
all: $(INSTR)
|
||||
|
||||
syntmono: syntmono.cpp $(O_FILES)
|
||||
$(CC) $(INCLUDE) -o syntmono syntmono.cpp $(O_FILES) $(LIBRARY)
|
||||
|
||||
MD2SKINI: MD2SKINI.cpp $(O_FILES)
|
||||
$(CC) -o MD2SKINI MD2SKINI.cpp $(O_FILES) $(LIBRARY)
|
||||
|
||||
clean :
|
||||
rm *.o
|
||||
rm $(INSTR)
|
||||
|
||||
cleanIns :
|
||||
rm $(INSTR)
|
||||
|
||||
strip :
|
||||
strip $(INSTR)
|
||||
@@ -1,47 +0,0 @@
|
||||
# STK98 Makefile - NeXTStep solo version
|
||||
|
||||
O_FILES = Object.o Envelope.o ADSR.o Noise.o SubNoise.o \
|
||||
RawWave.o RawShot.o RawLoop.o RawInterp.o \
|
||||
Modulatr.o Filter.o OneZero.o \
|
||||
OnePole.o TwoZero.o TwoPole.o DCBlock.o \
|
||||
BiQuad.o DLineA.o DLineL.o DLineN.o VoicMang.o \
|
||||
FormSwep.o BowTabl.o JetTabl.o ReedTabl.o \
|
||||
LipFilt.o Modal4.o FM4Op.o FM4Alg3.o FM4Alg4.o \
|
||||
FM4Alg5.o FM4Alg6.o FM4Alg8.o Plucked2.o \
|
||||
SamplFlt.o Sampler.o SKINI11.o Simple.o \
|
||||
SingWave.o VoicForm.o FMVoices.o swapstuf.o \
|
||||
\
|
||||
Instrmnt.o Marimba.o Vibraphn.o AgogoBel.o Shakers.o \
|
||||
Plucked.o Mandolin.o Clarinet.o Flute.o Moog1.o \
|
||||
Brass.o Bowed.o Rhodey.o Wurley.o TubeBell.o \
|
||||
HeavyMtl.o PercFlut.o BeeThree.o DrumSynt.o \
|
||||
\
|
||||
WvOut.o SndWvOut.o WavWvOut.o MatWvOut.o \
|
||||
Reverb.o PRCRev.o JCRev.o NRev.o
|
||||
|
||||
RM = /bin/rm
|
||||
|
||||
CC = cc -arch m68k -arch i386 -Wall
|
||||
INSTR = syntmono
|
||||
|
||||
.SUFFIXES: .cpp
|
||||
.cpp.o: Object.h
|
||||
$(CC) -c $*.cpp
|
||||
|
||||
all: $(INSTR)
|
||||
|
||||
syntmono: syntmono.cpp $(O_FILES)
|
||||
$(CC) $(INCLUDE) -o syntmono syntmono.cpp $(O_FILES) $(LIBRARY)
|
||||
|
||||
MD2SKINI: MD2SKINI.cpp $(O_FILES)
|
||||
$(CC) -o MD2SKINI MD2SKINI.cpp $(O_FILES) $(LIBRARY)
|
||||
|
||||
clean :
|
||||
rm *.o
|
||||
rm $(INSTR)
|
||||
|
||||
cleanIns :
|
||||
rm $(INSTR)
|
||||
|
||||
strip :
|
||||
strip $(INSTR)
|
||||
68
Makefile.all
68
Makefile.all
@@ -1,68 +0,0 @@
|
||||
# STK98 Makefile - Global version for Unix systems which have GNU
|
||||
# Makefile utilities installed. If this Makefile does not work on
|
||||
# your system, try using the platform specific Makefiles (.sgi,
|
||||
# .next, and .linux).
|
||||
|
||||
OS = $(shell uname)
|
||||
|
||||
O_FILES = Object.o Envelope.o ADSR.o Noise.o SubNoise.o \
|
||||
RawWave.o RawWvIn.o RawLoop.o \
|
||||
Modulatr.o Filter.o OneZero.o \
|
||||
OnePole.o TwoZero.o TwoPole.o DCBlock.o \
|
||||
BiQuad.o DLineA.o DLineL.o DLineN.o VoicMang.o \
|
||||
FormSwep.o BowTabl.o JetTabl.o ReedTabl.o \
|
||||
LipFilt.o Modal4.o FM4Op.o FM4Alg3.o FM4Alg4.o \
|
||||
FM4Alg5.o FM4Alg6.o FM4Alg8.o Plucked2.o \
|
||||
SamplFlt.o Sampler.o SKINI11.o Simple.o \
|
||||
SingWave.o VoicForm.o FMVoices.o swapstuf.o \
|
||||
\
|
||||
Instrmnt.o Marimba.o Vibraphn.o AgogoBel.o Shakers.o \
|
||||
Plucked.o Mandolin.o Clarinet.o Flute.o Moog1.o \
|
||||
Brass.o Bowed.o Rhodey.o Wurley.o TubeBell.o \
|
||||
HeavyMtl.o PercFlut.o BeeThree.o DrumSynt.o \
|
||||
\
|
||||
WvOut.o SndWvOut.o WavWvOut.o MatWvOut.o \
|
||||
Reverb.o PRCRev.o JCRev.o NRev.o
|
||||
|
||||
RM = /bin/rm
|
||||
|
||||
ifeq ($(OS),NEXTSTEP) # These are for NeXT
|
||||
CC = cc -arch m68k -arch i386 -Wall
|
||||
INSTR = syntmono
|
||||
endif
|
||||
|
||||
ifeq ($(OS),IRIX) # These are for SGI
|
||||
INSTR = MD2SKINI syntmono
|
||||
CC = CC -O # -g -fullwarn -D__SGI_CC__
|
||||
O_FILES += RTWvOut.o RTSoundIO.o MIDIIO.o
|
||||
LIBRARY = -L/usr/sgitcl/lib -laudio -lmd -lm
|
||||
endif
|
||||
|
||||
ifeq ($(OS),Linux) # These are for Linux
|
||||
INSTR = syntmono MD2SKINI
|
||||
CC = gcc -O3 # -g -pg -O3
|
||||
O_FILES += RTWvOut.o RTSoundIO.o MIDIIO.o
|
||||
LIBRARY = -lpthread -lm
|
||||
endif
|
||||
|
||||
.SUFFIXES: .cpp
|
||||
.cpp.o: Object.h
|
||||
$(CC) -c $*.cpp
|
||||
|
||||
all: $(INSTR)
|
||||
|
||||
syntmono: syntmono.cpp $(O_FILES)
|
||||
$(CC) $(INCLUDE) -o syntmono syntmono.cpp $(O_FILES) $(LIBRARY)
|
||||
|
||||
MD2SKINI: MD2SKINI.cpp $(O_FILES)
|
||||
$(CC) -o MD2SKINI MD2SKINI.cpp $(O_FILES) $(LIBRARY)
|
||||
|
||||
clean :
|
||||
rm *.o
|
||||
rm $(INSTR)
|
||||
|
||||
cleanIns :
|
||||
rm $(INSTR)
|
||||
|
||||
strip :
|
||||
strip $(INSTR)
|
||||
@@ -1,49 +0,0 @@
|
||||
# STK98 Makefile - Linux solo version
|
||||
|
||||
O_FILES = Object.o Envelope.o ADSR.o Noise.o SubNoise.o \
|
||||
RawWave.o RawShot.o RawLoop.o RawInterp.o \
|
||||
Modulatr.o Filter.o OneZero.o \
|
||||
OnePole.o TwoZero.o TwoPole.o DCBlock.o \
|
||||
BiQuad.o DLineA.o DLineL.o DLineN.o VoicMang.o \
|
||||
FormSwep.o BowTabl.o JetTabl.o ReedTabl.o \
|
||||
LipFilt.o Modal4.o FM4Op.o FM4Alg3.o FM4Alg4.o \
|
||||
FM4Alg5.o FM4Alg6.o FM4Alg8.o Plucked2.o \
|
||||
SamplFlt.o Sampler.o SKINI11.o Simple.o \
|
||||
SingWave.o VoicForm.o FMVoices.o swapstuf.o \
|
||||
\
|
||||
Instrmnt.o Marimba.o Vibraphn.o AgogoBel.o Shakers.o \
|
||||
Plucked.o Mandolin.o Clarinet.o Flute.o Moog1.o \
|
||||
Brass.o Bowed.o Rhodey.o Wurley.o TubeBell.o \
|
||||
HeavyMtl.o PercFlut.o BeeThree.o DrumSynt.o \
|
||||
\
|
||||
WvOut.o SndWvOut.o WavWvOut.o MatWvOut.o \
|
||||
Reverb.o PRCRev.o JCRev.o NRev.o \
|
||||
RTWvOut.o RTSoundIO.o MIDIIO.o
|
||||
|
||||
RM = /bin/rm
|
||||
|
||||
INSTR = syntmono MD2SKINI
|
||||
CC = gcc -O3 # -g -pg -O3
|
||||
LIBRARY = -lpthread -lm
|
||||
|
||||
.SUFFIXES: .cpp
|
||||
.cpp.o: Object.h
|
||||
$(CC) -c $*.cpp
|
||||
|
||||
all: $(INSTR)
|
||||
|
||||
syntmono: syntmono.cpp $(O_FILES)
|
||||
$(CC) $(INCLUDE) -o syntmono syntmono.cpp $(O_FILES) $(LIBRARY)
|
||||
|
||||
MD2SKINI: MD2SKINI.cpp $(O_FILES)
|
||||
$(CC) -o MD2SKINI MD2SKINI.cpp $(O_FILES) $(LIBRARY)
|
||||
|
||||
clean :
|
||||
rm *.o
|
||||
rm $(INSTR)
|
||||
|
||||
cleanIns :
|
||||
rm $(INSTR)
|
||||
|
||||
strip :
|
||||
strip $(INSTR)
|
||||
49
Makefile.sgi
49
Makefile.sgi
@@ -1,49 +0,0 @@
|
||||
# STK98 Makefile - SGI solo version
|
||||
|
||||
O_FILES = Object.o Envelope.o ADSR.o Noise.o SubNoise.o \
|
||||
RawWave.o RawShot.o RawLoop.o RawInterp.o \
|
||||
Modulatr.o Filter.o OneZero.o \
|
||||
OnePole.o TwoZero.o TwoPole.o DCBlock.o \
|
||||
BiQuad.o DLineA.o DLineL.o DLineN.o VoicMang.o \
|
||||
FormSwep.o BowTabl.o JetTabl.o ReedTabl.o \
|
||||
LipFilt.o Modal4.o FM4Op.o FM4Alg3.o FM4Alg4.o \
|
||||
FM4Alg5.o FM4Alg6.o FM4Alg8.o Plucked2.o \
|
||||
SamplFlt.o Sampler.o SKINI11.o Simple.o \
|
||||
SingWave.o VoicForm.o FMVoices.o swapstuf.o \
|
||||
\
|
||||
Instrmnt.o Marimba.o Vibraphn.o AgogoBel.o Shakers.o \
|
||||
Plucked.o Mandolin.o Clarinet.o Flute.o Moog1.o \
|
||||
Brass.o Bowed.o Rhodey.o Wurley.o TubeBell.o \
|
||||
HeavyMtl.o PercFlut.o BeeThree.o DrumSynt.o \
|
||||
\
|
||||
WvOut.o SndWvOut.o WavWvOut.o MatWvOut.o \
|
||||
Reverb.o PRCRev.o JCRev.o NRev.o \
|
||||
RTWvOut.o RTSoundIO.o MIDIIO.o
|
||||
|
||||
RM = /bin/rm
|
||||
|
||||
INSTR = MD2SKINI syntmono
|
||||
CC = CC -O # -g -fullwarn -D__SGI_CC__
|
||||
LIBRARY = -L/usr/sgitcl/lib -laudio -lmd -lm
|
||||
|
||||
.SUFFIXES: .cpp
|
||||
.cpp.o: Object.h
|
||||
$(CC) -c $*.cpp
|
||||
|
||||
all: $(INSTR)
|
||||
|
||||
syntmono: syntmono.cpp $(O_FILES)
|
||||
$(CC) $(INCLUDE) -o syntmono syntmono.cpp $(O_FILES) $(LIBRARY)
|
||||
|
||||
MD2SKINI: MD2SKINI.cpp $(O_FILES)
|
||||
$(CC) -o MD2SKINI MD2SKINI.cpp $(O_FILES) $(LIBRARY)
|
||||
|
||||
clean :
|
||||
rm *.o
|
||||
rm $(INSTR)
|
||||
|
||||
cleanIns :
|
||||
rm $(INSTR)
|
||||
|
||||
strip :
|
||||
strip $(INSTR)
|
||||
113
Marimba.cpp
113
Marimba.cpp
@@ -1,113 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Marimba SubClass of Modal4 Instrument, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Controls: CONTROL1 = stickHardness */
|
||||
/* CONTROL2 = strikePosition*/
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/*******************************************/
|
||||
|
||||
#include "Marimba.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
Marimba :: Marimba() : Modal4()
|
||||
{
|
||||
wave = new RawInterp("rawwaves/marmstk1.raw");
|
||||
wave->normalize();
|
||||
wave->setRate((MY_FLOAT) 0.5); /* normal stick */
|
||||
this->setRatioAndReson(0, (MY_FLOAT) 1.00,(MY_FLOAT) 0.9996); /* Set all 132.0 */
|
||||
this->setRatioAndReson(1, (MY_FLOAT) 3.99,(MY_FLOAT) 0.9994); /* of our 523.0 */
|
||||
this->setRatioAndReson(2,(MY_FLOAT) 10.65,(MY_FLOAT) 0.9994); /* default 1405.0 */
|
||||
this->setRatioAndReson(3,-(MY_FLOAT) 2443.0,(MY_FLOAT) 0.999); /* resonances 2443.0 */
|
||||
this->setFiltGain(0,(MY_FLOAT) 0.04); /* and */
|
||||
this->setFiltGain(1,(MY_FLOAT) 0.01); /* gains */
|
||||
this->setFiltGain(2,(MY_FLOAT) 0.01); /* for each */
|
||||
this->setFiltGain(3,(MY_FLOAT) 0.008); /* resonance */
|
||||
directGain = (MY_FLOAT) 0.1;
|
||||
multiStrike = 0;
|
||||
}
|
||||
|
||||
Marimba :: ~Marimba()
|
||||
{
|
||||
delete wave;
|
||||
}
|
||||
|
||||
void Marimba :: setStickHardness(MY_FLOAT hardness)
|
||||
{
|
||||
stickHardness = hardness;
|
||||
wave->setRate((MY_FLOAT) (0.25 * (MY_FLOAT) pow(4.0,stickHardness)));
|
||||
masterGain = (MY_FLOAT) 0.1 + ((MY_FLOAT) 1.8 * stickHardness);
|
||||
}
|
||||
|
||||
void Marimba :: setStrikePosition(MY_FLOAT position)
|
||||
{
|
||||
MY_FLOAT temp,temp2;
|
||||
temp2 = position * PI;
|
||||
strikePosition = position; /* Hack only first three modes */
|
||||
temp = (MY_FLOAT) sin(temp2);
|
||||
this->setFiltGain(0,(MY_FLOAT) 0.12 * temp); /* 1st mode function of pos. */
|
||||
temp = (MY_FLOAT) sin(0.05 + (3.9 * temp2));
|
||||
this->setFiltGain(1,(MY_FLOAT) -0.03 * temp); /* 2nd mode function of pos. */
|
||||
temp = (MY_FLOAT) sin(-0.05 + (11 * temp2));
|
||||
this->setFiltGain(2,(MY_FLOAT) 0.11 * temp); /* 3rd mode function of pos. */
|
||||
}
|
||||
|
||||
void Marimba :: setModulationSpeed(MY_FLOAT mSpeed)
|
||||
{
|
||||
/* don't bother here, marimba decay so fast, mod doesn't make sense */
|
||||
}
|
||||
|
||||
void Marimba :: setModulationDepth(MY_FLOAT mDepth)
|
||||
{
|
||||
}
|
||||
|
||||
void Marimba :: strike(MY_FLOAT amplitude)
|
||||
{
|
||||
int temp;
|
||||
temp = rand() >> 10;
|
||||
if (temp < 2) {
|
||||
multiStrike = 1;
|
||||
#if defined(_debug_)
|
||||
printf("striking twice here!!\n");
|
||||
#endif
|
||||
}
|
||||
else if (temp < 1) {
|
||||
multiStrike = 2;
|
||||
#if defined(_debug_)
|
||||
printf("striking three times here!!!\n");
|
||||
#endif
|
||||
}
|
||||
else multiStrike = 0;
|
||||
Modal4::strike(amplitude);
|
||||
}
|
||||
|
||||
void Marimba :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Marimba : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_StickHardness_)
|
||||
this->setStickHardness(value * NORM_7);
|
||||
else if (number == __SK_StrikePosition_)
|
||||
this->setStrikePosition(value * NORM_7);
|
||||
else if (number == __SK_ModFrequency_)
|
||||
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
|
||||
else if (number == __SK_ModWheel_)
|
||||
vibrGain = (value * NORM_7);
|
||||
else if (number == __SK_AfterTouch_Cont_)
|
||||
this->strike(value * NORM_7);
|
||||
else {
|
||||
printf("Marimba : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
MY_FLOAT Marimba :: tick()
|
||||
{
|
||||
if (multiStrike>0)
|
||||
if (wave->isFinished()) {
|
||||
wave->reset();
|
||||
multiStrike -= 1;
|
||||
}
|
||||
return Modal4::tick();
|
||||
}
|
||||
32
Marimba.h
32
Marimba.h
@@ -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
|
||||
214
MatWvOut.cpp
214
MatWvOut.cpp
@@ -1,214 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Matlab MAT File Output Class, */
|
||||
/* by Gary P. Scavone, 1998. */
|
||||
/* This object creates a Matlab MAT-file */
|
||||
/* structure and fills it with buffers of */
|
||||
/* samples (doubles). */
|
||||
/* */
|
||||
/* The Matlab MAT-file format is not */
|
||||
/* available to the general public. I */
|
||||
/* spent several days reverse-engineering */
|
||||
/* the file format to create this class. */
|
||||
/* I couldn't figure out what a few of */
|
||||
/* the header fields correspond to, but */
|
||||
/* for the purposes of STK, this */
|
||||
/* shouldn't create any problems. */
|
||||
/*******************************************/
|
||||
|
||||
#include "MatWvOut.h"
|
||||
|
||||
/******** Matlab Matfile Header Struct *******/
|
||||
struct matheaderform {
|
||||
char heading[124];
|
||||
short a[2];
|
||||
long b[10];
|
||||
/* There's more, but it's of variable length */
|
||||
};
|
||||
|
||||
FILE *openMatFile(int chans,char *fileName) {
|
||||
struct matheaderform hdr;
|
||||
FILE *fd;
|
||||
char tempName[128];
|
||||
int i, namelen;
|
||||
long longtmp, headsize;
|
||||
|
||||
strcpy(hdr.heading,"MATLAB 5.0 MAT-file, Generated by STK98. This file format was hacked by Gary P. Scavone, CCRMA, Stanford University, 1998.");
|
||||
|
||||
for (i=strlen(hdr.heading);i<124;i++) hdr.heading[i] = ' ';
|
||||
|
||||
hdr.a[0] = (short) 256;
|
||||
hdr.a[1] = (short) 'M';
|
||||
hdr.a[1] <<= 8;
|
||||
hdr.a[1] += 'I';
|
||||
hdr.b[0] = (long) 14;
|
||||
hdr.b[1] = (long) 0; /* Size of file after this point to end (in bytes) */
|
||||
hdr.b[2] = (long) 6;
|
||||
hdr.b[3] = (long) 8;
|
||||
hdr.b[4] = (long) 6;
|
||||
hdr.b[5] = (long) 0;
|
||||
hdr.b[6] = (long) 5;
|
||||
hdr.b[7] = (long) 8;
|
||||
hdr.b[8] = (long) chans; /* This is the number of rows */
|
||||
hdr.b[9] = (long) 0; /* This is the number of columns */
|
||||
|
||||
strcpy(tempName,fileName);
|
||||
strcat(tempName,".mat");
|
||||
|
||||
fd = fopen(tempName,"w+b");
|
||||
if (!fd) {
|
||||
printf("Couldn't create matfile %s !!!!!!!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
printf("Creating matfile %s.\n", tempName);
|
||||
fwrite(&hdr,sizeof(char),168,fd); /* Write the fixed portion of the header */
|
||||
|
||||
/* The next 4 bytes can be viewed as two shorts, but they are byteswapped
|
||||
as a long. The first short value seems to always be one; the second
|
||||
short will be the length of the variable name IF IT IS <= 4; if the
|
||||
variable name length is >4, this short is zero and the length is put
|
||||
in the next 4 bytes. The variable name length is limited to 31
|
||||
characters (32 with a '\n'). The actual variable name then follows.
|
||||
The variable name is "zero-padded" out to the following minimum
|
||||
lengths (in bits): 4, 8, 16, 24, 32.
|
||||
*/
|
||||
namelen = strlen(fileName);
|
||||
if (namelen > 31) { /* Check length of variable name (file name) */
|
||||
fprintf(stderr, "File name too long ... should be 31 characters or less.\n");
|
||||
fclose(fd);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (namelen > 4) {
|
||||
longtmp = 1;
|
||||
fwrite(&longtmp,sizeof(long),1,fd);
|
||||
fwrite(&namelen,sizeof(long),1,fd);
|
||||
headsize = 44 + namelen;
|
||||
} else {
|
||||
longtmp = namelen;
|
||||
longtmp <<= 16;
|
||||
longtmp += 1;
|
||||
fwrite(&longtmp,sizeof(long),1,fd);
|
||||
headsize = 40 + namelen;
|
||||
}
|
||||
|
||||
fwrite(fileName,sizeof(char),namelen,fd); /* Write the variable (file) name */
|
||||
if (namelen < 5)
|
||||
longtmp = 4 - namelen;
|
||||
else if (namelen < 9)
|
||||
longtmp = 8 - namelen;
|
||||
else if (namelen < 17)
|
||||
longtmp = 16 - namelen;
|
||||
else if (namelen < 25)
|
||||
longtmp = 24 - namelen;
|
||||
else longtmp = 32 - namelen;
|
||||
|
||||
headsize += longtmp + 8; /* Add length (8) of following bytes */
|
||||
fseek(fd,longtmp,SEEK_CUR);
|
||||
|
||||
longtmp = 9;
|
||||
fwrite(&longtmp,sizeof(long),1,fd);
|
||||
longtmp = 0; /* Size of data in bytes (8 per sample) */
|
||||
fwrite(&longtmp,sizeof(long),1,fd);
|
||||
|
||||
fseek(fd,132,SEEK_SET);
|
||||
fwrite(&headsize,sizeof(long),1,fd); /* Write header size ... will update at end */
|
||||
fseek(fd,0,SEEK_END);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
MatWvOut :: MatWvOut(char *fileName)
|
||||
{
|
||||
chans = 1;
|
||||
pan = 0.5;
|
||||
fd = openMatFile(chans,fileName);
|
||||
counter = 0;
|
||||
totalCount = 0;
|
||||
}
|
||||
|
||||
MatWvOut :: MatWvOut(int channels, char *fileName)
|
||||
{
|
||||
chans = channels;
|
||||
pan = 0.5;
|
||||
fd = openMatFile(chans,fileName);
|
||||
counter = 0;
|
||||
totalCount = 0;
|
||||
}
|
||||
|
||||
MatWvOut :: ~MatWvOut()
|
||||
{
|
||||
double temp;
|
||||
long headsize, temp1;
|
||||
|
||||
fwrite(data,sizeof(double),counter,fd);
|
||||
temp = (double) totalCount * ONE_OVER_SRATE;
|
||||
printf("%f Seconds Computed\n",temp);
|
||||
fseek(fd,164,SEEK_SET);
|
||||
fwrite(&totalCount,sizeof(long),1,fd); /* Write number of columns */
|
||||
fseek(fd,132,SEEK_SET);
|
||||
fread(&headsize,sizeof(long),1,fd);
|
||||
temp1 = headsize;
|
||||
headsize += (long) (totalCount * 8 * 2);
|
||||
fseek(fd,132,SEEK_SET);
|
||||
fwrite(&headsize,sizeof(long),1,fd); /* Write file size (minus some header info) */
|
||||
fseek(fd,temp1+128,SEEK_SET);
|
||||
temp1 = totalCount * 8 * 2;
|
||||
fwrite(&temp1,sizeof(long),1,fd); /* Write data size (in bytes) */
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
long MatWvOut :: getCounter()
|
||||
{
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
MY_FLOAT MatWvOut :: getTime()
|
||||
{
|
||||
return (MY_FLOAT) totalCount * ONE_OVER_SRATE;
|
||||
}
|
||||
|
||||
void MatWvOut :: tick(MY_FLOAT sample)
|
||||
{
|
||||
if (chans==1) {
|
||||
data[counter++] = (double) (sample);
|
||||
}
|
||||
else {
|
||||
data[counter++] = (double) (sample * (1.0 - pan));
|
||||
data[counter++] = (double) (sample * pan);
|
||||
}
|
||||
totalCount += 1;
|
||||
if (counter == MAT_BUFFER_SIZE) {
|
||||
fwrite(data,sizeof(double),MAT_BUFFER_SIZE,fd);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MatWvOut :: tick(MY_FLOAT lsamp, MY_FLOAT rsamp)
|
||||
{
|
||||
if (chans==1) {
|
||||
data[counter++] = (double) (lsamp + rsamp);
|
||||
}
|
||||
else {
|
||||
data[counter++] = (double) (lsamp);
|
||||
data[counter++] = (double) (rsamp);
|
||||
}
|
||||
totalCount += 1;
|
||||
if (counter == MAT_BUFFER_SIZE) {
|
||||
fwrite(data,sizeof(double),MAT_BUFFER_SIZE,fd);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MatWvOut :: setMonoPan(MY_FLOAT aPan)
|
||||
{
|
||||
pan = aPan;
|
||||
if (aPan < 0.0) {
|
||||
pan = 0.0;
|
||||
printf("Pan < 0.0, correcting to 0.0\n");
|
||||
}
|
||||
if (aPan > 1.0) {
|
||||
pan = 1.0;
|
||||
printf("Pan > 1.0, correcting to 1.0\n");
|
||||
}
|
||||
}
|
||||
46
MatWvOut.h
46
MatWvOut.h
@@ -1,46 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Matlab MAT File Output Class, */
|
||||
/* by Gary P. Scavone, 1998. */
|
||||
/* This object creates a Matlab MAT-file */
|
||||
/* structure and fills it with buffers of */
|
||||
/* samples (doubles). */
|
||||
/* */
|
||||
/* The Matlab MAT-file format is not */
|
||||
/* available to the general public. I */
|
||||
/* spent several days reverse-engineering */
|
||||
/* the file format to create this class. */
|
||||
/* I couldn't figure out what a few of */
|
||||
/* the header fields correspond to, but */
|
||||
/* for the purposes of STK, this */
|
||||
/* shouldn't create any problems. */
|
||||
/*******************************************/
|
||||
|
||||
#include "Object.h"
|
||||
#include "WvOut.h"
|
||||
|
||||
#if !defined(__MatWvOut_h)
|
||||
#define __MatWvOut_h
|
||||
|
||||
#define MAT_BUFFER_SIZE 1024
|
||||
|
||||
class MatWvOut : public WvOut
|
||||
{
|
||||
protected:
|
||||
FILE *fd;
|
||||
double data[MAT_BUFFER_SIZE]; /* not MY_FLOAT because MAT uses doubles */
|
||||
long counter;
|
||||
long totalCount;
|
||||
int chans;
|
||||
MY_FLOAT pan;
|
||||
public:
|
||||
MatWvOut(char *infileName);
|
||||
MatWvOut(int channels, char *infileName);
|
||||
~MatWvOut();
|
||||
long getCounter();
|
||||
MY_FLOAT getTime();
|
||||
void setMonoPan(MY_FLOAT aPan);
|
||||
void tick(MY_FLOAT sample);
|
||||
void tick(MY_FLOAT lsamp, MY_FLOAT rsamp);
|
||||
};
|
||||
|
||||
#endif // defined(__MatWvOut_h)
|
||||
186
Modal4.cpp
186
Modal4.cpp
@@ -1,186 +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((MY_FLOAT) 6.0);
|
||||
vibrGain = (MY_FLOAT) 0.05;
|
||||
|
||||
directGain = (MY_FLOAT) 0.0;
|
||||
masterGain = (MY_FLOAT) 1.0;
|
||||
baseFreq = (MY_FLOAT) 440.0;
|
||||
this->setRatioAndReson(0,(MY_FLOAT) 1.00,(MY_FLOAT) 0.9997); /* Set some */
|
||||
this->setRatioAndReson(1,(MY_FLOAT) 1.30,(MY_FLOAT) 0.9997); /* silly */
|
||||
this->setRatioAndReson(2,(MY_FLOAT) 1.77,(MY_FLOAT) 0.9997); /* default */
|
||||
this->setRatioAndReson(3,(MY_FLOAT) 2.37,(MY_FLOAT) 0.9997); /* values here */
|
||||
this->setFiltGain(0,(MY_FLOAT) 0.01);
|
||||
this->setFiltGain(1,(MY_FLOAT) 0.01);
|
||||
this->setFiltGain(2,(MY_FLOAT) 0.01);
|
||||
this->setFiltGain(3,(MY_FLOAT) 0.01);
|
||||
this->clear();
|
||||
filters[0]->setEqualGainZeroes();
|
||||
filters[1]->setEqualGainZeroes();
|
||||
filters[2]->setEqualGainZeroes();
|
||||
filters[3]->setEqualGainZeroes();
|
||||
stickHardness = (MY_FLOAT) 0.5;
|
||||
strikePosition = (MY_FLOAT) 0.561;
|
||||
}
|
||||
|
||||
Modal4 :: ~Modal4()
|
||||
{
|
||||
delete envelope;
|
||||
delete filters[0];
|
||||
delete filters[1];
|
||||
delete filters[2];
|
||||
delete filters[3];
|
||||
delete onepole;
|
||||
delete vibr;
|
||||
}
|
||||
|
||||
void Modal4 :: clear()
|
||||
{
|
||||
onepole->clear();
|
||||
filters[0]->clear();
|
||||
filters[1]->clear();
|
||||
filters[2]->clear();
|
||||
filters[3]->clear();
|
||||
}
|
||||
|
||||
void Modal4 :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
this->setRatioAndReson(0,ratios[0],resons[0]);
|
||||
this->setRatioAndReson(1,ratios[1],resons[1]);
|
||||
this->setRatioAndReson(2,ratios[2],resons[2]);
|
||||
this->setRatioAndReson(3,ratios[3],resons[3]);
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void Modal4 :: setRatioAndReson(int whichOne, MY_FLOAT ratio,MY_FLOAT reson)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
if (ratio*baseFreq < SRATE_OVER_TWO) {
|
||||
ratios[whichOne] = ratio;
|
||||
}
|
||||
else {
|
||||
temp = ratio;
|
||||
while (temp*baseFreq > SRATE_OVER_TWO) temp *= (MY_FLOAT) 0.5;
|
||||
ratios[whichOne] = temp;
|
||||
#if defined(_debug_)
|
||||
printf("Modal4 : Aliasing would occur here, correcting.\n");
|
||||
#endif
|
||||
}
|
||||
resons[whichOne] = reson;
|
||||
if (ratio<0)
|
||||
temp = -ratio;
|
||||
else
|
||||
temp = ratio*baseFreq;
|
||||
filters[whichOne]->setFreqAndReson(temp,reson);
|
||||
}
|
||||
|
||||
void Modal4 :: setMasterGain(MY_FLOAT aGain)
|
||||
{
|
||||
masterGain = aGain;
|
||||
}
|
||||
|
||||
void Modal4 :: setDirectGain(MY_FLOAT aGain)
|
||||
{
|
||||
directGain = aGain;
|
||||
}
|
||||
|
||||
void Modal4 :: setFiltGain(int whichOne, MY_FLOAT gain)
|
||||
{
|
||||
filters[whichOne]->setGain(gain);
|
||||
}
|
||||
|
||||
void Modal4 :: strike(MY_FLOAT amplitude)
|
||||
{
|
||||
int i;
|
||||
MY_FLOAT temp;
|
||||
envelope->setRate((MY_FLOAT) 1.0);
|
||||
envelope->setTarget(amplitude);
|
||||
onepole->setPole((MY_FLOAT) 1.0 - amplitude);
|
||||
envelope->tick();
|
||||
wave->reset();
|
||||
for (i=0;i<4;i++) {
|
||||
if (ratios[i] < 0)
|
||||
temp = -ratios[i];
|
||||
else
|
||||
temp = ratios[i] * baseFreq;
|
||||
filters[i]->setFreqAndReson(temp,resons[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Modal4 :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->strike(amp);
|
||||
this->setFreq(freq);
|
||||
#if defined(_debug_)
|
||||
printf("Modal4 : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Modal4 :: noteOff(MY_FLOAT amp) /* This calls damp, but inverts the */
|
||||
{ /* meaning of amplitude. */
|
||||
this->damp((MY_FLOAT) 1.0 - (amp * (MY_FLOAT) 0.03)); /* (high amplitude means fast damping) */
|
||||
#if defined(_debug_)
|
||||
printf("Modal4 : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Modal4 :: damp(MY_FLOAT amplitude)
|
||||
{
|
||||
int i;
|
||||
MY_FLOAT temp;
|
||||
for (i=0;i<4;i++) {
|
||||
if (ratios[i] < 0)
|
||||
temp = -ratios[i];
|
||||
else
|
||||
temp = ratios[i] * baseFreq;
|
||||
filters[i]->setFreqAndReson(temp,resons[i]*amplitude);
|
||||
}
|
||||
}
|
||||
|
||||
void Modal4 :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT Modal4 :: tick()
|
||||
{
|
||||
MY_FLOAT temp,temp2;
|
||||
temp = masterGain * onepole->tick(wave->tick() * envelope->tick());
|
||||
temp2 = filters[0]->tick(temp);
|
||||
temp2 += filters[1]->tick(temp);
|
||||
temp2 += filters[2]->tick(temp);
|
||||
temp2 += filters[3]->tick(temp);
|
||||
temp2 = temp2 - (temp2 * directGain);
|
||||
temp2 += directGain * temp;
|
||||
|
||||
if (vibrGain != 0.0) {
|
||||
temp = (MY_FLOAT) 1.0 + (vibr->tick() * vibrGain); /* Calculate AM */
|
||||
temp2 = temp * temp2; /* and apply to master out */
|
||||
}
|
||||
|
||||
lastOutput = temp2 * (MY_FLOAT) 2.0;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
52
Modal4.h
52
Modal4.h
@@ -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 "RawInterp.h"
|
||||
#include "RawLoop.h"
|
||||
#include "BiQuad.h"
|
||||
#include "OnePole.h"
|
||||
|
||||
class Modal4 : public Instrmnt
|
||||
{
|
||||
protected:
|
||||
Envelope *envelope;
|
||||
RawInterp *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();
|
||||
virtual ~Modal4();
|
||||
void clear();
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
void setRatioAndReson(int whichOne, MY_FLOAT ratio, MY_FLOAT reson);
|
||||
void setMasterGain(MY_FLOAT aGain);
|
||||
void setDirectGain(MY_FLOAT aGain);
|
||||
void setFiltGain(int whichOne, MY_FLOAT gain);
|
||||
virtual void strike(MY_FLOAT amplitude);
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
virtual void noteOff(MY_FLOAT amp);
|
||||
void damp(MY_FLOAT amplitude);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
virtual MY_FLOAT tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
107
Moog1.cpp
107
Moog1.cpp
@@ -1,107 +0,0 @@
|
||||
/******************************************/
|
||||
/* Test Sampler Subclass of */
|
||||
/* Sampling Synthesizer Class */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Controls: CONTROL1 = filterQ */
|
||||
/* CONTROL2 = filterRate */
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/******************************************/
|
||||
|
||||
#include "Moog1.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
Moog1 :: Moog1() : SamplFlt()
|
||||
{
|
||||
attacks[0] = new RawInterp("rawwaves/mandpluk.raw");
|
||||
loops[0] = new RawLoop("rawwaves/impuls20.raw");
|
||||
loops[1] = new RawLoop("rawwaves/sinewave.raw"); /* Steal one for vibrato */
|
||||
attacks[0]->normalize();
|
||||
loops[0]->normalize();
|
||||
loops[1]->normalize();
|
||||
loops[1]->setFreq((MY_FLOAT) 6.122);
|
||||
adsr->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 1.5,(MY_FLOAT) 0.6,(MY_FLOAT) 0.250);
|
||||
filterQ = (MY_FLOAT) 0.85;
|
||||
filterRate = (MY_FLOAT) 0.0001;
|
||||
modDepth = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
Moog1 :: ~Moog1()
|
||||
{
|
||||
delete attacks[0];
|
||||
delete loops[0];
|
||||
delete loops[1];
|
||||
}
|
||||
|
||||
void Moog1 :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
attacks[0]->setFreq(baseFreq * (MY_FLOAT) 0.01);
|
||||
loops[0]->setFreq(baseFreq);
|
||||
}
|
||||
|
||||
void Moog1 :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
|
||||
this->setFreq(freq);
|
||||
this->keyOn();
|
||||
attackGain = amp * (MY_FLOAT) 0.5;
|
||||
loopGain = amp;
|
||||
|
||||
temp = filterQ + (MY_FLOAT) 0.05;
|
||||
filters[0]->setStates((MY_FLOAT) 2000.0,temp,(MY_FLOAT) 2.0 * ((MY_FLOAT) 1.0 - temp));
|
||||
filters[1]->setStates((MY_FLOAT) 2000.0,temp,(MY_FLOAT) 2.0 * ((MY_FLOAT) 1.0 - temp));
|
||||
temp = filterQ + (MY_FLOAT) 0.099;
|
||||
filters[0]->setTargets((MY_FLOAT) freq,temp,(MY_FLOAT) 2.0 * ((MY_FLOAT) 1.0 - temp));
|
||||
filters[1]->setTargets((MY_FLOAT) freq,temp,(MY_FLOAT) 2.0 * ((MY_FLOAT) 1.0 - temp));
|
||||
filters[0]->setSweepRate(filterRate * (MY_FLOAT) 22050.0 / SRATE);
|
||||
filters[1]->setSweepRate(filterRate * (MY_FLOAT) 22050.0 / SRATE);
|
||||
#if defined(_debug_)
|
||||
printf("Moog1 : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Moog1 :: setModulationSpeed(MY_FLOAT mSpeed)
|
||||
{
|
||||
loops[1]->setFreq(mSpeed);
|
||||
}
|
||||
|
||||
void Moog1 :: setModulationDepth(MY_FLOAT mDepth)
|
||||
{
|
||||
modDepth = mDepth * (MY_FLOAT) 0.5;
|
||||
}
|
||||
|
||||
void Moog1 :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Moog1 : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_FilterQ_)
|
||||
filterQ = (MY_FLOAT) 0.80 + ((MY_FLOAT) 0.1 * value * NORM_7);
|
||||
else if (number == __SK_FilterSweepRate_)
|
||||
filterRate = (value * NORM_7 * (MY_FLOAT) 0.0002);
|
||||
else if (number == __SK_ModFrequency_)
|
||||
this->setModulationSpeed(value * NORM_7 * (MY_FLOAT) 12.0);
|
||||
else if (number == __SK_ModWheel_)
|
||||
this->setModulationDepth(value * NORM_7);
|
||||
else if (number == __SK_AfterTouch_Cont_)
|
||||
adsr->setTarget(value * NORM_7);
|
||||
else {
|
||||
printf("Moog1 : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
MY_FLOAT Moog1 :: tick()
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
|
||||
if (modDepth!=0.0) {
|
||||
temp = loops[1]->tick() * modDepth;
|
||||
loops[0]->setFreq(baseFreq * ((MY_FLOAT) 1.0 + temp));
|
||||
}
|
||||
lastOutput = SamplFlt :: tick();
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
23
Object.cpp
23
Object.cpp
@@ -1,23 +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"
|
||||
// #include "byteswap.c"
|
||||
|
||||
/* This is just here for compatibility and convenience,
|
||||
so there's no need to do any real calculations.
|
||||
I do set up some redefinable variables here. */
|
||||
|
||||
Object :: Object()
|
||||
{
|
||||
}
|
||||
|
||||
Object :: ~Object()
|
||||
{
|
||||
}
|
||||
|
||||
134
Object.h
134
Object.h
@@ -1,134 +0,0 @@
|
||||
/*********************************************/
|
||||
/* Object Class, by Perry R. Cook, 1995-96 */
|
||||
/* This is mostly here for compatibility */
|
||||
/* with Objective C. We'll also stick */
|
||||
/* global defines here, so everyone will */
|
||||
/* see them. */
|
||||
/*********************************************/
|
||||
|
||||
#if !defined(__Object_h)
|
||||
#define __Object_h
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
protected:
|
||||
Object();
|
||||
virtual ~Object();
|
||||
};
|
||||
|
||||
/* Uncomment your OS type below! */
|
||||
|
||||
/* #define __OS_NeXT_ */
|
||||
#define __OS_IRIX_
|
||||
/* #define __OS_Linux_ */
|
||||
/* #define __OS_Win_ */
|
||||
|
||||
#if defined(__OS_NeXT_) /* For NeXTStep - Black or White Hardware */
|
||||
#define __NeXT_
|
||||
#elif defined(__OS_IRIX_) /* For SGI */
|
||||
#define __SGI_REALTIME_
|
||||
typedef int bool;
|
||||
#elif defined(__OS_Linux_) /* For Linux */
|
||||
#define __USS_REALTIME_
|
||||
#define __LITTLE_ENDIAN__
|
||||
#elif defined(__OS_Win_) /* For Windows95 or NT */
|
||||
#define __WINDS_REALTIME_ /* For Direct Sound API */
|
||||
/* #define __WINMM_REALTIME_ */ /* For Win MM API */
|
||||
#define __SOCKET
|
||||
#define __LITTLE_ENDIAN__
|
||||
#endif
|
||||
|
||||
/* Real-time output buffer size. If clicks are occuring in the
|
||||
* output sound stream, a larger buffer size may help. Larger
|
||||
* buffer sizes, however, produce more latency between input and
|
||||
* output.
|
||||
*/
|
||||
#define RT_BUFFER_SIZE 256
|
||||
|
||||
/* This sets the maximum number of simultaneous
|
||||
* (within a buffer) MIDI messages that can be
|
||||
* serviced before messages begin to be lost or
|
||||
* overwritten. It should be a function of
|
||||
* RT_BUFFER_SIZE
|
||||
*/
|
||||
#define MAX_IN_STRINGS 25
|
||||
|
||||
/* SRATE here is 44100, others are derived accordingly */
|
||||
/*
|
||||
#define SRATE (MY_FLOAT) 44100.0
|
||||
#define SRATE_OVER_TWO (MY_FLOAT) 22050.0
|
||||
#define ONE_OVER_SRATE (MY_FLOAT) 0.00002267573696
|
||||
#define RATE_NORM (MY_FLOAT) 0.5
|
||||
#define TWO_PI_OVER_SRATE (MY_FLOAT) 0.0001424758573
|
||||
*/
|
||||
/* SRATE here is 22050, others are derived accordingly */
|
||||
|
||||
#define SRATE (MY_FLOAT) 22050.0
|
||||
#define SRATE_OVER_TWO (MY_FLOAT) 11025.0
|
||||
#define ONE_OVER_SRATE (MY_FLOAT) 0.00004535147392
|
||||
#define RATE_NORM (MY_FLOAT) 1.0
|
||||
#define TWO_PI_OVER_SRATE (MY_FLOAT) 0.0002849517146
|
||||
|
||||
/* SRATE here is 16000, others are derived accordingly */
|
||||
/*
|
||||
#define SRATE (MY_FLOAT) 16000.0
|
||||
#define SRATE_OVER_TWO (MY_FLOAT) 8000.0
|
||||
#define ONE_OVER_SRATE (MY_FLOAT) 0.0000625
|
||||
#define RATE_NORM (MY_FLOAT) 1.375
|
||||
#define TWO_PI_OVER_SRATE (MY_FLOAT) 0.000392699
|
||||
*/
|
||||
/* SRATE here is 8k, others are derived accordingly */
|
||||
/*
|
||||
#define SRATE (MY_FLOAT) 8000.0
|
||||
#define SRATE_OVER_TWO (MY_FLOAT) 4000
|
||||
#define ONE_OVER_SRATE (MY_FLOAT) 0.00012500000000
|
||||
#define RATE_NORM (MY_FLOAT) 2.75625
|
||||
#define TWO_PI_OVER_SRATE (MY_FLOAT) 0.0002849517146
|
||||
*/
|
||||
|
||||
/* Yer Basic Trigonometric constants */
|
||||
#if !defined(PI)
|
||||
#define PI (MY_FLOAT) 3.14159265359
|
||||
#endif
|
||||
#define TWO_PI (MY_FLOAT) 6.28318530718
|
||||
#define ONE_OVER_TWO_PI (MY_FLOAT) 0.15915494309
|
||||
#define SQRT_TWO 1.414213562
|
||||
|
||||
/* States for Envelopes, etc. */
|
||||
|
||||
#define ATTACK 0
|
||||
#define DECAY 1
|
||||
#define SUSTAIN 2
|
||||
#define RELEASE 3
|
||||
|
||||
/* Machine dependent stuff, possibly useful for optimization.
|
||||
* For example, changing double to float here increasesf
|
||||
* performance (speed) by a whopping 4-6% on 486-flavor machines.
|
||||
* BUT!! a change from float to double here increases speed by
|
||||
* 30% or so on SGI machines.
|
||||
*/
|
||||
|
||||
#define MY_FLOAT double
|
||||
#define MY_FLOAT_SIZE 8
|
||||
|
||||
/*
|
||||
#define MY_FLOAT float
|
||||
#define MY_FLOAT_SIZE 4
|
||||
*/
|
||||
|
||||
/* Debugging define, causes massive printf's to come out.
|
||||
* Also enables timing calculations in WaveOut class, other stuff.
|
||||
*/
|
||||
|
||||
/* #define _debug_ 1 */
|
||||
|
||||
/* MIDI definitions */
|
||||
#define NORM_7 (MY_FLOAT) 0.0078125 /* this is 1/128 */
|
||||
|
||||
#endif
|
||||
81
OnePole.cpp
81
OnePole.cpp
@@ -1,81 +0,0 @@
|
||||
/*******************************************/
|
||||
/* One Pole Filter Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* The parameter gain is an additional */
|
||||
/* gain parameter applied to the filter */
|
||||
/* on top of the normalization that takes */
|
||||
/* place automatically. So the net max */
|
||||
/* gain through the system equals the */
|
||||
/* value of gain. sgain is the combina- */
|
||||
/* tion of gain and the normalization */
|
||||
/* parameter, so if you set the poleCoeff */
|
||||
/* to alpha, sgain is always set to */
|
||||
/* gain * (1.0 - fabs(alpha)). */
|
||||
/*******************************************/
|
||||
|
||||
#include "OnePole.h"
|
||||
|
||||
OnePole :: OnePole() : Filter()
|
||||
{
|
||||
poleCoeff = (MY_FLOAT) 0.9;
|
||||
gain = (MY_FLOAT) 1.0;
|
||||
sgain = (MY_FLOAT) 0.1;
|
||||
outputs = (MY_FLOAT *) malloc(MY_FLOAT_SIZE);
|
||||
outputs[0] = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
OnePole :: ~OnePole()
|
||||
{
|
||||
free(outputs);
|
||||
}
|
||||
|
||||
void OnePole :: clear()
|
||||
{
|
||||
outputs[0] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void OnePole :: setPole(MY_FLOAT aValue)
|
||||
{
|
||||
poleCoeff = aValue;
|
||||
if (poleCoeff > 0.0) /* Normalize gain to 1.0 max */
|
||||
sgain = gain * ((MY_FLOAT) 1.0 - poleCoeff);
|
||||
else
|
||||
sgain = gain * ((MY_FLOAT) 1.0 + poleCoeff);
|
||||
}
|
||||
|
||||
void OnePole :: setGain(MY_FLOAT aValue)
|
||||
{
|
||||
gain = aValue;
|
||||
if (poleCoeff > 0.0)
|
||||
sgain = gain * ((MY_FLOAT) 1.0 - poleCoeff); /* Normalize gain to 1.0 max */
|
||||
else
|
||||
sgain = gain * ((MY_FLOAT) 1.0 + poleCoeff);
|
||||
}
|
||||
|
||||
MY_FLOAT OnePole :: tick(MY_FLOAT sample) /* Perform Filter Operation */
|
||||
{
|
||||
outputs[0] = (sgain * sample) + (poleCoeff * outputs[0]);
|
||||
lastOutput = outputs[0];
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main ************************/
|
||||
/*
|
||||
#include <stdio.h>
|
||||
|
||||
void main()
|
||||
{
|
||||
long i;
|
||||
OnePole test;
|
||||
test.setPole(0.99);
|
||||
for (i=0;i<150;i++) printf("%lf ",test.tick(1.0));
|
||||
printf("\n\n");
|
||||
|
||||
test.clear();
|
||||
test.setPole(0.9);
|
||||
test.setGain(2.0);
|
||||
for (i=0;i<150;i++) printf("%lf ",test.tick(0.5));
|
||||
printf("\n\n");
|
||||
}
|
||||
*/
|
||||
35
OnePole.h
35
OnePole.h
@@ -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
|
||||
54
PercFlut.cpp
54
PercFlut.cpp
@@ -1,54 +0,0 @@
|
||||
/******************************************/
|
||||
/* Percussive Flute Subclass */
|
||||
/* of Algorithm 4 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/******************************************/
|
||||
|
||||
#include "PercFlut.h"
|
||||
|
||||
PercFlut :: PercFlut() : FM4Alg4()
|
||||
{
|
||||
this->loadWaves("rawwaves/sinewave.raw",
|
||||
"rawwaves/sinewave.raw",
|
||||
"rawwaves/sinewave.raw",
|
||||
"rawwaves/sinewave.raw");
|
||||
|
||||
this->setRatio(0,(MY_FLOAT) (1.50 * 1.000));
|
||||
this->setRatio(1,(MY_FLOAT) (3.00 * 0.995));
|
||||
this->setRatio(2,(MY_FLOAT) (2.99 * 1.005));
|
||||
this->setRatio(3,(MY_FLOAT) (6.00 * 0.997));
|
||||
gains[0] = __FM4Op_gains[99];
|
||||
gains[1] = __FM4Op_gains[71];
|
||||
gains[2] = __FM4Op_gains[93];
|
||||
gains[3] = __FM4Op_gains[85];
|
||||
adsr[0]->setAllTimes((MY_FLOAT) 0.05,(MY_FLOAT) 0.05,
|
||||
__FM4Op_susLevels[14],(MY_FLOAT) 0.05);
|
||||
adsr[1]->setAllTimes((MY_FLOAT) 0.02,(MY_FLOAT) 0.50,
|
||||
__FM4Op_susLevels[13],(MY_FLOAT) 0.5);
|
||||
adsr[2]->setAllTimes((MY_FLOAT) 0.02,(MY_FLOAT) 0.30,
|
||||
__FM4Op_susLevels[11],(MY_FLOAT) 0.05);
|
||||
adsr[3]->setAllTimes((MY_FLOAT) 0.02,(MY_FLOAT) 0.05,
|
||||
__FM4Op_susLevels[13],(MY_FLOAT) 0.01);
|
||||
twozero->setGain((MY_FLOAT) 0.0);
|
||||
modDepth = (MY_FLOAT) 0.005;
|
||||
}
|
||||
|
||||
void PercFlut :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
}
|
||||
|
||||
void PercFlut :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
gains[0] = amp * __FM4Op_gains[99] * 0.5;
|
||||
gains[1] = amp * __FM4Op_gains[71] * 0.5;
|
||||
gains[2] = amp * __FM4Op_gains[93] * 0.5;
|
||||
gains[3] = amp * __FM4Op_gains[85] * 0.5;
|
||||
this->setFreq(freq);
|
||||
this->keyOn();
|
||||
#if defined(_debug_)
|
||||
printf("PercFlut : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
STK98v2: A ToolKit of Audio Synthesis Classes and Instruments in C++
|
||||
|
||||
By Perry R. Cook, 1995-98
|
||||
With recent help by Gary P. Scavone
|
||||
|
||||
Please read the file README.txt for more general STK information.
|
||||
|
||||
STK98 for Linux is currently using the OSS sound and MIDI API. The free version of OSS will probably work, though it doesn't work with as many soundcards as the commercial version (costs about $20).
|
||||
|
||||
STK98 should compile without much trouble, after you make the appropriate settings in Object.h and select an appropriate Makefile. Since all Linux systems should come with the GNU makefile utilities, you should be able to use either Makefile.all or Makefile.linux (which should be renamed "Makefile" before using). Typing "make" should initiate the compilation process.
|
||||
|
||||
NOTE REGARDING PTHREADS: The only issue which seems to crop up on different versions of Linux concerns threads. I am using the MIT pthreads API. Under RedHat Linux 4.x, I had to specifically include <pthread/mit/pthread.h> (the default pthread library didn't work). However, under RedHat Linux 5.0, the default works and the <pthread/mit/> path doesn't exist. I've decided to assume the default works. If you get errors with regard to pthreads when you compile, you'll have to search your system for the MIT pthread distribution and change the appropriate include statements in MIDIIO.cpp, MD2SKINI.cpp, and syntmono.cpp.
|
||||
|
||||
Once everything is compiled, you can use the scripts in "TCLSpecs" to run GUIs or invoke direct MIDI input controls. However, these scripts have been written for Tcl/Tk 8.0 ... they seem to work OK on older versions of Tcl/Tk under Linux, but not under IRIX. Tcl/Tk is free, so you might as well download the newest version.
|
||||
|
||||
Two primary executables are created during compilation - syntmono and MD2SKINI. Syntmono is the core STK synthesis server. All distributed STK instruments are run using syntmono. MD2SKINI takes raw MIDI input, converts it to SKINI format, and outputs the result to stdout or a socket port ID (under Windoze). Control data (in the form of SKINI messages) can be fed to syntmono through three principal means - SKINI scorefiles, MD2SKINI output, and Tcl/Tk GUIs. A variety of SKINI scorefiles are distributed with STK98 and can be found in the "scores" directory. Under all platforms, a scorefile can be piped or redirected to syntmono in the following way:
|
||||
|
||||
more scores/streetsf.ski | syntmono Clarinet -r
|
||||
or
|
||||
syntmono Clarinet -r < scores/streetsf.ski
|
||||
|
||||
A number of Tcl/Tk GUIs are provided in the "TCLSpecs" directory, though you will have to install Tcl/Tk on your system to use them. Realtime SKINI control data (via MD2SKINI or GUIs) can be piped to syntmono on Unix platforms in the following way:
|
||||
|
||||
MD2SKINI | syntmono Clarinet -r -i
|
||||
or
|
||||
wish < TCLSpecs/TCLPhys.tcl | syntmono Clarinet -r -i
|
||||
|
||||
|
||||
/******************************************************/
|
||||
|
||||
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.
|
||||
|
||||
/******************************************************/
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
STK98v2: A ToolKit of Audio Synthesis Classes and Instruments in C++
|
||||
|
||||
By Perry R. Cook, 1995-98
|
||||
With recent help by Gary P. Scavone
|
||||
|
||||
Please read the file README.txt for more general STK information.
|
||||
|
||||
STK98 should compile without much trouble, after you make the appropriate settings in Object.h and select an appropriate Makefile. Apparently, SGI systems are not distributed with the GNU makefile utilities, so your safest bet is to use Makefile.sgi (which should be renamed "Makefile" before using). If you do have the GNU makefile utilities on your system, you could also use Makefile.all (which is convenient if you are on a network with a variety of different computer systems). Typing "make" should initiate the compilation process.
|
||||
|
||||
Once everything is compiled, you can use the scripts in "TCLSpecs" to run GUIs or invoke direct MIDI input controls.
|
||||
|
||||
Two primary executables are created during compilation - syntmono and MD2SKINI. Syntmono is the core STK synthesis server. All distributed STK instruments are run using syntmono. MD2SKINI takes raw MIDI input, converts it to SKINI format, and outputs the result to stdout or a socket port ID (under Windoze). Control data (in the form of SKINI messages) can be fed to syntmono through three principal means - SKINI scorefiles, MD2SKINI output, and Tcl/Tk GUIs. A variety of SKINI scorefiles are distributed with STK98 and can be found in the "scores" directory. Under all platforms, a scorefile can be piped or redirected to syntmono in the following way:
|
||||
|
||||
more scores/streetsf.ski | syntmono Clarinet -r
|
||||
or
|
||||
syntmono Clarinet -r < scores/streetsf.ski
|
||||
|
||||
A number of Tcl/Tk GUIs are provided in the "TCLSpecs" directory, though you will have to install Tcl/Tk on your system to use them. Realtime SKINI control data (via MD2SKINI or GUIs) can be piped to syntmono on Unix platforms in the following way:
|
||||
|
||||
MD2SKINI | syntmono Clarinet -r -i
|
||||
or
|
||||
wish < TCLSpecs/TCLPhys.tcl | syntmono Clarinet -r -i
|
||||
|
||||
|
||||
/******************************************************/
|
||||
|
||||
Legal and Ethical:
|
||||
|
||||
This software was designed and created to be made publicly available for free, primarily for academic purposes, so if you use it, pass it on with this documentation, and for free.
|
||||
|
||||
If you make a million dollars with it, give me some. If you make compositions with it, put me in the program notes.
|
||||
|
||||
Some of the concepts are covered by various patents, some known to me and likely others which are unknown. Many of the ones known to me are administered by the Stanford Office of Technology and Licensing.
|
||||
|
||||
The good news is that large hunks of the techniques used here are public domain. To avoid subtle legal issues, I'll not state what's freely useable here, but I'll try to note within the various classes where certain things are likely to be protected by patents.
|
||||
|
||||
/******************************************************/
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
STK98v2: A ToolKit of Audio Synthesis Classes and Instruments in C++
|
||||
|
||||
By Perry R. Cook, 1995-98
|
||||
With recent help by Gary P. Scavone
|
||||
|
||||
Please read the file README.txt for more general STK information.
|
||||
|
||||
Realtime sound output under Win95 is supported using either the Direct Sound (dsound.lib) API or the old WinMM (winmm.lib) API. The Direct Sound version appears to well out-perform the older API. All new versions of Win95/NT come with the Direct Sound library, but early versions did not. If you have trouble running the distributed executables (compiled for Direct Sound API), then you probably don't have Direct Sound installed on your system. You can download the necessary Direct Sound stuff from Microsoft's WWW pages (http://www.microsoft.com/directx/download.asp). If all else fails, you should be able to compile using the winmm.lib routines ... more latency, but at least it will work.
|
||||
|
||||
Realtime MIDI input is supported using the winmm.lib API.
|
||||
|
||||
A Visual C++ workspace has been created for STK98, with two projects - syntmono and MD2SKINI. Everything has already been configured for you. The intermediate .obj files will be written to either the "Release" or "Debug" directories, but the executable files will be written to the main STK98 directory (where they need to be for proper execution). If you should somehow lose or hose the VC++ workspace file (STK98v2.dsw), then you will have to do a LOT of configuring to recreate it ... it's probably easier just to download the distribution again from our WWW sites. Anyway, for your benefit and mine, here is a list of things that need to be added to the various "Project Settings":
|
||||
|
||||
1. Under General: Set "Output files:" to <blank> (this will put the executable in the main STK directory.
|
||||
|
||||
2. Under C/C++ > Code Generation: Set "Use run-time library:" to Multithreaded.
|
||||
|
||||
3. Under Link > General: Add winmm.lib, dsound.lib, and Wsock32.lib to the end of the Object/library modules list.
|
||||
|
||||
4. Add all the necessary files to the project.
|
||||
|
||||
NOTE: For some of my personal STK files, I've had trouble compiling in VC++ with the "Optimize Speed" optimization setting (in Project Settings -> C/C++ -> Optimizations:). The files compile, but don't work the way they should when executed. These same files, however, have worked when compiled with the "Default" optimization setting. I've heard that there are bugs with some of these optimization settings.
|
||||
|
||||
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 -r < scores/streetsf.ski
|
||||
|
||||
USE TCL/TK GUIs FOR REALTIME CONTROL:
|
||||
|
||||
1. Open a DOS console window and start syntmono (eg. syntmono Clarinet -r -i).
|
||||
|
||||
2. Double click on a Tcl/Tk file in TCLSpecs (eg. TCLPhys.tcl) from the Windows Explorer to start the GUI. Select the "communications" menu item and "Socket" and make the connection.
|
||||
|
||||
3. Start moving the sliders to control the instrument.
|
||||
|
||||
USE REALTIME MIDI INPUT FOR CONTROL:
|
||||
|
||||
1. Open a DOS console window and start syntmono (eg. syntmono Clarinet -r -i).
|
||||
|
||||
2. Open another DOS console window and start MD2SKINI (assumes you already have
|
||||
MIDI setup correctly for your computer).
|
||||
|
||||
|
||||
/******************************************************/
|
||||
|
||||
Legal and Ethical:
|
||||
|
||||
This software was designed and created to be made publicly available for free, primarily for academic purposes, so if you use it, pass it on with this documentation, and for free.
|
||||
|
||||
If you make a million dollars with it, give me some. If you make compositions with it, put me in the program notes.
|
||||
|
||||
Some of the concepts are covered by various patents, some known to me and likely others which are unknown. Many of the ones known to me are administered by the Stanford Office of Technology and Licensing.
|
||||
|
||||
The good news is that large hunks of the techniques used here are public domain. To avoid subtle legal issues, I'll not state what's freely useable here, but I'll try to note within the various classes where certain things are likely to be protected by patents.
|
||||
|
||||
/******************************************************/
|
||||
|
||||
91
README.txt
91
README.txt
@@ -1,91 +0,0 @@
|
||||
STK98v2: A ToolKit of Audio Synthesis Classes and Instruments in C++
|
||||
|
||||
By Perry R. Cook, 1995-98
|
||||
With recent help by Gary P. Scavone
|
||||
|
||||
Please read the Legal and Ethical notes at the bottom of this document.
|
||||
|
||||
STK has undergone a large number of revisions, changes, and additions since its initial release in 1996. With this version 2.0 release, it has been completely ported to Linux and Win95 (not tested on WinNT but should work), as well as SGI and NeXTStep (no real time capabilities under NeXTStep). See the individual README's (eg. README-linux) for platform specific information and system requirements. In general, you will have to specify your system type in Object.h and then use either the Makefile (Unix platforms) or the VC++ workspace file (STK98v2.dsw) to compile the code.
|
||||
|
||||
STK now features realtime sound output and MIDI input under SGI, Linux (OSS), and Win95/NT (Direct Sound and Winmm routines). It is also possible to generate simultaneous .snd, .wav, and .mat (Matlab) output file types, as well as SKINI scorefiles using MD2SKINI.
|
||||
|
||||
Two primary executables are created during compilation - syntmono and MD2SKINI. Syntmono is the core STK synthesis server. All distributed STK instruments are run using syntmono. MD2SKINI takes raw MIDI input, converts it to SKINI format, and outputs the result to stdout or a socket port ID (under Windoze). Control data (in the form of SKINI messages) can be fed to syntmono through three principal means - SKINI scorefiles, MD2SKINI output, and Tcl/Tk GUIs. A variety of SKINI scorefiles are distributed with STK98 and can be found in the "scores" directory. Under all platforms, a scorefile can be piped or redirected to syntmono in the following way:
|
||||
|
||||
more scores/streetsf.ski | syntmono Clarinet -r
|
||||
or
|
||||
syntmono Clarinet -r < scores/streetsf.ski
|
||||
|
||||
A number of Tcl/Tk GUIs are provided in the "TCLSpecs" directory, though you will have to install Tcl/Tk version 8.0 or higher on your system to use them (older versions of Tcl/Tk under Linux seem to be more forgiving than under IRIX). Realtime SKINI control data (via MD2SKINI or GUIs) can be piped to syntmono on Unix platforms and perhaps under WinNT in the following way:
|
||||
|
||||
MD2SKINI | syntmono Clarinet -r -i
|
||||
or
|
||||
wish < TCLSpecs/TCLPhys.tcl | syntmono Clarinet -r -i
|
||||
|
||||
It is not possible to use realtime pipes under Win95, so socket communication is used instead. Perhaps in the future, all STK communications will be conducted using sockets. For socket communication, it is necessary to first start the syntmono socket server. For the time being, a default (hardwired) socket port of 2001 is being used by syntmono. After syntmono is running (and waiting for a socket client connection), either MD2SKINI or a Tcl/Tk GUI can be started. When using the GUI, it is necessary to invoke the "communications" menu item and select "socket" to establish the connection.
|
||||
|
||||
For more documentation on this ToolKit, the classes, etc, read the file HIERARCH.txt and the individual class definitions. Also check the platform specific README's for specific system requirements.
|
||||
|
||||
You probably already guessed this, but just to be sure, we don't guarantee anything works. :-) It's free ... what do you expect? If you find a bug, please let us know and we'll try to correct it. You can also make suggestions, but again, no guarantees. Send email to prc@cs.princeton.edu and gary@ccrma.stanford.edu.
|
||||
|
||||
Perry's comments from the original distribution:
|
||||
|
||||
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++ 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.
|
||||
|
||||
/******************************************************/
|
||||
|
||||
492
RTSoundIO.cpp
492
RTSoundIO.cpp
@@ -1,492 +0,0 @@
|
||||
/******************************************/
|
||||
/* RTSoundIO.cpp */
|
||||
/* Realtime Sound I/O Object for STK, */
|
||||
/* by Gary P. Scavone, 1998. */
|
||||
/* Based in part on code by Doug */
|
||||
/* Scott (SGI), Tim Stilson (Linux), */
|
||||
/* Bill Putnam (Win Wav), and */
|
||||
/* R. Marsanyi (DirectSound). */
|
||||
/* */
|
||||
/* At the moment, this object only */
|
||||
/* handles realtime sound output, though */
|
||||
/* input code can go here when someone */
|
||||
/* decides they need it (and writes it). */
|
||||
/* */
|
||||
/* This object provides a standard API */
|
||||
/* across all platforms for STK realtime */
|
||||
/* sound output. At the moment, this */
|
||||
/* object is only used by RTWvOut. */
|
||||
/******************************************/
|
||||
|
||||
#include "RTSoundIO.h"
|
||||
|
||||
#if defined(__SGI_REALTIME_)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
RTSoundIO :: RTSoundIO(MY_FLOAT srate, int channels)
|
||||
{
|
||||
ALconfig audio_port_config;
|
||||
int lookaheadbuffers = 8; // number of lookahead buffers
|
||||
long pvbuf[2];
|
||||
int nbuf, totalBufSize;
|
||||
|
||||
audio_port_config = ALnewconfig();
|
||||
if(ALsetchannels(audio_port_config, channels) < 0) {
|
||||
fprintf(stderr,"Cannot initialize audio port\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Size the output queue */
|
||||
nbuf = (channels == 2) ? lookaheadbuffers : lookaheadbuffers/2;
|
||||
totalBufSize = RT_BUFFER_SIZE * nbuf;
|
||||
if(ALsetqueuesize(audio_port_config, totalBufSize) < 0) {
|
||||
fprintf(stderr,"Cannot initialize audio port\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(audio_port) ALcloseport(audio_port);
|
||||
audio_port = ALopenport("sgi.driver", "w", audio_port_config);
|
||||
if(!audio_port) {
|
||||
fprintf(stderr,"Cannot initialize audio port\n");
|
||||
exit(0);
|
||||
}
|
||||
ALfreeconfig(audio_port_config);
|
||||
audio_port_config = 0;
|
||||
|
||||
pvbuf[0] = AL_OUTPUT_RATE;
|
||||
pvbuf[1] = (long) srate;
|
||||
ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 2); /* set output SR */
|
||||
/* tell port to accept refill at buffers - 1 */
|
||||
ALsetfillpoint(audio_port,RT_BUFFER_SIZE * (lookaheadbuffers - 1));
|
||||
}
|
||||
|
||||
RTSoundIO :: ~RTSoundIO()
|
||||
{
|
||||
if(audio_port) ALcloseport(audio_port);
|
||||
audio_port=0;
|
||||
}
|
||||
|
||||
int RTSoundIO :: playBuffer(short *buf, int bufsize)
|
||||
{
|
||||
ALwritesamps(audio_port, buf, bufsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(__USS_REALTIME_)
|
||||
|
||||
#define ABS(x) ((x < 0) ? (-x) : (x))
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/soundcard.h>
|
||||
|
||||
RTSoundIO :: RTSoundIO(MY_FLOAT srate, int channels)
|
||||
{
|
||||
int lookaheadbuffers = 8; // number of lookahead buffers
|
||||
int nbuf, totalBufSize;
|
||||
|
||||
char DEVICE_NAME[100];
|
||||
int format;
|
||||
int stereo; /* 0=mono, 1=stereo */
|
||||
int stereoset;
|
||||
int speed;
|
||||
int BUFFER_SIZE_LOG;
|
||||
int fragsize;
|
||||
|
||||
BUFFER_SIZE_LOG = (int)(log10((double)RT_BUFFER_SIZE)/log10(2.0));
|
||||
|
||||
if (channels > 2)
|
||||
{
|
||||
fprintf(stderr,"Unsupported # of output channels!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (channels == 2) stereo = 1;
|
||||
else stereo = 0;
|
||||
|
||||
strcpy(DEVICE_NAME,"/dev/dspW");
|
||||
|
||||
if ((audio_fd = open(DEVICE_NAME, O_WRONLY, 0)) == -1)
|
||||
{ /* Opening device failed */
|
||||
fprintf(stderr,"Cannot open audio device: %s\n",DEVICE_NAME);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Size the output queue */
|
||||
nbuf = (channels == 2) ? lookaheadbuffers : lookaheadbuffers/2;
|
||||
totalBufSize = RT_BUFFER_SIZE * nbuf;
|
||||
|
||||
fragsize = (nbuf << 16) + BUFFER_SIZE_LOG;
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &fragsize))
|
||||
{
|
||||
close(audio_fd);
|
||||
fprintf(stderr,"Error setting audio buffer size!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
format = AFMT_S16_LE;
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format)==-1)
|
||||
{ /* Fatal error */
|
||||
close(audio_fd);
|
||||
fprintf(stderr,"SNDCTL_DSP_SETFMT error\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (format != AFMT_S16_LE)
|
||||
{
|
||||
close(audio_fd);
|
||||
fprintf(stderr,"Soundcard doesn't support 16-bit signed LE format\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
stereoset = stereo;
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereoset)==-1)
|
||||
{ /* Fatal error */
|
||||
close(audio_fd);
|
||||
fprintf(stderr,"SNDCTL_DSP_STEREO\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (stereoset != stereo)
|
||||
{
|
||||
close(audio_fd);
|
||||
fprintf(stderr,"The sound card did not set correct stereo mode\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
speed = (int)srate;
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &speed)==-1)
|
||||
{ /* Fatal error */
|
||||
close(audio_fd);
|
||||
fprintf(stderr,"SNDCTL_DSP_SPEED\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (ABS(speed - srate)>100)
|
||||
{
|
||||
close(audio_fd);
|
||||
fprintf(stderr,"The device doesn't support the requested speed.\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
RTSoundIO :: ~RTSoundIO()
|
||||
{
|
||||
if(audio_fd) close(audio_fd);
|
||||
audio_fd=0;
|
||||
}
|
||||
|
||||
int RTSoundIO :: playBuffer(short *buf, int bufsize)
|
||||
{
|
||||
/* The OSS write() routine takes the buffer size in bytes, thus the
|
||||
multiplication by two.
|
||||
*/
|
||||
int len;
|
||||
|
||||
if ((len = write(audio_fd, buf, 2*bufsize)) == -1)
|
||||
{
|
||||
fprintf(stderr,"Audio write error!\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(__WINDS_REALTIME_)
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
RTSoundIO :: RTSoundIO(MY_FLOAT srate, int channels)
|
||||
{
|
||||
HRESULT result;
|
||||
HWND hWnd;
|
||||
DWORD dwDataLen;
|
||||
WAVEFORMATEX wfFormat;
|
||||
DSBUFFERDESC dsbdDesc, primarydsbDesc;
|
||||
LPDIRECTSOUNDBUFFER m_pDSPrimeBuffer;
|
||||
BYTE *pDSBuffData;
|
||||
|
||||
/* Number of buffers of size RT_BUFFER_SIZE to make secondary DS buffer */
|
||||
int nBufs = 16;
|
||||
|
||||
/* Initialize pointers to NULL */
|
||||
m_pDirectSound = NULL;
|
||||
m_pDSBuffer = NULL;
|
||||
m_pDSPrimeBuffer = NULL;
|
||||
|
||||
/* Create the DS object */
|
||||
if ((result = DirectSoundCreate(NULL, &m_pDirectSound, NULL)) != DS_OK)
|
||||
{
|
||||
fprintf(stderr,"Cannot open default sound device!!\n");
|
||||
exit(0);
|
||||
}
|
||||
hWnd = GetForegroundWindow();
|
||||
if ((result = m_pDirectSound->SetCooperativeLevel(hWnd, DSSCL_EXCLUSIVE)) != DS_OK)
|
||||
{
|
||||
fprintf(stderr,"DS Constructor: couldn't set cooperative level!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Define the wave format structure */
|
||||
wfFormat.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfFormat.nChannels = channels;
|
||||
wfFormat.nSamplesPerSec = (unsigned long) srate;
|
||||
wfFormat.wBitsPerSample = 8 * sizeof(short);
|
||||
wfFormat.nBlockAlign = wfFormat.nChannels * wfFormat.wBitsPerSample / 8;
|
||||
wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
|
||||
wfFormat.cbSize = 0;
|
||||
|
||||
/* Setup the primary DS buffer description */
|
||||
ZeroMemory(&primarydsbDesc, sizeof(DSBUFFERDESC));
|
||||
primarydsbDesc.dwSize = sizeof(DSBUFFERDESC);
|
||||
primarydsbDesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
|
||||
primarydsbDesc.dwBufferBytes = 0;
|
||||
primarydsbDesc.lpwfxFormat = NULL;
|
||||
|
||||
/* Create the primary DS buffer */
|
||||
if ((result = m_pDirectSound->CreateSoundBuffer(&primarydsbDesc,
|
||||
&m_pDSPrimeBuffer, NULL)) != DS_OK)
|
||||
{
|
||||
fprintf(stderr,"Cannot get the primary DS buffer address!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Set the primary DS buffer sound format. We have to do this because
|
||||
the default primary buffer is 8-bit, 22kHz! */
|
||||
if ((result = m_pDSPrimeBuffer->SetFormat(&wfFormat)) != DS_OK)
|
||||
{
|
||||
fprintf(stderr,"Cannot set the primary DS buffer to proper sound format!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Setup the secondary DS buffer description */
|
||||
m_cbBufSize = RT_BUFFER_SIZE * sizeof(short) * nBufs;
|
||||
ZeroMemory(&dsbdDesc, sizeof(DSBUFFERDESC));
|
||||
dsbdDesc.dwSize = sizeof(DSBUFFERDESC);
|
||||
dsbdDesc.dwFlags = DSBCAPS_GLOBALFOCUS;
|
||||
dsbdDesc.dwBufferBytes = m_cbBufSize;
|
||||
dsbdDesc.lpwfxFormat = &wfFormat;
|
||||
|
||||
/* Create the secondary DS buffer */
|
||||
if ((result = m_pDirectSound->CreateSoundBuffer(&dsbdDesc,
|
||||
&m_pDSBuffer, NULL)) != DS_OK)
|
||||
{
|
||||
fprintf(stderr,"DS Constructor: couldn't create sound buffer!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Lock the DS buffer */
|
||||
if ((result = m_pDSBuffer->Lock(0, m_cbBufSize, (LPLPVOID)&pDSBuffData,
|
||||
&dwDataLen, NULL, NULL, 0)) != DS_OK)
|
||||
{
|
||||
fprintf(stderr,"DS Constructor: couldn't lock sound buffer!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Zero the DS buffer */
|
||||
ZeroMemory(pDSBuffData, dwDataLen);
|
||||
|
||||
/* Unlock the DS buffer */
|
||||
if ((result = m_pDSBuffer->Unlock(pDSBuffData, dwDataLen, NULL, 0)) != DS_OK)
|
||||
{
|
||||
fprintf(stderr,"DS Constructor: couldn't unlock sound buffer!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
m_cbBufOffset = 0; // reset last write position to start of buffer
|
||||
|
||||
/* Start the buffer playback */
|
||||
if ((result = m_pDSBuffer->Play( 0, 0, DSBPLAY_LOOPING ) != DS_OK))
|
||||
{
|
||||
fprintf(stderr,"DS Constructor: couldn't play sound buffer!\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
RTSoundIO :: ~RTSoundIO()
|
||||
{
|
||||
// Cleanup the sound buffer
|
||||
if (m_pDSBuffer)
|
||||
{
|
||||
m_pDSBuffer->Stop();
|
||||
m_pDSBuffer->Release();
|
||||
m_pDSBuffer = NULL;
|
||||
}
|
||||
|
||||
// Cleanup the DS object
|
||||
if (m_pDirectSound)
|
||||
{
|
||||
m_pDirectSound->Release();
|
||||
m_pDirectSound = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int RTSoundIO :: playBuffer(short *buf, int bufsize)
|
||||
{
|
||||
HRESULT hr;
|
||||
DWORD status;
|
||||
LPVOID lpbuf1 = NULL;
|
||||
LPVOID lpbuf2 = NULL;
|
||||
DWORD dwsize1 = 0;
|
||||
DWORD dwsize2 = 0;
|
||||
DWORD playPos, safePos, endWrite;
|
||||
DWORD millis;
|
||||
|
||||
// Should be playing, right?
|
||||
hr = m_pDSBuffer->GetStatus( &status );
|
||||
if (!(status && DSBSTATUS_PLAYING))
|
||||
{
|
||||
printf("Buffer not playing!\n");
|
||||
}
|
||||
|
||||
// Sleep until we have enough room in buffer.
|
||||
hr = m_pDSBuffer->GetCurrentPosition( &playPos, &safePos );
|
||||
if( hr != DS_OK ) return -1;
|
||||
if( playPos < m_cbBufOffset ) playPos += m_cbBufSize; // unwrap offset
|
||||
|
||||
endWrite = m_cbBufOffset + RT_BUFFER_SIZE * sizeof(short);
|
||||
while ( playPos < endWrite ) {
|
||||
// Calculate number of milliseconds until we will have room, as
|
||||
// time = distance * (milliseconds/second) / ((bytes/sample) * (samples/second)),
|
||||
// rounded up.
|
||||
millis = (DWORD) (1.0 + ((endWrite - playPos) * 1000.0) / ( sizeof(short) * SRATE));
|
||||
|
||||
// Sleep for that long
|
||||
Sleep( millis );
|
||||
|
||||
// Wake up, find out where we are now
|
||||
hr = m_pDSBuffer->GetCurrentPosition( &playPos, &safePos );
|
||||
if( hr != DS_OK ) return -1;
|
||||
if( playPos < m_cbBufOffset ) playPos += m_cbBufSize; // unwrap offset
|
||||
}
|
||||
|
||||
// Lock free space in the DS
|
||||
hr = m_pDSBuffer->Lock (m_cbBufOffset, RT_BUFFER_SIZE * sizeof(short), &lpbuf1, &dwsize1, &lpbuf2, &dwsize2, 0);
|
||||
if (hr == DS_OK)
|
||||
{
|
||||
// Copy the buffer into the DS
|
||||
CopyMemory(lpbuf1, buf, dwsize1);
|
||||
if(NULL != lpbuf2) CopyMemory(lpbuf2, buf+dwsize1, dwsize2);
|
||||
|
||||
// Update our buffer offset and unlock sound buffer
|
||||
m_cbBufOffset = (m_cbBufOffset + dwsize1 + dwsize2) % m_cbBufSize;
|
||||
m_pDSBuffer->Unlock (lpbuf1, dwsize1, lpbuf2, dwsize2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(__WINMM_REALTIME_)
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define FRAMETIME (long) (1000.0 * RT_BUFFER_SIZE / SRATE)
|
||||
|
||||
RTSoundIO :: RTSoundIO(MY_FLOAT srate, int channels)
|
||||
{
|
||||
MMRESULT result;
|
||||
WAVEFORMATEX wfx;
|
||||
int bufferSize = RT_BUFFER_SIZE;
|
||||
|
||||
audioPort = NULL;
|
||||
|
||||
wfx.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx.nChannels = channels;
|
||||
wfx.nSamplesPerSec = (unsigned long) srate;
|
||||
wfx.nBlockAlign = sizeof(short) * channels;
|
||||
wfx.nAvgBytesPerSec = (unsigned long) srate * wfx.nBlockAlign;
|
||||
wfx.wBitsPerSample = 8 * sizeof(short);
|
||||
wfx.cbSize = 0;
|
||||
|
||||
/* Open a Wave Out device using the wave mapper to guide us */
|
||||
result = waveOutOpen(&audioPort,WAVE_MAPPER,&wfx,(DWORD)NULL,(DWORD)NULL,CALLBACK_NULL);
|
||||
if (result != MMSYSERR_NOERROR) {
|
||||
fprintf(stderr,"Cannot open audio port!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for( outBufNum = 0; outBufNum < (UINT)NUM_OUT_BUFFERS; outBufNum++ )
|
||||
{
|
||||
/* set up a couple of wave headers */
|
||||
whOut[outBufNum].lpData = (LPSTR)calloc(channels*bufferSize, sizeof(short));
|
||||
if (whOut[outBufNum].lpData == NULL){
|
||||
waveOutClose( audioPort );
|
||||
fprintf(stderr,"Error initializing audio buffers!\n");
|
||||
exit(0);
|
||||
}
|
||||
whOut[outBufNum].dwBufferLength = channels*bufferSize*sizeof(short);
|
||||
whOut[outBufNum].dwBytesRecorded = 0;
|
||||
whOut[outBufNum].dwUser = 1;
|
||||
//whOut[outBufNum].dwFlags = 0;
|
||||
whOut[outBufNum].dwFlags = WHDR_DONE;
|
||||
whOut[outBufNum].dwLoops = 0;
|
||||
whOut[outBufNum].lpNext = NULL;
|
||||
whOut[outBufNum].reserved = 0;
|
||||
}
|
||||
|
||||
/* Write the first buffer out to get things going */
|
||||
outBufNum = 0;
|
||||
result = waveOutPrepareHeader(audioPort, &whOut[outBufNum],sizeof(WAVEHDR));
|
||||
result = waveOutWrite(audioPort, &whOut[outBufNum], sizeof(WAVEHDR));
|
||||
|
||||
/* Keep track of time so that we know how long we can sleep */
|
||||
lastWriteTime = timeGetTime();
|
||||
}
|
||||
|
||||
RTSoundIO :: ~RTSoundIO()
|
||||
{
|
||||
MMRESULT result;
|
||||
long timeToGo;
|
||||
|
||||
/* Close Audio Port */
|
||||
if (audioPort != NULL) {
|
||||
result = waveOutReset(audioPort);
|
||||
for( outBufNum = 0; outBufNum < (UINT)NUM_OUT_BUFFERS; outBufNum++ )
|
||||
{
|
||||
/* Loop until the next waveheader indicates that we are done */
|
||||
while( !(whOut[outBufNum].dwFlags & WHDR_DONE) )
|
||||
{
|
||||
//printf(".");
|
||||
timeToGo = (long) (FRAMETIME - (timeGetTime()-lastWriteTime));
|
||||
if( timeToGo > 0 ) Sleep( (long) timeToGo );
|
||||
}
|
||||
/* Unprepare the header */
|
||||
result = waveOutUnprepareHeader(audioPort, &whOut[outBufNum],sizeof(WAVEHDR));
|
||||
if (whOut[outBufNum].lpData != NULL) {
|
||||
free(whOut[outBufNum].lpData);
|
||||
whOut[outBufNum].lpData = NULL;
|
||||
}
|
||||
}
|
||||
result = waveOutClose(audioPort);
|
||||
}
|
||||
}
|
||||
|
||||
int RTSoundIO :: playBuffer(short *buf, int bufsize)
|
||||
{
|
||||
MMRESULT result;
|
||||
long timeToGo;
|
||||
|
||||
outBufNum++;
|
||||
if( outBufNum >= (UINT)NUM_OUT_BUFFERS ) outBufNum = 0;
|
||||
|
||||
/* Loop until the next waveheader indicates that we are done */
|
||||
while( !(whOut[outBufNum].dwFlags & WHDR_DONE) )
|
||||
{
|
||||
//printf(".");
|
||||
timeToGo = (long) (FRAMETIME - (timeGetTime()-lastWriteTime));
|
||||
//timeToGo = (long) (FRAMETIME * 0.5);
|
||||
if( timeToGo > 0 ) Sleep( (long) timeToGo );
|
||||
}
|
||||
result = waveOutUnprepareHeader(audioPort, &whOut[outBufNum], sizeof(WAVEHDR));
|
||||
|
||||
memcpy( whOut[outBufNum].lpData, buf, bufsize*sizeof(short));
|
||||
result = waveOutPrepareHeader(audioPort, &whOut[outBufNum], sizeof(WAVEHDR));
|
||||
result = waveOutWrite(audioPort, &whOut[outBufNum], sizeof(WAVEHDR));
|
||||
lastWriteTime = timeGetTime();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
61
RTSoundIO.h
61
RTSoundIO.h
@@ -1,61 +0,0 @@
|
||||
/******************************************/
|
||||
/* RTSoundIO.h */
|
||||
/* Realtime Sound I/O Object for STK, */
|
||||
/* by Gary P. Scavone, 1998. */
|
||||
/* Based in part on code by Doug */
|
||||
/* Scott (SGI), Tim Stilson (Linux), */
|
||||
/* Bill Putnam (Win Wav), and */
|
||||
/* R. Marsanyi (DirectSound). */
|
||||
/* */
|
||||
/* At the moment, this object only */
|
||||
/* handles realtime sound output, though */
|
||||
/* input code can go here when someone */
|
||||
/* decides they need it (and writes it). */
|
||||
/* */
|
||||
/* This object provides a standard API */
|
||||
/* across all platforms for STK realtime */
|
||||
/* sound output. At the moment, this */
|
||||
/* object is only used by RTWvOut. */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__RTSOUNDIO_h)
|
||||
#define __RTSOUNDIO_h
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
#if defined(__SGI_REALTIME_)
|
||||
#include <audio.h>
|
||||
#elif defined(__WINDS_REALTIME_)
|
||||
#include <windows.h>
|
||||
#include "include/dsound.h"
|
||||
#elif defined(__WINMM_REALTIME_)
|
||||
#include <windows.h>
|
||||
#include <MMSystem.h>
|
||||
#define NUM_OUT_BUFFERS 6
|
||||
#endif
|
||||
|
||||
class RTSoundIO : public Object
|
||||
{
|
||||
protected:
|
||||
#if defined(__SGI_REALTIME_)
|
||||
ALport audio_port;
|
||||
#elif defined(__USS_REALTIME_)
|
||||
int audio_fd;
|
||||
#elif defined(__WINDS_REALTIME_)
|
||||
LPDIRECTSOUND m_pDirectSound;
|
||||
LPDIRECTSOUNDBUFFER m_pDSBuffer;
|
||||
UINT m_cbBufOffset;
|
||||
UINT m_cbBufSize;
|
||||
#elif defined(__WINMM_REALTIME_)
|
||||
HWAVEOUT audioPort;
|
||||
WAVEHDR whOut[NUM_OUT_BUFFERS];
|
||||
UINT outBufNum;
|
||||
DWORD lastWriteTime;
|
||||
#endif
|
||||
public:
|
||||
RTSoundIO(MY_FLOAT srate, int channels);
|
||||
~RTSoundIO();
|
||||
int playBuffer(short *buf, int bufsize);
|
||||
};
|
||||
|
||||
#endif
|
||||
56
RTWvOut.cpp
56
RTWvOut.cpp
@@ -1,56 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Raw Wave File Output Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This version opens a mono NeXT .snd */
|
||||
/* file 16bit data at 22KHz, and */
|
||||
/* pokes buffers of samples into it. */
|
||||
/*******************************************/
|
||||
|
||||
/*******************************************/
|
||||
/* SGI Real-Time Wave File Output Class, */
|
||||
/* by Perry R. Cook, 1996 */
|
||||
/* This Object can opens the SGI soundout */
|
||||
/* device, and pokes buffers of samples */
|
||||
/* into it. The real code that does the */
|
||||
/* is from Doug Scott of SGI. */
|
||||
/*******************************************/
|
||||
|
||||
/*******************************************/
|
||||
/* USS Real-Time Wave File Output Class, */
|
||||
/* by Tim Stilson, 1996 */
|
||||
/* based on code by Perry R. Cook, 1996 */
|
||||
/* This Object opens the USS sound output */
|
||||
/* device, and pokes buffers of samples */
|
||||
/* into it. */
|
||||
/*******************************************/
|
||||
|
||||
#include "RTWvOut.h"
|
||||
|
||||
RTWvOut :: RTWvOut()
|
||||
{
|
||||
soundIO = new RTSoundIO(SRATE, 1);
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
RTWvOut :: ~RTWvOut()
|
||||
{
|
||||
soundIO->playBuffer(data,counter);
|
||||
counter = 0;
|
||||
while (counter<RT_BUFFER_SIZE) {
|
||||
data[counter++] = 0;
|
||||
}
|
||||
soundIO->playBuffer(data,counter);
|
||||
soundIO->playBuffer(data,counter); // Are these extra writes necessary in USS?
|
||||
soundIO->playBuffer(data,counter);
|
||||
delete soundIO;
|
||||
}
|
||||
|
||||
void RTWvOut :: tick(MY_FLOAT sample)
|
||||
{
|
||||
|
||||
data[counter++] = (short) (sample * 32000.0);
|
||||
if (counter >= RT_BUFFER_SIZE) {
|
||||
soundIO->playBuffer(data,counter);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
46
RTWvOut.h
46
RTWvOut.h
@@ -1,46 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Real-Time Output Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* Separated into just realtime by */
|
||||
/* Tim Stilson, 1996 */
|
||||
/*******************************************/
|
||||
|
||||
/*******************************************/
|
||||
/* SGI Real-Time Wave File Output Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This Object can opens the SGI soundout */
|
||||
/* device, and pokes buffers of samples */
|
||||
/* into it. The real code that does the */
|
||||
/* is originally from Doug Scott of SGI. */
|
||||
/*******************************************/
|
||||
|
||||
/*******************************************/
|
||||
/* USS Real-Time Wave File Output Class, */
|
||||
/* by Tim Stilson, 1996 */
|
||||
/* based on code by Perry R. Cook, 1996 */
|
||||
/* This Object opens the USS sound output */
|
||||
/* device, and pokes buffers of samples */
|
||||
/* into it. */
|
||||
/*******************************************/
|
||||
|
||||
|
||||
#include "Object.h"
|
||||
#include "WvOut.h"
|
||||
#include "RTSoundIO.h"
|
||||
|
||||
#if !defined(__RTWvOut_h)
|
||||
#define __RTWvOut_h
|
||||
|
||||
class RTWvOut : public WvOut
|
||||
{
|
||||
protected:
|
||||
RTSoundIO *soundIO;
|
||||
short data[RT_BUFFER_SIZE];
|
||||
long counter;
|
||||
public:
|
||||
RTWvOut();
|
||||
~RTWvOut();
|
||||
void tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif // defined(__RTWvOut_h)
|
||||
245
RawInterp.cpp
245
RawInterp.cpp
@@ -1,245 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Interpolating RawWave Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This object can open a raw 16bit data */
|
||||
/* (signed integers) file, and play back */
|
||||
/* the data once or looping, with linear */
|
||||
/* interpolation on playback. */
|
||||
/* */
|
||||
/* Made inherited from RawWave */
|
||||
/* by Gary P. Scavone (11/11/98) */
|
||||
/*******************************************/
|
||||
|
||||
#include "RawInterp.h"
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#include "swapstuf.h"
|
||||
#endif
|
||||
|
||||
RawInterp :: RawInterp(char *fileName)
|
||||
{
|
||||
long i;
|
||||
short temp;
|
||||
FILE *fd;
|
||||
fd = fopen(fileName,"rb");
|
||||
if (!fd) {
|
||||
printf("Couldn't find soundfile %s !!!!!!!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
i = 0;
|
||||
while (fread(&temp,2,1,fd)) i++;
|
||||
|
||||
length = i;
|
||||
fseek(fd,0,0);
|
||||
data = (MY_FLOAT *) malloc(MY_FLOAT_SIZE * (length + 1));
|
||||
myData = 1;
|
||||
i = 0;
|
||||
while (fread(&temp,2,1,fd)) {
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
temp = SwapShort (temp);
|
||||
#endif
|
||||
data[i] = temp;
|
||||
i++;
|
||||
}
|
||||
data[length] = data[length-1];
|
||||
fclose(fd);
|
||||
looping = 0;
|
||||
time = (MY_FLOAT) 0.0;
|
||||
phaseOffset = (MY_FLOAT) 0.0;
|
||||
rate = (MY_FLOAT) 1.0;
|
||||
finished = 0;
|
||||
}
|
||||
|
||||
RawInterp :: RawInterp(MY_FLOAT *someData, long aLength)
|
||||
{
|
||||
|
||||
length = aLength;
|
||||
data = someData;
|
||||
myData = 0;
|
||||
looping = 0;
|
||||
time = (MY_FLOAT) 0.0;
|
||||
phaseOffset = (MY_FLOAT) 0.0;
|
||||
rate = (MY_FLOAT) 1.0;
|
||||
}
|
||||
|
||||
RawInterp :: ~RawInterp()
|
||||
{
|
||||
if (myData) {
|
||||
free(data);
|
||||
data = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RawInterp :: reset()
|
||||
{
|
||||
time = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
finished = 0;
|
||||
}
|
||||
|
||||
void RawInterp :: normalize()
|
||||
{
|
||||
this->normalize((MY_FLOAT) 1.0);
|
||||
}
|
||||
|
||||
void RawInterp :: normalize(MY_FLOAT newPeak)
|
||||
{
|
||||
long i;
|
||||
MY_FLOAT max = (MY_FLOAT) 0.0;
|
||||
for (i=0;i<=length;i++)
|
||||
if (fabs(data[i]) > max)
|
||||
max = (MY_FLOAT) fabs(data[i]);
|
||||
if (max > 0.0) {
|
||||
max = (MY_FLOAT) 1.0 / max;
|
||||
max *= newPeak;
|
||||
for (i=0;i<=length;i++)
|
||||
data[i] *= max;
|
||||
}
|
||||
}
|
||||
|
||||
void RawInterp :: setRate(MY_FLOAT aRate)
|
||||
{
|
||||
rate = aRate;
|
||||
}
|
||||
|
||||
void RawInterp :: setFreq(MY_FLOAT aFreq)
|
||||
{
|
||||
rate = length * (MY_FLOAT) ONE_OVER_SRATE * aFreq;
|
||||
}
|
||||
|
||||
void RawInterp :: addTime(MY_FLOAT aTime) /* Add an absolute time */
|
||||
{ /* in samples */
|
||||
time += aTime;
|
||||
}
|
||||
|
||||
void RawInterp :: addPhase(MY_FLOAT anAngle) /* Add a time in cycles */
|
||||
{ /* Cycles here means */
|
||||
time += length * anAngle; /* 1.0 = length */
|
||||
}
|
||||
|
||||
void RawInterp :: addPhaseOffset(MY_FLOAT anAngle)
|
||||
{ /* Add a phase offset */
|
||||
phaseOffset = length * anAngle; /* in cycles, where */
|
||||
} /* 1.0 = length */
|
||||
|
||||
void RawInterp :: setLooping(int aLoopStatus)
|
||||
{
|
||||
time = (MY_FLOAT) 0;
|
||||
looping = aLoopStatus;
|
||||
if (looping) data[length] = data[0];
|
||||
}
|
||||
|
||||
long RawInterp :: getLength()
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
MY_FLOAT* RawInterp :: getData()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
MY_FLOAT RawInterp :: tick()
|
||||
{
|
||||
this->informTick();
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
int RawInterp :: isFinished()
|
||||
{
|
||||
return finished;
|
||||
}
|
||||
|
||||
int RawInterp :: informTick()
|
||||
{
|
||||
long temp;
|
||||
|
||||
MY_FLOAT temp_time, alpha;
|
||||
|
||||
time += rate; /* Update current time */
|
||||
|
||||
if (looping) {
|
||||
while (time >= length) /* Check for end of sound */
|
||||
time -= length; /* loop back to beginning */
|
||||
while (time < 0.0) /* Check for end of sound */
|
||||
time += length; /* loop back to beginning */
|
||||
}
|
||||
else {
|
||||
if (time >= length) { /* Check for end of sound */
|
||||
time = length-(MY_FLOAT) 1; /* stick at end */
|
||||
finished = 1; /* Information for one-shot use */
|
||||
}
|
||||
else if (time < 0.0) /* Check for end of sound */
|
||||
time = (MY_FLOAT) 0.0; /* stick at beg */
|
||||
}
|
||||
|
||||
temp_time = time;
|
||||
|
||||
if (phaseOffset != 0.0) {
|
||||
temp_time += phaseOffset; /* Add phase offset */
|
||||
if (looping) {
|
||||
while (temp_time >= length) /* Check for end of sound */
|
||||
temp_time -= length; /* loop back to beginning */
|
||||
while (temp_time < 0.0) /* Check for end of sound */
|
||||
temp_time += length; /* loop back to beginning */
|
||||
}
|
||||
else {
|
||||
if (temp_time >= length) /* Check for end of sound */
|
||||
temp_time = length - (MY_FLOAT) 1; /* stick at end */
|
||||
else if (temp_time < 0.0) /* check for end of sound */
|
||||
temp_time = (MY_FLOAT) 0.0; /* stick at beg */
|
||||
}
|
||||
}
|
||||
|
||||
temp = (long) temp_time; /* Integer part of time address */
|
||||
alpha = temp_time - (MY_FLOAT) temp; /* fractional part of time address */
|
||||
lastOutput = data[temp]; /* Do linear interpolation */
|
||||
lastOutput = lastOutput + /* same as alpha*data[temp+1] */
|
||||
(alpha * (data[temp+1] -
|
||||
lastOutput)); /* + (1-alpha)data[temp] */
|
||||
|
||||
return finished;
|
||||
}
|
||||
|
||||
MY_FLOAT RawInterp :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
void main()
|
||||
{
|
||||
RawInterp loopWave("rawwaves/sinewave.raw");
|
||||
RawInterp oneShot("rawwaves/mandpluk.raw");
|
||||
FILE *fd;
|
||||
short data;
|
||||
long i;
|
||||
|
||||
loopWave.setLooping(1);
|
||||
loopWave.setFreq(5500);
|
||||
fd = fopen("test.raw","wb");
|
||||
for (i=0;i<4096;i++) {
|
||||
data = loopWave.tick();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
loopWave.setFreq(2750);
|
||||
for (i=0;i<4096;i++) {
|
||||
data = loopWave.tick();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
oneShot.setLooping(0);
|
||||
for (i=0;i<8192;i++) {
|
||||
data = oneShot.tick();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
oneShot.reset();
|
||||
oneShot.setRate(0.5);
|
||||
for (i=0;i<16384;i++) {
|
||||
data = oneShot.tick();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
52
RawInterp.h
52
RawInterp.h
@@ -1,52 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Interpolating RawWave Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This object can open a raw 16bit data */
|
||||
/* (signed integers) file, and play back */
|
||||
/* the data once or looping, with linear */
|
||||
/* interpolation on playback. */
|
||||
/* */
|
||||
/* Made inherited from RawWave */
|
||||
/* by Gary P. Scavone (11/11/98) */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__RawInterp_h)
|
||||
#define __RawInterp_h
|
||||
|
||||
#include "Object.h"
|
||||
#include "RawWave.h"
|
||||
|
||||
class RawInterp : public RawWave
|
||||
{
|
||||
protected:
|
||||
int looping;
|
||||
int myData;
|
||||
int finished;
|
||||
long length;
|
||||
MY_FLOAT *data;
|
||||
MY_FLOAT rate;
|
||||
MY_FLOAT time;
|
||||
MY_FLOAT phaseOffset;
|
||||
MY_FLOAT lastOutput;
|
||||
public:
|
||||
RawInterp(char *fileName);
|
||||
RawInterp(MY_FLOAT *someData,long aLength);
|
||||
~RawInterp();
|
||||
void reset();
|
||||
void normalize();
|
||||
void normalize(MY_FLOAT newPeak);
|
||||
void setRate(MY_FLOAT aRate);
|
||||
void setFreq(MY_FLOAT aFreq);
|
||||
void addTime(MY_FLOAT aTime);
|
||||
void addPhase(MY_FLOAT anAngle);
|
||||
void addPhaseOffset(MY_FLOAT anAngle);
|
||||
void setLooping(int aLoopStatus);
|
||||
int isFinished();
|
||||
long getLength();
|
||||
MY_FLOAT* getData();
|
||||
MY_FLOAT tick();
|
||||
int informTick();
|
||||
MY_FLOAT lastOut();
|
||||
};
|
||||
|
||||
#endif
|
||||
160
RawLoop.cpp
160
RawLoop.cpp
@@ -1,160 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Raw Looped Soundfile Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This Object can open a raw 16bit data */
|
||||
/* (signed integers) file, and play back */
|
||||
/* the data, looping only, with linear */
|
||||
/* interpolation on playback. */
|
||||
/*******************************************/
|
||||
|
||||
#include "RawLoop.h"
|
||||
|
||||
#include "swapstuf.h"
|
||||
|
||||
RawLoop :: RawLoop(char *fileName)
|
||||
{
|
||||
long i;
|
||||
short temp;
|
||||
FILE *fd;
|
||||
fd = fopen(fileName,"rb");
|
||||
if (!fd) {
|
||||
printf("Couldn't find soundfile %s !!!!!!!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
i = 0;
|
||||
while (fread(&temp,2,1,fd)) i++;
|
||||
length = i;
|
||||
fseek(fd,0,0);
|
||||
data = (MY_FLOAT *) malloc(MY_FLOAT_SIZE * (length + 1));
|
||||
i = 0;
|
||||
while (fread(&temp,2,1,fd)) {
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
temp = SwapShort (temp);
|
||||
#endif
|
||||
data[i] = temp;
|
||||
i++;
|
||||
}
|
||||
data[length] = data[0];
|
||||
fclose(fd);
|
||||
time = (MY_FLOAT) 0.0;
|
||||
phaseOffset = (MY_FLOAT) 0.0;
|
||||
rate = (MY_FLOAT) 1.0;
|
||||
}
|
||||
|
||||
RawLoop :: ~RawLoop()
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
|
||||
void RawLoop :: reset()
|
||||
{
|
||||
time = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void RawLoop :: normalize()
|
||||
{
|
||||
this->normalize((MY_FLOAT) 1.0);
|
||||
}
|
||||
|
||||
void RawLoop :: normalize(MY_FLOAT newPeak)
|
||||
{
|
||||
long i;
|
||||
MY_FLOAT max = (MY_FLOAT) 0.0;
|
||||
for (i=0;i<=length;i++)
|
||||
if (fabs(data[i]) > max)
|
||||
max = (MY_FLOAT) fabs((double) data[i]);
|
||||
if (max > 0.0) {
|
||||
max = (MY_FLOAT) 1.0 / max;
|
||||
max *= newPeak;
|
||||
for (i=0;i<=length;i++)
|
||||
data[i] *= max;
|
||||
}
|
||||
}
|
||||
|
||||
void RawLoop :: setRate(MY_FLOAT aRate)
|
||||
{
|
||||
rate = aRate;
|
||||
}
|
||||
|
||||
void RawLoop :: setFreq(MY_FLOAT aFreq)
|
||||
{
|
||||
rate = length * ONE_OVER_SRATE * aFreq;
|
||||
}
|
||||
|
||||
void RawLoop :: addTime(MY_FLOAT aTime) /* Add an absolute time */
|
||||
{ /* in samples */
|
||||
time += aTime;
|
||||
}
|
||||
|
||||
void RawLoop :: addPhase(MY_FLOAT anAngle) /* Add a time in cycles */
|
||||
{ /* Cycles here means */
|
||||
time += length * anAngle; /* 1.0 = length */
|
||||
}
|
||||
|
||||
void RawLoop :: addPhaseOffset(MY_FLOAT anAngle)
|
||||
{ /* Add a phase offset */
|
||||
phaseOffset = length * anAngle; /* in cycles, where */
|
||||
} /* 1.0 = length */
|
||||
|
||||
MY_FLOAT RawLoop :: tick()
|
||||
{
|
||||
long temp;
|
||||
|
||||
MY_FLOAT temp_time, alpha;
|
||||
|
||||
time += rate; /* Update current time */
|
||||
|
||||
while (time >= length) /* Check for end of sound */
|
||||
time -= length; /* loop back to beginning */
|
||||
while (time < 0.0) /* Check for end of sound */
|
||||
time += length; /* loop back to beginning */
|
||||
|
||||
temp_time = time;
|
||||
|
||||
if (phaseOffset != 0.0) {
|
||||
temp_time += phaseOffset; /* Add phase offset */
|
||||
while (temp_time >= length) /* Check for end of sound */
|
||||
temp_time -= length; /* loop back to beginning */
|
||||
while (temp_time < 0.0) /* Check for end of sound */
|
||||
temp_time += length; /* loop back to beginning */
|
||||
}
|
||||
|
||||
temp = (long) temp_time; /* Integer part of time address */
|
||||
alpha = temp_time - (MY_FLOAT) temp; /* fractional part of time address */
|
||||
lastOutput = data[temp]; /* Do linear interpolation */
|
||||
lastOutput = lastOutput + /* same as alpha*data[temp+1] */
|
||||
(alpha * (data[temp+1]
|
||||
- lastOutput)); /* + (1-alpha)data[temp] */
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT RawLoop :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
void main()
|
||||
{
|
||||
RawLoop loopWave("rawwaves/sinewave.raw");
|
||||
FILE *fd;
|
||||
short data;
|
||||
long i;
|
||||
|
||||
loopWave.setFreq(5500);
|
||||
fd = fopen("test.raw","wb");
|
||||
for (i=0;i<4096;i++) {
|
||||
data = loopWave.tick();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
loopWave.setFreq(2750);
|
||||
for (i=0;i<4096;i++) {
|
||||
data = loopWave.tick();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
40
RawLoop.h
40
RawLoop.h
@@ -1,40 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Raw Looped Soundfile Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This Object can open a raw 16bit data */
|
||||
/* (signed integers) file, and play back */
|
||||
/* the data, looping only, with linear */
|
||||
/* interpolation on playback. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__RawLoop_h)
|
||||
#define __RawLoop_h
|
||||
|
||||
#include "Object.h"
|
||||
#include "RawWave.h"
|
||||
|
||||
class RawLoop : public RawWave
|
||||
{
|
||||
protected:
|
||||
long length;
|
||||
MY_FLOAT *data;
|
||||
MY_FLOAT rate;
|
||||
MY_FLOAT time;
|
||||
MY_FLOAT phaseOffset;
|
||||
MY_FLOAT lastOutput;
|
||||
public:
|
||||
RawLoop(char *fileName);
|
||||
~RawLoop();
|
||||
void reset();
|
||||
void normalize();
|
||||
void normalize(MY_FLOAT newPeak);
|
||||
void setRate(MY_FLOAT aRate);
|
||||
void setFreq(MY_FLOAT aFreq);
|
||||
void addTime(MY_FLOAT aTime);
|
||||
void addPhase(MY_FLOAT anAngle);
|
||||
void addPhaseOffset(MY_FLOAT anAngle);
|
||||
MY_FLOAT tick();
|
||||
MY_FLOAT lastOut();
|
||||
};
|
||||
|
||||
#endif
|
||||
178
RawShot.cpp
178
RawShot.cpp
@@ -1,178 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Non-Interpolating One-Shot Raw Sound- */
|
||||
/* file Class, by Perry R. Cook, 1995-96 */
|
||||
/* This Object can open a raw 16bit data */
|
||||
/* (signed integers) file, and play back */
|
||||
/* the data once, with no interpolation */
|
||||
/* on playback. Once finished, it closes */
|
||||
/* the file, the file is reopened with */
|
||||
/* the reset() method. */
|
||||
/* This is useful for small memory model, */
|
||||
/* applications, or for streaming from */
|
||||
/* disk (and generally non real-time */
|
||||
/* applications). */
|
||||
/*******************************************/
|
||||
|
||||
#include "RawShot.h"
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#include "swapstuf.h"
|
||||
#endif
|
||||
|
||||
RawShot :: RawShot(char *fileName)
|
||||
{
|
||||
long i;
|
||||
|
||||
strcpy(fileNm,fileName);
|
||||
myFile = fopen(fileNm,"rb");
|
||||
if (!myFile) {
|
||||
printf("Couldn't find soundfile %s !!!!!!!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (fread(&data,2,1,myFile)) i++;
|
||||
length = i;
|
||||
fseek(myFile,0,0);
|
||||
|
||||
time = (MY_FLOAT) 0.0;
|
||||
rate = (MY_FLOAT) 1.0;
|
||||
lastTime = 0;
|
||||
finished = 0;
|
||||
gain = (MY_FLOAT) 1.0;
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
RawShot :: ~RawShot()
|
||||
{
|
||||
this->finish();
|
||||
}
|
||||
|
||||
void RawShot :: reset()
|
||||
{
|
||||
if (finished) {
|
||||
myFile = fopen(fileNm,"rb");
|
||||
}
|
||||
fseek(myFile,0,0);
|
||||
|
||||
#if defined(_debug_)
|
||||
printf("Resetting\n");
|
||||
#endif
|
||||
|
||||
time = (MY_FLOAT) 0.0;
|
||||
lastTime = 0;
|
||||
finished = 0;
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void RawShot :: normalize()
|
||||
{
|
||||
this->normalize((MY_FLOAT) 1.0);
|
||||
}
|
||||
|
||||
void RawShot :: normalize(MY_FLOAT newPeak)
|
||||
{
|
||||
long i;
|
||||
FILE *fd;
|
||||
|
||||
gain = (MY_FLOAT) 0.0;
|
||||
fd = fopen(fileNm,"rb");
|
||||
for (i=0;i<length;i++) {
|
||||
fread(&data,2,1,fd);
|
||||
#ifdef __LITTLE_ENDIAN_
|
||||
data = SwapShort(data);
|
||||
#endif
|
||||
if (fabs(data) > gain)
|
||||
gain = (MY_FLOAT) fabs((double) data);
|
||||
}
|
||||
if (gain > 0.0) {
|
||||
gain = newPeak / gain;
|
||||
}
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
void RawShot :: setRate(MY_FLOAT aRate)
|
||||
{
|
||||
rate = aRate;
|
||||
}
|
||||
|
||||
void RawShot :: finish()
|
||||
{
|
||||
finished = 1;
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
if (myFile) {
|
||||
fclose(myFile);
|
||||
myFile = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int RawShot :: isFinished()
|
||||
{
|
||||
return finished;
|
||||
}
|
||||
|
||||
MY_FLOAT RawShot :: tick()
|
||||
{
|
||||
this->informTick();
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
int RawShot :: informTick()
|
||||
{
|
||||
long temp;
|
||||
|
||||
if (!finished) {
|
||||
time += rate; /* Update current time */
|
||||
|
||||
if (time >= length) { /* Check for end of sound */
|
||||
time = (MY_FLOAT) length - 1; /* stick at end */
|
||||
finished = 1; /* Information for one-shot use */
|
||||
fclose(myFile);
|
||||
myFile = 0;
|
||||
}
|
||||
else {
|
||||
temp = (long) time; /* Integer part of time address */
|
||||
if (temp > lastTime) { /* If we cross next sample time */
|
||||
lastTime = temp;
|
||||
fread(&data,2,1,myFile); /* Snarf next sample from file */
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
data = SwapShort(data);
|
||||
#endif
|
||||
lastOutput = data * gain; /* And save as non-interpolated data */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return finished;
|
||||
}
|
||||
|
||||
MY_FLOAT RawShot :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
void main()
|
||||
{
|
||||
RawShot oneShot("rawwaves/mandpluk.raw");
|
||||
FILE *fd;
|
||||
short data;
|
||||
long i;
|
||||
|
||||
fd = fopen("test.raw","wb");
|
||||
oneShot.setRate(1.0);
|
||||
while (!oneShot.informTick()) {
|
||||
data = oneShot.lastOut();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
oneShot.reset();
|
||||
oneShot.setRate(0.5);
|
||||
for (i=0;i<16384;i++) {
|
||||
data = oneShot.tick();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
49
RawShot.h
49
RawShot.h
@@ -1,49 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Non-Interpolating One-Shot Raw Sound- */
|
||||
/* file Class, by Perry R. Cook, 1995-96 */
|
||||
/* This Object can open a raw 16bit data */
|
||||
/* (signed integers) file, and play back */
|
||||
/* the data once, with no interpolation */
|
||||
/* on playback. Once finished, it closes */
|
||||
/* the file, the file is reopened with */
|
||||
/* the reset() method. */
|
||||
/* This is useful for small memory model, */
|
||||
/* applications, or for streaming from */
|
||||
/* disk (and generally non real-time */
|
||||
/* applications). */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__RawShot_h)
|
||||
#define __RawShot_h
|
||||
|
||||
#include "Object.h"
|
||||
#include "RawWave.h"
|
||||
|
||||
class RawShot : public RawWave
|
||||
{
|
||||
protected:
|
||||
long length;
|
||||
long lastTime;
|
||||
int finished;
|
||||
short data;
|
||||
char fileNm[128];
|
||||
FILE *myFile;
|
||||
MY_FLOAT rate;
|
||||
MY_FLOAT time;
|
||||
MY_FLOAT gain;
|
||||
MY_FLOAT lastOutput;
|
||||
public:
|
||||
RawShot(char *fileName);
|
||||
~RawShot();
|
||||
void reset();
|
||||
void normalize();
|
||||
void normalize(MY_FLOAT newPeak);
|
||||
void setRate(MY_FLOAT aRate);
|
||||
void finish();
|
||||
int isFinished();
|
||||
MY_FLOAT tick();
|
||||
int informTick();
|
||||
MY_FLOAT lastOut();
|
||||
};
|
||||
|
||||
#endif
|
||||
42
RawWave.cpp
42
RawWave.cpp
@@ -1,42 +0,0 @@
|
||||
/********************************************/
|
||||
/* RawWave Abstract Class, */
|
||||
/* by Gary P. Scavone, 1998 */
|
||||
/********************************************/
|
||||
|
||||
#include "RawWave.h"
|
||||
|
||||
RawWave :: RawWave()
|
||||
{
|
||||
}
|
||||
|
||||
RawWave :: ~RawWave()
|
||||
{
|
||||
}
|
||||
|
||||
void RawWave :: reset()
|
||||
{
|
||||
}
|
||||
|
||||
void RawWave :: normalize(MY_FLOAT newPeak)
|
||||
{
|
||||
}
|
||||
|
||||
void RawWave :: setRate(MY_FLOAT aRate)
|
||||
{
|
||||
}
|
||||
|
||||
int RawWave :: informTick()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
MY_FLOAT RawWave :: tick()
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
MY_FLOAT RawWave :: lastOut()
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
25
RawWave.h
25
RawWave.h
@@ -1,25 +0,0 @@
|
||||
/********************************************/
|
||||
/* RawWave Abstract Class, */
|
||||
/* by Gary P. Scavone, 1998 */
|
||||
/********************************************/
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
#if !defined(__RawWave_h)
|
||||
#define __RawWave_h
|
||||
|
||||
class RawWave : public Object
|
||||
{
|
||||
public:
|
||||
RawWave();
|
||||
virtual ~RawWave();
|
||||
virtual void reset();
|
||||
virtual void normalize(MY_FLOAT newPeak);
|
||||
virtual void setRate(MY_FLOAT aRate);
|
||||
virtual int informTick();
|
||||
virtual MY_FLOAT tick();
|
||||
virtual MY_FLOAT lastOut();
|
||||
};
|
||||
|
||||
|
||||
#endif // defined(__RawWave_h)
|
||||
@@ -1,39 +0,0 @@
|
||||
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
|
||||
|
||||
By Perry R. Cook, 1995-98
|
||||
and Gary P. Scavone, 1997-98
|
||||
|
||||
I'll call this latest release STK98v2.02. There was a v2.01 release shortly after the initial v2.0 release in July 1998, to correct a few SGI/Win return character incompatibilities. Since I am just creating this set of release notes with v2.02, I'll just gloss over the past changes. Hopefully, I'll be able to keep this document updated with future releases.
|
||||
|
||||
--Gary Scavone
|
||||
|
||||
|
||||
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.
|
||||
57
Rhodey.cpp
57
Rhodey.cpp
@@ -1,57 +0,0 @@
|
||||
/******************************************/
|
||||
/* Fender Rhodes Electric Piano Subclass */
|
||||
/* of Algorithm 5 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/******************************************/
|
||||
|
||||
#include "Rhodey.h"
|
||||
|
||||
Rhodey :: Rhodey() : FM4Alg5()
|
||||
{
|
||||
this->loadWaves("rawwaves/sinewave.raw",
|
||||
"rawwaves/sinewave.raw",
|
||||
"rawwaves/sinewave.raw",
|
||||
"rawwaves/fwavblnk.raw");
|
||||
this->setRatio(0,(MY_FLOAT) 1.0);
|
||||
this->setRatio(1,(MY_FLOAT) 0.5);
|
||||
this->setRatio(2,(MY_FLOAT) 1.0);
|
||||
this->setRatio(3,(MY_FLOAT) 15.0);
|
||||
gains[0] = __FM4Op_gains[99];
|
||||
gains[1] = __FM4Op_gains[90];
|
||||
gains[2] = __FM4Op_gains[99];
|
||||
gains[3] = __FM4Op_gains[67];
|
||||
adsr[0]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 1.50,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
adsr[1]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 1.50,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
adsr[2]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 1.00,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
adsr[3]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 0.25,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
twozero->setGain((MY_FLOAT) 1.0);
|
||||
}
|
||||
|
||||
Rhodey :: ~Rhodey()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Rhodey :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency * (MY_FLOAT) 2.0;
|
||||
waves[0]->setFreq(baseFreq * ratios[0]);
|
||||
waves[1]->setFreq(baseFreq * ratios[1]);
|
||||
waves[2]->setFreq(baseFreq * ratios[2]);
|
||||
waves[3]->setFreq(baseFreq * ratios[3]);
|
||||
}
|
||||
|
||||
void Rhodey :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
gains[0] = amp * __FM4Op_gains[99];
|
||||
gains[1] = amp * __FM4Op_gains[90];
|
||||
gains[2] = amp * __FM4Op_gains[99];
|
||||
gains[3] = amp * __FM4Op_gains[67];
|
||||
this->setFreq(freq);
|
||||
this->keyOn();
|
||||
#if defined(_debug_)
|
||||
printf("Rhodey : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
345
SKINI11.cpp
345
SKINI11.cpp
@@ -1,345 +0,0 @@
|
||||
/******************************************/
|
||||
/* 2nd generation SKINI Text File Reader */
|
||||
/* Class, by Perry R. Cook, 1996 */
|
||||
/* This Object can open a SKINI File */
|
||||
/* and parse it. The file spec is mine */
|
||||
/* and mine alone, but it's all text so */
|
||||
/* that should help you figuring it out. */
|
||||
/* */
|
||||
/* SKINI (Synthesis toolKit Instrument */
|
||||
/* Network Interface) is like MIDI, but */
|
||||
/* allows for floating point control */
|
||||
/* changes, note numbers, etc. Example: */
|
||||
/* noteOn 60.01 111.132 plays a sharp */
|
||||
/* middle C with a velocity of 111.132 */
|
||||
/* See SKINI11.txt for more information */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#include "SKINI11.h"
|
||||
|
||||
SKINI11 :: SKINI11(char *fileName) /* Constructor for reading SKINI files */
|
||||
{ /* Use nextMessage() method */
|
||||
myFile = fopen(fileName,"r");
|
||||
if ((int) myFile < 0) printf("SKINI11: Can't open SKINI score file\n");
|
||||
this->nextMessage();
|
||||
}
|
||||
|
||||
SKINI11 :: SKINI11() /* Constructor to use this object for parsing */
|
||||
{ /* SKINI Strings (coming over socket for example */
|
||||
} /* Use parseThis() method with string argument */
|
||||
|
||||
SKINI11 :: ~SKINI11()
|
||||
{
|
||||
}
|
||||
|
||||
/***************** SOME HANDY ROUTINES *******************/
|
||||
|
||||
#include "SKINI11.tbl"
|
||||
|
||||
#define __SK_MAX_FIELDS_ 5
|
||||
#define __SK_MAX_SIZE_ 32
|
||||
|
||||
short ignore(char aChar)
|
||||
{
|
||||
short ignoreIt = 0;
|
||||
if (aChar == 0) ignoreIt = 1; // Null String Termination
|
||||
if (aChar == '\n') ignoreIt = 1; // Carraige Return???
|
||||
if (aChar == '/') ignoreIt = 2; // Comment Line
|
||||
return ignoreIt;
|
||||
}
|
||||
|
||||
short delimit(char aChar)
|
||||
{
|
||||
if (aChar == ' ' || // Space
|
||||
aChar == ',' || // Or Comma
|
||||
aChar == '\t') // Or Tab
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
short nextChar(char* aString)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;i<__SK_MAX_SIZE_;i++) {
|
||||
if ( aString[i] != ' ' && // Space
|
||||
aString[i] != ',' && // Or Comma
|
||||
aString[i] != '\t' ) // Or Tab
|
||||
return i;
|
||||
}
|
||||
return 1024;
|
||||
}
|
||||
|
||||
int subStrings(char *aString,
|
||||
char someStrings[__SK_MAX_FIELDS_][__SK_MAX_SIZE_],
|
||||
int somePointrs[__SK_MAX_FIELDS_],
|
||||
char *remainderString)
|
||||
{
|
||||
int notDone,howMany,point,temp;
|
||||
notDone = 1;
|
||||
howMany = 0;
|
||||
point = 0;
|
||||
temp = nextChar(aString);
|
||||
if (temp >= __SK_MAX_SIZE_) {
|
||||
notDone = 0;
|
||||
printf("Confusion here: Ignoring this line\n");
|
||||
printf("%s\n",aString);
|
||||
return howMany;
|
||||
}
|
||||
point = temp;
|
||||
somePointrs[howMany] = point;
|
||||
temp = 0;
|
||||
while (notDone) {
|
||||
if (aString[point] == '\n') {
|
||||
notDone = 0;
|
||||
}
|
||||
else {
|
||||
someStrings[howMany][temp++] = aString[point++];
|
||||
if (temp >= __SK_MAX_SIZE_) {
|
||||
howMany = 0;
|
||||
return howMany;
|
||||
}
|
||||
if (delimit(aString[point]) || aString[point] == '\n') {
|
||||
someStrings[howMany][temp] = 0;
|
||||
howMany += 1;
|
||||
if (howMany < __SK_MAX_FIELDS_) {
|
||||
temp = nextChar(&aString[point]);
|
||||
point += temp;
|
||||
somePointrs[howMany-1] = point;
|
||||
temp = 0;
|
||||
}
|
||||
else {
|
||||
temp = 0;
|
||||
somePointrs[howMany-1] = point;
|
||||
while(aString[point] != '\n')
|
||||
remainderString[temp++] = aString[point++];
|
||||
remainderString[temp] = aString[point];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// printf("Got: %i Strings:\n",howMany);
|
||||
// for (temp=0;temp<howMany;temp++)
|
||||
// printf("%s\n",someStrings[temp]);
|
||||
return howMany;
|
||||
|
||||
}
|
||||
|
||||
/**************** THE ENCHILLADA !!!! **********************/
|
||||
/*** This function parses a single string (if it can) ****/
|
||||
/*** of SKINI message, setting the appropriate variables ***/
|
||||
/*************************************************************/
|
||||
|
||||
long SKINI11 :: parseThis(char* aString)
|
||||
{
|
||||
int which,aField;
|
||||
int temp,temp2;
|
||||
char someStrings[__SK_MAX_FIELDS_][__SK_MAX_SIZE_];
|
||||
int somePointrs[__SK_MAX_FIELDS_];
|
||||
|
||||
temp = nextChar(aString);
|
||||
if (which = ignore(aString[temp])) {
|
||||
if (which == 2) printf("// CommentLine: %s\n",aString);
|
||||
messageType = 0;
|
||||
return messageType;
|
||||
}
|
||||
else {
|
||||
temp = subStrings(aString,someStrings,somePointrs,remainderString);
|
||||
if (temp > 0)
|
||||
which = 0;
|
||||
aField = 0;
|
||||
strcpy(msgTypeString,someStrings[aField]);
|
||||
while ((which < __SK_MaxMsgTypes_) &&
|
||||
(strcmp(msgTypeString,
|
||||
skini_msgs[which].messageString))) {
|
||||
which += 1;
|
||||
}
|
||||
if (which >= __SK_MaxMsgTypes_) {
|
||||
messageType = -1;
|
||||
printf("Couldn't parse this message field: =%s\n %s\n",
|
||||
msgTypeString,aString);
|
||||
return messageType;
|
||||
}
|
||||
else {
|
||||
messageType = skini_msgs[which].type;
|
||||
// printf("Message Token = %s type = %i\n",
|
||||
// msgTypeString,messageType);
|
||||
}
|
||||
aField += 1;
|
||||
|
||||
if (someStrings[0][0] == '=') {
|
||||
deltaTime = (MY_FLOAT) atof(&someStrings[aField][1]);
|
||||
deltaTime = -deltaTime;
|
||||
}
|
||||
else {
|
||||
deltaTime = (MY_FLOAT) atof(someStrings[aField]);
|
||||
}
|
||||
// printf("DeltaTime = %f\n",deltaTime);
|
||||
aField += 1;
|
||||
|
||||
channel = atoi(someStrings[aField]);
|
||||
// printf("Channel = %i\n",channel);
|
||||
aField += 1;
|
||||
|
||||
if (skini_msgs[which].data2 != NOPE) {
|
||||
if (skini_msgs[which].data2 == SK_INT) {
|
||||
byteTwoInt = atoi(someStrings[aField]);
|
||||
byteTwo = (MY_FLOAT) byteTwoInt;
|
||||
}
|
||||
else if (skini_msgs[which].data2 == SK_DBL) {
|
||||
byteTwo = (MY_FLOAT) atof(someStrings[aField]);
|
||||
byteTwoInt = (long) byteTwo;
|
||||
}
|
||||
else if (skini_msgs[which].data2 == SK_STR) {
|
||||
temp = somePointrs[aField-1]; /* Hack Danger Here, Why -1??? */
|
||||
temp2 = 0;
|
||||
while (aString[temp] != '\n') {
|
||||
remainderString[temp2++] = aString[temp++];
|
||||
}
|
||||
remainderString[temp2] = 0;
|
||||
}
|
||||
else {
|
||||
byteTwoInt = skini_msgs[which].data2;
|
||||
byteTwo = (MY_FLOAT) byteTwoInt;
|
||||
aField -= 1;
|
||||
}
|
||||
|
||||
aField += 1;
|
||||
if (skini_msgs[which].data3 != NOPE) {
|
||||
if (skini_msgs[which].data3 == SK_INT) {
|
||||
byteThreeInt = atoi(someStrings[aField]);
|
||||
byteThree = (MY_FLOAT) byteThreeInt;
|
||||
}
|
||||
else if (skini_msgs[which].data3 == SK_DBL) {
|
||||
byteThree = (MY_FLOAT) atof(someStrings[aField]);
|
||||
byteThreeInt = (long) byteThree;
|
||||
}
|
||||
else if (skini_msgs[which].data3 == SK_STR) {
|
||||
temp = somePointrs[aField-1]; /* Hack Danger Here, Why -1??? */
|
||||
temp2 = 0;
|
||||
while (aString[temp] != '\n') {
|
||||
remainderString[temp2++] = aString[temp++];
|
||||
}
|
||||
remainderString[temp2] = 0;
|
||||
}
|
||||
else {
|
||||
byteThreeInt = skini_msgs[which].data3;
|
||||
byteThree = (MY_FLOAT) byteThreeInt;
|
||||
}
|
||||
}
|
||||
else {
|
||||
byteThreeInt = byteTwoInt;
|
||||
byteThree = byteTwo;
|
||||
}
|
||||
}
|
||||
}
|
||||
return messageType;
|
||||
}
|
||||
|
||||
long SKINI11 :: nextMessage()
|
||||
{
|
||||
int notDone;
|
||||
char inputString[1024];
|
||||
|
||||
notDone = 1;
|
||||
while (notDone) {
|
||||
notDone = 0;
|
||||
if (!fgets(inputString,1024,myFile)) {
|
||||
printf("//End of Score. Thanks for using SKINI0.9 Bye Bye!!\n");
|
||||
messageType = -1;
|
||||
return messageType;
|
||||
}
|
||||
else if (parseThis(inputString) == 0) {
|
||||
notDone = 1;
|
||||
}
|
||||
}
|
||||
return messageType;
|
||||
}
|
||||
|
||||
long SKINI11 :: getType()
|
||||
{
|
||||
return messageType;
|
||||
}
|
||||
|
||||
long SKINI11 :: getChannel()
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
|
||||
MY_FLOAT SKINI11 :: getDelta()
|
||||
{
|
||||
return deltaTime;
|
||||
}
|
||||
|
||||
MY_FLOAT SKINI11 :: getByteTwo()
|
||||
{
|
||||
return byteTwo;
|
||||
}
|
||||
|
||||
long SKINI11 :: getByteTwoInt()
|
||||
{
|
||||
return byteTwoInt;
|
||||
}
|
||||
|
||||
MY_FLOAT SKINI11 :: getByteThree()
|
||||
{
|
||||
return byteThree;
|
||||
}
|
||||
|
||||
long SKINI11 :: getByteThreeInt()
|
||||
{
|
||||
return byteThreeInt;
|
||||
}
|
||||
|
||||
char* SKINI11 :: getRemainderString()
|
||||
{
|
||||
return remainderString;
|
||||
}
|
||||
|
||||
char* SKINI11 :: getMessageTypeString()
|
||||
{
|
||||
return msgTypeString;
|
||||
}
|
||||
|
||||
char sk_tempString[1024];
|
||||
|
||||
char* SKINI11 :: whatsThisType(long type)
|
||||
{
|
||||
int i = 0;
|
||||
sk_tempString[0] = 0;
|
||||
for (i=0;i<__SK_MaxMsgTypes_;i++) {
|
||||
if (type == skini_msgs[i].type) {
|
||||
strcat(sk_tempString,skini_msgs[i].messageString);
|
||||
strcat(sk_tempString,",");
|
||||
}
|
||||
}
|
||||
return sk_tempString;
|
||||
}
|
||||
|
||||
char* SKINI11 :: whatsThisController(long contNum)
|
||||
{
|
||||
int i = 0;
|
||||
sk_tempString[0] = 0;
|
||||
for (i=0;i<__SK_MaxMsgTypes_;i++) {
|
||||
if (skini_msgs[i].type == __SK_ControlChange_
|
||||
&& contNum == skini_msgs[i].data2) {
|
||||
strcat(sk_tempString,skini_msgs[i].messageString);
|
||||
strcat(sk_tempString,",");
|
||||
}
|
||||
}
|
||||
return sk_tempString;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
void main(int argc,char *argv[])
|
||||
{
|
||||
SKINI11 testFile(argv[1]);
|
||||
|
||||
while(testFile.nextMessage() > 0) ;
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
BIN
STK98v2.ncb
BIN
STK98v2.ncb
Binary file not shown.
BIN
STK98v2.opt
BIN
STK98v2.opt
Binary file not shown.
43
Sampler.h
43
Sampler.h
@@ -1,43 +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 "RawInterp.h"
|
||||
#include "RawLoop.h"
|
||||
#include "OnePole.h"
|
||||
|
||||
class Sampler : public Instrmnt
|
||||
{
|
||||
protected:
|
||||
ADSR *adsr;
|
||||
RawInterp *attacks[5];
|
||||
RawLoop *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();
|
||||
virtual ~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
|
||||
643
Shakers.cpp
643
Shakers.cpp
@@ -1,643 +0,0 @@
|
||||
/**********************************************************/
|
||||
/* PhISEM (Physically Informed Stochastic Event Modeling */
|
||||
/* by Perry R. Cook, Princeton, February 1997 */
|
||||
/* Meta-model that simulates all of: */
|
||||
/* Maraca Simulation by Perry R. Cook, Princeton, 1996-7 */
|
||||
/* Sekere Simulation by Perry R. Cook, Princeton, 1996-7 */
|
||||
/* Cabasa Simulation by Perry R. Cook, Princeton, 1996-7 */
|
||||
/* Bamboo Windchime Simulation, by Perry R. Cook, 1996-7 */
|
||||
/* Water Drops Simulation, by Perry R. Cook, 1996-7 */
|
||||
/* Tambourine Simulation, by Perry R. Cook, 1996-7 */
|
||||
/* Sleighbells Simulation, by Perry R. Cook, 1996-7 */
|
||||
/* Guiro Simulation, by Perry R. Cook, 1996-7 */
|
||||
/**********************************************************/
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
#ifdef __NeXT_
|
||||
#include <libc.h>
|
||||
#endif
|
||||
|
||||
int my_random(int max) { // Return Random Int Between 0 and max
|
||||
unsigned long temp;
|
||||
|
||||
#if defined(__OS_Linux_) /* RAND_MAX for Linux is 32 bit */
|
||||
temp = (unsigned long) rand() >> 16;
|
||||
#else /* RAND_MAX for everything else is 16 bit */
|
||||
temp = (unsigned long) rand();
|
||||
#endif
|
||||
temp *= (unsigned long) max;
|
||||
temp >>= 15;
|
||||
return (int) temp;
|
||||
}
|
||||
|
||||
MY_FLOAT noise_tick() // Return random MY_FLOAT float between -1.0 and 1.0
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
temp = (MY_FLOAT) (my_random(32767) - 16384);
|
||||
temp *= 0.0000610351;
|
||||
return temp;
|
||||
}
|
||||
|
||||
MY_FLOAT guiroScrape = 0;
|
||||
MY_FLOAT shakeEnergy = 0.0;
|
||||
MY_FLOAT input = 0.0,output[2] = {0.0,0.0};
|
||||
MY_FLOAT coeffs[2];
|
||||
MY_FLOAT input1 = 0.0,output1[2] = {0.0,0.0};
|
||||
MY_FLOAT coeffs1[2];
|
||||
MY_FLOAT input2 = 0.0,output2[2] = {0.0,0.0};
|
||||
MY_FLOAT coeffs2[2];
|
||||
MY_FLOAT input3 = 0.0,output3[2] = {0.0, 0.0};
|
||||
MY_FLOAT coeffs3[2];
|
||||
MY_FLOAT input4 = 0.0,output4[2] = {0.0, 0.0};
|
||||
MY_FLOAT coeffs4[2];
|
||||
MY_FLOAT sndLevel = 0.0;
|
||||
MY_FLOAT gain = 0.0, gain1 = 0, gain2 = 0;
|
||||
MY_FLOAT freq_rand = 0.0;
|
||||
MY_FLOAT soundDecay = 0.0;
|
||||
MY_FLOAT systemDecay = 0.0;
|
||||
MY_FLOAT cymb_rand = 0.0;
|
||||
long num_objects;
|
||||
MY_FLOAT freq, freq1, freq2;
|
||||
|
||||
MY_FLOAT collLikely,scrapeVel = 0.00015;
|
||||
MY_FLOAT totalEnergy;
|
||||
MY_FLOAT ratchet=0.0,ratchetDelta=0.0005;
|
||||
MY_FLOAT finalZ[3] = {0.0, 0.0, 0.0};
|
||||
|
||||
/************************* MARACA *****************************/
|
||||
#define MARA_SOUND_DECAY 0.95
|
||||
#define MARA_SYSTEM_DECAY 0.999
|
||||
#define MARA_NUM_BEANS 25
|
||||
|
||||
void maraca_setup() {
|
||||
num_objects = MARA_NUM_BEANS;
|
||||
gain = log(num_objects) / log(4.0) * 40.0 / (MY_FLOAT) num_objects;
|
||||
coeffs[0] = -0.96 * 2.0 * cos(3200.0 * TWO_PI / SRATE);
|
||||
coeffs[1] = 0.96*0.96;
|
||||
soundDecay = MARA_SOUND_DECAY;
|
||||
systemDecay = MARA_SYSTEM_DECAY;
|
||||
}
|
||||
|
||||
MY_FLOAT maraca_tick() {
|
||||
MY_FLOAT data;
|
||||
shakeEnergy *= systemDecay; // Exponential system decay
|
||||
if (my_random(1024) < num_objects) // If collision
|
||||
sndLevel += gain * shakeEnergy; // add energy
|
||||
input = sndLevel * noise_tick(); // Actual Sound is Random
|
||||
sndLevel *= soundDecay; // Exponential Sound decay
|
||||
input -= output[0]*coeffs[0]; // Do gourd
|
||||
input -= output[1]*coeffs[1]; // resonance
|
||||
output[1] = output[0]; // filter
|
||||
output[0] = input; // calculations
|
||||
data = output[0] - output[1]; // Extra zero for shape
|
||||
return data;
|
||||
}
|
||||
|
||||
/*********************** SEKERE *****************************/
|
||||
#define SEKE_SOUND_DECAY 0.96
|
||||
#define SEKE_SYSTEM_DECAY 0.999
|
||||
#define SEKE_NUM_BEANS 64
|
||||
|
||||
void sekere_setup() {
|
||||
num_objects = SEKE_NUM_BEANS;
|
||||
gain = log(num_objects) / log(4.0) * 40.0 / (MY_FLOAT) num_objects;
|
||||
coeffs[0] = -0.6 * 2.0 * cos(5500.0 * TWO_PI / SRATE);
|
||||
coeffs[1] = 0.6*0.6;
|
||||
soundDecay = SEKE_SOUND_DECAY;
|
||||
systemDecay = SEKE_SYSTEM_DECAY;
|
||||
}
|
||||
|
||||
MY_FLOAT sekere_tick() {
|
||||
MY_FLOAT data;
|
||||
shakeEnergy *= systemDecay; // Exponential system decay
|
||||
if (my_random(1024) < num_objects) // If collision
|
||||
sndLevel += gain * shakeEnergy; // add energy
|
||||
input = sndLevel * noise_tick(); // Actual Sound is Random
|
||||
sndLevel *= soundDecay; // Exponential Sound decay
|
||||
input -= output[0]*coeffs[0]; // Do gourd
|
||||
input -= output[1]*coeffs[1]; // resonance
|
||||
output[1] = output[0]; // filter
|
||||
output[0] = input; // calculations
|
||||
finalZ[2] = finalZ[1];
|
||||
finalZ[1] = finalZ[0];
|
||||
finalZ[0] = output[1];
|
||||
data = finalZ[0] - finalZ[2];
|
||||
return data * 2; // Normalization hack
|
||||
}
|
||||
|
||||
/************************ CABASA ***************************/
|
||||
#define CABA_SOUND_DECAY 0.95
|
||||
#define CABA_SYSTEM_DECAY 0.997
|
||||
#define CABA_NUM_BEADS 512
|
||||
|
||||
void cabasa_setup() {
|
||||
num_objects = CABA_NUM_BEADS;
|
||||
gain = log(num_objects) / log(4.0) * 120.0 / (MY_FLOAT) num_objects;
|
||||
coeffs[0] = -0.7 * 2.0 * cos(3000.0 * TWO_PI / SRATE);
|
||||
coeffs[1] = 0.7*0.7;
|
||||
soundDecay = CABA_SOUND_DECAY;
|
||||
systemDecay = CABA_SYSTEM_DECAY;
|
||||
}
|
||||
|
||||
MY_FLOAT cabasa_tick() {
|
||||
MY_FLOAT data;
|
||||
shakeEnergy *= systemDecay; // Exponential system decay
|
||||
if (my_random(1024) < num_objects) // If collision
|
||||
sndLevel += gain * shakeEnergy; // add energy
|
||||
input = sndLevel * noise_tick(); // Actual Sound is Random
|
||||
sndLevel *= soundDecay; // Exponential Sound decay
|
||||
input -= output[0]*coeffs[0]; // Do gourd
|
||||
input -= output[1]*coeffs[1]; // resonance
|
||||
output[1] = output[0]; // filter
|
||||
output[0] = input; // calculations
|
||||
data = output[0] - output[1];
|
||||
return data * 2; // Normalization hack
|
||||
}
|
||||
|
||||
/************************ Bamboo Wind Chimes *****************/
|
||||
#define BAMB_SOUND_DECAY 0.95
|
||||
#define BAMB_SYSTEM_DECAY 0.99995
|
||||
#define BAMB_NUM_TUBES 5
|
||||
#define BAMB_BASE_FREQ 2800
|
||||
|
||||
void bamboo_setup() {
|
||||
num_objects = BAMB_NUM_TUBES;
|
||||
soundDecay = BAMB_SOUND_DECAY;
|
||||
systemDecay = BAMB_SYSTEM_DECAY;
|
||||
gain = 4.0 / (MY_FLOAT) num_objects;
|
||||
coeffs[0] = -0.995 * 2.0 * cos(BAMB_BASE_FREQ * TWO_PI / SRATE);
|
||||
coeffs[1] = 0.995*0.995;
|
||||
coeffs1[0] = -0.995 * 2.0 * cos(BAMB_BASE_FREQ * 0.8 * TWO_PI / SRATE);
|
||||
coeffs1[1] = 0.995*0.995;
|
||||
coeffs2[0] = -0.995 * 2.0 * cos(BAMB_BASE_FREQ * 1.2 * TWO_PI / SRATE);
|
||||
coeffs2[1] = 0.995*0.995;
|
||||
}
|
||||
|
||||
MY_FLOAT bamboo_tick() {
|
||||
MY_FLOAT data;
|
||||
shakeEnergy *= systemDecay; // Exponential System Decay
|
||||
if (my_random(4096) < num_objects) {
|
||||
sndLevel += gain * shakeEnergy;
|
||||
freq_rand = BAMB_BASE_FREQ * (1.0 + (0.2 * noise_tick()));
|
||||
coeffs[0] = -0.995 * 2.0 *
|
||||
cos(freq_rand * TWO_PI / SRATE);
|
||||
freq_rand = BAMB_BASE_FREQ * (0.8 + (0.2 * noise_tick()));
|
||||
coeffs1[0] = -0.995 * 2.0 *
|
||||
cos(freq_rand * TWO_PI / SRATE);
|
||||
freq_rand = BAMB_BASE_FREQ * (1.2 + (0.2 * noise_tick()));
|
||||
coeffs2[0] = -0.995 * 2.0 *
|
||||
cos(freq_rand * TWO_PI / SRATE);
|
||||
}
|
||||
input = sndLevel;
|
||||
input *= noise_tick(); // Actual Sound is Random
|
||||
input1 = input;
|
||||
input2 = input;
|
||||
|
||||
sndLevel *= soundDecay; // Each (all) event(s)
|
||||
// decay(s) exponentially
|
||||
input -= output[0]*coeffs[0];
|
||||
input -= output[1]*coeffs[1];
|
||||
output[1] = output[0];
|
||||
output[0] = input;
|
||||
data = output[0];
|
||||
input1 -= output1[0]*coeffs1[0];
|
||||
input1 -= output1[1]*coeffs1[1];
|
||||
output1[1] = output1[0];
|
||||
output1[0] = input1;
|
||||
data += output1[0];
|
||||
input2 -= output2[0]*coeffs2[0];
|
||||
input2 -= output2[1]*coeffs2[1];
|
||||
output2[1] = output2[0];
|
||||
output2[0] = input2;
|
||||
data += output2[0];
|
||||
return data * 0.5; // Normalization hack
|
||||
}
|
||||
|
||||
/******************* Water Drops ******************************/
|
||||
#define WUTR_SOUND_DECAY 0.95
|
||||
#define WUTR_NUM_SOURCES 4
|
||||
#define WUTR_FILT_POLE 0.9985
|
||||
#define WUTR_FREQ_SWEEP 1.0001
|
||||
#define WUTR_BASE_FREQ 600
|
||||
|
||||
void wuter_setup() {
|
||||
num_objects = WUTR_NUM_SOURCES;
|
||||
soundDecay = WUTR_SOUND_DECAY;
|
||||
freq = WUTR_BASE_FREQ * TWO_PI / SRATE;
|
||||
freq1 = WUTR_BASE_FREQ * 2.0 * TWO_PI / SRATE;
|
||||
freq2 = WUTR_BASE_FREQ * 3.0 * TWO_PI / SRATE;
|
||||
coeffs[0] = -WUTR_FILT_POLE * 2.0 * cos(freq);
|
||||
coeffs[1] = WUTR_FILT_POLE * WUTR_FILT_POLE;
|
||||
coeffs1[0] = -WUTR_FILT_POLE * 2.0 * cos(freq1);
|
||||
coeffs1[1] = WUTR_FILT_POLE * WUTR_FILT_POLE;
|
||||
coeffs2[0] = -WUTR_FILT_POLE * 2.0 * cos(freq2);
|
||||
coeffs2[1] = WUTR_FILT_POLE * WUTR_FILT_POLE;
|
||||
}
|
||||
MY_FLOAT wuter_tick() {
|
||||
MY_FLOAT data;
|
||||
int j;
|
||||
if (my_random(32767) < num_objects) {
|
||||
sndLevel = shakeEnergy;
|
||||
j = my_random(3);
|
||||
if (j == 0) {
|
||||
freq = WUTR_BASE_FREQ * (0.75 + (0.25 * noise_tick()));
|
||||
gain = fabs(noise_tick());
|
||||
}
|
||||
else if (j == 1) {
|
||||
freq1 = WUTR_BASE_FREQ * (1.0 + (0.25 * noise_tick()));
|
||||
gain1 = fabs(noise_tick());
|
||||
}
|
||||
else {
|
||||
freq2 = WUTR_BASE_FREQ * (1.25 + (0.25 * noise_tick()));
|
||||
gain2 = fabs(noise_tick());
|
||||
}
|
||||
}
|
||||
|
||||
gain *= WUTR_FILT_POLE;
|
||||
if (gain > 0.001) {
|
||||
freq *= WUTR_FREQ_SWEEP;
|
||||
coeffs[0] = -WUTR_FILT_POLE * 2.0 *
|
||||
cos(freq * TWO_PI / SRATE);
|
||||
}
|
||||
gain1 *= WUTR_FILT_POLE;
|
||||
if (gain1 > 0.001) {
|
||||
freq1 *= WUTR_FREQ_SWEEP;
|
||||
coeffs1[0] = -WUTR_FILT_POLE * 2.0 *
|
||||
cos(freq1 * TWO_PI / SRATE);
|
||||
}
|
||||
gain2 *= WUTR_FILT_POLE;
|
||||
if (gain2 > 0.001) {
|
||||
freq2 *= WUTR_FREQ_SWEEP;
|
||||
coeffs2[0] = -WUTR_FILT_POLE * 2.0 *
|
||||
cos(freq2 * TWO_PI / SRATE);
|
||||
}
|
||||
|
||||
sndLevel *= soundDecay; // Each (all) event(s)
|
||||
// decay(s) exponentially
|
||||
input = sndLevel;
|
||||
input *= noise_tick(); // Actual Sound is Random
|
||||
input1 = input * gain1;
|
||||
input2 = input * gain2;
|
||||
input *= gain;
|
||||
input -= output[0]*coeffs[0];
|
||||
input -= output[1]*coeffs[1];
|
||||
output[1] = output[0];
|
||||
output[0] = input;
|
||||
data = output[0];
|
||||
input1 -= output1[0]*coeffs1[0];
|
||||
input1 -= output1[1]*coeffs1[1];
|
||||
output1[1] = output1[0];
|
||||
output1[0] = input1;
|
||||
data += output1[0];
|
||||
input2 -= output2[0]*coeffs2[0];
|
||||
input2 -= output2[1]*coeffs2[1];
|
||||
output2[1] = output2[0];
|
||||
output2[0] = input2;
|
||||
data += output2[0];
|
||||
|
||||
finalZ[2] = finalZ[1];
|
||||
finalZ[1] = finalZ[0];
|
||||
finalZ[0] = data * 4;
|
||||
|
||||
data = finalZ[2] - finalZ[0];
|
||||
return data;
|
||||
}
|
||||
|
||||
/****************** TAMBOURINE ******************************/
|
||||
#define TAMB_SOUND_DECAY 0.95
|
||||
#define TAMB_SYSTEM_DECAY 0.9985
|
||||
#define TAMB_NUM_TIMBRELS 32
|
||||
#define TAMB_SHELL_FREQ 2300
|
||||
#define TAMB_SHELL_GAIN 0.1
|
||||
#define TAMB_CYMB_FREQ 5600
|
||||
#define TAMB_CYMB_FREQ2 8100
|
||||
#define TAMB_CYMB_RESON 0.99
|
||||
|
||||
void tambourine_setup() {
|
||||
num_objects = TAMB_NUM_TIMBRELS;
|
||||
soundDecay = TAMB_SOUND_DECAY;
|
||||
systemDecay = TAMB_SYSTEM_DECAY;
|
||||
gain = 24.0 / num_objects;
|
||||
coeffs[0] = -0.96 * 2.0 * cos(TAMB_SHELL_FREQ * TWO_PI / SRATE);
|
||||
coeffs[1] = 0.96*0.96;
|
||||
coeffs1[0] = -TAMB_CYMB_RESON * 2.0 * cos(TAMB_CYMB_FREQ * TWO_PI / SRATE);
|
||||
coeffs1[1] = TAMB_CYMB_RESON * TAMB_CYMB_RESON;
|
||||
coeffs2[0] = -TAMB_CYMB_RESON * 2.0 * cos(TAMB_CYMB_FREQ2 * TWO_PI / SRATE);
|
||||
coeffs2[1] = TAMB_CYMB_RESON * TAMB_CYMB_RESON;
|
||||
}
|
||||
|
||||
MY_FLOAT tambourine_tick() {
|
||||
MY_FLOAT data;
|
||||
shakeEnergy *= systemDecay; // Exponential System Decay
|
||||
if (my_random(1024) < num_objects) {
|
||||
sndLevel += gain * shakeEnergy;
|
||||
cymb_rand = noise_tick() * TAMB_CYMB_FREQ * 0.05;
|
||||
coeffs1[0] = -TAMB_CYMB_RESON * 2.0 *
|
||||
cos((TAMB_CYMB_FREQ + cymb_rand) * TWO_PI / SRATE);
|
||||
cymb_rand = noise_tick() * TAMB_CYMB_FREQ * 0.05;
|
||||
coeffs2[0] = -TAMB_CYMB_RESON * 2.0 *
|
||||
cos((TAMB_CYMB_FREQ2 + cymb_rand) * TWO_PI / SRATE);
|
||||
}
|
||||
input = sndLevel;
|
||||
input *= noise_tick(); // Actual Sound is Random
|
||||
input1 = input * 0.8;
|
||||
input2 = input;
|
||||
input *= TAMB_SHELL_GAIN;
|
||||
|
||||
sndLevel *= soundDecay; // Each (all) event(s)
|
||||
// decay(s) exponentially
|
||||
input -= output[0]*coeffs[0];
|
||||
input -= output[1]*coeffs[1];
|
||||
output[1] = output[0];
|
||||
output[0] = input;
|
||||
data = output[0];
|
||||
input1 -= output1[0]*coeffs1[0];
|
||||
input1 -= output1[1]*coeffs1[1];
|
||||
output1[1] = output1[0];
|
||||
output1[0] = input1;
|
||||
data += output1[0];
|
||||
input2 -= output2[0]*coeffs2[0];
|
||||
input2 -= output2[1]*coeffs2[1];
|
||||
output2[1] = output2[0];
|
||||
output2[0] = input2;
|
||||
data += output2[0];
|
||||
|
||||
finalZ[2] = finalZ[1];
|
||||
finalZ[1] = finalZ[0];
|
||||
finalZ[0] = data;
|
||||
data = finalZ[2] - finalZ[0];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/************************ SLEIGHBELLS **************************/
|
||||
#define SLEI_SOUND_DECAY 0.97
|
||||
#define SLEI_SYSTEM_DECAY 0.9994
|
||||
#define SLEI_NUM_BELLS 32
|
||||
#define SLEI_CYMB_FREQ0 2500
|
||||
#define SLEI_CYMB_FREQ1 5300
|
||||
#define SLEI_CYMB_FREQ2 6500
|
||||
#define SLEI_CYMB_FREQ3 8300
|
||||
#define SLEI_CYMB_FREQ4 9800
|
||||
#define SLEI_CYMB_RESON 0.99
|
||||
|
||||
void sleighbell_setup() {
|
||||
num_objects = SLEI_NUM_BELLS;
|
||||
soundDecay = SLEI_SOUND_DECAY;
|
||||
systemDecay = SLEI_SYSTEM_DECAY;
|
||||
gain = 8.0 / num_objects;
|
||||
coeffs[0] = -SLEI_CYMB_RESON * 2.0 * cos(SLEI_CYMB_FREQ0 * TWO_PI / SRATE);
|
||||
coeffs[1] = SLEI_CYMB_RESON*SLEI_CYMB_RESON;
|
||||
coeffs1[0] = -SLEI_CYMB_RESON * 2.0 * cos(SLEI_CYMB_FREQ1 * TWO_PI / SRATE);
|
||||
coeffs1[1] = SLEI_CYMB_RESON*SLEI_CYMB_RESON;
|
||||
coeffs2[0] = -SLEI_CYMB_RESON * 2.0 * cos(SLEI_CYMB_FREQ2 * TWO_PI / SRATE);
|
||||
coeffs2[1] = SLEI_CYMB_RESON*SLEI_CYMB_RESON;
|
||||
coeffs3[0] = -SLEI_CYMB_RESON * 2.0 * cos(SLEI_CYMB_FREQ3 * TWO_PI / SRATE);
|
||||
coeffs3[1] = SLEI_CYMB_RESON*SLEI_CYMB_RESON;
|
||||
coeffs4[0] = -SLEI_CYMB_RESON * 2.0 * cos(SLEI_CYMB_FREQ4 * TWO_PI / SRATE);
|
||||
coeffs4[1] = SLEI_CYMB_RESON*SLEI_CYMB_RESON;
|
||||
}
|
||||
|
||||
MY_FLOAT sleighbell_tick() {
|
||||
MY_FLOAT data;
|
||||
shakeEnergy *= systemDecay; // Exponential System Decay
|
||||
if (my_random(1024) < num_objects) {
|
||||
sndLevel += gain * shakeEnergy;
|
||||
cymb_rand = noise_tick() * SLEI_CYMB_FREQ0 * 0.05;
|
||||
coeffs[0] = -SLEI_CYMB_RESON * 2.0 *
|
||||
cos((SLEI_CYMB_FREQ0 + cymb_rand) * TWO_PI / SRATE);
|
||||
cymb_rand = noise_tick() * SLEI_CYMB_FREQ1 * 0.03;
|
||||
coeffs1[0] = -SLEI_CYMB_RESON * 2.0 *
|
||||
cos((SLEI_CYMB_FREQ1 + cymb_rand) * TWO_PI / SRATE);
|
||||
cymb_rand = noise_tick() * SLEI_CYMB_FREQ2 * 0.03;
|
||||
coeffs2[0] = -SLEI_CYMB_RESON * 2.0 *
|
||||
cos((SLEI_CYMB_FREQ2 + cymb_rand) * TWO_PI / SRATE);
|
||||
cymb_rand = noise_tick() * SLEI_CYMB_FREQ3 * 0.03;
|
||||
coeffs3[0] = -SLEI_CYMB_RESON * 2.0 *
|
||||
cos((SLEI_CYMB_FREQ3 + cymb_rand) * TWO_PI / SRATE);
|
||||
cymb_rand = noise_tick() * SLEI_CYMB_FREQ4 * 0.03;
|
||||
coeffs4[0] = -SLEI_CYMB_RESON * 2.0 *
|
||||
cos((SLEI_CYMB_FREQ4 + cymb_rand) * TWO_PI / SRATE);
|
||||
}
|
||||
input = sndLevel;
|
||||
input *= noise_tick(); // Actual Sound is Random
|
||||
input1 = input;
|
||||
input2 = input;
|
||||
input3 = input * 0.5;
|
||||
input4 = input * 0.3;
|
||||
|
||||
sndLevel *= soundDecay; // Each (all) event(s)
|
||||
// decay(s) exponentially
|
||||
input -= output[0]*coeffs[0];
|
||||
input -= output[1]*coeffs[1];
|
||||
output[1] = output[0];
|
||||
output[0] = input;
|
||||
data = output[0];
|
||||
|
||||
input1 -= output1[0]*coeffs1[0];
|
||||
input1 -= output1[1]*coeffs1[1];
|
||||
output1[1] = output1[0];
|
||||
output1[0] = input1;
|
||||
data += output1[0];
|
||||
|
||||
input2 -= output2[0]*coeffs2[0];
|
||||
input2 -= output2[1]*coeffs2[1];
|
||||
output2[1] = output2[0];
|
||||
output2[0] = input2;
|
||||
data += output2[0];
|
||||
|
||||
input3 -= output3[0]*coeffs3[0];
|
||||
input3 -= output3[1]*coeffs3[1];
|
||||
output3[1] = output3[0];
|
||||
output3[0] = input3;
|
||||
data += output3[0];
|
||||
|
||||
input4 -= output4[0]*coeffs4[0];
|
||||
input4 -= output4[1]*coeffs4[1];
|
||||
output4[1] = output4[0];
|
||||
output4[0] = input4;
|
||||
data += output4[0];
|
||||
|
||||
finalZ[2] = finalZ[1];
|
||||
finalZ[1] = finalZ[0];
|
||||
finalZ[0] = data;
|
||||
data = finalZ[2] - finalZ[0];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**************************** GUIRO ***********************/
|
||||
#define GUIR_SOUND_DECAY 0.95
|
||||
#define GUIR_NUM_RATCHETS 128
|
||||
#define GUIR_GOURD_FREQ 2500.0
|
||||
#define GUIR_GOURD_RESON 0.97
|
||||
#define GUIR_GOURD_FREQ2 4000.0
|
||||
#define GUIR_GOURD_RESON2 0.97
|
||||
|
||||
void guiro_setup() {
|
||||
num_objects = GUIR_NUM_RATCHETS;
|
||||
soundDecay = GUIR_SOUND_DECAY;
|
||||
coeffs[0] = -GUIR_GOURD_RESON * 2.0 * cos(GUIR_GOURD_FREQ * TWO_PI / SRATE);
|
||||
coeffs[1] = GUIR_GOURD_RESON*GUIR_GOURD_RESON;
|
||||
coeffs2[0] = -GUIR_GOURD_RESON2 * 2.0 * cos(GUIR_GOURD_FREQ2 * TWO_PI / SRATE);
|
||||
coeffs2[1] = GUIR_GOURD_RESON2*GUIR_GOURD_RESON2;
|
||||
ratchet = 0;
|
||||
guiroScrape = 0;
|
||||
}
|
||||
|
||||
MY_FLOAT guiro_tick() {
|
||||
MY_FLOAT data;
|
||||
if (my_random(1024) < num_objects) {
|
||||
sndLevel += 512 * ratchet * totalEnergy;
|
||||
}
|
||||
input = sndLevel;
|
||||
input *= noise_tick() * ratchet;
|
||||
sndLevel *= soundDecay;
|
||||
|
||||
input2 = input;
|
||||
input -= output[0]*coeffs[0];
|
||||
input -= output[1]*coeffs[1];
|
||||
output[1] = output[0];
|
||||
output[0] = input;
|
||||
input2 -= output2[0]*coeffs2[0];
|
||||
input2 -= output2[1]*coeffs2[1];
|
||||
output2[1] = output2[0];
|
||||
output2[0] = input2;
|
||||
|
||||
finalZ[2] = finalZ[1];
|
||||
finalZ[1] = finalZ[0];
|
||||
finalZ[0] = output[1] + output2[1];
|
||||
data = finalZ[0] - finalZ[2];
|
||||
return data;
|
||||
}
|
||||
|
||||
/******************* THE ACTUAL CLASS ITSELF ***********************/
|
||||
|
||||
#include "Shakers.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
Shakers :: Shakers() : Instrmnt()
|
||||
{
|
||||
instType = 0;
|
||||
}
|
||||
|
||||
Shakers :: ~Shakers()
|
||||
{
|
||||
}
|
||||
|
||||
#define MAX_SHAKE 2000.0
|
||||
|
||||
void Shakers :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
shakeEnergy = amp * MAX_SHAKE * 0.1;
|
||||
#if defined(_debug_)
|
||||
printf("Shakers : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Shakers :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
shakeEnergy = 0.0;
|
||||
}
|
||||
|
||||
MY_FLOAT Shakers :: tick()
|
||||
{
|
||||
if (instType==0) {
|
||||
lastOutput = maraca_tick();
|
||||
}
|
||||
else if (instType==1) {
|
||||
lastOutput = sekere_tick();
|
||||
}
|
||||
else if (instType==2) {
|
||||
lastOutput = cabasa_tick();
|
||||
}
|
||||
else if (instType==3) {
|
||||
lastOutput = bamboo_tick();
|
||||
}
|
||||
else if (instType==4) {
|
||||
lastOutput = wuter_tick();
|
||||
}
|
||||
else if (instType==5) {
|
||||
lastOutput = tambourine_tick();
|
||||
}
|
||||
else if (instType==6) {
|
||||
lastOutput = sleighbell_tick();
|
||||
}
|
||||
else if (instType==7) {
|
||||
if (guiroScrape < 1.0) {
|
||||
guiroScrape += scrapeVel;
|
||||
totalEnergy = guiroScrape;
|
||||
ratchet -= (ratchetDelta + (0.002*totalEnergy));
|
||||
if (ratchet<0.0) ratchet = 1.0;
|
||||
lastOutput = guiro_tick();
|
||||
}
|
||||
else lastOutput = 0.0;
|
||||
}
|
||||
|
||||
lastOutput *= 0.0001;
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void Shakers :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
#if defined(_debug_)
|
||||
printf("Shakers : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_Breath_) {
|
||||
#if defined(_debug_)
|
||||
printf("shaking \n");
|
||||
#endif
|
||||
shakeEnergy += value * NORM_7 * MAX_SHAKE * 0.1;
|
||||
if (shakeEnergy > MAX_SHAKE) shakeEnergy = MAX_SHAKE;
|
||||
}
|
||||
else if (number == __SK_FootControl_) {
|
||||
#if defined(_debug_)
|
||||
printf("setting decay\n");
|
||||
#endif
|
||||
systemDecay = 0.998 + (value * NORM_7 * 0.002);
|
||||
}
|
||||
else if (number == __SK_ModFrequency_) {
|
||||
#if defined(_debug_)
|
||||
printf("setting number of beans\n");
|
||||
#endif
|
||||
num_objects = (int) value;
|
||||
gain = log(num_objects) * 30.0 / (MY_FLOAT) num_objects;
|
||||
}
|
||||
else if (number == __SK_ModWheel_) {
|
||||
#if defined(_debug_)
|
||||
printf("setting resonance freq.\n");
|
||||
#endif
|
||||
temp = 900 * pow (1.015,value);
|
||||
coeffs[0] = -0.96 * 2.0 * cos(temp * TWO_PI / SRATE);
|
||||
coeffs[1] = 0.96*0.96;
|
||||
}
|
||||
else if (number == __SK_AfterTouch_Cont_) {
|
||||
#if defined(_debug_)
|
||||
printf("shaking \n");
|
||||
#endif
|
||||
shakeEnergy += value * NORM_7 * MAX_SHAKE * 0.1;
|
||||
if (shakeEnergy > MAX_SHAKE) shakeEnergy = MAX_SHAKE;
|
||||
}
|
||||
else if (number == __SK_ShakerInst_) {
|
||||
instType = (int) (value + 0.5); // Just to be safe
|
||||
if (instType==0) maraca_setup();
|
||||
else if (instType==1) sekere_setup();
|
||||
else if (instType==2) cabasa_setup();
|
||||
else if (instType==3) bamboo_setup();
|
||||
else if (instType==4) wuter_setup();
|
||||
else if (instType==5) tambourine_setup();
|
||||
else if (instType==6) sleighbell_setup();
|
||||
else if (instType==7) guiro_setup();
|
||||
else {
|
||||
instType = 0;
|
||||
maraca_setup();
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("Shakers : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
35
Shakers.h
35
Shakers.h
@@ -1,35 +0,0 @@
|
||||
/**********************************************************/
|
||||
/* PhISEM (Physically Informed Stochastic Event Modeling */
|
||||
/* by Perry R. Cook, Princeton, February 1997 */
|
||||
/* Meta-model that simulates all of: */
|
||||
/* Maraca Simulation by Perry R. Cook, Princeton, 1996-7 */
|
||||
/* Sekere Simulation by Perry R. Cook, Princeton, 1996-7 */
|
||||
/* Cabasa Simulation by Perry R. Cook, Princeton, 1996-7 */
|
||||
/* Bamboo Windchime Simulation, by Perry R. Cook, 1996-7 */
|
||||
/* Water Drops Simulation, by Perry R. Cook, 1996-7 */
|
||||
/* Tambourine Simulation, by Perry R. Cook, 1996-7 */
|
||||
/* Sleighbells Simulation, by Perry R. Cook, 1996-7 */
|
||||
/* Guiro Simulation, by Perry R. Cook, 1996-7 */
|
||||
/**********************************************************/
|
||||
|
||||
|
||||
#if !defined(__Shakers_h)
|
||||
#define __Shakers_h
|
||||
|
||||
#include "Instrmnt.h"
|
||||
|
||||
|
||||
class Shakers : public Instrmnt
|
||||
{
|
||||
protected:
|
||||
int instType;
|
||||
public:
|
||||
Shakers();
|
||||
~Shakers();
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
virtual void noteOff(MY_FLOAT amp);
|
||||
MY_FLOAT tick();
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
};
|
||||
|
||||
#endif
|
||||
111
Simple.cpp
111
Simple.cpp
@@ -1,111 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Master Class for Simple Instrument */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This instrument contains 1 looped */
|
||||
/* wave, 1 noise source, 1 biquad filter */
|
||||
/* 1 one-pole filter, and 1 ADSR envelope */
|
||||
/*******************************************/
|
||||
|
||||
#include "Simple.h"
|
||||
|
||||
Simple :: Simple()
|
||||
{
|
||||
MY_FLOAT coeffs[2];
|
||||
adsr = new ADSR;
|
||||
baseFreq = (MY_FLOAT) 440.0;
|
||||
loop = new RawLoop("rawwaves/impuls10.raw");
|
||||
loop->normalize();
|
||||
filter = new OnePole;
|
||||
noise = new Noise;
|
||||
bqpoles = new TwoPole;
|
||||
bqzeroes = new TwoZero;
|
||||
coeffs[0] = 0;
|
||||
coeffs[1] = -1;
|
||||
bqzeroes->setZeroCoeffs(coeffs);
|
||||
filter->setPole(0.5);
|
||||
this->setFreq(baseFreq);
|
||||
loopGain = 0.5;
|
||||
}
|
||||
|
||||
Simple :: ~Simple()
|
||||
{
|
||||
delete adsr;
|
||||
delete loop;
|
||||
delete filter;
|
||||
delete bqzeroes;
|
||||
delete bqpoles;
|
||||
}
|
||||
|
||||
void Simple :: keyOn()
|
||||
{
|
||||
adsr->keyOn();
|
||||
}
|
||||
|
||||
void Simple :: keyOff()
|
||||
{
|
||||
adsr->keyOff();
|
||||
}
|
||||
|
||||
void Simple :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->keyOn();
|
||||
this->setFreq(freq);
|
||||
filter->setGain(amp);
|
||||
#if defined(_debug_)
|
||||
printf("Simple : NoteOn: Freq= %lf, Amp=%lf\n",freq, amp);
|
||||
#endif
|
||||
}
|
||||
void Simple :: noteOff(MY_FLOAT amplitude)
|
||||
{
|
||||
this->keyOff();
|
||||
#if defined(_debug_)
|
||||
printf("Simple : NoteOff: Amp=%lf\n",amplitude);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Simple :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
#define R 0.98
|
||||
|
||||
MY_FLOAT coeffs[2];
|
||||
coeffs[0] = 2 * R * cos(TWO_PI * ONE_OVER_SRATE * frequency);
|
||||
coeffs[1] = - R * R;
|
||||
bqpoles->setPoleCoeffs(coeffs);
|
||||
bqpoles->setGain(1.0 - R);
|
||||
loop->setFreq(frequency);
|
||||
}
|
||||
|
||||
MY_FLOAT Simple :: tick()
|
||||
{
|
||||
lastOutput = loopGain * loop->tick();
|
||||
bqzeroes->tick(bqpoles->tick(noise->tick()));
|
||||
lastOutput += (1.0 - loopGain) * bqzeroes->lastOut();
|
||||
lastOutput = filter->tick(lastOutput);
|
||||
lastOutput *= adsr->tick();
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
#include "SKINI11.msg"
|
||||
|
||||
void Simple :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Simple : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_Breath_)
|
||||
filter->setPole(0.99 * (1.0 - (value * NORM_7 * 2.0)));
|
||||
else if (number == __SK_NoiseLevel_)
|
||||
loopGain = 1.0 - (NORM_7 * value);
|
||||
else if (number == __SK_ModFrequency_) {
|
||||
adsr->setAttackRate(value * NORM_7);
|
||||
adsr->setDecayRate(value * NORM_7);
|
||||
adsr->setReleaseRate(value * NORM_7);
|
||||
}
|
||||
else if (number == __SK_ModWheel_)
|
||||
printf("Mod Wheel Unimplemented\n");
|
||||
else if (number == __SK_AfterTouch_Cont_)
|
||||
adsr->setTarget(value * NORM_7);
|
||||
else {
|
||||
printf("Simple : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
44
Simple.h
44
Simple.h
@@ -1,44 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Master Class for Simple Instrument */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This instrument contains 1 looped */
|
||||
/* wave, 1 noise source, 1 biquad filter */
|
||||
/* 1 one-pole filter, and 1 ADSR envelope */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__Simple_h)
|
||||
#define __Simple_h
|
||||
|
||||
#include "Instrmnt.h"
|
||||
#include "ADSR.h"
|
||||
#include "RawLoop.h"
|
||||
#include "OnePole.h"
|
||||
#include "TwoPole.h"
|
||||
#include "TwoZero.h"
|
||||
#include "Noise.h"
|
||||
|
||||
class Simple : public Instrmnt
|
||||
{
|
||||
protected:
|
||||
ADSR *adsr;
|
||||
RawLoop *loop;
|
||||
OnePole *filter;
|
||||
TwoPole *bqpoles;
|
||||
TwoZero *bqzeroes;
|
||||
Noise *noise;
|
||||
MY_FLOAT baseFreq;
|
||||
MY_FLOAT loopGain;
|
||||
public:
|
||||
Simple();
|
||||
~Simple();
|
||||
void clear();
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
void keyOn();
|
||||
void keyOff();
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
virtual void noteOff(MY_FLOAT amplitude);
|
||||
virtual MY_FLOAT tick();
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
};
|
||||
|
||||
#endif
|
||||
168
SndWvOut.cpp
168
SndWvOut.cpp
@@ -1,168 +0,0 @@
|
||||
/*******************************************/
|
||||
/* NeXT Sound 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. */
|
||||
/*******************************************/
|
||||
|
||||
/*******************************************/
|
||||
/* NeXT Soundfile Output Class, Improved */
|
||||
/* by Perry R. Cook, 1996 */
|
||||
/* This one opens a NeXT .snd file, and */
|
||||
/* even knows how to byte-swap! */
|
||||
/*******************************************/
|
||||
|
||||
#include "SndWvOut.h"
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#include "swapstuf.h"
|
||||
#endif
|
||||
|
||||
/******** 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[16];
|
||||
};
|
||||
|
||||
FILE *openNeXTFile(int chans,char *fileName) {
|
||||
struct headerform hdr = {".sn",40,0,3,(long) SRATE,1,"STK98"};
|
||||
char tempName[128];
|
||||
FILE *fd;
|
||||
|
||||
hdr.pref[3] = 'd';
|
||||
|
||||
strcpy(tempName,fileName);
|
||||
strcat(tempName,".snd");
|
||||
hdr.num_channels = chans;
|
||||
fd = fopen(tempName,"wb");
|
||||
if (!fd) {
|
||||
printf("Couldn't create soundfile %s !!!!!!!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
hdr.hdr_length = SwapInt (hdr.hdr_length);
|
||||
hdr.file_length = SwapInt (hdr.file_length);
|
||||
hdr.mode = SwapInt (hdr.mode);
|
||||
hdr.samp_rate = SwapInt (hdr.samp_rate);
|
||||
hdr.num_channels = SwapInt (hdr.num_channels);
|
||||
#endif
|
||||
printf("Creating soundfile %s.\n", tempName);
|
||||
fwrite(&hdr,4,10,fd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
SndWvOut :: SndWvOut(char *fileName)
|
||||
{
|
||||
chans = 1;
|
||||
pan = 0.5;
|
||||
fd = openNeXTFile(chans,fileName);
|
||||
counter = 0;
|
||||
totalCount = 0;
|
||||
}
|
||||
|
||||
SndWvOut :: SndWvOut(int channels, char *fileName)
|
||||
{
|
||||
chans = channels;
|
||||
pan = 0.5;
|
||||
fd = openNeXTFile(chans,fileName);
|
||||
counter = 0;
|
||||
totalCount = 0;
|
||||
}
|
||||
|
||||
SndWvOut :: ~SndWvOut()
|
||||
{
|
||||
double temp;
|
||||
|
||||
fwrite(data,2,counter,fd);
|
||||
fseek(fd,8,SEEK_SET);
|
||||
temp = (double) totalCount * ONE_OVER_SRATE;
|
||||
printf("%f Seconds Computed\n",temp);
|
||||
totalCount *= 2*chans;
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
totalCount = SwapInt (totalCount);
|
||||
#endif
|
||||
fwrite(&totalCount,4,1,fd);
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
long SndWvOut :: getCounter()
|
||||
{
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
MY_FLOAT SndWvOut :: getTime()
|
||||
{
|
||||
return (MY_FLOAT) totalCount * ONE_OVER_SRATE;
|
||||
}
|
||||
|
||||
void SndWvOut :: tick(MY_FLOAT sample)
|
||||
{
|
||||
short isample;
|
||||
|
||||
isample = (short) (sample * 32000.0);
|
||||
if (chans==1) {
|
||||
data[counter] = isample;
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
data[counter] = SwapShort (data[counter]);
|
||||
#endif
|
||||
counter += 1;
|
||||
}
|
||||
else {
|
||||
data[counter] = (short) (isample * (1.0 - pan));
|
||||
data[counter+1] = (short) (isample * pan);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
data[counter] = SwapShort (data[counter]);
|
||||
data[counter+1] = SwapShort (data[counter+1]);
|
||||
#endif
|
||||
counter += 2;
|
||||
}
|
||||
totalCount += 1;
|
||||
if (counter == SND_BUFFER_SIZE) {
|
||||
fwrite(data,2,SND_BUFFER_SIZE,fd);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SndWvOut :: tick(MY_FLOAT lsamp, MY_FLOAT rsamp)
|
||||
{
|
||||
if (chans==1) {
|
||||
data[counter] = (short) ((lsamp + rsamp) * 16000.0);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
data[counter] = SwapShort (data[counter]);
|
||||
#endif
|
||||
counter += 1;
|
||||
}
|
||||
else {
|
||||
data[counter] = (short) (lsamp * 32000.0);
|
||||
data[counter+1] = (short) (rsamp * 32000.0);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
data[counter] = SwapShort (data[counter]);
|
||||
data[counter+1] = SwapShort (data[counter+1]);
|
||||
#endif
|
||||
counter += 2;
|
||||
}
|
||||
totalCount += 1;
|
||||
if (counter == SND_BUFFER_SIZE) {
|
||||
fwrite(data,2,SND_BUFFER_SIZE,fd);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SndWvOut :: setMonoPan(MY_FLOAT aPan)
|
||||
{
|
||||
pan = aPan;
|
||||
if (aPan < 0.0) {
|
||||
pan = 0.0;
|
||||
printf("Pan < 0.0, correcting to 0.0\n");
|
||||
}
|
||||
if (aPan > 1.0) {
|
||||
pan = 1.0;
|
||||
printf("Pan > 1.0, correcting to 1.0\n");
|
||||
}
|
||||
}
|
||||
44
SndWvOut.h
44
SndWvOut.h
@@ -1,44 +0,0 @@
|
||||
/*******************************************/
|
||||
/* NeXT Sound 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. */
|
||||
/*******************************************/
|
||||
|
||||
/*******************************************/
|
||||
/* NeXT Soundfile Output Class, Improved */
|
||||
/* by Perry R. Cook, 1996 */
|
||||
/* This one opens a NeXT .snd file, and */
|
||||
/* even knows how to byte-swap! */
|
||||
/*******************************************/
|
||||
|
||||
#include "Object.h"
|
||||
#include "WvOut.h"
|
||||
|
||||
#if !defined(__SndWvOut_h)
|
||||
#define __SndWvOut_h
|
||||
|
||||
#define SND_BUFFER_SIZE 1024
|
||||
|
||||
class SndWvOut : public WvOut
|
||||
{
|
||||
protected:
|
||||
FILE *fd;
|
||||
short data[SND_BUFFER_SIZE];
|
||||
long counter;
|
||||
long totalCount;
|
||||
int chans;
|
||||
MY_FLOAT pan;
|
||||
public:
|
||||
SndWvOut(char *fileName);
|
||||
SndWvOut(int channels, char *fileName);
|
||||
~SndWvOut();
|
||||
long getCounter();
|
||||
MY_FLOAT getTime();
|
||||
void setMonoPan(MY_FLOAT aPan);
|
||||
void tick(MY_FLOAT sample);
|
||||
void tick(MY_FLOAT lsamp, MY_FLOAT rsamp);
|
||||
};
|
||||
|
||||
#endif // defined(__SndWvOut_h)
|
||||
BIN
TCLSpecs/.swp
BIN
TCLSpecs/.swp
Binary file not shown.
@@ -1,2 +0,0 @@
|
||||
cd ..
|
||||
wish < TCLSpecs/TCLDrums.tcl | syntmono DrumSynt -r -i
|
||||
@@ -1,2 +0,0 @@
|
||||
cd ..
|
||||
wish < TCLSpecs/TCLPhys.tcl | syntmono Clarinet -r -i
|
||||
@@ -1,2 +0,0 @@
|
||||
cd ..
|
||||
wish < TCLSpecs/TCLStruk.tcl | syntmono Mandolin -r -i
|
||||
@@ -1,2 +0,0 @@
|
||||
cd ..
|
||||
wish < TCLSpecs/TCLShakers.tcl | syntmono Maraca -r -i
|
||||
@@ -1,2 +0,0 @@
|
||||
cd ..
|
||||
wish < TCLSpecs/TCLVoice.tcl | syntmono FMVoices -r -i
|
||||
@@ -1,2 +0,0 @@
|
||||
cd ..
|
||||
MD2SKINI | syntmono Clarinet -r -i
|
||||
@@ -1,2 +0,0 @@
|
||||
cd ..
|
||||
MD2SKINI | syntmono Mandolin -r -i
|
||||
@@ -1,2 +0,0 @@
|
||||
cd ..
|
||||
MD2SKINI | syntmono FMVoices -r -i
|
||||
@@ -1,268 +0,0 @@
|
||||
set pitch 64.0
|
||||
set press 64.0
|
||||
set cont1 0.0
|
||||
set cont2 64.0
|
||||
set cont4 64.0
|
||||
set cont11 127.0
|
||||
set outID "stdout"
|
||||
set commtype "stdout"
|
||||
set patchnum 5
|
||||
|
||||
# Configure main window
|
||||
wm title . "STK Struck-Pluck Model Controller"
|
||||
wm iconname . "struck"
|
||||
. config -bg black
|
||||
|
||||
# Configure "communications" menu
|
||||
menu .menu -tearoff 0
|
||||
menu .menu.communication -tearoff 0
|
||||
.menu add cascade -label "Communication" -menu .menu.communication \
|
||||
-underline 0
|
||||
.menu.communication add radio -label "Console" -variable commtype \
|
||||
-value "stdout" -command { setComm }
|
||||
.menu.communication add radio -label "Socket" -variable commtype \
|
||||
-value "socket" -command { setComm }
|
||||
. configure -menu .menu
|
||||
|
||||
# Configure patch change buttons
|
||||
frame .plucked -bg black
|
||||
frame .modal -bg black
|
||||
frame .fm -bg black
|
||||
|
||||
radiobutton .plucked.pluk1 -text Plucked -bg grey66 \
|
||||
-command { patchChange 4 } -variable patchnum -value 4
|
||||
radiobutton .plucked.mand -text Mandolin -bg grey66 \
|
||||
-command { patchChange 5 } -variable patchnum -value 5
|
||||
radiobutton .modal.mari -text Marimba -bg grey66 \
|
||||
-command { patchChange 6 } -variable patchnum -value 6
|
||||
radiobutton .modal.vibr -text Vibraphn -bg grey66 \
|
||||
-command { patchChange 7 } -variable patchnum -value 7
|
||||
radiobutton .modal.agog -text AgogoBel -bg grey66 \
|
||||
-command { patchChange 8 } -variable patchnum -value 8
|
||||
radiobutton .fm.rhod -text Rhodey -bg grey66 \
|
||||
-command { patchChange 9 } -variable patchnum -value 9
|
||||
radiobutton .fm.wurl -text Wurley -bg grey66 \
|
||||
-command { patchChange 10 } -variable patchnum -value 10
|
||||
radiobutton .fm.tube -text TubeBell -bg grey66 \
|
||||
-command { patchChange 11 } -variable patchnum -value 11
|
||||
|
||||
pack .plucked.pluk1 -side left -padx 5
|
||||
pack .plucked.mand -side left -padx 5 -pady 10
|
||||
pack .plucked
|
||||
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
|
||||
|
||||
# Configure bitmap display
|
||||
if {$tcl_platform(platform) == "windows"} {
|
||||
set bitmappath bitmaps
|
||||
} else {
|
||||
set bitmappath TCLSpecs/bitmaps
|
||||
}
|
||||
button .pretty -bitmap @$bitmappath/prcFunny.xbm \
|
||||
-background white -foreground black
|
||||
.pretty config -bitmap @$bitmappath/prc.xbm
|
||||
pack .pretty -padx 5 -pady 10
|
||||
|
||||
# Configure "note-on" buttons
|
||||
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
|
||||
|
||||
# Configure sliders
|
||||
frame .left -bg black
|
||||
frame .right -bg black
|
||||
|
||||
scale .left.bPressure -from 0 -to 128 -length 250 \
|
||||
-command {changePress } -variable press \
|
||||
-orient horizontal -label "Breath Pressure" \
|
||||
-tickinterval 32 -showvalue true -bg grey66
|
||||
|
||||
scale .left.pitch -from 0 -to 128 -length 250 \
|
||||
-command {changePitch } -variable pitch \
|
||||
-orient horizontal -label "MIDI Note Number" \
|
||||
-tickinterval 32 -showvalue true -bg grey66
|
||||
|
||||
scale .left.cont1 -from 0 -to 128 -length 250 \
|
||||
-command {printWhatz "ControlChange 0.0 1 " 2} \
|
||||
-orient horizontal -label "Stick/Pick Hardness (Mand Body Size)" \
|
||||
-tickinterval 32 -showvalue true -bg grey66 \
|
||||
-variable cont2
|
||||
|
||||
scale .right.cont2 -from 0 -to 128 -length 250 \
|
||||
-command {printWhatz "ControlChange 0.0 1 " 4} \
|
||||
-orient horizontal -label "Strike/Pick Position" \
|
||||
-tickinterval 32 -showvalue true -bg grey66 \
|
||||
-variable cont4
|
||||
|
||||
scale .right.cont3 -from 0 -to 128 -length 250 \
|
||||
-command {printWhatz "ControlChange 0.0 1 " 11} \
|
||||
-orient horizontal -label "Vibrato Rate (String Sustain)" \
|
||||
-tickinterval 32 -showvalue true -bg grey66 \
|
||||
-variable cont11
|
||||
|
||||
scale .right.vibrato -from 0 -to 128 -length 250 \
|
||||
-command {printWhatz "ControlChange 0.0 1 " 1} \
|
||||
-orient horizontal -label "Vibrato Amount (Mand Detune) " \
|
||||
-tickinterval 32 -showvalue true -bg grey66\
|
||||
-variable cont1
|
||||
|
||||
pack .left.bPressure -padx 10 -pady 10
|
||||
pack .left.pitch -padx 10 -pady 10
|
||||
pack .left.cont1 -padx 10 -pady 10
|
||||
pack .right.cont2 -padx 10 -pady 10
|
||||
pack .right.cont3 -padx 10 -pady 10
|
||||
pack .right.vibrato -padx 10 -pady 10
|
||||
|
||||
pack .left -side left
|
||||
pack .right -side right
|
||||
|
||||
bind all <KeyPress> {
|
||||
noteOn $pitch $press
|
||||
}
|
||||
|
||||
proc myExit {} {
|
||||
global pitch
|
||||
global outID
|
||||
puts $outID [format "NoteOff 0.0 1 %f 127" $pitch ]
|
||||
flush $outID
|
||||
puts $outID [format "ExitProgram"]
|
||||
flush $outID
|
||||
close $outID
|
||||
exit
|
||||
}
|
||||
|
||||
proc noteOn {pitchVal pressVal} {
|
||||
global outID
|
||||
puts $outID [format "NoteOn 0.0 1 %f %f" $pitchVal $pressVal]
|
||||
flush $outID
|
||||
}
|
||||
|
||||
proc noteOff {pitchVal pressVal} {
|
||||
global outID
|
||||
puts $outID [format "NoteOff 0.0 1 %f %f" $pitchVal $pressVal]
|
||||
flush $outID
|
||||
}
|
||||
|
||||
proc patchChange {value} {
|
||||
global outID
|
||||
global bitmappath
|
||||
global cont1
|
||||
global cont2
|
||||
global cont4
|
||||
global cont11
|
||||
puts $outID [format "ProgramChange 0.0 1 %i" $value]
|
||||
if {$value==4} {
|
||||
.pretty config -bitmap @$bitmappath/KPluk.xbm
|
||||
}
|
||||
if {$value==5} {
|
||||
.pretty config -bitmap @$bitmappath/KPluk.xbm
|
||||
}
|
||||
if {$value==6} {
|
||||
.pretty config -bitmap @$bitmappath/KModal.xbm
|
||||
}
|
||||
if {$value==7} {
|
||||
.pretty config -bitmap @$bitmappath/KModal.xbm
|
||||
}
|
||||
if {$value==8} {
|
||||
.pretty config -bitmap @$bitmappath/KModal.xbm
|
||||
}
|
||||
if {$value==9} {
|
||||
.pretty config -bitmap @$bitmappath/KFMod.xbm
|
||||
}
|
||||
if {$value==10} {
|
||||
.pretty config -bitmap @$bitmappath/KFMod.xbm
|
||||
}
|
||||
if {$value==11} {
|
||||
.pretty config -bitmap @$bitmappath/KFMod.xbm
|
||||
}
|
||||
flush $outID
|
||||
set cont1 0.0
|
||||
set cont2 20.0
|
||||
set cont4 64.0
|
||||
set cont11 64.0
|
||||
}
|
||||
|
||||
proc printWhatz {tag value1 value2 } {
|
||||
global outID
|
||||
puts $outID [format "%s %i %f" $tag $value1 $value2]
|
||||
flush $outID
|
||||
}
|
||||
|
||||
proc changePress {value} {
|
||||
global outID
|
||||
puts $outID [format "AfterTouch 0.0 1 %f" $value]
|
||||
flush $outID
|
||||
}
|
||||
|
||||
proc changePitch {value} {
|
||||
global outID
|
||||
puts $outID [format "PitchBend 0.0 1 %.3f" $value]
|
||||
flush $outID
|
||||
}
|
||||
|
||||
# Socket connection procedure
|
||||
set d .socketdialog
|
||||
|
||||
proc setComm {} {
|
||||
global outID
|
||||
global commtype
|
||||
global d
|
||||
if {$commtype == "stdout"} {
|
||||
if { [string compare "stdout" $outID] } {
|
||||
set i [tk_dialog .dialog "Break Socket Connection?" {You are about to break an existing socket connection ... is this what you want to do?} "" 0 Cancel OK]
|
||||
switch $i {
|
||||
0 {set commtype "socket"}
|
||||
1 {close $outID
|
||||
set outID "stdout"}
|
||||
}
|
||||
}
|
||||
} elseif { ![string compare "stdout" $outID] } {
|
||||
set sockport 2001
|
||||
toplevel $d
|
||||
wm title $d "STK Client Socket Connection"
|
||||
wm resizable $d 0 0
|
||||
grab $d
|
||||
label $d.message -text "Specify a socket port number below (if different than the STK default of 2001) and then click the \"Connect\" button to invoke a socket-client connection attempt to the STK socket server." \
|
||||
-background white -font {Helvetica 10 bold} \
|
||||
-wraplength 3i -justify left
|
||||
frame $d.sockport
|
||||
entry $d.sockport.entry -width 6
|
||||
label $d.sockport.text -text "Socket Port Number:" \
|
||||
-font {Helvetica 10 bold}
|
||||
pack $d.message -side top -padx 5 -pady 10
|
||||
pack $d.sockport.text -side left -padx 1 -pady 10
|
||||
pack $d.sockport.entry -side right -padx 5 -pady 10
|
||||
pack $d.sockport -side top -padx 5 -pady 10
|
||||
$d.sockport.entry insert 0 $sockport
|
||||
frame $d.buttons
|
||||
button $d.buttons.cancel -text "Cancel" -bg grey66 \
|
||||
-command { set commtype "stdout"
|
||||
set outID "stdout"
|
||||
destroy $d }
|
||||
button $d.buttons.connect -text "Connect" -bg grey66 \
|
||||
-command {
|
||||
set sockport [$d.sockport.entry get]
|
||||
set err [catch {socket localhost $sockport} outID]
|
||||
if {$err == 0} {
|
||||
destroy $d
|
||||
} else {
|
||||
tk_dialog $d.error "Socket Error" {Error: Unable to make socket connection. Make sure the STK socket server is first running and that the port number is correct.} "" 0 OK
|
||||
} }
|
||||
pack $d.buttons.cancel -side left -padx 5 -pady 10
|
||||
pack $d.buttons.connect -side right -padx 5 -pady 10
|
||||
pack $d.buttons -side bottom -padx 5 -pady 10
|
||||
}
|
||||
}
|
||||
53
TubeBell.cpp
53
TubeBell.cpp
@@ -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,(MY_FLOAT) (1.0 * 0.995));
|
||||
this->setRatio(1,(MY_FLOAT) (1.414 * 0.995));
|
||||
this->setRatio(2,(MY_FLOAT) (1.0 * 1.005));
|
||||
this->setRatio(3,(MY_FLOAT) (1.414 * 1.000));
|
||||
gains[0] = __FM4Op_gains[94];
|
||||
gains[1] = __FM4Op_gains[76];
|
||||
gains[2] = __FM4Op_gains[99];
|
||||
gains[3] = __FM4Op_gains[71];
|
||||
adsr[0]->setAllTimes((MY_FLOAT) 0.005,(MY_FLOAT) 4.0,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
adsr[1]->setAllTimes((MY_FLOAT) 0.005,(MY_FLOAT) 4.0,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
adsr[2]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 2.0,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
adsr[3]->setAllTimes((MY_FLOAT) 0.004,(MY_FLOAT) 4.0,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
twozero->setGain((MY_FLOAT) 0.5);
|
||||
vibWave->setFreq((MY_FLOAT) 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
|
||||
}
|
||||
61
TwoPole.cpp
61
TwoPole.cpp
@@ -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] = (MY_FLOAT) 0.0;
|
||||
poleCoeffs[1] = (MY_FLOAT) 0.0;
|
||||
gain = (MY_FLOAT) 1.0;
|
||||
this->clear();
|
||||
}
|
||||
|
||||
TwoPole :: ~TwoPole()
|
||||
{
|
||||
// free(inputs);
|
||||
free(outputs);
|
||||
}
|
||||
|
||||
void TwoPole :: clear()
|
||||
{
|
||||
outputs[0] = (MY_FLOAT) 0.0;
|
||||
outputs[1] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 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] = (MY_FLOAT) 2.0 * reson * cos(TWO_PI * (double) 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;
|
||||
}
|
||||
|
||||
53
TwoZero.cpp
53
TwoZero.cpp
@@ -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] = (MY_FLOAT) 0.0;
|
||||
zeroCoeffs[1] = (MY_FLOAT) 0.0;
|
||||
gain = (MY_FLOAT) 1.0;
|
||||
this->clear();
|
||||
}
|
||||
|
||||
TwoZero :: ~TwoZero()
|
||||
{
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
void TwoZero :: clear()
|
||||
{
|
||||
inputs[0] = (MY_FLOAT) 0.0;
|
||||
inputs[1] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 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;
|
||||
}
|
||||
|
||||
77
Vibraphn.cpp
77
Vibraphn.cpp
@@ -1,77 +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"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
Vibraphn :: Vibraphn() : Modal4()
|
||||
{
|
||||
wave = new RawInterp("rawwaves/marmstk1.raw");
|
||||
wave->normalize();
|
||||
wave->setRate((MY_FLOAT) 13.33);
|
||||
vibr->setFreq((MY_FLOAT) 4.0);
|
||||
onepole->setPole((MY_FLOAT) 0.2);
|
||||
this->setRatioAndReson(0, (MY_FLOAT) 1.0,(MY_FLOAT) 0.99995); /* Set */
|
||||
this->setRatioAndReson(1, (MY_FLOAT) 2.01,(MY_FLOAT) 0.99991); /* our */
|
||||
this->setRatioAndReson(2, (MY_FLOAT) 3.9,(MY_FLOAT) 0.99992); /* resonance */
|
||||
this->setRatioAndReson(3,(MY_FLOAT) 14.37,(MY_FLOAT) 0.99990); /* values here */
|
||||
this->setFiltGain(0,(MY_FLOAT) 0.025);
|
||||
this->setFiltGain(1,(MY_FLOAT) 0.015);
|
||||
this->setFiltGain(2,(MY_FLOAT) 0.015);
|
||||
this->setFiltGain(3,(MY_FLOAT) 0.015);
|
||||
masterGain = (MY_FLOAT) 1.0;
|
||||
directGain = (MY_FLOAT) 0.0;
|
||||
vibrGain = (MY_FLOAT) 0.2;
|
||||
}
|
||||
|
||||
Vibraphn :: ~Vibraphn()
|
||||
{
|
||||
delete wave;
|
||||
}
|
||||
|
||||
void Vibraphn :: setStickHardness(MY_FLOAT hardness)
|
||||
{
|
||||
wave->setRate((MY_FLOAT) 2.0 + ((MY_FLOAT) 22.66 * hardness));
|
||||
masterGain = (MY_FLOAT) 0.2 + (hardness * (MY_FLOAT) 1.6);
|
||||
}
|
||||
|
||||
void Vibraphn :: setStrikePosition(MY_FLOAT position)
|
||||
{
|
||||
MY_FLOAT temp,temp2;
|
||||
temp2 = position * PI;
|
||||
strikePosition = position; /* Hack only first three modes */
|
||||
temp = (MY_FLOAT) sin(strikePosition * PI);
|
||||
this->setFiltGain(0,(MY_FLOAT) 0.025 * temp);
|
||||
temp = (MY_FLOAT) sin(0.1 + (2.01 * temp2));
|
||||
this->setFiltGain(1,(MY_FLOAT) 0.015 * temp);
|
||||
temp = (MY_FLOAT) sin(3.95 * temp2);
|
||||
this->setFiltGain(2,(MY_FLOAT) 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 == __SK_StickHardness_)
|
||||
this->setStickHardness(value * NORM_7);
|
||||
else if (number == __SK_StrikePosition_)
|
||||
this->setStrikePosition(value * NORM_7);
|
||||
else if (number == __SK_ModFrequency_)
|
||||
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
|
||||
else if (number == __SK_ModWheel_)
|
||||
vibrGain = (value * NORM_7);
|
||||
else if (number == __SK_AfterTouch_Cont_)
|
||||
this->strike(value * NORM_7);
|
||||
else {
|
||||
printf("Vibraphn : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
27
Vibraphn.h
27
Vibraphn.h
@@ -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
|
||||
189
WavWvOut.cpp
189
WavWvOut.cpp
@@ -1,189 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Wave file Output Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This Object opens a DOS/Windows .wav */
|
||||
/* 16bit data (signed integers) file, and */
|
||||
/* poke buffers of samples into it. */
|
||||
/*******************************************/
|
||||
|
||||
#include "WavWvOut.h"
|
||||
#include "swapstuf.h"
|
||||
|
||||
/******** Wav Soundfile Header Struct *******/
|
||||
struct wavehdr {char riff[4];
|
||||
long flength;
|
||||
char wave[4];
|
||||
char fmt[4];
|
||||
long format;
|
||||
short aone;
|
||||
short numchans;
|
||||
long srate;
|
||||
long bps;
|
||||
short numchans2;
|
||||
short bps2;
|
||||
char data[4];
|
||||
long dlength;
|
||||
};
|
||||
|
||||
FILE *openWAVFile(int chans,char *fileName) {
|
||||
struct wavehdr hdr = {"RIF",44,"WAV","fmt",
|
||||
16,1,1,(long) SRATE,(long) SRATE*2,1,16,"dat",0};
|
||||
char tempName[128];
|
||||
FILE *fd;
|
||||
extern int SwapInt(int);
|
||||
extern short SwapShort(short);
|
||||
|
||||
hdr.riff[3] = 'F';
|
||||
hdr.wave[3] = 'E';
|
||||
hdr.fmt[3] = ' ';
|
||||
hdr.data[3] = 'a';
|
||||
|
||||
strcpy(tempName,fileName);
|
||||
strcat(tempName,".wav");
|
||||
hdr.numchans = chans;
|
||||
hdr.numchans2 = chans;
|
||||
hdr.bps = 16; // WARNING!! This may need to be 16 * chans //
|
||||
hdr.bps2 = 16;
|
||||
fd = fopen(tempName,"wb");
|
||||
if (!fd) {
|
||||
printf("Couldn't create soundfile %s !!!!!!!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
hdr.flength = SwapInt(hdr.flength);
|
||||
hdr.format = SwapInt(hdr.format);
|
||||
hdr.aone = SwapShort(hdr.aone);
|
||||
hdr.numchans = SwapShort(hdr.numchans);
|
||||
hdr.srate = SwapInt(hdr.srate);
|
||||
hdr.bps = SwapInt(hdr.bps);
|
||||
hdr.numchans2 = SwapShort(hdr.numchans2);
|
||||
hdr.bps2 = SwapShort(hdr.bps2);
|
||||
hdr.dlength = SwapInt(hdr.dlength);
|
||||
#endif
|
||||
|
||||
printf("Creating soundfile %s.\n", tempName);
|
||||
fwrite(&hdr,4,11,fd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
WavWvOut :: WavWvOut(char *fileName)
|
||||
{
|
||||
chans = 1;
|
||||
pan = 0.5;
|
||||
fd = openWAVFile(chans,fileName);
|
||||
counter = 0;
|
||||
totalCount = 0;
|
||||
}
|
||||
|
||||
WavWvOut :: WavWvOut(int channels, char *fileName)
|
||||
{
|
||||
chans = channels;
|
||||
pan = 0.5;
|
||||
fd = openWAVFile(chans,fileName);
|
||||
counter = 0;
|
||||
totalCount = 0;
|
||||
}
|
||||
|
||||
WavWvOut :: ~WavWvOut()
|
||||
{
|
||||
MY_FLOAT time;
|
||||
long bytes;
|
||||
extern int SwapInt(int);
|
||||
|
||||
fwrite(data,2,counter,fd);
|
||||
fseek(fd,40,SEEK_SET);
|
||||
time = (double) totalCount * ONE_OVER_SRATE;
|
||||
printf("%f Seconds Computed\n",time);
|
||||
bytes = totalCount*2*chans;
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
bytes = SwapInt(bytes);
|
||||
#endif
|
||||
fwrite(&bytes,4,1,fd);
|
||||
bytes = totalCount*2*chans + 44;
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
bytes = SwapInt(bytes);
|
||||
#endif
|
||||
fseek(fd,4,SEEK_SET);
|
||||
fwrite(&totalCount,4,1,fd);
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
long WavWvOut :: getCounter()
|
||||
{
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
MY_FLOAT WavWvOut :: getTime()
|
||||
{
|
||||
return (MY_FLOAT) totalCount * ONE_OVER_SRATE;
|
||||
}
|
||||
|
||||
void WavWvOut :: tick(MY_FLOAT sample)
|
||||
{
|
||||
short isample;
|
||||
extern short SwapShort(short);
|
||||
|
||||
isample = (short) (sample * 32000.0);
|
||||
if (chans==1) {
|
||||
data[counter] = isample;
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
data[counter] = SwapShort(data[counter]);
|
||||
#endif
|
||||
counter += 1;
|
||||
}
|
||||
else {
|
||||
data[counter] = (short) (isample * (1.0 - pan));
|
||||
data[counter+1] = (short) (isample * pan);
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
data[counter] = SwapShort(data[counter]);
|
||||
data[counter+1] = SwapShort(data[counter+1]);
|
||||
#endif
|
||||
counter += 2;
|
||||
}
|
||||
totalCount += 1;
|
||||
if (counter == WAV_BUFFER_SIZE) {
|
||||
fwrite(data,2,WAV_BUFFER_SIZE,fd);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void WavWvOut :: tick(MY_FLOAT lsamp, MY_FLOAT rsamp)
|
||||
{
|
||||
extern short SwapShort(short);
|
||||
|
||||
if (chans==1) {
|
||||
data[counter] = (short) ((lsamp + rsamp) * 16000.0);
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
data[counter] = SwapShort(data[counter]);
|
||||
#endif
|
||||
counter += 1;
|
||||
}
|
||||
else {
|
||||
data[counter] = (short) (lsamp * 32000.0);
|
||||
data[counter+1] = (short) (rsamp * 32000.0);
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
data[counter] = SwapShort(data[counter]);
|
||||
data[counter+1] = SwapShort(data[counter+1]);
|
||||
#endif
|
||||
counter += 2;
|
||||
}
|
||||
totalCount += 1;
|
||||
if (counter == WAV_BUFFER_SIZE) {
|
||||
fwrite(data,2,WAV_BUFFER_SIZE,fd);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void WavWvOut :: setMonoPan(MY_FLOAT aPan)
|
||||
{
|
||||
pan = aPan;
|
||||
if (aPan < 0.0) {
|
||||
pan = 0.0;
|
||||
printf("Pan < 0.0, correcting to 0.0\n");
|
||||
}
|
||||
if (aPan > 1.0) {
|
||||
pan = 1.0;
|
||||
printf("Pan > 1.0, correcting to 1.0\n");
|
||||
}
|
||||
}
|
||||
53
Wurley.cpp
53
Wurley.cpp
@@ -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,(MY_FLOAT) 1.0);
|
||||
this->setRatio(1,(MY_FLOAT) 4.0);
|
||||
this->setRatio(2,(MY_FLOAT) -510.0);
|
||||
this->setRatio(3,(MY_FLOAT) -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((MY_FLOAT) 2.0);
|
||||
adsr[0]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 1.50,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
adsr[1]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 1.50,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
adsr[2]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 0.25,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
adsr[3]->setAllTimes((MY_FLOAT) 0.001,(MY_FLOAT) 0.15,(MY_FLOAT) 0.0,(MY_FLOAT) 0.04);
|
||||
vibWave->setFreq((MY_FLOAT) 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
|
||||
}
|
||||
21
WvOut.cpp
21
WvOut.cpp
@@ -1,21 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Output Abstract Class, */
|
||||
/* by Tim Stilson, 1996 */
|
||||
/* based on code by Perry R. Cook, 1995-96*/
|
||||
/*******************************************/
|
||||
|
||||
#include "WvOut.h"
|
||||
#include <stdio.h>
|
||||
|
||||
WvOut :: WvOut()
|
||||
{
|
||||
}
|
||||
|
||||
WvOut :: ~WvOut()
|
||||
{
|
||||
}
|
||||
|
||||
void WvOut :: tick(MY_FLOAT sample)
|
||||
{
|
||||
}
|
||||
|
||||
23
WvOut.h
23
WvOut.h
@@ -1,23 +0,0 @@
|
||||
/********************************************/
|
||||
/* Output Abstract Class, */
|
||||
/* by Tim Stilson, 1996 */
|
||||
/* based on code by Perry R. Cook, 1995-96 */
|
||||
/********************************************/
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
#if !defined(__WvOut_h)
|
||||
#define __WvOut_h
|
||||
|
||||
|
||||
|
||||
class WvOut : public Object
|
||||
{
|
||||
public:
|
||||
WvOut();
|
||||
virtual ~WvOut();
|
||||
virtual void tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
|
||||
#endif // defined(__WvOut_h)
|
||||
156
doc/Hierarchy.txt
Normal file
156
doc/Hierarchy.txt
Normal 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
28
doc/README-Linux.txt
Normal 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
14
doc/README-NeXT.txt
Normal 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
15
doc/README-SGI.txt
Normal 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
69
doc/README-Win.txt
Normal 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
128
doc/README.txt
Normal 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
90
doc/ReleaseNotes.txt
Normal 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.
|
||||
@@ -1,8 +1,10 @@
|
||||
This describes the 0.9 implementation of SKINI:
|
||||
This describes the 1.1 implementation of SKINI,
|
||||
updated for the 2.x release of STK:
|
||||
|
||||
Synthesis toolKit Instrument Network Interface
|
||||
|
||||
for the Synthesis Toolkit in C++ by Perry R. Cook 1996.
|
||||
for the Synthesis Toolkit in C++ by Perry R. Cook
|
||||
and Gary Scavone, 1999.
|
||||
|
||||
*********************************
|
||||
* Too good to be true? *
|
||||
@@ -10,35 +12,36 @@ for the Synthesis Toolkit in C++ by Perry R. Cook 1996.
|
||||
* A SKINI Haiku. *
|
||||
*********************************
|
||||
|
||||
Profound thanks to Dan Trueman and Brad Garton for input on
|
||||
this revision. Thanks also to MIDI, the NeXT MusicKit, ZIPI
|
||||
and all the creators and modifiers of these for good bases
|
||||
Profound thanks to Dan Trueman, Brad Garton, and
|
||||
Gary Scavone for input on this revision. Thanks
|
||||
also to MIDI, the NeXT MusicKit, ZIPI and all
|
||||
the creators and modifiers of these for good bases
|
||||
upon/from which to build and depart.
|
||||
|
||||
1) MIDI Compatibility
|
||||
|
||||
SKINI was designed to be MIDI compatible wherever possible,
|
||||
and extend MIDI in incremental, then maybe profound ways.
|
||||
|
||||
and extend MIDI in incremental, then maybe profound ways.
|
||||
|
||||
Differences from MIDI, and motivations, include:
|
||||
|
||||
Text-based messages are used, with meaningful names
|
||||
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,
|
||||
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
|
||||
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.
|
||||
and grapics. Live a little.
|
||||
|
||||
Floating point numbers are used wherever possible.
|
||||
Note Numbers, Velocities, Controller Values, and
|
||||
@@ -46,10 +49,10 @@ upon/from which to build and depart.
|
||||
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
|
||||
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
|
||||
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.
|
||||
@@ -58,26 +61,23 @@ upon/from which to build and depart.
|
||||
|
||||
SKINI was designed to be extensable and hackable for a number
|
||||
of applications: imbedded synthesis in a game or VR simulation,
|
||||
scoring and mixing tasks, real-time and non-real time applications
|
||||
which could benefit from a controllable sound synthesis,
|
||||
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
|
||||
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
|
||||
down design ideas, so SKINI above all reflects the needs of my
|
||||
particular research and creative projects as they have arisen and
|
||||
developed. SKINI09 represents a profound advance beyond SKINI08
|
||||
(the first version), but it is likely that SKINI1.0x will
|
||||
developed. SKINI11 represents a profound advance beyond SKINI08
|
||||
and SKINI09 (the first versions), future SKINI's might
|
||||
reflect some changes. Compatibility with prior scorefiles
|
||||
will be attempted, but there aren't that many scorefiles out
|
||||
there yet. The one thing I will attempt to keep in mind is
|
||||
enough consistency to allow the creation of a SKINI0x to SKINIx0
|
||||
file and stream converter object. SKINI09 should be fully
|
||||
compatible with SKINI08.
|
||||
|
||||
there yet.
|
||||
|
||||
3) SKINI MESSAGES
|
||||
|
||||
A basic SKINI message is a line of text. There are only three
|
||||
@@ -87,58 +87,59 @@ upon/from which to build and depart.
|
||||
the channel number is scanned as a long int. Channels could be socket
|
||||
numbers, machine IDs, serial numbers, or even unique tags for each
|
||||
event in a synthesis. Other fields might be used, as specified in the
|
||||
SKINI09.tbl file. This is described in more detail later.
|
||||
|
||||
SKINI11.tbl file. This is described in more detail later.
|
||||
|
||||
Fields in a SKINI line are delimited by spaces, commas, or
|
||||
tabs. The SKINI parser only operates on a line at a time,
|
||||
so a newline means the message is over. Multiple messages are
|
||||
NOT allowed directly on a single line (by use of the ; for
|
||||
example in C). This could be supported, but it isn't in 0.9.
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
SKINI09.tbl.
|
||||
|
||||
The other important file used by SKINI is SKINI09.msg, which is a
|
||||
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
|
||||
quick re-mapping of control numbers, etc.. All of these defined
|
||||
symbols are assigned integer values. For JAVA, the #defines could
|
||||
be replaced by declaration and assignment statements, preserving
|
||||
the look and behavior of the rest of the code.
|
||||
|
||||
4) C Files Used To Implement SKINI09
|
||||
4) C Files Used To Implement SKINI11
|
||||
|
||||
SKINI09.cpp is an object which can either open a SKINI file, and
|
||||
successively read and parse lines of text as SKINI strings, or
|
||||
accept strings from another object and parse them. The latter
|
||||
SKINI11.cpp is an object which can either open a SKINI file, and
|
||||
successively read and parse lines of text as SKINI strings, or
|
||||
accept strings from another object and parse them. The latter
|
||||
functionality would be used by a socket, pipe, or other connection
|
||||
receiving SKINI messages a line at a time, usually in real time,
|
||||
but not restricted to real time.
|
||||
|
||||
SKINI09.msg should be included by anything wanting to use the
|
||||
SKINI09.cpp object. This is not mandatory, but use of the __SK_blah_
|
||||
symbols which are defined in the .msg file will help to ensure
|
||||
SKINI11.msg should be included by anything wanting to use the
|
||||
SKINI11.cpp object. This is not mandatory, but use of the __SK_blah_
|
||||
symbols which are defined in the .msg file will help to ensure
|
||||
clarity and consistency when messages are added and changed.
|
||||
|
||||
SKINI09.tbl is used only by the SKINI parser object (SKINI09.cpp).
|
||||
In the file SKINI09.tbl, an array of structures is declared and
|
||||
SKINI11.tbl is used only by the SKINI parser object (SKINI11.cpp).
|
||||
In the file SKINI11.tbl, an array of structures is declared and
|
||||
assigned values which instruct the parser as to what the message
|
||||
types are, and what the fields mean for those message types.
|
||||
This table is compiled and linked into applications using SKINI, but
|
||||
could be dynamically loaded and changed in a future version of
|
||||
could be dynamically loaded and changed in a future version of
|
||||
SKINI.
|
||||
|
||||
5) SKINI Messages and the SKINI Parser:
|
||||
@@ -146,68 +147,68 @@ upon/from which to build and depart.
|
||||
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
|
||||
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
|
||||
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,
|
||||
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 SKINI09+, so don't plan
|
||||
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
|
||||
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,
|
||||
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 SKINI0.9 parser
|
||||
doesn't know about time, however. The RawWvOut 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.
|
||||
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
|
||||
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,
|
||||
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 SKINI09.tbl file.
|
||||
g) All remaining fields are specified in the SKINI11.tbl file.
|
||||
In general, there are maximum two more fields, which are either
|
||||
SK_INT (long), SK_DBL (double float), or SK_STR (string). The
|
||||
latter is the mechanism by which more arguments can be specified
|
||||
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 SKINI09, by P. Cook 1996
|
||||
/* Howdy!!! Welcome to SKINI11, by P. Cook 1999
|
||||
|
||||
NoteOn 0.000082 2 55 82
|
||||
NoteOff 1.000000 2 55 0
|
||||
@@ -239,11 +240,11 @@ upon/from which to build and depart.
|
||||
NoteOff 0.000000 2 71 82
|
||||
NoteOff 0.000000 2 79 82
|
||||
|
||||
7) The SKINI09.tbl File, How Messages are Parsed
|
||||
7) The SKINI11.tbl File, How Messages are Parsed
|
||||
|
||||
The SKINI11.tbl file contains an array of structures which
|
||||
are accessed by the parser object SKINI11.cpp. The struct is:
|
||||
|
||||
The SKINI09.tbl file contains an array of structures which
|
||||
are accessed by the parser object SKINI09.cpp. The struct is:
|
||||
|
||||
struct SKINISpec { char messageString[32];
|
||||
long type;
|
||||
long data2;
|
||||
@@ -251,38 +252,38 @@ upon/from which to build and depart.
|
||||
};
|
||||
|
||||
so an assignment of one of these structs looks like:
|
||||
|
||||
MessageStr$ ,type, data2, data3,
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
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 SKINI09.tbl file
|
||||
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},
|
||||
|
||||
@@ -292,20 +293,20 @@ upon/from which to build and depart.
|
||||
The first three are basic MIDI messages. The first two would cause the
|
||||
parser, after recognizing a match of the string "NoteOff" or "NoteOn",
|
||||
to set the message type to 128 or 144 (__SK_NoteOff_ and __SK_NoteOn_
|
||||
are #defined in the file SKINI09.msg to be the MIDI byte value, without
|
||||
channel, of the actual MIDI messages for NoteOn and NoteOff). The parser
|
||||
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 line is basically the same as NoteOn and NoteOff, but
|
||||
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 line is a MIDI Extension message, which behaves like a
|
||||
ControlChange message with the controller number set explicitly 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:
|
||||
|
||||
@@ -314,28 +315,29 @@ upon/from which to build and depart.
|
||||
|
||||
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 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
|
||||
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 SKINI09(argv[1]);
|
||||
score = new SKINI11(argv[1]);
|
||||
while(score->getType() > 0) {
|
||||
tempDouble = score->getDelta();
|
||||
tempDouble = score->getDelta();
|
||||
if (tempDouble < 0) {
|
||||
tempDouble = - tempDouble;
|
||||
tempDouble = tempDouble - output.getTime();
|
||||
if (tempDouble < 0) {
|
||||
printf("Bad News Here!!! Backward Absolute Time Required.\n");
|
||||
printf("Bad News Here!!! Backward Absolute Time
|
||||
Required.\n");
|
||||
tempDouble = 0.0;
|
||||
}
|
||||
}
|
||||
@@ -367,13 +369,13 @@ upon/from which to build and depart.
|
||||
score->nextMessage();
|
||||
}
|
||||
|
||||
When the score (SKINI09 object) object is created from the
|
||||
When the score (SKINI11 object) object is created from the
|
||||
filename in argv[1], the first valid command line is read
|
||||
from the file and parsed.
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
@@ -382,7 +384,7 @@ upon/from which to build and depart.
|
||||
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
|
||||
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
|
||||
@@ -391,7 +393,3 @@ upon/from which to build and depart.
|
||||
control number, but all other data is treated as double float.
|
||||
|
||||
The last line reads and parses the next message in the file.
|
||||
|
||||
|
||||
|
||||
|
||||
133
hierarch.txt
133
hierarch.txt
@@ -1,133 +0,0 @@
|
||||
Brief Descriptions of Classes in STK98, ver. 2.01
|
||||
A ToolKit of Sound Synthesis Classes
|
||||
and Instruments in C++
|
||||
Perry Cook, 1995-96, free distribution for
|
||||
academic, instructional, tutorial, etc. purposes.
|
||||
Please read README.txt for more information.
|
||||
|
||||
<--------Building Blocks---------->|<----------------Instruments------------------>
|
||||
|
||||
SourcSink Filters Reverb Non-Lin ModalSyn FM Physical Sampling PhISM
|
||||
& Formant
|
||||
|
||||
Object-----------------------------------Instrmnt----------.
|
||||
| | | | | | |
|
||||
Envelope| Filter Reverb BowTabl | .------------------|---------------------.
|
||||
| | | | JetTabl | | | | | | | | |
|
||||
ADSR | OneZero PRCRev ReedTabl| Modal4 | FM4Op---.| | | | Shakers
|
||||
| OnePole JCRev | | | | || | | | |
|
||||
._____| TwoZero NRev .____| Marimba | FM4Alg3 || Plucked Sampler | Maraca
|
||||
| | TwoPole | Vibraphn| | || Clarinet | | Sekere
|
||||
Noise | DCBlock LipFilt AgogoBel| HeavyMtl|| Brass SamplFlt| Cabasa
|
||||
| | BiQuad | || Flute | | Bamboo
|
||||
SubNoise| DlineL .____| .____|| Bowed Moog1 | Water Drops
|
||||
| DLineA | | || | Tambourine
|
||||
._____| DLineN VoicForm FM4Alg4 ||____. | SleighBells
|
||||
| | FormSwep | | | | Guiro
|
||||
RawWave | PercFlut| Plucked2 |
|
||||
| | | |
|
||||
._____| .____| Mandolin .____|
|
||||
| | | | |
|
||||
RawLoop | FM4Alg5 | DrumSynt
|
||||
| | |
|
||||
._____| Rhodey |
|
||||
| | Wurley |
|
||||
Modulatr| TubeBell |
|
||||
| .____|
|
||||
._____| | |
|
||||
| | FM4Alg6 |
|
||||
SingWave| | |
|
||||
| FMVoices|
|
||||
._____|_____. |
|
||||
| | | .____|
|
||||
VoicMang| WvOut |
|
||||
| | FM4Alg8
|
||||
._____| WavWvOut |
|
||||
| | SndWvOut BeeThree
|
||||
RawWvIn | RTWvOut
|
||||
| MatWvOut
|
||||
._____|
|
||||
|
|
||||
MIDIInpt
|
||||
|
||||
|
||||
********** 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,RawLoop
|
||||
Clarinet.cpp Pretty Good Clarinet DLineL,ReedTabl,OneZero,Envelope,Noise,RawLoop
|
||||
Flute.cpp Pretty Good Flute JetTabl,DLineL,OnePole,DCBlock,Noise,ADSR,RawLoop
|
||||
Modal4.cpp 4 Resonances Envelope,RawWave,RawLoop,BiQuad,OnePole
|
||||
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), RawLoop (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: RawWave.cpp Lin-Interp Wavetable, Looped or 1 Shot
|
||||
RawLoop.cpp Lin-Interp Wavetable, Looping
|
||||
RawWvIn.cpp Lin-Interp Wave In streaming 'device'
|
||||
Envelope.cpp Linearly Goes to Target by Rate, + noteOn/Off
|
||||
ADSR.cpp ADSR Flavor of Envelope
|
||||
Noise.cpp Random Number Generator
|
||||
SubNoise.cpp Random Numbers each N samples
|
||||
|
||||
Outputs: WvOut.cpp Output Master Class
|
||||
SndWvOut.cpp .snd Output Class
|
||||
WavWvOut.cpp .wav Output Class
|
||||
RTWvOut.cpp Realtime Output Class
|
||||
MatWvOut.cpp Matlab Matfile Output Class
|
||||
|
||||
Inputs: MIDIInpt.cpp MIDI Stream Parser Class
|
||||
|
||||
Filters: Filter.cpp Filter Master Class
|
||||
OneZero.cpp One Zero Filter
|
||||
OnePole.cpp One Pole 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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user