mirror of
https://github.com/thestk/stk
synced 2026-01-11 20:11:52 +00:00
Version 0.99
This commit is contained in:
173
ADSR.cpp
Normal file
173
ADSR.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
/*******************************************/
|
||||
/* ADSR Subclass of the Envelope Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This is the traditional ADSR (Attack */
|
||||
/* Decay, Sustain, Release) ADSR. */
|
||||
/* It responds to simple KeyOn and KeyOff */
|
||||
/* messages, keeping track of it's state. */
|
||||
/* There are two tick (update value) */
|
||||
/* methods, one returns the value, and */
|
||||
/* other returns the state (0 = A, 1 = D, */
|
||||
/* 2 = S, 3 = R) */
|
||||
/*******************************************/
|
||||
|
||||
#include "ADSR.h"
|
||||
|
||||
ADSR :: ADSR() : Envelope()
|
||||
{
|
||||
target = 0.0;
|
||||
value = 0.0;
|
||||
attackRate = 0.001;
|
||||
decayRate = 0.001;
|
||||
sustainLevel = 0.5;
|
||||
releaseRate = 0.01;
|
||||
state = 0;
|
||||
}
|
||||
|
||||
ADSR :: ~ADSR()
|
||||
{
|
||||
/* Nothing to do here */
|
||||
}
|
||||
|
||||
void ADSR :: keyOn()
|
||||
{
|
||||
target = 1.0;
|
||||
rate = attackRate;
|
||||
state = 0;
|
||||
}
|
||||
|
||||
void ADSR :: keyOff()
|
||||
{
|
||||
target = 0.0;
|
||||
rate = releaseRate;
|
||||
state = 3;
|
||||
}
|
||||
|
||||
void ADSR :: setAttackRate(MY_FLOAT aRate)
|
||||
{
|
||||
if (aRate < 0.0) {
|
||||
printf("negative rates not allowed!!, correcting\n");
|
||||
attackRate = -aRate;
|
||||
}
|
||||
else attackRate = aRate;
|
||||
attackRate = attackRate * RATE_NORM; /* SEE Object.h */
|
||||
}
|
||||
|
||||
void ADSR :: setDecayRate(MY_FLOAT aRate)
|
||||
{
|
||||
if (aRate < 0.0) {
|
||||
printf("negative rates not allowed!!, correcting\n");
|
||||
decayRate = -aRate;
|
||||
}
|
||||
else decayRate = aRate;
|
||||
decayRate = decayRate * RATE_NORM; /* SEE Object.h */
|
||||
}
|
||||
|
||||
void ADSR :: setSustainLevel(MY_FLOAT aLevel)
|
||||
{
|
||||
if (aLevel < 0.0 ) {
|
||||
printf("Sustain level out of range!!, correcting\n");
|
||||
sustainLevel = 0.0;
|
||||
}
|
||||
else sustainLevel = aLevel;
|
||||
}
|
||||
|
||||
void ADSR :: setReleaseRate(MY_FLOAT aRate)
|
||||
{
|
||||
if (aRate < 0.0) {
|
||||
printf("negative rates not allowed!!, correcting\n");
|
||||
releaseRate = -aRate;
|
||||
}
|
||||
else releaseRate = aRate;
|
||||
releaseRate = releaseRate * RATE_NORM; /* SEE Object.h */
|
||||
}
|
||||
|
||||
void ADSR :: setAll(MY_FLOAT attRate, MY_FLOAT decRate, MY_FLOAT susLevel, MY_FLOAT relRate)
|
||||
{
|
||||
this->setAttackRate(attRate);
|
||||
this->setDecayRate(decRate);
|
||||
this->setSustainLevel(susLevel);
|
||||
this->setReleaseRate(relRate);
|
||||
}
|
||||
|
||||
void ADSR :: setTarget(MY_FLOAT aTarget)
|
||||
{
|
||||
target = aTarget;
|
||||
if (value < target) {
|
||||
state = ATTACK;
|
||||
this->setSustainLevel(target);
|
||||
rate = attackRate;
|
||||
}
|
||||
if (value > target) {
|
||||
this->setSustainLevel(target);
|
||||
state = DECAY;
|
||||
rate = decayRate;
|
||||
}
|
||||
}
|
||||
|
||||
void ADSR :: setValue(MY_FLOAT aValue)
|
||||
{
|
||||
state = SUSTAIN;
|
||||
target = aValue;
|
||||
value = aValue;
|
||||
this->setSustainLevel(aValue);
|
||||
rate = 0.0;
|
||||
}
|
||||
|
||||
MY_FLOAT ADSR :: tick()
|
||||
{
|
||||
if (state==ATTACK) {
|
||||
value += rate;
|
||||
if (value >= target) {
|
||||
value = target;
|
||||
rate = decayRate;
|
||||
target = sustainLevel;
|
||||
state = DECAY;
|
||||
}
|
||||
}
|
||||
else if (state==DECAY) {
|
||||
value -= decayRate;
|
||||
if (value <= sustainLevel) {
|
||||
value = sustainLevel;
|
||||
rate = 0.0;
|
||||
state = SUSTAIN;
|
||||
}
|
||||
}
|
||||
else if (state==RELEASE) {
|
||||
value -= releaseRate;
|
||||
if (value <= 0.0) {
|
||||
value = 0.0;
|
||||
state = 4;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
int ADSR :: informTick()
|
||||
{
|
||||
this->tick();
|
||||
return state;
|
||||
}
|
||||
|
||||
MY_FLOAT ADSR :: lastOut()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/************ Test Main ************************/
|
||||
/*
|
||||
void main()
|
||||
{
|
||||
long i;
|
||||
ADSR test;
|
||||
|
||||
test.setAttackRate(0.15);
|
||||
test.keyOn();
|
||||
while(test.informTick()==ATTACK) printf("%lf\n",test.tick());
|
||||
test.setDecayRate(0.1);
|
||||
while (test.informTick()==DECAY) printf("%lf\n",test.lastOut());
|
||||
test.setReleaseRate(0.05);
|
||||
test.keyOff();
|
||||
while(test.informTick()==RELEASE) printf("%lf\n",test.lastOut());
|
||||
}
|
||||
*/
|
||||
43
ADSR.h
Normal file
43
ADSR.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*******************************************/
|
||||
/* ADSR Subclass of the Envelope Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This is the traditional ADSR (Attack */
|
||||
/* Decay, Sustain, Release) envelope. */
|
||||
/* It responds to simple KeyOn and KeyOff */
|
||||
/* messages, keeping track of it's state. */
|
||||
/* There are two tick (update value) */
|
||||
/* methods, one returns the value, and */
|
||||
/* other returns the state (0 = A, 1 = D, */
|
||||
/* 2 = S, 3 = R) */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__ADSR_h)
|
||||
#define __ADSR_h
|
||||
|
||||
#include "Envelope.h"
|
||||
|
||||
class ADSR : public Envelope
|
||||
{
|
||||
protected:
|
||||
MY_FLOAT attackRate;
|
||||
MY_FLOAT decayRate;
|
||||
MY_FLOAT sustainLevel;
|
||||
MY_FLOAT releaseRate;
|
||||
public:
|
||||
ADSR();
|
||||
~ADSR();
|
||||
void keyOn();
|
||||
void keyOff();
|
||||
void setAttackRate(MY_FLOAT aRate);
|
||||
void setDecayRate(MY_FLOAT aRate);
|
||||
void setSustainLevel(MY_FLOAT aLevel);
|
||||
void setReleaseRate(MY_FLOAT aRate);
|
||||
void setAll(MY_FLOAT attRate, MY_FLOAT decRate, MY_FLOAT susLevel, MY_FLOAT relRate);
|
||||
void setTarget(MY_FLOAT aTarget);
|
||||
void setValue(MY_FLOAT aValue);
|
||||
MY_FLOAT tick();
|
||||
int informTick();
|
||||
MY_FLOAT lastOut();
|
||||
};
|
||||
|
||||
#endif
|
||||
75
AgogoBel.cpp
Normal file
75
AgogoBel.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/*******************************************/
|
||||
/* AgogoBell SubClass of Modal4 Instrument*/
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Controls: CONTROL1 = stickHardness */
|
||||
/* CONTROL2 = strikePosition*/
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/*******************************************/
|
||||
|
||||
/* Modes measured from my Agogo Bell by FFT: */
|
||||
/* 360, 1470, 2401, 4600 */
|
||||
|
||||
#include "AgogoBel.h"
|
||||
|
||||
AgogoBel :: AgogoBel() : Modal4()
|
||||
{
|
||||
wave = new RawWave("rawwaves/britestk.raw");
|
||||
wave->normalize();
|
||||
wave->setRate(7.0); /* hardstick */
|
||||
this->setRatioAndReson(0, 1.00,0.999); /* Set our */
|
||||
this->setRatioAndReson(1, 4.08,0.999); /* resonances */
|
||||
this->setRatioAndReson(2,6.669,0.999); /* here */
|
||||
this->setRatioAndReson(3,-3725.0,0.999); /* (One fixed) */
|
||||
this->setFiltGain(0,0.07); /* And filter */
|
||||
this->setFiltGain(1,0.06); /* gains too */
|
||||
this->setFiltGain(2,0.04);
|
||||
this->setFiltGain(3,0.02);
|
||||
directGain = 0.3;
|
||||
}
|
||||
|
||||
AgogoBel :: ~AgogoBel()
|
||||
{
|
||||
delete wave;
|
||||
}
|
||||
|
||||
void AgogoBel :: setStickHardness(MY_FLOAT hardness)
|
||||
{
|
||||
stickHardness = hardness; /* To an approximation, */
|
||||
wave->setRate(3.0 + (8.0 * stickHardness)); /* hardness <-> center */
|
||||
masterGain = 1.0; /* freq and amplitude */
|
||||
}
|
||||
|
||||
void AgogoBel :: setStrikePosition(MY_FLOAT position)
|
||||
{
|
||||
MY_FLOAT temp,temp2;
|
||||
temp2 = position * PI;
|
||||
strikePosition = position; /* Hack only first */
|
||||
temp = sin(0.7 * temp2); /* three modes, */
|
||||
this->setFiltGain(0,0.08 * temp); /* leave the other */
|
||||
temp = sin(0.1 + (5.0 * temp2)); /* fixed. Why? */
|
||||
this->setFiltGain(1,0.07 * temp); /* So it doesn't */
|
||||
temp = sin(0.2 + (7.0 * temp2)); /* sound like a */
|
||||
this->setFiltGain(2,0.04 * temp); /* sample! */
|
||||
}
|
||||
|
||||
void AgogoBel :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("AgogoBel : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == MIDI_control1)
|
||||
this->setStickHardness(value * NORM_7);
|
||||
else if (number == MIDI_control2)
|
||||
this->setStrikePosition(value * NORM_7);
|
||||
else if (number == MIDI_control3)
|
||||
vibr->setFreq((value * NORM_7 * 12.0));
|
||||
else if (number == MIDI_mod_wheel)
|
||||
vibrGain = (value * NORM_7);
|
||||
else if (number == MIDI_after_touch)
|
||||
this->strike(value * NORM_7);
|
||||
else {
|
||||
printf("AgogoBel : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
26
AgogoBel.h
Normal file
26
AgogoBel.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*******************************************/
|
||||
/* AgogoBell SubClass of Modal4 Instrument*/
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Controls: CONTROL1 = stickHardness */
|
||||
/* CONTROL2 = strikePosition*/
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__AgogoBel_h)
|
||||
#define __AgogoBel_h
|
||||
|
||||
#include "Modal4.h"
|
||||
|
||||
class AgogoBel : public Modal4
|
||||
{
|
||||
public:
|
||||
AgogoBel();
|
||||
~AgogoBel();
|
||||
void setStickHardness(MY_FLOAT hardness);
|
||||
void setStrikePosition(MY_FLOAT position);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
};
|
||||
|
||||
#endif
|
||||
39
AllPass1.cpp
Normal file
39
AllPass1.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
/*******************************************/
|
||||
/* 1st order allpass filter. */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* A special case of the one pole */
|
||||
/* one zero filter. */
|
||||
/*******************************************/
|
||||
|
||||
#include "AllPass1.h"
|
||||
|
||||
AllPass1 :: AllPass1()
|
||||
{
|
||||
inputs = (MY_FLOAT *) malloc(MY_FLOAT_SIZE);
|
||||
outputs = (MY_FLOAT *) malloc(MY_FLOAT_SIZE);
|
||||
this->clear();
|
||||
|
||||
}
|
||||
|
||||
AllPass1 :: ~AllPass1()
|
||||
{
|
||||
free(inputs);
|
||||
free(outputs);
|
||||
}
|
||||
|
||||
void AllPass1 :: clear()
|
||||
{
|
||||
outputs[0] = 0.0;
|
||||
inputs[0] = 0.0;
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
|
||||
MY_FLOAT AllPass1 :: tick(MY_FLOAT sample)
|
||||
{
|
||||
outputs[0] = sample - inputs[0] + (0.99 * outputs[0]);
|
||||
inputs[0] = sample;
|
||||
lastOutput = outputs[0];
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
|
||||
24
AllPass1.h
Normal file
24
AllPass1.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*******************************************/
|
||||
/* 1st order allpass filter. */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* A special case of the one pole */
|
||||
/* one zero filter. */
|
||||
/*******************************************/
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
#if !defined(__AllPass1_h)
|
||||
#define __AllPass1_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class AllPass1 : Filter
|
||||
{
|
||||
public:
|
||||
AllPass1();
|
||||
~AllPass1();
|
||||
void clear();
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
71
BeeThree.cpp
Normal file
71
BeeThree.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/******************************************/
|
||||
/* Hammond(OID) Organ Subclass */
|
||||
/* of Algorithm 8 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/******************************************/
|
||||
|
||||
#include "BeeThree.h"
|
||||
|
||||
BeeThree :: BeeThree() : FM4Alg8()
|
||||
{
|
||||
this->loadWaves("rawwaves/sinewave.raw",
|
||||
"rawwaves/sinewave.raw",
|
||||
"rawwaves/sinewave.raw",
|
||||
"rawwaves/sinewave.raw");
|
||||
this->setRatio(0,0.999);
|
||||
this->setRatio(1,1.997);
|
||||
this->setRatio(2,3.006);
|
||||
this->setRatio(3,6.009);
|
||||
gains[0] = __FM4Op_gains[95];
|
||||
gains[1] = __FM4Op_gains[95];
|
||||
gains[2] = __FM4Op_gains[99];
|
||||
gains[3] = __FM4Op_gains[95];
|
||||
adsr[0]->setAll(0.05,0.03,1.0,0.04);
|
||||
adsr[1]->setAll(0.05,0.03,1.0,0.04);
|
||||
adsr[2]->setAll(0.05,0.03,1.0,0.04);
|
||||
adsr[3]->setAll(0.05,0.001,0.4,0.06);
|
||||
twozero->setGain(0.1);
|
||||
}
|
||||
|
||||
BeeThree :: ~BeeThree()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BeeThree :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
waves[0]->setFreq(baseFreq * ratios[0]);
|
||||
waves[1]->setFreq(baseFreq * ratios[1]);
|
||||
waves[2]->setFreq(baseFreq * ratios[2]);
|
||||
waves[3]->setFreq(baseFreq * ratios[3]);
|
||||
}
|
||||
|
||||
MY_FLOAT BeeThree :: tick()
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
if (modDepth > 0.0) {
|
||||
temp = 1.0 + (modDepth * vibWave->tick() * 0.1);
|
||||
waves[0]->setFreq(baseFreq * ratios[0] * temp);
|
||||
waves[1]->setFreq(baseFreq * ratios[1] * temp);
|
||||
waves[2]->setFreq(baseFreq * ratios[2] * temp);
|
||||
waves[3]->setFreq(baseFreq * ratios[3] * temp);
|
||||
}
|
||||
lastOutput = FM4Alg8 :: tick();
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void BeeThree :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
gains[0] = amp * __FM4Op_gains[95];
|
||||
gains[1] = amp * __FM4Op_gains[95];
|
||||
gains[2] = amp * __FM4Op_gains[99];
|
||||
gains[3] = amp * __FM4Op_gains[95];
|
||||
this->setFreq(freq);
|
||||
this->keyOn();
|
||||
#if defined(_debug_)
|
||||
printf("BeeThree : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
23
BeeThree.h
Normal file
23
BeeThree.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/******************************************/
|
||||
/* HammondOid Organ Subclass */
|
||||
/* of Algorithm 8 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__BeeThree_h)
|
||||
#define __BeeThree_h
|
||||
|
||||
#include "FM4Alg8.h"
|
||||
|
||||
class BeeThree : public FM4Alg8
|
||||
{
|
||||
public:
|
||||
BeeThree();
|
||||
~BeeThree();
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
MY_FLOAT tick();
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
};
|
||||
|
||||
#endif
|
||||
80
BiQuad.cpp
Normal file
80
BiQuad.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
/*******************************************/
|
||||
/* BiQuad (2-pole, 2-zero) Filter Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* See books on filters to understand */
|
||||
/* more about how this works. Nothing */
|
||||
/* out of the ordinary in this version. */
|
||||
/*******************************************/
|
||||
|
||||
#include "BiQuad.h"
|
||||
|
||||
BiQuad :: BiQuad() : Filter()
|
||||
{
|
||||
inputs = (MY_FLOAT *) malloc(2 * MY_FLOAT_SIZE);
|
||||
zeroCoeffs[0] = 0.0;
|
||||
zeroCoeffs[1] = 0.0;
|
||||
poleCoeffs[0] = 0.0;
|
||||
poleCoeffs[1] = 0.0;
|
||||
gain = 1.0;
|
||||
this->clear();
|
||||
}
|
||||
|
||||
BiQuad :: ~BiQuad()
|
||||
{
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
void BiQuad :: clear()
|
||||
{
|
||||
inputs[0] = 0.0;
|
||||
inputs[1] = 0.0;
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
|
||||
void BiQuad :: setPoleCoeffs(MY_FLOAT *coeffs)
|
||||
{
|
||||
poleCoeffs[0] = coeffs[0];
|
||||
poleCoeffs[1] = coeffs[1];
|
||||
}
|
||||
|
||||
void BiQuad :: setZeroCoeffs(MY_FLOAT *coeffs)
|
||||
{
|
||||
zeroCoeffs[0] = coeffs[0];
|
||||
zeroCoeffs[1] = coeffs[1];
|
||||
}
|
||||
|
||||
void BiQuad :: setFreqAndReson(MY_FLOAT freq, MY_FLOAT reson)
|
||||
{
|
||||
poleCoeffs[1] = - (reson * reson);
|
||||
poleCoeffs[0] = 2.0 * reson * cos(TWO_PI * freq / SRATE);
|
||||
}
|
||||
|
||||
void BiQuad :: setEqualGainZeroes()
|
||||
{
|
||||
zeroCoeffs[1] = -1.0;
|
||||
zeroCoeffs[0] = 0.0;
|
||||
}
|
||||
|
||||
void BiQuad :: setGain(MY_FLOAT aValue)
|
||||
{
|
||||
gain = aValue;
|
||||
}
|
||||
|
||||
MY_FLOAT BiQuad :: tick(MY_FLOAT sample) /* Perform Filter Operation */
|
||||
{ /* Biquad is two pole, two zero filter */
|
||||
MY_FLOAT temp; /* Look it up in your favorite DSP text */
|
||||
|
||||
temp = sample * gain; /* Here's the math for the */
|
||||
temp += inputs[0] * poleCoeffs[0]; /* version which implements */
|
||||
temp += inputs[1] * poleCoeffs[1]; /* only 2 state variables. */
|
||||
|
||||
lastOutput = temp; /* This form takes */
|
||||
lastOutput += (inputs[0] * zeroCoeffs[0]); /* 5 multiplies and */
|
||||
lastOutput += (inputs[1] * zeroCoeffs[1]); /* 4 adds */
|
||||
inputs[1] = inputs[0]; /* and 3 moves */
|
||||
inputs[0] = temp; /* like the 2 state-var form*/
|
||||
|
||||
return lastOutput;
|
||||
|
||||
}
|
||||
|
||||
31
BiQuad.h
Normal file
31
BiQuad.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*******************************************/
|
||||
/* BiQuad (2-pole, 2-zero) Filter Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* See books on filters to understand */
|
||||
/* more about how this works. Nothing */
|
||||
/* out of the ordinary in this version. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__BiQuad_h)
|
||||
#define __BiQuad_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class BiQuad : public Filter
|
||||
{
|
||||
protected:
|
||||
MY_FLOAT poleCoeffs[2];
|
||||
MY_FLOAT zeroCoeffs[2];
|
||||
public:
|
||||
BiQuad();
|
||||
~BiQuad();
|
||||
void clear();
|
||||
void setPoleCoeffs(MY_FLOAT *coeffs);
|
||||
void setZeroCoeffs(MY_FLOAT *coeffs);
|
||||
void setGain(MY_FLOAT aValue);
|
||||
void setFreqAndReson(MY_FLOAT freq, MY_FLOAT reson);
|
||||
void setEqualGainZeroes();
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
46
BowTabl.cpp
Normal file
46
BowTabl.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/***********************************************/
|
||||
/* Simple Bow Table Object, after Smith */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/***********************************************/
|
||||
|
||||
#include "BowTabl.h"
|
||||
|
||||
BowTabl :: BowTabl()
|
||||
{
|
||||
offSet = 0.0; /* offset is a bias, really not needed unless */
|
||||
/* friction is different in each direction */
|
||||
slope = 0.1; /* controls width of friction pulse, */
|
||||
/* related to bowForce */
|
||||
}
|
||||
|
||||
BowTabl :: ~BowTabl()
|
||||
{
|
||||
}
|
||||
|
||||
void BowTabl :: setOffset(MY_FLOAT aValue)
|
||||
{
|
||||
offSet = aValue;
|
||||
}
|
||||
|
||||
void BowTabl :: setSlope(MY_FLOAT aValue)
|
||||
{
|
||||
slope = aValue;
|
||||
}
|
||||
|
||||
MY_FLOAT BowTabl :: lookup(MY_FLOAT sample) /* Perform Table Lookup */
|
||||
{ /* sample is differential */
|
||||
/* string vs. bow velocity */
|
||||
MY_FLOAT input;
|
||||
input = sample + offSet; /* add bias to sample */
|
||||
input *= slope; /* scale it */
|
||||
lastOutput = fabs(input) + 0.75; /* below min delta, friction = 1 */
|
||||
lastOutput = pow(lastOutput,-4.0);
|
||||
// if (lastOutput < 0.0 ) lastOutput = 0.0; /* minimum friction is 0.0 */
|
||||
if (lastOutput > 1.0 ) lastOutput = 1.0; /* maximum friction is 1.0 */
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT BowTabl :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
22
BowTabl.h
Normal file
22
BowTabl.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/***********************************************/
|
||||
/* Simple Bow Table Object, after Smith */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/***********************************************/
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class BowTabl : public Object
|
||||
{
|
||||
protected:
|
||||
MY_FLOAT offSet;
|
||||
MY_FLOAT slope;
|
||||
MY_FLOAT lastOutput;
|
||||
public:
|
||||
BowTabl();
|
||||
~BowTabl();
|
||||
void setOffset(MY_FLOAT aValue);
|
||||
void setSlope(MY_FLOAT aValue);
|
||||
MY_FLOAT lookup(MY_FLOAT sample);
|
||||
MY_FLOAT lastOut();
|
||||
};
|
||||
|
||||
160
Bowed.cpp
Normal file
160
Bowed.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
/******************************************/
|
||||
/* Bowed String model ala Smith */
|
||||
/* after McIntyre, Schumacher, Woodhouse */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* */
|
||||
/* This is a waveguide model, and thus */
|
||||
/* relates to various Stanford Univ. */
|
||||
/* and possibly Yamaha and other patents.*/
|
||||
/* */
|
||||
/* Controls: CONTROL1 = bowPressure */
|
||||
/* CONTROL2 = bowPosition */
|
||||
/* CONTROL3 = vibrFreq */
|
||||
/* MOD_WHEEL= vibrGain */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#include "Bowed.h"
|
||||
|
||||
Bowed :: Bowed(MY_FLOAT lowestFreq)
|
||||
{
|
||||
long length;
|
||||
length = (long) (SRATE / lowestFreq + 1);
|
||||
neckDelay = new DLineL(length);
|
||||
length >> 1;
|
||||
bridgeDelay = new DLineL(length);
|
||||
bowTabl = new BowTabl;
|
||||
reflFilt = new OnePole;
|
||||
bodyFilt = new BiQuad;
|
||||
vibr = new RawLoop("rawwaves/sinewave.raw");
|
||||
adsr = new ADSR;
|
||||
vibrGain = 0.0;
|
||||
|
||||
neckDelay->setDelay(100.0);
|
||||
bridgeDelay->setDelay(29.0);
|
||||
|
||||
bowTabl->setSlope(3.0);
|
||||
|
||||
reflFilt->setPole(0.6 - (0.1 * RATE_NORM));
|
||||
reflFilt->setGain(0.95);
|
||||
|
||||
bodyFilt->setFreqAndReson(500.0, 0.85);
|
||||
bodyFilt->setEqualGainZeroes();
|
||||
bodyFilt->setGain(0.2);
|
||||
|
||||
vibr->normalize();
|
||||
vibr->setFreq(6.12723);
|
||||
|
||||
adsr->setAll(0.002,0.01,0.9,0.01);
|
||||
|
||||
betaRatio = 0.127236;
|
||||
}
|
||||
|
||||
Bowed :: ~Bowed()
|
||||
{
|
||||
delete neckDelay;
|
||||
delete bridgeDelay;
|
||||
delete bowTabl;
|
||||
delete reflFilt;
|
||||
delete bodyFilt;
|
||||
delete vibr;
|
||||
delete adsr;
|
||||
}
|
||||
|
||||
void Bowed :: clear()
|
||||
{
|
||||
neckDelay->clear();
|
||||
bridgeDelay->clear();
|
||||
}
|
||||
|
||||
void Bowed :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseDelay = (MY_FLOAT) SRATE / frequency - 4.0; /* delay - approx. filter delay */
|
||||
bridgeDelay->setDelay(baseDelay * betaRatio); /* bow to bridge length */
|
||||
neckDelay->setDelay(baseDelay * (1.0 - betaRatio)); /* bow to nut (finger) length */
|
||||
}
|
||||
|
||||
void Bowed :: startBowing(MY_FLOAT amplitude, MY_FLOAT rate)
|
||||
{
|
||||
adsr->setRate(rate);
|
||||
adsr->keyOn();
|
||||
maxVelocity = 0.03 + (0.2 * amplitude);
|
||||
}
|
||||
|
||||
void Bowed :: stopBowing(MY_FLOAT rate)
|
||||
{
|
||||
adsr->setRate(rate);
|
||||
adsr->keyOff();
|
||||
}
|
||||
|
||||
void Bowed :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->startBowing(amp,amp * 0.001);
|
||||
this->setFreq(freq);
|
||||
#if defined(_debug_)
|
||||
printf("Bowed : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Bowed :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
this->stopBowing((1.0 - amp) * 0.005);
|
||||
#if defined(_debug_)
|
||||
printf("Bowed : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Bowed :: setVibrato(MY_FLOAT amount)
|
||||
{
|
||||
vibrGain = amount;
|
||||
}
|
||||
|
||||
MY_FLOAT Bowed :: tick()
|
||||
{
|
||||
MY_FLOAT bowVelocity;
|
||||
MY_FLOAT bridgeRefl=0,nutRefl=0;
|
||||
MY_FLOAT newVel=0,velDiff=0,stringVel=0;
|
||||
|
||||
bowVelocity = maxVelocity * adsr->tick();
|
||||
|
||||
bridgeRefl = -reflFilt->tick(
|
||||
bridgeDelay->lastOut()); /* Bridge Reflection */
|
||||
nutRefl = -neckDelay->lastOut(); /* Nut Reflection */
|
||||
stringVel = bridgeRefl + nutRefl; /* Sum is String Velocity */
|
||||
velDiff = bowVelocity - stringVel; /* Differential Velocity */
|
||||
newVel = velDiff * bowTabl->lookup(velDiff); /* Non-Lin Bow Function */
|
||||
neckDelay->tick(bridgeRefl + newVel); /* Do string */
|
||||
bridgeDelay->tick(nutRefl + newVel); /* propagations */
|
||||
|
||||
if (vibrGain > 0.0) {
|
||||
neckDelay->setDelay((baseDelay * (1.0 - betaRatio)) +
|
||||
(baseDelay * vibrGain*vibr->tick()));
|
||||
}
|
||||
|
||||
lastOutput = bodyFilt->tick(bridgeDelay->lastOut());
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void Bowed :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Bowed : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == MIDI_control1)
|
||||
bowTabl->setSlope(5.0 - (4.0 * value * NORM_7));
|
||||
else if (number == MIDI_control2) {
|
||||
betaRatio = 0.027236 + (0.2 * value * NORM_7);
|
||||
bridgeDelay->setDelay(baseDelay * betaRatio); /* bow to bridge length */
|
||||
neckDelay->setDelay(baseDelay * (1.0 - betaRatio)); /* bow to nut (finger) length */
|
||||
}
|
||||
else if (number == MIDI_control3)
|
||||
vibr->setFreq((value * NORM_7 * 12.0));
|
||||
else if (number == MIDI_mod_wheel)
|
||||
vibrGain = (value * NORM_7 * 0.4);
|
||||
else if (number == MIDI_after_touch)
|
||||
adsr->setTarget(value * NORM_7);
|
||||
else {
|
||||
printf("Bowed : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
56
Bowed.h
Normal file
56
Bowed.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/******************************************/
|
||||
/* Bowed String model ala Smith */
|
||||
/* after McIntyre, Schumacher, Woodhouse */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* */
|
||||
/* This is a waveguide model, and thus */
|
||||
/* relates to various Stanford Univ. */
|
||||
/* and possibly Yamaha and other patents.*/
|
||||
/* */
|
||||
/* Controls: CONTROL1 = bowPressure */
|
||||
/* CONTROL2 = bowPosition */
|
||||
/* CONTROL3 = vibrFreq */
|
||||
/* MOD_WHEEL= vibrGain */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__Bowed_h)
|
||||
#define __Bowed_h
|
||||
|
||||
#include "Instrmnt.h"
|
||||
#include "DLineL.h"
|
||||
#include "BowTabl.h"
|
||||
#include "OnePole.h"
|
||||
#include "BiQuad.h"
|
||||
#include "RawLoop.h"
|
||||
#include "ADSR.h"
|
||||
|
||||
class Bowed : public Instrmnt
|
||||
{
|
||||
protected:
|
||||
DLineL *neckDelay;
|
||||
DLineL *bridgeDelay;
|
||||
BowTabl *bowTabl;
|
||||
OnePole *reflFilt;
|
||||
BiQuad *bodyFilt;
|
||||
RawLoop *vibr;
|
||||
ADSR *adsr;
|
||||
MY_FLOAT maxVelocity;
|
||||
MY_FLOAT baseDelay;
|
||||
MY_FLOAT vibrGain;
|
||||
MY_FLOAT betaRatio;
|
||||
public:
|
||||
Bowed(MY_FLOAT lowestFreq);
|
||||
~Bowed();
|
||||
void clear();
|
||||
void startBowing(MY_FLOAT amplitude,MY_FLOAT rate);
|
||||
void stopBowing(MY_FLOAT rate);
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
virtual void noteOff(MY_FLOAT amp);
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
void setVibrato(MY_FLOAT amount);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
virtual MY_FLOAT tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
129
Brass.cpp
Normal file
129
Brass.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
/******************************************/
|
||||
/* Waveguide Brass Instrument Model ala */
|
||||
/* Cook (TBone, HosePlayer) */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* This is a waveguide model, and thus */
|
||||
/* relates to various Stanford Univ. */
|
||||
/* and possibly Yamaha and other patents.*/
|
||||
/* */
|
||||
/* Controls: CONTROL1 = lipTension */
|
||||
/* CONTROL2 = slideLength */
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/******************************************/
|
||||
|
||||
#include "Brass.h"
|
||||
|
||||
Brass :: Brass(MY_FLOAT lowestFreq)
|
||||
{
|
||||
length = (long) (SRATE / lowestFreq + 1);
|
||||
delayLine = new DLineA(length);
|
||||
lipFilter = new LipFilt;
|
||||
dcBlock = new DCBlock;
|
||||
adsr = new ADSR;
|
||||
adsr->setAll(0.02, 0.05, 1.0, 0.001);
|
||||
vibr = new RawLoop("rawwaves/sinewave.raw");
|
||||
this->clear();
|
||||
|
||||
vibr->normalize();
|
||||
vibr->setFreq(6.137);
|
||||
vibrGain = 0.05; /* breath periodic vibrato component */
|
||||
}
|
||||
|
||||
Brass :: ~Brass()
|
||||
{
|
||||
delete delayLine;
|
||||
delete lipFilter;
|
||||
delete dcBlock;
|
||||
delete adsr;
|
||||
delete vibr;
|
||||
}
|
||||
|
||||
void Brass :: clear()
|
||||
{
|
||||
delayLine->clear();
|
||||
lipFilter->clear();
|
||||
dcBlock->clear();
|
||||
/* adsr->reset(); */
|
||||
}
|
||||
|
||||
void Brass :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
slideTarget = ((MY_FLOAT) SRATE / frequency * 2.0) + 3.0;
|
||||
/* fudge correction for filter delays */
|
||||
delayLine->setDelay(slideTarget); /* we'll play a harmonic */
|
||||
lipTarget = frequency;
|
||||
lipFilter->setFreq(frequency);
|
||||
}
|
||||
|
||||
void Brass :: setLip(MY_FLOAT frequency)
|
||||
{
|
||||
lipFilter->setFreq(frequency);
|
||||
}
|
||||
|
||||
void Brass :: startBlowing(MY_FLOAT amplitude,MY_FLOAT rate)
|
||||
{
|
||||
adsr->setAttackRate(rate);
|
||||
maxPressure = amplitude;
|
||||
adsr->keyOn();
|
||||
}
|
||||
|
||||
void Brass :: stopBlowing(MY_FLOAT rate)
|
||||
{
|
||||
adsr->setReleaseRate(rate);
|
||||
adsr->keyOff();
|
||||
}
|
||||
|
||||
void Brass :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->setFreq(freq);
|
||||
this->startBlowing(amp, amp * 0.001);
|
||||
#if defined(_debug_)
|
||||
printf("Brass : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Brass :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
this->stopBlowing(amp * 0.005);
|
||||
#if defined(_debug_)
|
||||
printf("Brass : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
MY_FLOAT Brass :: tick()
|
||||
{
|
||||
MY_FLOAT breathPressure;
|
||||
|
||||
breathPressure = maxPressure * adsr->tick();
|
||||
breathPressure += vibrGain * vibr->tick();
|
||||
lastOutput = delayLine->tick( /* bore delay */
|
||||
dcBlock->tick( /* block DC */
|
||||
lipFilter->tick(0.3 * breathPressure, /* mouth input */
|
||||
0.85 * delayLine->lastOut()))); /* and bore reflection */
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void Brass :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
#if defined(_debug_)
|
||||
printf("Brass : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == MIDI_control1) {
|
||||
temp = lipTarget * pow(4.0,(2.0*value*NORM_7) - 1.0);
|
||||
this->setLip(temp);
|
||||
}
|
||||
else if (number == MIDI_control2)
|
||||
delayLine->setDelay(slideTarget * (0.5 + (value * NORM_7)));
|
||||
else if (number == MIDI_control3)
|
||||
vibr->setFreq((value * NORM_7 * 12.0));
|
||||
else if (number == MIDI_mod_wheel)
|
||||
vibrGain = (value * NORM_7 * 0.4);
|
||||
else if (number == MIDI_after_touch)
|
||||
adsr->setTarget(value * NORM_7);
|
||||
else {
|
||||
printf("Brass : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
53
Brass.h
Normal file
53
Brass.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/******************************************/
|
||||
/* Simple Brass Instrument Model ala */
|
||||
/* Cook (TBone, HosePlayer) */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* This is a waveguide model, and thus */
|
||||
/* relates to various Stanford Univ. */
|
||||
/* and possibly Yamaha and other patents.*/
|
||||
/* */
|
||||
/* Controls: CONTROL1 = lipTension */
|
||||
/* CONTROL2 = slideLength */
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__Brass_h)
|
||||
#define __Brass_h
|
||||
|
||||
#include "Instrmnt.h"
|
||||
#include "DLineA.h"
|
||||
#include "LipFilt.h"
|
||||
#include "DCBlock.h"
|
||||
#include "ADSR.h"
|
||||
#include "RawLoop.h"
|
||||
|
||||
class Brass: public Instrmnt
|
||||
{
|
||||
protected:
|
||||
DLineA *delayLine;
|
||||
LipFilt *lipFilter;
|
||||
DCBlock *dcBlock;
|
||||
ADSR *adsr;
|
||||
RawLoop *vibr;
|
||||
long length;
|
||||
MY_FLOAT lipTarget;
|
||||
MY_FLOAT slideTarget;
|
||||
MY_FLOAT vibrGain;
|
||||
MY_FLOAT maxPressure;
|
||||
public:
|
||||
Brass(MY_FLOAT lowestFreq);
|
||||
~Brass();
|
||||
void clear();
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
void setLip(MY_FLOAT frequency);
|
||||
void startBlowing(MY_FLOAT amplitude,MY_FLOAT rate);
|
||||
void stopBlowing(MY_FLOAT rate);
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
virtual void noteOff(MY_FLOAT amp);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
virtual MY_FLOAT tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
125
Clarinet.cpp
Normal file
125
Clarinet.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/******************************************/
|
||||
/* Waveguide Clarinet model ala Smith */
|
||||
/* after McIntyre, Schumacher, Woodhouse */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* */
|
||||
/* This is a waveguide model, and thus */
|
||||
/* relates to various Stanford Univ. */
|
||||
/* and possibly Yamaha and other patents.*/
|
||||
/* */
|
||||
/* Controls: CONTROL1 = reedStiffns */
|
||||
/* CONTROL2 = noiseGain */
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/******************************************/
|
||||
|
||||
#include "Clarinet.h"
|
||||
|
||||
Clarinet :: Clarinet(MY_FLOAT lowestFreq)
|
||||
{
|
||||
length = (long) (SRATE / lowestFreq + 1);
|
||||
delayLine = new DLineL(length);
|
||||
reedTable = new ReedTabl;
|
||||
reedTable->setOffset(0.7);
|
||||
reedTable->setSlope(-0.3);
|
||||
filter = new OneZero;
|
||||
envelope = new Envelope;
|
||||
noise = new Noise;
|
||||
vibr = new RawLoop("rawwaves/sinewave.raw");
|
||||
vibr->normalize();
|
||||
vibr->setFreq(5.735);
|
||||
outputGain = 1.0;
|
||||
noiseGain = 0.2;
|
||||
vibrGain = 0.1;
|
||||
}
|
||||
|
||||
Clarinet :: ~Clarinet()
|
||||
{
|
||||
delete delayLine;
|
||||
delete reedTable;
|
||||
delete filter;
|
||||
delete envelope;
|
||||
delete noise;
|
||||
delete vibr;
|
||||
}
|
||||
|
||||
void Clarinet :: clear()
|
||||
{
|
||||
delayLine->clear();
|
||||
filter->tick(0.0);
|
||||
}
|
||||
|
||||
void Clarinet :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
delayLine->setDelay /* length - approx filter delay */
|
||||
((SRATE / frequency) * 0.5 - 1.5);
|
||||
}
|
||||
|
||||
void Clarinet :: startBlowing(MY_FLOAT amplitude,MY_FLOAT rate)
|
||||
{
|
||||
envelope->setRate(rate);
|
||||
envelope->setTarget(amplitude);
|
||||
}
|
||||
|
||||
void Clarinet :: stopBlowing(MY_FLOAT rate)
|
||||
{
|
||||
envelope->setRate(rate);
|
||||
envelope->setTarget(0.0);
|
||||
}
|
||||
|
||||
void Clarinet :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->setFreq(freq);
|
||||
this->startBlowing(0.55 + (amp * 0.30),amp * 0.005);
|
||||
outputGain = amp + 0.001;
|
||||
#if defined(_debug_)
|
||||
printf("Clarinet : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Clarinet :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
this->stopBlowing(amp * 0.01);
|
||||
#if defined(_debug_)
|
||||
printf("Clarinet : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
MY_FLOAT Clarinet :: tick()
|
||||
{
|
||||
MY_FLOAT pressureDiff;
|
||||
MY_FLOAT breathPressure;
|
||||
|
||||
breathPressure = envelope->tick();
|
||||
breathPressure += breathPressure *
|
||||
noiseGain * noise->tick();
|
||||
breathPressure += breathPressure *
|
||||
vibrGain * vibr->tick();
|
||||
pressureDiff = filter->tick(delayLine->lastOut()); /* differential pressure */
|
||||
pressureDiff = (pressureDiff * -0.95) - breathPressure; /* of reflected and mouth */
|
||||
lastOutput = delayLine->tick(breathPressure + /* perform scattering */
|
||||
pressureDiff * reedTable->lookup(pressureDiff)); /* in economical way */
|
||||
lastOutput *= outputGain;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void Clarinet :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Clarinet : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == MIDI_control1)
|
||||
reedTable->setSlope(-0.44 + (0.26 * value * NORM_7));
|
||||
else if (number == MIDI_control2)
|
||||
noiseGain = (value * NORM_7 * 0.4);
|
||||
else if (number == MIDI_control3)
|
||||
vibr->setFreq((value * NORM_7 * 12.0));
|
||||
else if (number == MIDI_mod_wheel)
|
||||
vibrGain = (value * NORM_7 * 0.5);
|
||||
else if (number == MIDI_after_touch) {
|
||||
envelope->setValue(value * NORM_7);
|
||||
}
|
||||
else {
|
||||
printf("Clarinet : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
53
Clarinet.h
Normal file
53
Clarinet.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/******************************************/
|
||||
/* Clarinet model ala Smith */
|
||||
/* after McIntyre, Schumacher, Woodhouse */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* */
|
||||
/* This is a waveguide model, and thus */
|
||||
/* relates to various Stanford Univ. */
|
||||
/* and possibly Yamaha and other patents.*/
|
||||
/* */
|
||||
/* Controls: CONTROL1 = reedStiffns */
|
||||
/* CONTROL2 = noiseGain */
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__Clarinet_h)
|
||||
#define __Clarinet_h
|
||||
|
||||
#include "Instrmnt.h"
|
||||
#include "DLineL.h"
|
||||
#include "ReedTabl.h"
|
||||
#include "OneZero.h"
|
||||
#include "Envelope.h"
|
||||
#include "Noise.h"
|
||||
#include "RawLoop.h"
|
||||
|
||||
class Clarinet : public Instrmnt
|
||||
{
|
||||
protected:
|
||||
DLineL *delayLine;
|
||||
ReedTabl *reedTable;
|
||||
OneZero *filter;
|
||||
Envelope *envelope;
|
||||
Noise *noise;
|
||||
RawLoop *vibr;
|
||||
long length;
|
||||
MY_FLOAT outputGain;
|
||||
MY_FLOAT noiseGain;
|
||||
MY_FLOAT vibrGain;
|
||||
public:
|
||||
Clarinet(MY_FLOAT lowestFreq);
|
||||
~Clarinet();
|
||||
void clear();
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
void startBlowing(MY_FLOAT amplitude,MY_FLOAT rate);
|
||||
void stopBlowing(MY_FLOAT rate);
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
virtual void noteOff(MY_FLOAT amp);
|
||||
virtual MY_FLOAT tick();
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
};
|
||||
|
||||
#endif
|
||||
41
DCBlock.cpp
Normal file
41
DCBlock.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/*******************************************/
|
||||
/* DC Blocking Filter */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This guy is very helpful in, uh, */
|
||||
/* blocking DC. Needed because a simple */
|
||||
/* low-pass reflection filter allows DC */
|
||||
/* to build up inside recursive */
|
||||
/* structures. */
|
||||
/*******************************************/
|
||||
|
||||
#include "DCBlock.h"
|
||||
|
||||
DCBlock :: DCBlock()
|
||||
{
|
||||
inputs = (MY_FLOAT *) malloc(MY_FLOAT_SIZE);
|
||||
outputs = (MY_FLOAT *) malloc(MY_FLOAT_SIZE);
|
||||
this->clear();
|
||||
|
||||
}
|
||||
|
||||
DCBlock :: ~DCBlock()
|
||||
{
|
||||
free(inputs);
|
||||
free(outputs);
|
||||
}
|
||||
|
||||
void DCBlock :: clear()
|
||||
{
|
||||
outputs[0] = 0.0;
|
||||
inputs[0] = 0.0;
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
|
||||
MY_FLOAT DCBlock :: tick(MY_FLOAT sample)
|
||||
{
|
||||
outputs[0] = sample - inputs[0] + (0.99 * outputs[0]);
|
||||
inputs[0] = sample;
|
||||
lastOutput = outputs[0];
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
25
DCBlock.h
Normal file
25
DCBlock.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*******************************************/
|
||||
/* DC Blocking Filter */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This guy is very helpful in, uh, */
|
||||
/* blocking DC. Needed because a simple */
|
||||
/* low-pass reflection filter allows DC */
|
||||
/* to build up inside recursive */
|
||||
/* structures. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__DCBlock_h)
|
||||
#define __DCBlock_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class DCBlock : public Filter
|
||||
{
|
||||
public:
|
||||
DCBlock();
|
||||
~DCBlock();
|
||||
void clear();
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
104
DLineA.cpp
Normal file
104
DLineA.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
/*******************************************/
|
||||
/* */
|
||||
/* AllPass Interpolating Delay Line */
|
||||
/* Object by Perry R. Cook 1995-96 */
|
||||
/* This one uses a delay line of maximum */
|
||||
/* length specified on creation, and */
|
||||
/* interpolates fractional length using */
|
||||
/* an all-pass filter. This version is */
|
||||
/* more efficient for computing static */
|
||||
/* length delay lines (alpha and coeff */
|
||||
/* are computed only when the length */
|
||||
/* is set, there probably is a more */
|
||||
/* efficient computational form if alpha */
|
||||
/* is changed often (each sample)). */
|
||||
/* */
|
||||
/*******************************************/
|
||||
|
||||
#include "DLineA.h"
|
||||
|
||||
DLineA :: DLineA(long max_length)
|
||||
{
|
||||
long i;
|
||||
length = max_length;
|
||||
inputs = (MY_FLOAT *) malloc(length * MY_FLOAT_SIZE);
|
||||
for (i=0;i<length;i++) inputs[i] = 0;
|
||||
this->clear();
|
||||
inPoint = 0;
|
||||
outPoint = length >> 1;
|
||||
}
|
||||
|
||||
DLineA :: ~DLineA()
|
||||
{
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
void DLineA :: clear()
|
||||
{
|
||||
long i;
|
||||
for (i=0;i<length;i++) inputs[i] = 0.0;
|
||||
lastIn = 0;
|
||||
lastOutput = 0;
|
||||
}
|
||||
|
||||
void DLineA :: setDelay(MY_FLOAT lag)
|
||||
{
|
||||
MY_FLOAT outputPointer;
|
||||
outputPointer = inPoint - lag + 2; /* outPoint chases inpoint */
|
||||
/* + 2 for interp and other */
|
||||
while (outputPointer<0)
|
||||
outputPointer += length; /* modulo table length */
|
||||
outPoint = (long) outputPointer; /* Integer part of delay */
|
||||
alpha = 1.0 + outPoint - outputPointer; /* fractional part of delay */
|
||||
if (alpha<0.1) {
|
||||
outputPointer += 1.0; /* Hack to avoid pole/zero */
|
||||
outPoint += 1; /* cancellation. Keeps allpass */
|
||||
alpha += 1.0; /* delay in range of .1 to 1.1 */
|
||||
}
|
||||
coeff = (1.0 - alpha) / (1.0 + alpha); /* coefficient for all pass */
|
||||
}
|
||||
|
||||
MY_FLOAT DLineA :: tick(MY_FLOAT sample) /* Take sample, yield sample */
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
inputs[inPoint++] = sample; /* Write input sample */
|
||||
if (inPoint == length) /* Increment input pointer */
|
||||
inPoint -= length; /* modulo length */
|
||||
temp = inputs[outPoint++]; /* filter input */
|
||||
if (outPoint == length) /* Increment output pointer */
|
||||
outPoint -= length; /* modulo length */
|
||||
lastOutput = -coeff * lastOutput; /* delayed output */
|
||||
lastOutput += lastIn + (coeff * temp); /* input + delayed Input */
|
||||
lastIn = temp;
|
||||
return lastOutput; /* save output and return */
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
|
||||
void main()
|
||||
{
|
||||
DLineA delay(140);
|
||||
FILE *fd;
|
||||
MY_FLOAT temp;
|
||||
short data;
|
||||
long i;
|
||||
|
||||
fd = fopen("test.raw","wb");
|
||||
|
||||
delay.setDelay(128);
|
||||
for (i=0;i<4096;i++) {
|
||||
if (i%256 != 0) temp = 0.0; else temp = 1.0;
|
||||
data = (temp + delay.tick(temp)) * 16000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
delay.setDelay(64.5);
|
||||
for (i=0;i<4096;i++) {
|
||||
if (i%256 != 0) temp = 0.0; else temp = 1.0;
|
||||
data = (temp + delay.tick(temp)) * 16000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
41
DLineA.h
Normal file
41
DLineA.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*******************************************/
|
||||
/* */
|
||||
/* AllPass Interpolating Delay Line */
|
||||
/* Object by Perry R. Cook 1995-96 */
|
||||
/* This one uses a delay line of maximum */
|
||||
/* length specified on creation, and */
|
||||
/* interpolates fractional length using */
|
||||
/* an all-pass filter. This version is */
|
||||
/* more efficient for computing static */
|
||||
/* length delay lines (alpha and coeff */
|
||||
/* are computed only when the length */
|
||||
/* is set, there probably is a more */
|
||||
/* efficient computational form if alpha */
|
||||
/* is changed often (each sample)). */
|
||||
/* */
|
||||
/*******************************************/
|
||||
|
||||
|
||||
#if !defined(__DLineA_h)
|
||||
#define __DLineA_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class DLineA : public Filter
|
||||
{
|
||||
protected:
|
||||
long inPoint;
|
||||
long outPoint;
|
||||
long length;
|
||||
MY_FLOAT alpha;
|
||||
MY_FLOAT coeff;
|
||||
MY_FLOAT lastIn;
|
||||
public:
|
||||
DLineA(long max_length);
|
||||
~DLineA();
|
||||
void clear();
|
||||
void setDelay(MY_FLOAT length);
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
90
DLineL.cpp
Normal file
90
DLineL.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/*******************************************/
|
||||
/* Linearly Interpolating Delay Line */
|
||||
/* Object by Perry R. Cook 1995-96 */
|
||||
/* This one uses a delay line of maximum */
|
||||
/* length specified on creation, and */
|
||||
/* linearly interpolates fractional */
|
||||
/* length. It is designed to be more */
|
||||
/* efficient if the delay length is not */
|
||||
/* changed very often. */
|
||||
/*******************************************/
|
||||
|
||||
#include "DLineL.h"
|
||||
|
||||
DLineL :: DLineL(long max_length)
|
||||
{
|
||||
length = max_length;
|
||||
inputs = (MY_FLOAT *) malloc(length * MY_FLOAT_SIZE);
|
||||
this->clear();
|
||||
outPoint = 0;
|
||||
inPoint = length >> 1;
|
||||
}
|
||||
|
||||
DLineL :: ~DLineL()
|
||||
{
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
void DLineL :: clear()
|
||||
{
|
||||
long i;
|
||||
for (i=0;i<length;i++) inputs[i] = 0.0;
|
||||
lastOutput = 0;
|
||||
}
|
||||
|
||||
void DLineL :: setDelay(MY_FLOAT lag)
|
||||
{
|
||||
MY_FLOAT outputPointer;
|
||||
outputPointer = inPoint - lag; /* read chases write, add 1 for interp. */
|
||||
while (outputPointer<0)
|
||||
outputPointer += length; /* modulo maximum length */
|
||||
outPoint = (long) outputPointer; /* integer part */
|
||||
alpha = outputPointer - outPoint; /* fractional part */
|
||||
omAlpha = 1.0 - alpha; /* 1.0 - fractional part (more efficient) */
|
||||
}
|
||||
|
||||
MY_FLOAT DLineL :: tick(MY_FLOAT sample) /* Take one, yield one */
|
||||
{
|
||||
inputs[inPoint++] = sample; /* Input next sample */
|
||||
if (inPoint == length) /* Check for end condition */
|
||||
inPoint -= length;
|
||||
lastOutput = inputs[outPoint++] * omAlpha; /* first 1/2 of interpolation */
|
||||
if (outPoint<length) { /* Check for end condition */
|
||||
lastOutput += inputs[outPoint] * alpha; /* second 1/2 of interpolation */
|
||||
}
|
||||
else { /* if at end . . . */
|
||||
lastOutput += inputs[0] * alpha; /* second 1/2 of interpolation */
|
||||
outPoint -= length;
|
||||
}
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
|
||||
void main()
|
||||
{
|
||||
DLineL delay(140);
|
||||
FILE *fd;
|
||||
MY_FLOAT temp;
|
||||
short data;
|
||||
long i;
|
||||
|
||||
fd = fopen("test.raw","wb");
|
||||
|
||||
delay.setDelay(128);
|
||||
for (i=0;i<4096;i++) {
|
||||
if (i%256 != 0) temp = 0.0; else temp = 1.0;
|
||||
data = (temp + delay.tick(temp)) * 16000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
delay.setDelay(64.5);
|
||||
for (i=0;i<4096;i++) {
|
||||
if (i%256 != 0) temp = 0.0; else temp = 1.0;
|
||||
data = (temp + delay.tick(temp)) * 16000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
33
DLineL.h
Normal file
33
DLineL.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*******************************************/
|
||||
/* Linearly Interpolating Delay Line */
|
||||
/* Object by Perry R. Cook 1995-96 */
|
||||
/* This one uses a delay line of maximum */
|
||||
/* length specified on creation, and */
|
||||
/* linearly interpolates fractional */
|
||||
/* length. It is designed to be more */
|
||||
/* efficient if the delay length is not */
|
||||
/* changed very often. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__DLineL_h)
|
||||
#define __DLineL_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class DLineL : public Filter
|
||||
{
|
||||
protected:
|
||||
long inPoint;
|
||||
long outPoint;
|
||||
long length;
|
||||
MY_FLOAT alpha;
|
||||
MY_FLOAT omAlpha;
|
||||
public:
|
||||
DLineL(long max_length);
|
||||
~DLineL();
|
||||
void clear();
|
||||
void setDelay(MY_FLOAT length);
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
80
DLineN.cpp
Normal file
80
DLineN.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
/*******************************************/
|
||||
/* Non-Interpolating Delay Line */
|
||||
/* Object by Perry R. Cook 1995-96 */
|
||||
/* This one uses a delay line of maximum */
|
||||
/* length specified on creation. A non- */
|
||||
/* interpolating delay line should be */
|
||||
/* used in non-time varying (reverb) or */
|
||||
/* non-critical (????) applications. */
|
||||
/*******************************************/
|
||||
|
||||
#include "DLineN.h"
|
||||
|
||||
DLineN :: DLineN(long max_length)
|
||||
{
|
||||
length = max_length;
|
||||
inputs = (MY_FLOAT *) malloc(length * MY_FLOAT_SIZE);
|
||||
this->clear();
|
||||
this->setDelay(length * 0.5);
|
||||
inPoint = 0;
|
||||
outPoint = 0;
|
||||
}
|
||||
|
||||
DLineN :: ~DLineN()
|
||||
{
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
void DLineN :: clear()
|
||||
{
|
||||
long i;
|
||||
for (i=0;i<length;i++) inputs[i] = 0.0;
|
||||
lastOutput = 0;
|
||||
}
|
||||
|
||||
void DLineN :: setDelay(MY_FLOAT lag)
|
||||
{
|
||||
outPoint = inPoint - (long) lag; /* read chases write */
|
||||
while (outPoint<0) outPoint += length; /* modulo maximum length */
|
||||
}
|
||||
|
||||
MY_FLOAT DLineN :: tick(MY_FLOAT sample) /* Take one, yield one */
|
||||
{
|
||||
inputs[inPoint++] = sample; /* Input next sample */
|
||||
if (inPoint == length) /* Check for end condition */
|
||||
inPoint -= length;
|
||||
lastOutput = inputs[outPoint++]; // first 1/2 of interpolation */
|
||||
if (outPoint>=length) { // Check for end condition */
|
||||
outPoint -= length;
|
||||
}
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
void main()
|
||||
{
|
||||
DLineN delay(140);
|
||||
FILE *fd;
|
||||
MY_FLOAT temp;
|
||||
short data;
|
||||
long i;
|
||||
|
||||
fd = fopen("test.raw","wb");
|
||||
|
||||
delay.setDelay(128);
|
||||
for (i=0;i<4096;i++) {
|
||||
if (i%256 != 0) temp = 0.0; else temp = 1.0;
|
||||
data = (temp + delay.tick(temp)) * 16000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
delay.setDelay(64.5);
|
||||
for (i=0;i<4096;i++) {
|
||||
if (i%256 != 0) temp = 0.0; else temp = 1.0;
|
||||
data = (temp + delay.tick(temp)) * 16000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
30
DLineN.h
Normal file
30
DLineN.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*******************************************/
|
||||
/* Non-Interpolating Delay Line */
|
||||
/* Object by Perry R. Cook 1995-96 */
|
||||
/* This one uses a delay line of maximum */
|
||||
/* length specified on creation. A non- */
|
||||
/* interpolating delay line should be */
|
||||
/* used in non-time varying (reverb) or */
|
||||
/* non-critical (????) applications. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__DLineN_h)
|
||||
#define __DLineN_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class DLineN : public Filter
|
||||
{
|
||||
protected:
|
||||
long inPoint;
|
||||
long outPoint;
|
||||
long length;
|
||||
public:
|
||||
DLineN(long max_length);
|
||||
~DLineN();
|
||||
void clear();
|
||||
void setDelay(MY_FLOAT length);
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
164
DrumSynt.cpp
Normal file
164
DrumSynt.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/*******************************************/
|
||||
/* Master Class for Drum Synthesizer */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This instrument contains a bunch of */
|
||||
/* RawWvIn objects (Non-Interpolating, */
|
||||
/* 1 shot players), run through a bunch */
|
||||
/* of one-pole filters. You can specify */
|
||||
/* the maximum Polyphony (maximum number */
|
||||
/* of simultaneous voices) in a #define */
|
||||
/* in the .h file. */
|
||||
/*******************************************/
|
||||
|
||||
#include "DrumSynt.h"
|
||||
#include <string.h>
|
||||
|
||||
char waveNames[DRUM_NUMWAVES][16] = {
|
||||
"bass.raw",
|
||||
"snar.raw",
|
||||
"tomlow.raw",
|
||||
"tommid.raw",
|
||||
"tomhi.raw",
|
||||
"hat.raw",
|
||||
"ride.raw",
|
||||
"crash.raw",
|
||||
"cowbell.raw",
|
||||
"tamb.raw"
|
||||
};
|
||||
|
||||
DrumSynt :: DrumSynt() : Object()
|
||||
{
|
||||
int i;
|
||||
/* char temp[64]; */
|
||||
|
||||
/* for (i=0;i<DRUM_NUMWAVES;i++) { */
|
||||
/* strcpy(temp,"rawwaves/drumwavs/"); */
|
||||
/* strcat(temp,waveNames[i]); */
|
||||
/* waves[i] = new RawWvIn(temp); */
|
||||
/* waves[i]->finish(); */
|
||||
/* waves[i]->normalize(0.2); */
|
||||
/* } */
|
||||
|
||||
for (i=0;i<DRUM_POLYPHONY;i++) {
|
||||
filters[i] = new OnePole;
|
||||
sounding[i] = -1;
|
||||
/* filtSounding[i] = -1; */
|
||||
}
|
||||
numSounding = 0; /* This counts the number */
|
||||
/* of sounding voices */
|
||||
}
|
||||
|
||||
void DrumSynt :: noteOn(int noteNum, int vel)
|
||||
{
|
||||
int i,notDone;
|
||||
char tempString[64];
|
||||
RawWvIn *tempWv;
|
||||
OnePole *tempFilt;
|
||||
|
||||
printf("NoteOn: %s vel=%i\n",waveNames[noteNum],vel);
|
||||
|
||||
notDone = -1;
|
||||
for (i=0;i<DRUM_POLYPHONY;i++) { /* Check first to see */
|
||||
if (sounding[i] == noteNum) notDone = i; /* if there's already */
|
||||
} /* one like this sounding */
|
||||
|
||||
if (notDone<0) { /* If not, then */
|
||||
if (numSounding == DRUM_POLYPHONY) { /* If we're already */
|
||||
delete waves[0]; /* at max polyphony, */
|
||||
filters[0]->clear(); /* then */
|
||||
tempWv = waves[0];
|
||||
tempFilt = filters[0];
|
||||
for (i=0;i<DRUM_POLYPHONY-1;i++) { /* preempt oldest */
|
||||
waves[i] = waves[i+1]; /* oldest voice and */
|
||||
filters[i] = filters[i+1]; /* ripple all down */
|
||||
}
|
||||
waves[DRUM_POLYPHONY-1] = tempWv;
|
||||
filters[DRUM_POLYPHONY-1] = tempFilt;
|
||||
}
|
||||
else {
|
||||
numSounding += 1; /* otherwise just add one */
|
||||
}
|
||||
|
||||
sounding[numSounding-1] = noteNum; /* allocate new wave */
|
||||
strcpy(tempString,"rawwaves/drumwavs/");
|
||||
strcat(tempString,waveNames[noteNum]);
|
||||
waves[numSounding-1] = new RawWvIn(tempString);
|
||||
waves[numSounding-1]->normalize(0.2);
|
||||
filters[numSounding-1]->setPole(0.999 - (vel / 32.0));
|
||||
filters[numSounding-1]->setGain(vel / 128.0);
|
||||
}
|
||||
else {
|
||||
waves[notDone]->reset();
|
||||
filters[notDone]->setPole(0.999 - (vel / 32.0));
|
||||
filters[notDone]->setGain(vel / 128.0);
|
||||
}
|
||||
|
||||
printf("Number Sounding = %i\n",numSounding);
|
||||
for (i=0;i<numSounding;i++) printf(" %i ",sounding[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
MY_FLOAT DrumSynt :: tick()
|
||||
{
|
||||
int i, j, notDone;
|
||||
MY_FLOAT output;
|
||||
OnePole *tempFilt;
|
||||
|
||||
i = 0;
|
||||
notDone = 1;
|
||||
output = 0.0;
|
||||
|
||||
if (numSounding == 0) notDone = 0;
|
||||
while (notDone && (i < numSounding)) {
|
||||
|
||||
output += waves[i]->lastOut();
|
||||
|
||||
if (waves[i]->informTick() == 1) {
|
||||
|
||||
printf("Wave %i %i down here\n",i,sounding[i]);
|
||||
|
||||
delete waves[i];
|
||||
tempFilt = filters[i];
|
||||
|
||||
for (j=i;j<numSounding-1;j++) {
|
||||
sounding[j] = sounding[j+1];
|
||||
waves[j] = waves[j+1];
|
||||
filters[j] = filters[j+1];
|
||||
}
|
||||
filters[j] = tempFilt;
|
||||
filters[j]->clear();
|
||||
sounding[j] = -1;
|
||||
numSounding -= 1;
|
||||
if (numSounding == 0) notDone = 0;
|
||||
i -= 1;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/************** Test Main Program *********************/
|
||||
|
||||
#include "miditabl.h"
|
||||
#include "RawWvOut.h"
|
||||
#include "Reverb.h"
|
||||
#include "Noise.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
long i,j;
|
||||
DrumSynt instrument;
|
||||
RawWvOut output("test.snd");
|
||||
Reverb reverb(2137);
|
||||
Noise noise;
|
||||
|
||||
for (j=0;j<100;j++) {
|
||||
i = (int) (fabs(noise.tick()) * DRUM_NUMWAVES);
|
||||
instrument.noteOn(i,127);
|
||||
for (i=0;i<2000;i++) output.tick(reverb.tick(instrument.tick()));
|
||||
}
|
||||
|
||||
for (i=0;i<22000;i++) output.tick(reverb.tick(instrument.tick()));
|
||||
|
||||
}
|
||||
37
DrumSynt.h
Normal file
37
DrumSynt.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*******************************************/
|
||||
/* Master Class for Drum Synthesizer */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This instrument contains a bunch of */
|
||||
/* RawWvIn objects (Non-Interpolating, */
|
||||
/* 1 shot players), run through a bunch */
|
||||
/* of one-pole filters. You can specify */
|
||||
/* the maximum Polyphony (maximum number */
|
||||
/* of simultaneous voices) in a #define */
|
||||
/* in the .h file. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__DrumSynt_h)
|
||||
#define __DrumSynt_h
|
||||
|
||||
#include "Object.h"
|
||||
#include "RawWvIn.h"
|
||||
#include "OnePole.h"
|
||||
|
||||
#define DRUM_NUMWAVES 10
|
||||
#define DRUM_POLYPHONY 4
|
||||
|
||||
class DrumSynt : public Object
|
||||
{
|
||||
protected:
|
||||
RawWvIn *waves[DRUM_POLYPHONY];
|
||||
OnePole *filters[DRUM_POLYPHONY];
|
||||
int sounding[DRUM_POLYPHONY];
|
||||
int numSounding;
|
||||
public:
|
||||
DrumSynt();
|
||||
/* ~DrumSynt(); */
|
||||
void noteOn(int noteNum, int vel);
|
||||
MY_FLOAT tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
113
Envelope.cpp
Normal file
113
Envelope.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
/*******************************************/
|
||||
/* Envelope Class, Perry R. Cook, 1995-96 */
|
||||
/* This is the base class for envelopes. */
|
||||
/* This one is capable of ramping state */
|
||||
/* from where it is to a target value by */
|
||||
/* a rate. It also responds to simple */
|
||||
/* KeyOn and KeyOff messages, ramping to */
|
||||
/* 1.0 on keyon and to 0.0 on keyoff. */
|
||||
/* There are two tick (update value) */
|
||||
/* methods, one returns the value, and */
|
||||
/* other returns 0 if the envelope is at */
|
||||
/* the target value (the state bit). */
|
||||
/*******************************************/
|
||||
|
||||
#include "Envelope.h"
|
||||
|
||||
Envelope :: Envelope() : Object()
|
||||
{
|
||||
target = 0.0;
|
||||
value = 0.0;
|
||||
rate = 0.001;
|
||||
state = 0;
|
||||
}
|
||||
|
||||
Envelope :: ~Envelope()
|
||||
{
|
||||
}
|
||||
|
||||
void Envelope :: keyOn()
|
||||
{
|
||||
target = 1.0;
|
||||
if (value != target) state = 1;
|
||||
}
|
||||
|
||||
void Envelope :: keyOff()
|
||||
{
|
||||
target = 0.0;
|
||||
if (value != target) state = 1;
|
||||
}
|
||||
|
||||
void Envelope :: setRate(MY_FLOAT aRate)
|
||||
{
|
||||
if (aRate < 0.0) {
|
||||
printf("negative rates not allowed!!, correcting\n");
|
||||
rate = -aRate;
|
||||
}
|
||||
else rate = aRate;
|
||||
rate = rate * RATE_NORM; /* SEE Object.h */
|
||||
}
|
||||
|
||||
void Envelope :: setTarget(MY_FLOAT aTarget)
|
||||
{
|
||||
target = aTarget;
|
||||
if (value != target) state = 1;
|
||||
}
|
||||
|
||||
void Envelope :: setValue(MY_FLOAT aValue)
|
||||
{
|
||||
state = 0;
|
||||
target = aValue;
|
||||
value = aValue;
|
||||
}
|
||||
|
||||
MY_FLOAT Envelope :: tick()
|
||||
{
|
||||
if (state) {
|
||||
if (target > value) {
|
||||
value += rate;
|
||||
if (value >= target) {
|
||||
value = target;
|
||||
state = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
value -= rate;
|
||||
if (value <= target) {
|
||||
value = target;
|
||||
state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
int Envelope :: informTick()
|
||||
{
|
||||
this->tick();
|
||||
return state;
|
||||
}
|
||||
|
||||
MY_FLOAT Envelope :: lastOut()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/************ Test Main ************************/
|
||||
/*
|
||||
void main()
|
||||
{
|
||||
long i;
|
||||
Envelope test;
|
||||
|
||||
test.setRate(0.15);
|
||||
test.keyOn();
|
||||
for (i=0;i<10;i++) printf("%lf\n",test.tick());
|
||||
test.setRate(0.1);
|
||||
test.setTarget(0.5);
|
||||
while (test.informTick()) printf("%lf\n",test.lastOut());
|
||||
test.setRate(0.05);
|
||||
test.keyOff();
|
||||
while(test.informTick()) printf("%lf\n",test.lastOut());
|
||||
}
|
||||
*/
|
||||
40
Envelope.h
Normal file
40
Envelope.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*******************************************/
|
||||
/* Envelope Class, Perry R. Cook, 1995-96 */
|
||||
/* This is the base class for envelopes. */
|
||||
/* This one is capable of ramping state */
|
||||
/* from where it is to a target value by */
|
||||
/* a rate. It also responds to simple */
|
||||
/* KeyOn and KeyOff messages, ramping to */
|
||||
/* 1.0 on keyon and to 0.0 on keyoff. */
|
||||
/* There are two tick (update value) */
|
||||
/* methods, one returns the value, and */
|
||||
/* other returns 0 if the envelope is at */
|
||||
/* the target value (the state bit). */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__Envelope_h)
|
||||
#define __Envelope_h
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class Envelope : public Object
|
||||
{
|
||||
protected:
|
||||
MY_FLOAT value;
|
||||
MY_FLOAT target;
|
||||
MY_FLOAT rate;
|
||||
int state;
|
||||
public:
|
||||
Envelope();
|
||||
~Envelope();
|
||||
void keyOn();
|
||||
void keyOff();
|
||||
void setRate(MY_FLOAT aRate);
|
||||
void setTarget(MY_FLOAT aTarget);
|
||||
void setValue(MY_FLOAT aValue);
|
||||
MY_FLOAT tick();
|
||||
int informTick();
|
||||
MY_FLOAT lastOut();
|
||||
};
|
||||
|
||||
#endif
|
||||
51
FM4Alg3.cpp
Normal file
51
FM4Alg3.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
/******************************************/
|
||||
/* Algorithm 3 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Alg 3 is : 4--\ */
|
||||
/* 3-->2-- + -->1-->Out */
|
||||
/* */
|
||||
/* Controls: control1 = total mod index */
|
||||
/* control2 = crossfade of two */
|
||||
/* modulators */
|
||||
/* control3 = LFO speed */
|
||||
/* modWheel = LFO amount */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#include "FM4Alg3.h"
|
||||
|
||||
FM4Alg3 :: FM4Alg3() : FM4Op()
|
||||
{
|
||||
/* We still don't make the waves here yet, because */
|
||||
/* we still don't know what they will be. */
|
||||
}
|
||||
|
||||
MY_FLOAT FM4Alg3 :: tick()
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
|
||||
temp = vibWave->tick() * modDepth * 0.2;
|
||||
waves[0]->setFreq(baseFreq * (1.0 + temp) * ratios[0]);
|
||||
waves[1]->setFreq(baseFreq * (1.0 + temp) * ratios[1]);
|
||||
waves[2]->setFreq(baseFreq * (1.0 + temp) * ratios[2]);
|
||||
waves[3]->setFreq(baseFreq * (1.0 + temp) * ratios[3]);
|
||||
|
||||
temp = gains[2] * adsr[2]->tick() * waves[2]->tick();
|
||||
waves[1]->addPhaseOffset(temp);
|
||||
|
||||
waves[3]->addPhaseOffset(twozero->lastOut());
|
||||
temp = (1.0 - (control2 * 0.5)) * gains[3] * adsr[3]->tick() * waves[3]->tick();
|
||||
twozero->tick(temp);
|
||||
|
||||
temp += control2 * 0.5 * gains[1] * adsr[1]->tick() * waves[1]->tick();
|
||||
temp = temp * control1;
|
||||
|
||||
waves[0]->addPhaseOffset(temp);
|
||||
temp = gains[0] * adsr[0]->tick() * waves[0]->tick();
|
||||
|
||||
lastOutput = temp * 0.5;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
29
FM4Alg3.h
Normal file
29
FM4Alg3.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/******************************************/
|
||||
/* Algorithm 3 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Alg 3 is : 4--\ */
|
||||
/* 3-->2-- + -->1-->Out */
|
||||
/* */
|
||||
/* Controls: control1 = total mod index */
|
||||
/* control2 = crossfade of two */
|
||||
/* modulators */
|
||||
/* control3 = LFO speed */
|
||||
/* modWheel = LFO amount */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__FM4Alg3_h)
|
||||
#define __FM4Alg3_h
|
||||
|
||||
#include "FM4Op.h"
|
||||
|
||||
class FM4Alg3 : public FM4Op
|
||||
{
|
||||
public:
|
||||
FM4Alg3();
|
||||
MY_FLOAT tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
48
FM4Alg4.cpp
Normal file
48
FM4Alg4.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/******************************************/
|
||||
/* Algorithm 4 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Alg 4 is : 4->3--\ */
|
||||
/* 2-- + -->1-->Out */
|
||||
/* */
|
||||
/* Controls: control1 = total mod index */
|
||||
/* control2 = crossfade of two */
|
||||
/* modulators */
|
||||
/* control3 = LFO speed */
|
||||
/* modWheel = LFO amount */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#include "FM4Alg4.h"
|
||||
|
||||
FM4Alg4 :: FM4Alg4() : FM4Op()
|
||||
{
|
||||
/* We still don't make the waves here yet, because */
|
||||
/* we still don't know what they will be. */
|
||||
}
|
||||
|
||||
MY_FLOAT FM4Alg4 :: tick()
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
|
||||
temp = vibWave->tick() * modDepth * 0.2;
|
||||
waves[0]->setFreq(baseFreq * (1.0 + temp) * ratios[0]);
|
||||
waves[1]->setFreq(baseFreq * (1.0 + temp) * ratios[1]);
|
||||
waves[2]->setFreq(baseFreq * (1.0 + temp) * ratios[2]);
|
||||
waves[3]->setFreq(baseFreq * (1.0 + temp) * ratios[3]);
|
||||
|
||||
waves[3]->addPhaseOffset(twozero->lastOut());
|
||||
temp = gains[3] * adsr[3]->tick() * waves[3]->tick();
|
||||
twozero->tick(temp);
|
||||
waves[2]->addPhaseOffset(temp);
|
||||
temp = (1.0 - (control2 * 0.5)) * gains[2] * adsr[2]->tick() * waves[2]->tick();
|
||||
temp += control2 * 0.5 * gains[1] * adsr[1]->tick() * waves[1]->tick();
|
||||
temp = temp * control1;
|
||||
waves[0]->addPhaseOffset(temp);
|
||||
temp = gains[0] * adsr[0]->tick() * waves[0]->tick();
|
||||
|
||||
lastOutput = temp * 0.5;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
29
FM4Alg4.h
Normal file
29
FM4Alg4.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/******************************************/
|
||||
/* Algorithm 4 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Alg 4 is : 4->3--\ */
|
||||
/* 2-- + -->1-->Out */
|
||||
/* */
|
||||
/* Controls: control1 = total mod index */
|
||||
/* control2 = crossfade of two */
|
||||
/* modulators */
|
||||
/* control3 = LFO speed */
|
||||
/* modWheel = LFO amount */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__FM4Alg4_h)
|
||||
#define __FM4Alg4_h
|
||||
|
||||
#include "FM4Op.h"
|
||||
|
||||
class FM4Alg4 : public FM4Op
|
||||
{
|
||||
public:
|
||||
FM4Alg4();
|
||||
MY_FLOAT tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
48
FM4Alg5.cpp
Normal file
48
FM4Alg5.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/******************************************/
|
||||
/* Algorithm 5 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This connection topology is 2 simple */
|
||||
/* FM Pairs summed together, like: */
|
||||
/* */
|
||||
/* Alg 5 is : 4->3--\ */
|
||||
/* + --> Out */
|
||||
/* 2->1--/ */
|
||||
/* */
|
||||
/* Controls: control1 = mod index 1 */
|
||||
/* control2 = crossfade of two */
|
||||
/* outputs */
|
||||
/* control3 = LFO speed */
|
||||
/* modWheel = LFO amount */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#include "FM4Alg5.h"
|
||||
|
||||
FM4Alg5 :: FM4Alg5() : FM4Op()
|
||||
{
|
||||
/* We still don't make the waves here yet, because */
|
||||
/* we still don't know what they will be. */
|
||||
}
|
||||
|
||||
MY_FLOAT FM4Alg5 :: tick()
|
||||
{
|
||||
MY_FLOAT temp,temp2;
|
||||
|
||||
temp = gains[1] * adsr[1]->tick() * waves[1]->tick();
|
||||
temp = temp * control1;
|
||||
waves[0]->addPhaseOffset(temp);
|
||||
waves[3]->addPhaseOffset(twozero->lastOut());
|
||||
temp = gains[3] * adsr[3]->tick() * waves[3]->tick();
|
||||
twozero->tick(temp);
|
||||
waves[2]->addPhaseOffset(temp);
|
||||
temp = (1.0 - (control2 * 0.5)) * gains[0] * adsr[0]->tick() * waves[0]->tick();
|
||||
temp += control2 * 0.5 * gains[2] * adsr[2]->tick() * waves[2]->tick();
|
||||
|
||||
temp2 = vibWave->tick() * modDepth; /* Calculate amplitude mod */
|
||||
temp = temp * (1.0 + temp2); /* and apply it to output */
|
||||
|
||||
lastOutput = temp * 0.5;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
32
FM4Alg5.h
Normal file
32
FM4Alg5.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/******************************************/
|
||||
/* Algorithm 5 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This connection topology is 2 simple */
|
||||
/* FM Pairs summed together, like: */
|
||||
/* */
|
||||
/* 1 -> 2 -\ */
|
||||
/* +-> Out */
|
||||
/* 3 -> 4 -/ */
|
||||
/* */
|
||||
/* Controls: control1 = mod index 1 */
|
||||
/* control2 = crossfade of two */
|
||||
/* outputs */
|
||||
/* control3 = LFO speed */
|
||||
/* modWheel = LFO amount */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__FM4Alg5_h)
|
||||
#define __FM4Alg5_h
|
||||
|
||||
#include "FM4Op.h"
|
||||
|
||||
class FM4Alg5 : public FM4Op
|
||||
{
|
||||
public:
|
||||
FM4Alg5();
|
||||
MY_FLOAT tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
54
FM4Alg6.cpp
Normal file
54
FM4Alg6.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/******************************************/
|
||||
/* Algorithm 6 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This connection topology is three */
|
||||
/* Carriers and a common Modulator */
|
||||
/* */
|
||||
/* /->1 -\ */
|
||||
/* 4-|-->2 - +-> Out */
|
||||
/* \->3 -/ */
|
||||
/* */
|
||||
/* Controls: control1 = vowel */
|
||||
/* control2 = spectral tilt */
|
||||
/* control3 = LFO speed */
|
||||
/* modWheel = LFO amount */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#include "FM4Alg6.h"
|
||||
|
||||
FM4Alg6 :: FM4Alg6() : FM4Op()
|
||||
{
|
||||
/* We still don't make the waves here yet, because */
|
||||
/* we still don't know what they will be. */
|
||||
}
|
||||
|
||||
MY_FLOAT FM4Alg6 :: tick()
|
||||
{
|
||||
MY_FLOAT temp,temp2;
|
||||
|
||||
temp = gains[3] * adsr[3]->tick() * waves[3]->tick();
|
||||
temp2 = vibWave->tick() * modDepth * 0.1; /* Calculate frequency mod */
|
||||
|
||||
waves[0]->setFreq(baseFreq * (1.0 + temp2) * ratios[0]);
|
||||
waves[1]->setFreq(baseFreq * (1.0 + temp2) * ratios[1]);
|
||||
waves[2]->setFreq(baseFreq * (1.0 + temp2) * ratios[2]);
|
||||
waves[3]->setFreq(baseFreq * (1.0 + temp2) * ratios[3]);
|
||||
|
||||
waves[0]->addPhaseOffset(temp * mods[0]);
|
||||
waves[1]->addPhaseOffset(temp * mods[1]);
|
||||
waves[2]->addPhaseOffset(temp * mods[2]);
|
||||
waves[3]->addPhaseOffset(twozero->lastOut());
|
||||
twozero->tick(temp);
|
||||
temp = gains[0] * tilt[0] * adsr[0]->tick() * waves[0]->tick();
|
||||
temp += gains[1] * tilt[1] * adsr[1]->tick() * waves[1]->tick();
|
||||
temp += gains[2] * tilt[2] * adsr[2]->tick() * waves[2]->tick();
|
||||
|
||||
return temp * 0.33;
|
||||
}
|
||||
|
||||
void FM4Alg6 :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
|
||||
}
|
||||
35
FM4Alg6.h
Normal file
35
FM4Alg6.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/******************************************/
|
||||
/* Algorithm 6 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This connection topology is three */
|
||||
/* Carriers and a common Modulator */
|
||||
/* */
|
||||
/* /->1 -\ */
|
||||
/* 4-|-->2 - +-> Out */
|
||||
/* \->3 -/ */
|
||||
/* */
|
||||
/* Controls: control1 = vowel */
|
||||
/* control2 = spectral tilt */
|
||||
/* control3 = LFO speed */
|
||||
/* modWheel = LFO amount */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__FM4Alg6_h)
|
||||
#define __FM4Alg6_h
|
||||
|
||||
#include "FM4Op.h"
|
||||
|
||||
class FM4Alg6 : public FM4Op
|
||||
{
|
||||
protected:
|
||||
MY_FLOAT tilt[3];
|
||||
MY_FLOAT mods[3];
|
||||
public:
|
||||
FM4Alg6();
|
||||
MY_FLOAT tick();
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
};
|
||||
|
||||
#endif
|
||||
43
FM4Alg8.cpp
Normal file
43
FM4Alg8.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/******************************************/
|
||||
/* Algorithm 8 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This connection topology is simple */
|
||||
/* Additive Synthesis, like: */
|
||||
/* */
|
||||
/* 1 --. */
|
||||
/* 2 -\| */
|
||||
/* +-> Out */
|
||||
/* 3 -/| */
|
||||
/* 4 -- */
|
||||
/* */
|
||||
/* Controls: control1 = op4 (fb) gain */
|
||||
/* control2 = op3 gain */
|
||||
/* control3 = LFO speed */
|
||||
/* modWheel = LFO amount */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#include "FM4Alg8.h"
|
||||
|
||||
FM4Alg8 :: FM4Alg8() : FM4Op()
|
||||
{
|
||||
/* We still don't make the waves here yet, because */
|
||||
/* we still don't know what they will be. */
|
||||
}
|
||||
|
||||
MY_FLOAT FM4Alg8 :: tick()
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
|
||||
waves[3]->addPhaseOffset(twozero->lastOut());
|
||||
temp = control1 * 2.0 * gains[3] * adsr[3]->tick() * waves[3]->tick();
|
||||
twozero->tick(temp);
|
||||
temp += control2 * 2.0 * gains[2] * adsr[2]->tick() * waves[2]->tick();
|
||||
temp += gains[1] * adsr[1]->tick() * waves[1]->tick();
|
||||
temp += gains[0] * adsr[0]->tick() * waves[0]->tick();
|
||||
|
||||
lastOutput = temp * 0.125;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
33
FM4Alg8.h
Normal file
33
FM4Alg8.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/******************************************/
|
||||
/* Algorithm 8 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This connection topology is simple */
|
||||
/* Additive Synthesis, like: */
|
||||
/* */
|
||||
/* 1 --. */
|
||||
/* 2 -\| */
|
||||
/* +-> Out */
|
||||
/* 3 -/| */
|
||||
/* 4 -- */
|
||||
/* */
|
||||
/* Controls: control1 = op4 (fb) gain */
|
||||
/* control2 = op3 gain */
|
||||
/* control3 = LFO speed */
|
||||
/* modWheel = LFO amount */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__FM4Alg8_h)
|
||||
#define __FM4Alg8_h
|
||||
|
||||
#include "FM4Op.h"
|
||||
|
||||
class FM4Alg8 : public FM4Op
|
||||
{
|
||||
public:
|
||||
FM4Alg8();
|
||||
virtual MY_FLOAT tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
179
FM4Op.cpp
Normal file
179
FM4Op.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
/*******************************************/
|
||||
/* Master Class for 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This instrument contains 4 waves, */
|
||||
/* 4 adsr, and various state vars. */
|
||||
/* */
|
||||
/* The basic Chowning/Stanford FM patent */
|
||||
/* expired April 1995, but there exist */
|
||||
/* follow-on patents, mostly assigned to */
|
||||
/* Yamaha. If you are of the type who */
|
||||
/* should worry about this (making money) */
|
||||
/* worry away. */
|
||||
/* */
|
||||
/*******************************************/
|
||||
|
||||
#include "FM4Op.h"
|
||||
|
||||
FM4Op :: FM4Op()
|
||||
{
|
||||
int i;
|
||||
MY_FLOAT temp;
|
||||
MY_FLOAT tempCoeffs[2] = {0.0, -1.0};
|
||||
adsr[0] = new ADSR;
|
||||
adsr[1] = new ADSR;
|
||||
adsr[2] = new ADSR;
|
||||
adsr[3] = new ADSR;
|
||||
twozero = new TwoZero;
|
||||
vibWave = new RawLoop("rawwaves/sinewave.raw");
|
||||
vibWave->normalize();
|
||||
vibWave->setFreq(6.0); /* should make this random?? */
|
||||
modDepth = 0.0;
|
||||
/* We don't make the waves here yet, because */
|
||||
/* we don't know what they will be. */
|
||||
baseFreq = 440.0;
|
||||
ratios[0] = 1.0;
|
||||
ratios[1] = 1.0;
|
||||
ratios[2] = 1.0;
|
||||
ratios[3] = 1.0;
|
||||
gains[0] = 1.0;
|
||||
gains[1] = 1.0;
|
||||
gains[2] = 1.0;
|
||||
gains[3] = 1.0;
|
||||
twozero->setZeroCoeffs(tempCoeffs);
|
||||
twozero->setGain(0.0);
|
||||
control1 = 1.0;
|
||||
control2 = 1.0;
|
||||
temp = 1.0;
|
||||
for (i=99;i>=0;i--) {
|
||||
__FM4Op_gains[i] = temp;
|
||||
temp *= 0.933033;
|
||||
}
|
||||
temp = 1.0;
|
||||
for (i=15;i>=0;i--) {
|
||||
__FM4Op_susLevels[i] = temp;
|
||||
temp *= 0.707101;
|
||||
}
|
||||
temp = 8.498186;
|
||||
for (i=0;i<32;i++) {
|
||||
__FM4Op_attTimes[i] = temp;
|
||||
temp *= 0.707101;
|
||||
}
|
||||
}
|
||||
|
||||
FM4Op :: ~FM4Op()
|
||||
{
|
||||
delete adsr[0];
|
||||
delete adsr[1];
|
||||
delete adsr[2];
|
||||
delete adsr[3];
|
||||
delete waves[0];
|
||||
delete waves[1];
|
||||
delete waves[2];
|
||||
delete waves[3];
|
||||
delete vibWave;
|
||||
delete twozero;
|
||||
}
|
||||
|
||||
void FM4Op :: loadWaves(char* wave1, char* wave2, char* wave3, char* wave4)
|
||||
{
|
||||
int i;
|
||||
waves[0] = new RawLoop(wave1);
|
||||
waves[1] = new RawLoop(wave2);
|
||||
waves[2] = new RawLoop(wave3);
|
||||
waves[3] = new RawLoop(wave4);
|
||||
for (i=0;i<4;i++) {
|
||||
waves[i]->normalize();
|
||||
}
|
||||
}
|
||||
void FM4Op :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
waves[0]->setFreq(baseFreq * ratios[0]);
|
||||
waves[1]->setFreq(baseFreq * ratios[1]);
|
||||
waves[2]->setFreq(baseFreq * ratios[2]);
|
||||
waves[3]->setFreq(baseFreq * ratios[3]);
|
||||
}
|
||||
|
||||
void FM4Op :: setRatio(int whichOne, MY_FLOAT ratio)
|
||||
{
|
||||
ratios[whichOne] = ratio;
|
||||
if (ratio>0.0)
|
||||
waves[whichOne]->setFreq(baseFreq * ratio);
|
||||
else
|
||||
waves[whichOne]->setFreq(ratio);
|
||||
}
|
||||
|
||||
void FM4Op :: setGain(int whichOne, MY_FLOAT gain)
|
||||
{
|
||||
gains[whichOne]=gain;
|
||||
}
|
||||
|
||||
void FM4Op :: keyOn()
|
||||
{
|
||||
adsr[0]->keyOn();
|
||||
adsr[1]->keyOn();
|
||||
adsr[2]->keyOn();
|
||||
adsr[3]->keyOn();
|
||||
}
|
||||
|
||||
void FM4Op :: keyOff()
|
||||
{
|
||||
adsr[0]->keyOff();
|
||||
adsr[1]->keyOff();
|
||||
adsr[2]->keyOff();
|
||||
adsr[3]->keyOff();
|
||||
}
|
||||
|
||||
void FM4Op :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
this->keyOff();
|
||||
#if defined(_debug_)
|
||||
printf("FM4Op : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FM4Op :: setModulationSpeed(MY_FLOAT mSpeed)
|
||||
{
|
||||
vibWave->setFreq(mSpeed);
|
||||
}
|
||||
|
||||
void FM4Op :: setModulationDepth(MY_FLOAT mDepth)
|
||||
{
|
||||
modDepth = mDepth;
|
||||
}
|
||||
|
||||
void FM4Op :: setControl1(MY_FLOAT cVal)
|
||||
{
|
||||
control1 = cVal*2.0;
|
||||
}
|
||||
|
||||
void FM4Op :: setControl2(MY_FLOAT cVal)
|
||||
{
|
||||
control2 = cVal*2.0;
|
||||
}
|
||||
|
||||
void FM4Op :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("FM4Op : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == MIDI_control1)
|
||||
this->setControl1(value * NORM_7);
|
||||
else if (number == MIDI_control2)
|
||||
this->setControl2(value * NORM_7);
|
||||
else if (number == MIDI_control3)
|
||||
this->setModulationSpeed(value * NORM_7 * 12.0); /* 0 to 12 Hz */
|
||||
else if (number == MIDI_mod_wheel)
|
||||
this->setModulationDepth(value * NORM_7);
|
||||
else if (number == MIDI_after_touch) {
|
||||
adsr[0]->setTarget(value * NORM_7);
|
||||
adsr[1]->setTarget(value * NORM_7);
|
||||
adsr[2]->setTarget(value * NORM_7);
|
||||
adsr[3]->setTarget(value * NORM_7);
|
||||
}
|
||||
else {
|
||||
printf("FM4Op : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
59
FM4Op.h
Normal file
59
FM4Op.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*******************************************/
|
||||
/* Master Class for 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This instrument contains an 4 waves, */
|
||||
/* 4 envelopes, and various state vars. */
|
||||
/* */
|
||||
/* The basic Chowning/Stanford FM patent */
|
||||
/* expired April 1995, but there exist */
|
||||
/* follow-on patents, mostly assigned to */
|
||||
/* Yamaha. If you are of the type who */
|
||||
/* should worry about this (making money) */
|
||||
/* worry away. */
|
||||
/* */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__FM4Op_h)
|
||||
#define __FM4Op_h
|
||||
|
||||
#include "Instrmnt.h"
|
||||
#include "ADSR.h"
|
||||
#include "RawLoop.h"
|
||||
#include "TwoZero.h"
|
||||
|
||||
class FM4Op : public Instrmnt
|
||||
{
|
||||
protected:
|
||||
ADSR *adsr[4];
|
||||
RawLoop *waves[4];
|
||||
RawLoop *vibWave;
|
||||
TwoZero *twozero;
|
||||
MY_FLOAT baseFreq;
|
||||
MY_FLOAT ratios[4];
|
||||
MY_FLOAT gains[4];
|
||||
MY_FLOAT modDepth;
|
||||
MY_FLOAT control1;
|
||||
MY_FLOAT control2;
|
||||
MY_FLOAT __FM4Op_gains[100];
|
||||
MY_FLOAT __FM4Op_susLevels[16];
|
||||
MY_FLOAT __FM4Op_attTimes[32];
|
||||
public:
|
||||
FM4Op();
|
||||
~FM4Op();
|
||||
void loadWaves(char* wave1, char* wave2, char* wave3, char* wave4);
|
||||
void clear();
|
||||
void setFreq(MY_FLOAT frequency);
|
||||
void setRatio(int whichOne, MY_FLOAT ratio);
|
||||
void setGain(int whichOne, MY_FLOAT gain);
|
||||
void keyOn();
|
||||
void keyOff();
|
||||
void noteOff(MY_FLOAT amp);
|
||||
/* There's no tick() method here, because that depends on the algorithm */
|
||||
void setModulationSpeed(MY_FLOAT mSpeed);
|
||||
void setModulationDepth(MY_FLOAT mDepth);
|
||||
void setControl1(MY_FLOAT cVal);
|
||||
void setControl2(MY_FLOAT cVal);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
};
|
||||
|
||||
#endif
|
||||
118
FMVoices.cpp
Normal file
118
FMVoices.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/******************************************/
|
||||
/* Singing Voice Synthesis Subclass */
|
||||
/* of Algorithm 6 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1996 */
|
||||
/******************************************/
|
||||
|
||||
#include "FMVoices.h"
|
||||
|
||||
FMVoices :: FMVoices() : FM4Alg6()
|
||||
{
|
||||
this->loadWaves("rawwaves/sinewave.raw",
|
||||
"rawwaves/sinewave.raw",
|
||||
"rawwaves/sinewave.raw",
|
||||
"rawwaves/sinewave.raw");
|
||||
|
||||
this->setRatio(0,2.00);
|
||||
this->setRatio(1,4.00);
|
||||
this->setRatio(2,12.0);
|
||||
this->setRatio(3,1.00);
|
||||
gains[3] = __FM4Op_gains[80];
|
||||
adsr[0]->setAll(0.001,0.001,__FM4Op_susLevels[15],0.001);
|
||||
adsr[1]->setAll(0.001,0.001,__FM4Op_susLevels[15],0.001);
|
||||
adsr[2]->setAll(0.001,0.001,__FM4Op_susLevels[15],0.001);
|
||||
adsr[3]->setAll(0.05,0.05,__FM4Op_susLevels[15],0.0001);
|
||||
twozero->setGain(0.0);
|
||||
modDepth = 0.005;
|
||||
currentVowel = 0;
|
||||
tilt[0] = 1.0;
|
||||
tilt[1] = 0.5;
|
||||
tilt[2] = 0.2;
|
||||
mods[0] = 1.0;
|
||||
mods[1] = 1.1;
|
||||
mods[2] = 1.1;
|
||||
baseFreq = 110.0;
|
||||
this->setFreq(110.0);
|
||||
}
|
||||
|
||||
#include "phonTabl.h"
|
||||
|
||||
void FMVoices :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT temp,temp2;
|
||||
int tempi,tempi2;
|
||||
|
||||
if (currentVowel < 16) {
|
||||
tempi2 = currentVowel;
|
||||
temp2 = 0.9;
|
||||
}
|
||||
else if (currentVowel < 32) {
|
||||
tempi2 = currentVowel - 16;
|
||||
temp2 = 1.0;
|
||||
}
|
||||
else if (currentVowel < 48) {
|
||||
tempi2 = currentVowel - 32;
|
||||
temp2 = 1.1;
|
||||
}
|
||||
else if (currentVowel < 64) {
|
||||
tempi2 = currentVowel - 48;
|
||||
temp2 = 1.2;
|
||||
}
|
||||
baseFreq = frequency;
|
||||
temp = (temp2 * phonParams[tempi2][0][0] / baseFreq) + 0.5;
|
||||
tempi = (int) temp;
|
||||
this->setRatio(0,(MY_FLOAT) tempi);
|
||||
temp = (temp2 * phonParams[tempi2][1][0] / baseFreq) + 0.5;
|
||||
tempi = (int) temp;
|
||||
this->setRatio(1,(MY_FLOAT) tempi);
|
||||
temp = (temp2 * phonParams[tempi2][2][0] / baseFreq) + 0.5;
|
||||
tempi = (int) temp;
|
||||
this->setRatio(2,(MY_FLOAT) tempi);
|
||||
gains[0] = 1.0; // pow(10.0,phonParams[tempi2][0][2] * 0.05);
|
||||
gains[1] = 1.0; // pow(10.0,phonParams[tempi2][1][2] * 0.05);
|
||||
gains[2] = 1.0; // pow(10.0,phonParams[tempi2][2][2] * 0.05);
|
||||
}
|
||||
|
||||
void FMVoices :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->setFreq(freq);
|
||||
tilt[0] = amp;
|
||||
tilt[1] = amp * amp;
|
||||
tilt[2] = amp * amp * amp;
|
||||
this->keyOn();
|
||||
#if defined(_debug_)
|
||||
printf("FMVoices : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FMVoices :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
int tempi;
|
||||
|
||||
#if defined(_debug_)
|
||||
printf("FM4Op : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == MIDI_control1)
|
||||
gains[3] = __FM4Op_gains[(int) (value * 0.78125)];
|
||||
else if (number == MIDI_control2) {
|
||||
tempi = (int) (value / 2);
|
||||
currentVowel = tempi;
|
||||
this->setFreq(baseFreq);
|
||||
}
|
||||
else if (number == MIDI_control3)
|
||||
this->setModulationSpeed(value * NORM_7 * 12.0); /* 0 to 12 Hz */
|
||||
else if (number == MIDI_mod_wheel)
|
||||
this->setModulationDepth(value * NORM_7);
|
||||
else if (number == MIDI_after_touch) {
|
||||
temp = value * NORM_7;
|
||||
tilt[0] = temp;
|
||||
tilt[1] = temp * temp;
|
||||
tilt[2] = temp * temp * temp;
|
||||
}
|
||||
else {
|
||||
printf("FM4Op : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
24
FMVoices.h
Normal file
24
FMVoices.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/******************************************/
|
||||
/* Singing Voice Synthesis Subclass */
|
||||
/* of Algorithm 6 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1996 */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__FMVoices_h)
|
||||
#define __FMVoices_h
|
||||
|
||||
#include "FM4Alg6.h"
|
||||
|
||||
class FMVoices : public FM4Alg6
|
||||
{
|
||||
protected:
|
||||
int currentVowel;
|
||||
public:
|
||||
FMVoices();
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
};
|
||||
|
||||
#endif
|
||||
24
Filter.cpp
Normal file
24
Filter.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
/*******************************************/
|
||||
/* Filter Class, by Perry R. Cook, 1995-96*/
|
||||
/* This is the base class for all filters.*/
|
||||
/* To me, most anything is a filter, but */
|
||||
/* I'll be a little less general here, and*/
|
||||
/* define a filter as something which has */
|
||||
/* input(s), output(s), and gain. */
|
||||
/*******************************************/
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
Filter :: Filter() : Object()
|
||||
{
|
||||
}
|
||||
|
||||
Filter :: ~Filter()
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT Filter :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
28
Filter.h
Normal file
28
Filter.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*******************************************/
|
||||
/* Filter Class, by Perry R. Cook, 1995-96*/
|
||||
/* This is the base class for all filters.*/
|
||||
/* To me, most anything is a filter, but */
|
||||
/* I'll be a little less general here, and*/
|
||||
/* define a filter as something which has */
|
||||
/* input(s), output(s), and gain. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__Filter_h)
|
||||
#define __Filter_h
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class Filter : public Object
|
||||
{
|
||||
protected:
|
||||
MY_FLOAT gain;
|
||||
MY_FLOAT *outputs;
|
||||
MY_FLOAT *inputs;
|
||||
MY_FLOAT lastOutput;
|
||||
public:
|
||||
Filter();
|
||||
~Filter();
|
||||
MY_FLOAT lastOut();
|
||||
};
|
||||
|
||||
#endif
|
||||
172
Flute.cpp
Normal file
172
Flute.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
/******************************************/
|
||||
/* WaveGuide Flute ala Karjalainen, */
|
||||
/* Smith, Waryznyk, etc. */
|
||||
/* with polynomial Jet ala Cook */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* */
|
||||
/* This is a waveguide model, and thus */
|
||||
/* relates to various Stanford Univ. */
|
||||
/* and possibly Yamaha and other patents.*/
|
||||
/* */
|
||||
/* Controls: CONTROL1 = jetDelay */
|
||||
/* CONTROL2 = noiseGain */
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/******************************************/
|
||||
|
||||
#include "Flute.h"
|
||||
|
||||
Flute :: Flute(MY_FLOAT lowestFreq)
|
||||
{
|
||||
long length;
|
||||
length = (long) (SRATE / lowestFreq + 1);
|
||||
boreDelay = new DLineL(length);
|
||||
length >> 1;
|
||||
jetDelay = new DLineL(length);
|
||||
jetTable = new JetTabl;
|
||||
filter = new OnePole;
|
||||
dcBlock = new DCBlock;
|
||||
noise = new Noise;
|
||||
adsr = new ADSR;
|
||||
vibr = new RawLoop("rawwaves/sinewave.raw");
|
||||
this->clear();
|
||||
|
||||
boreDelay->setDelay(100.0);
|
||||
jetDelay->setDelay(49.0);
|
||||
|
||||
filter->setPole(0.7 - (0.1 * RATE_NORM));
|
||||
filter->setGain(-1.0);
|
||||
vibr->normalize();
|
||||
vibr->setFreq(5.925);
|
||||
adsr->setAll(0.02, 0.05, 0.8, 0.001);
|
||||
endRefl = 0.5;
|
||||
jetRefl = 0.5;
|
||||
noiseGain = 0.15; /* Breath pressure random component */
|
||||
vibrGain = 0.05; /* breath periodic vibrato component */
|
||||
jetRatio = 0.32;
|
||||
}
|
||||
|
||||
Flute :: ~Flute()
|
||||
{
|
||||
delete jetDelay;
|
||||
delete boreDelay;
|
||||
delete jetTable;
|
||||
delete filter;
|
||||
delete dcBlock;
|
||||
delete noise;
|
||||
delete adsr;
|
||||
delete vibr;
|
||||
}
|
||||
|
||||
void Flute :: clear()
|
||||
{
|
||||
jetDelay->clear();
|
||||
boreDelay->clear();
|
||||
filter->clear();
|
||||
dcBlock->clear();
|
||||
/* adsr->reset(); */
|
||||
}
|
||||
|
||||
void Flute :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
lastFreq = frequency * 0.66666; /* we're overblowing here */
|
||||
temp = SRATE / lastFreq - 2.0; /* Length - approx. filter delay */
|
||||
boreDelay->setDelay(temp); /* Length of bore tube */
|
||||
jetDelay->setDelay(temp * jetRatio); /* jet delay shorter */
|
||||
}
|
||||
|
||||
void Flute :: startBlowing(MY_FLOAT amplitude, MY_FLOAT rate)
|
||||
{
|
||||
adsr->setAttackRate(rate);
|
||||
maxPressure = amplitude / 0.8;
|
||||
adsr->keyOn();
|
||||
}
|
||||
|
||||
void Flute :: stopBlowing(MY_FLOAT rate)
|
||||
{
|
||||
adsr->setReleaseRate(rate);
|
||||
adsr->keyOff();
|
||||
}
|
||||
|
||||
void Flute :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->setFreq(freq);
|
||||
this->startBlowing(1.1 + (amp * 0.20),amp * 0.02);
|
||||
outputGain = amp + 0.001;
|
||||
#if defined(_debug_)
|
||||
printf("Flute : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Flute :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
this->stopBlowing(amp * 0.02);
|
||||
#if defined(_debug_)
|
||||
printf("Flute : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Flute :: setJetRefl(MY_FLOAT refl)
|
||||
{
|
||||
jetRefl = refl;
|
||||
}
|
||||
|
||||
void Flute :: setEndRefl(MY_FLOAT refl)
|
||||
{
|
||||
endRefl = refl;
|
||||
}
|
||||
|
||||
void Flute :: setJetDelay(MY_FLOAT aRatio)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
temp = SRATE / lastFreq - 2.0; /* Length - approx. filter delay */
|
||||
jetRatio = aRatio;
|
||||
jetDelay->setDelay(temp * aRatio); /* Scaled by ratio */
|
||||
}
|
||||
|
||||
MY_FLOAT Flute :: tick()
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
MY_FLOAT pressureDiff;
|
||||
MY_FLOAT randPressure;
|
||||
MY_FLOAT breathPressure;
|
||||
|
||||
breathPressure = maxPressure * adsr->tick(); /* Breath Pressure */
|
||||
randPressure = noiseGain * noise->tick(); /* Random Deviation */
|
||||
randPressure += vibrGain * vibr->tick(); /* + breath vibrato */
|
||||
randPressure *= breathPressure; /* All scaled by Breath Pressure */
|
||||
|
||||
temp = filter->tick(boreDelay->lastOut());
|
||||
temp = dcBlock->tick(temp); /* Block DC on reflection */
|
||||
pressureDiff = breathPressure + randPressure - /* Breath Pressure */
|
||||
(jetRefl * temp); /* - reflected */
|
||||
pressureDiff = jetDelay->tick(pressureDiff); /* Jet Delay Line */
|
||||
pressureDiff = jetTable->lookup(pressureDiff) /* Non-Lin Jet + reflected */
|
||||
+ (endRefl * temp);
|
||||
lastOutput = 0.3 * boreDelay->tick(pressureDiff); /* Bore Delay and "bell" filter */
|
||||
|
||||
lastOutput *= outputGain;
|
||||
return lastOutput;
|
||||
|
||||
}
|
||||
|
||||
void Flute :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Flute : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == MIDI_control1)
|
||||
this->setJetDelay(0.08 + (0.48 * value * NORM_7));
|
||||
else if (number == MIDI_control2)
|
||||
noiseGain = (value * NORM_7 * 0.4);
|
||||
else if (number == MIDI_control3)
|
||||
vibr->setFreq((value * NORM_7 * 12.0));
|
||||
else if (number == MIDI_mod_wheel)
|
||||
vibrGain = (value * NORM_7 * 0.4);
|
||||
else if (number == MIDI_after_touch)
|
||||
adsr->setTarget(value * NORM_7);
|
||||
else {
|
||||
printf("Flute : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
64
Flute.h
Normal file
64
Flute.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/******************************************/
|
||||
/* WaveGuide Flute ala Karjalainen, */
|
||||
/* Smith, Waryznyk, etc. */
|
||||
/* with polynomial Jet ala Cook */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* */
|
||||
/* This is a waveguide model, and thus */
|
||||
/* relates to various Stanford Univ. */
|
||||
/* and possibly Yamaha and other patents.*/
|
||||
/* */
|
||||
/* Controls: CONTROL1 = jetDelay */
|
||||
/* CONTROL2 = noiseGain */
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__Flute_h)
|
||||
#define __Flute_h
|
||||
|
||||
#include "Instrmnt.h"
|
||||
#include "JetTabl.h"
|
||||
#include "DLineL.h"
|
||||
#include "OnePole.h"
|
||||
#include "DCBlock.h"
|
||||
#include "Noise.h"
|
||||
#include "ADSR.h"
|
||||
#include "RawLoop.h"
|
||||
|
||||
class Flute : public Instrmnt
|
||||
{
|
||||
protected:
|
||||
DLineL *jetDelay;
|
||||
DLineL *boreDelay;
|
||||
JetTabl *jetTable;
|
||||
OnePole *filter;
|
||||
DCBlock *dcBlock;
|
||||
Noise *noise;
|
||||
ADSR *adsr;
|
||||
RawLoop *vibr;
|
||||
MY_FLOAT lastFreq;
|
||||
MY_FLOAT maxPressure;
|
||||
MY_FLOAT jetRefl;
|
||||
MY_FLOAT endRefl;
|
||||
MY_FLOAT noiseGain;
|
||||
MY_FLOAT vibrGain;
|
||||
MY_FLOAT outputGain;
|
||||
MY_FLOAT jetRatio;
|
||||
public:
|
||||
Flute(MY_FLOAT lowestFreq);
|
||||
~Flute();
|
||||
void clear();
|
||||
void startBlowing(MY_FLOAT amplitude,MY_FLOAT rate);
|
||||
void stopBlowing(MY_FLOAT rate);
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
virtual void noteOff(MY_FLOAT amp);
|
||||
void setJetRefl(MY_FLOAT refl);
|
||||
void setEndRefl(MY_FLOAT refl);
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
virtual MY_FLOAT tick();
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
void setJetDelay(MY_FLOAT aLength);
|
||||
};
|
||||
|
||||
#endif
|
||||
170
FormSwep.cpp
Normal file
170
FormSwep.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
/*******************************************/
|
||||
/* Sweepable Formant (2-pole) */
|
||||
/* Filter Class, by Perry R. Cook, 1995-96*/
|
||||
/* See books on filters to understand */
|
||||
/* more about how this works. This drives*/
|
||||
/* to a target at speed set by rate. */
|
||||
/*******************************************/
|
||||
|
||||
#include "FormSwep.h"
|
||||
|
||||
FormSwep :: FormSwep() : Filter()
|
||||
{
|
||||
outputs = (MY_FLOAT *) malloc(2 * MY_FLOAT_SIZE);
|
||||
poleCoeffs[0] = 0.0;
|
||||
poleCoeffs[1] = 0.0;
|
||||
gain = 1.0;
|
||||
freq = 0.0;
|
||||
reson = 0.0;
|
||||
currentGain = 1.0;
|
||||
currentFreq = 0.0;
|
||||
currentReson = 0.0;
|
||||
targetGain = 1.0;
|
||||
targetFreq = 0.0;
|
||||
targetReson = 0.0;
|
||||
deltaGain = 0.0;
|
||||
deltaFreq = 0.0;
|
||||
deltaReson = 0.0;
|
||||
sweepState = 0;
|
||||
sweepRate = 0.002;
|
||||
dirty = 0;
|
||||
this->clear();
|
||||
}
|
||||
|
||||
FormSwep :: ~FormSwep()
|
||||
{
|
||||
free(outputs);
|
||||
}
|
||||
|
||||
void FormSwep :: clear()
|
||||
{
|
||||
outputs[0] = 0.0;
|
||||
outputs[1] = 0.0;
|
||||
}
|
||||
|
||||
void FormSwep :: setPoleCoeffs(MY_FLOAT *coeffs)
|
||||
{
|
||||
dirty = 0;
|
||||
poleCoeffs[0] = coeffs[0];
|
||||
poleCoeffs[1] = coeffs[1];
|
||||
}
|
||||
|
||||
void FormSwep :: setFreqAndReson(MY_FLOAT aFreq, MY_FLOAT aReson)
|
||||
{
|
||||
dirty = 0;
|
||||
reson = aReson;
|
||||
freq = aFreq;
|
||||
currentReson = aReson;
|
||||
currentFreq = aFreq;
|
||||
poleCoeffs[1] = - (reson * reson);
|
||||
poleCoeffs[0] = 2.0 * reson * cos(TWO_PI * freq / SRATE);
|
||||
}
|
||||
|
||||
void FormSwep :: setStates(MY_FLOAT aFreq, MY_FLOAT aReson, MY_FLOAT aGain)
|
||||
{
|
||||
dirty = 0;
|
||||
freq = aFreq;
|
||||
reson = aReson;
|
||||
gain = aGain;
|
||||
targetFreq = aFreq;
|
||||
targetReson = aReson;
|
||||
targetGain = aGain;
|
||||
currentFreq = aFreq;
|
||||
currentReson = aReson;
|
||||
currentGain = aGain;
|
||||
}
|
||||
|
||||
void FormSwep :: setTargets(MY_FLOAT aFreq, MY_FLOAT aReson, MY_FLOAT aGain)
|
||||
{
|
||||
dirty = 1;
|
||||
targetFreq = aFreq;
|
||||
targetReson = aReson;
|
||||
targetGain = aGain;
|
||||
deltaFreq = aFreq - currentFreq;
|
||||
deltaReson = aReson - currentReson;
|
||||
deltaGain = aGain - currentGain;
|
||||
sweepState = 0.0;
|
||||
}
|
||||
|
||||
void FormSwep :: setSweepRate(MY_FLOAT aRate)
|
||||
{
|
||||
sweepRate = aRate;
|
||||
}
|
||||
|
||||
void FormSwep :: setGain(MY_FLOAT aValue)
|
||||
{
|
||||
gain = aValue;
|
||||
}
|
||||
|
||||
MY_FLOAT FormSwep :: tick(MY_FLOAT sample) /* Perform Filter Operation */
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
|
||||
if (dirty) {
|
||||
sweepState += sweepRate;
|
||||
if (sweepState>= 1.0) {
|
||||
sweepState = 1.0;
|
||||
dirty = 0;
|
||||
currentReson = targetReson;
|
||||
reson = targetReson;
|
||||
currentFreq = targetFreq;
|
||||
freq = targetFreq;
|
||||
currentGain = targetGain;
|
||||
gain = targetGain;
|
||||
}
|
||||
else {
|
||||
currentReson = reson + (deltaReson * sweepState);
|
||||
currentFreq = freq + (deltaFreq * sweepState);
|
||||
currentGain = gain + (deltaGain * sweepState);
|
||||
}
|
||||
poleCoeffs[1] = - (currentReson * currentReson);
|
||||
poleCoeffs[0] = 2.0 * currentReson * cos(TWO_PI * currentFreq / SRATE);
|
||||
}
|
||||
|
||||
temp = currentGain * sample;
|
||||
temp += poleCoeffs[0] * outputs[0];
|
||||
temp += poleCoeffs[1] * outputs[1];
|
||||
outputs[1] = outputs[0];
|
||||
outputs[0] = temp;
|
||||
lastOutput = outputs[0];
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
|
||||
void main()
|
||||
{
|
||||
FormSwep filter;
|
||||
FILE *fd;
|
||||
MY_FLOAT temp;
|
||||
short data;
|
||||
long i;
|
||||
|
||||
fd = fopen("test.raw","wb");
|
||||
|
||||
filter.setTargets(100.0,0.99,0.01);
|
||||
for (i=0;i<20000;i++) {
|
||||
if (i%100 != 0) temp = 0.0; else temp = 1.0;
|
||||
data = filter.tick(temp) * 32000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
filter.setTargets(1000.0,0.99,0.01);
|
||||
for (i=0;i<20000;i++) {
|
||||
if (i%100 != 0) temp = 0.0; else temp = 1.0;
|
||||
data = filter.tick(temp) * 32000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
filter.setTargets(500.0,0.9999,0.001);
|
||||
for (i=0;i<20000;i++) {
|
||||
if (i%100 != 0) temp = 0.0; else temp = 1.0;
|
||||
data = filter.tick(temp) * 32000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
|
||||
45
FormSwep.h
Normal file
45
FormSwep.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*******************************************/
|
||||
/* Sweepable Formant (2-pole) */
|
||||
/* Filter Class, by Perry R. Cook, 1995-96*/
|
||||
/* See books on filters to understand */
|
||||
/* more about how this works. Nothing */
|
||||
/* out of the ordinary in this version. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__FormSwep_h)
|
||||
#define __FormSwep_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class FormSwep : public Filter
|
||||
{
|
||||
protected:
|
||||
MY_FLOAT poleCoeffs[2];
|
||||
MY_FLOAT freq;
|
||||
MY_FLOAT reson;
|
||||
int dirty;
|
||||
MY_FLOAT targetFreq;
|
||||
MY_FLOAT targetReson;
|
||||
MY_FLOAT targetGain;
|
||||
MY_FLOAT currentFreq;
|
||||
MY_FLOAT currentReson;
|
||||
MY_FLOAT currentGain;
|
||||
MY_FLOAT deltaFreq;
|
||||
MY_FLOAT deltaReson;
|
||||
MY_FLOAT deltaGain;
|
||||
MY_FLOAT sweepState;
|
||||
MY_FLOAT sweepRate;
|
||||
public:
|
||||
FormSwep();
|
||||
~FormSwep();
|
||||
void clear();
|
||||
void setPoleCoeffs(MY_FLOAT *coeffs);
|
||||
void setGain(MY_FLOAT aValue);
|
||||
void setFreqAndReson(MY_FLOAT aFreq, MY_FLOAT aReson);
|
||||
void setStates(MY_FLOAT aFreq, MY_FLOAT aReson, MY_FLOAT aGain);
|
||||
void setTargets(MY_FLOAT aFreq, MY_FLOAT aReson, MY_FLOAT aGain);
|
||||
void setSweepRate(MY_FLOAT aRate);
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
125
HIERARCH.txt
Normal file
125
HIERARCH.txt
Normal file
@@ -0,0 +1,125 @@
|
||||
Brief Descriptions of Classes in TK96CPP
|
||||
A ToolKit of Sound Synthesis Classes
|
||||
and Instruments in C++
|
||||
Perry Cook, 1995-96, free distribution for
|
||||
academic, instructional, tutorial, etc. purposes.
|
||||
Please read README.txt for more information.
|
||||
|
||||
<-----Building Blocks----->|<----------------Instruments------------------>
|
||||
|
||||
SourcSink Filters Non-Lin ModalSyn FM Physical Sampling PhISM
|
||||
& Formant
|
||||
|
||||
Object---------------------------Instrmnt----------.
|
||||
| | | | | |
|
||||
Envelope| Filter BowTabl | .------------------|---------------------.
|
||||
| | | JetTabl | | | | | | | | |
|
||||
ADSR | OneZero ReedTabl| Modal4 | FM4Op---.| | | | PhISEM
|
||||
| OnePole | | | | || | | | |
|
||||
._____| TwoZero .____| Marimba | FM4Alg3 || Plucked Sampler | Maracha
|
||||
| | TwoPole | Vibraphn| | || Clarinet | | Whistle
|
||||
Noise | DCBlock LipFilt AgogoBel| HeavyMtl|| Brass SamplFlt| VibraSlp
|
||||
| | BiQuad | || Flute | | Tambourn
|
||||
SubNoise| AllPass1 .____| .____|| Bowed Moog1 |
|
||||
| DLineA | | || |
|
||||
._____| DLineL VoicForm FM4Alg4 ||____. |
|
||||
| | DLineN | | | |
|
||||
RawWave | FormSwep PercFlut| Plucked2 |
|
||||
| | | |
|
||||
._____| .____| Mandolin .____|
|
||||
| | | | |
|
||||
RawLoop | FM4Alg5 | DrumSynt
|
||||
| | |
|
||||
._____| Rhodey |
|
||||
| | Wurley |
|
||||
NiWave1S| TubeBell |
|
||||
| .____|
|
||||
._____| | |
|
||||
| | FM4Alg6 |
|
||||
Modulatr| | |
|
||||
| FMVoices|
|
||||
._____| |
|
||||
| | .____|
|
||||
SingWave| |
|
||||
| FM4Alg8
|
||||
._____| |
|
||||
| | BeeThree
|
||||
RawWvOut|
|
||||
|
|
||||
._____|
|
||||
| |
|
||||
RawWvIn |
|
||||
._____|
|
||||
|
|
||||
NIFileIn
|
||||
|
||||
********** Instruments and Algorithms **************
|
||||
Each Class will be listed either with all UGs it uses,
|
||||
or the <<Algorithm>> of which it is a flavor.
|
||||
All inherit from Instrmnt, which inherits from Object.
|
||||
|
||||
Plucked.cpp Basic Plucked String DLineA,OneZero,OnePole,Noise
|
||||
Plucked2.cpp Not so Basic Pluck DLineL,DlineA,OneZero
|
||||
Mandolin.cpp My Own Mandolin <<flavor of PLUCKED2>>
|
||||
Bowed.cpp Not Hideous Bowed String DlineL,BowTabl,OnePole,BiQuad,RawWave,ADSR
|
||||
Brass.cpp Not So Bad Brass Inst. DLineA,LipFilt,DCBlock,ADSR,BiQuad
|
||||
Clarinet.cpp Pretty Good Clarinet DLineL,ReedTabl,OneZero,Envelope,Noise.h
|
||||
Flute.cpp Pretty Good Flute JetTabl,DLineL,OnePole,DCBlock,Noise,ADSR,RawWave
|
||||
Modal4.cpp 4 Resonances Envelope,RawWave,BiQuad,OnePole
|
||||
Marimba.cpp <<flavor of MODAL4>>
|
||||
Vibraphn.cpp <<flavor of MODAL4>>
|
||||
Agogobel.cpp <<flavor of MODAL4>>
|
||||
FM4Op.cpp 4 Operator FM Master ADSR,RawLoop,TwoZero
|
||||
FM4Alg3.cpp 3 Cascade w/ FB Mod. <<flavor of FM4OP>>
|
||||
FM4Alg4.cpp Like Alg3 but diff. <<flavor of FM4OP>>
|
||||
FM4Alg5.cpp 2 Parallel Simple FMs <<flavor of FM4OP>>
|
||||
FM4Alg6.cpp 3 Carr. with 1 Mod. <<flavor of FM4OP>>
|
||||
FM4Alg8.cpp 4 Osc. Additive <<flavor of FM4OP>>
|
||||
HeavyMtl.cpp Distorted Synth <<flavor of FM4Alg3>>
|
||||
PercFlut.cpp Perc. Flute <<flavor of FM4Alg4>>
|
||||
Rhodey.cpp Rhodes-Like Elec. Piano <<flavor of FM4Alg5>>
|
||||
Wurley.cpp Wurlitz. Elec. Piano <<flavor of FM4Alg5>>
|
||||
TubeBell.cpp Classic FM Bell <<flavor of FM4Alg5>>
|
||||
FMVoices.cpp 3-Formant Voice Synth. <<flavor of FM4Alg6>>
|
||||
BeeThree.cpp Cheezy Organ for Paul <<flavor of FM4Alg8>>
|
||||
Sampler.cpp Sampling Synth. 4 each ADSR, RawWave (att), RawWave (loop), OnePole
|
||||
SamplFlt.cpp Sampler with Swept Filt.<<flavor of Sampler>>
|
||||
Moog1.cpp Swept filter flavor of <<flavor of SamplFlt>>
|
||||
Voicform.cpp Source/Filter Voice Envelope,Noise,SingWave,FormSwep,OnePole,OneZero
|
||||
DrumSynt.cpp Drum Synthesizer bunch of NIFileIn, and OnePole
|
||||
|
||||
*********** Basic Unit Generators **************
|
||||
|
||||
Master Object: Object.cpp for compatibility with Objective C
|
||||
|
||||
Source&Sink: RawWave.cpp Lin-Interp Wavetable, Looped or 1 Shot
|
||||
NIWave1S.cpp Non-Interp Wavetable, 1 Shot
|
||||
RawLoop.cpp Lin-Interp Wavetable, Looping
|
||||
RawWvIn.cpp Lin-Interp Wave In streaming 'device'
|
||||
NIFileIn.cpp Non-Interp Wave In streamer, closes & opens
|
||||
RawWvOut.cpp Non-Interp Wave Out streaming 'device'
|
||||
Envelope.cpp Linearly Goes to Target by Rate, + noteOn/Off
|
||||
ADSR.cpp ADSR Flavor of Envelope
|
||||
Noise.cpp Random Number Generator
|
||||
SubNoise.cpp Random Numbers each N samples
|
||||
|
||||
Filters: Filter.cpp Filter Master Class
|
||||
OneZero.cpp One Zero Filter
|
||||
OnePole.cpp One Pole Filter
|
||||
AllPass1.cpp 1st Order All-Pass (phase) Filter
|
||||
DCBlock.cpp DC Blocking 1Pole/1Zero Filter
|
||||
TwoZero.cpp Two Zero Filter
|
||||
TwoPole.cpp Two Pole Filter
|
||||
BiQuad.cpp 2Pole/2Zero Filter
|
||||
FormSwep.cpp Sweepable 2Pole filter, go to target by rate
|
||||
DLineL.cpp Linearly Interpolating Delay Line
|
||||
DLineA.cpp AllPass Interpolating Delay Line
|
||||
DLineN.cpp Non Interpolating Delay Line
|
||||
|
||||
NonLin&Lookup: JetTabl.cpp Cubic Jet NonLinearity
|
||||
BowTabl.cpp 1/x^3-like Bow NonLinearity
|
||||
ReedTabl.cpp 1 break point Reed NonLinearity
|
||||
LipFilt.cpp Pressure Controlled BiQuad with NonLin
|
||||
|
||||
Derived: Modulatr.cpp Per. and Rnd. Vibrato: RawWave,SubNoise,OnePole
|
||||
SingWave.cpp Looping Wavetable with: Modulatr,Envelope
|
||||
60
HeavyMtl.cpp
Normal file
60
HeavyMtl.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
/******************************************/
|
||||
/* Heavy Metal Synth Subclass */
|
||||
/* of Algorithm 3 (TX81Z) Subclass of */
|
||||
/* 3 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/******************************************/
|
||||
|
||||
#include "HeavyMtl.h"
|
||||
|
||||
HeavyMtl :: HeavyMtl() : FM4Alg3()
|
||||
{
|
||||
this->loadWaves("rawwaves/sinewave.raw",
|
||||
"rawwaves/twopeaks.raw",
|
||||
"rawwaves/twopeaks.raw",
|
||||
"rawwaves/sinewave.raw");
|
||||
|
||||
this->setRatio(0,1.00 );
|
||||
this->setRatio(1,4.00 * 0.999);
|
||||
this->setRatio(2,3.00 * 1.001);
|
||||
this->setRatio(3,0.50 * 1.002);
|
||||
gains[0] = __FM4Op_gains[92];
|
||||
gains[1] = __FM4Op_gains[76];
|
||||
gains[2] = __FM4Op_gains[91];
|
||||
gains[3] = __FM4Op_gains[68];
|
||||
adsr[0]->setAll(0.050,0.0100,1.0,0.001);
|
||||
adsr[1]->setAll(0.050,0.0010,1.0,0.0001);
|
||||
adsr[2]->setAll(0.001,0.0020,1.0,0.0002);
|
||||
adsr[3]->setAll(0.050,0.0010,0.2,0.0002);
|
||||
twozero->setGain(2.0);
|
||||
vibWave->setFreq(5.5);
|
||||
modDepth = 0.00;
|
||||
}
|
||||
|
||||
HeavyMtl :: ~HeavyMtl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void HeavyMtl :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
waves[0]->setFreq(baseFreq * ratios[0]);
|
||||
waves[1]->setFreq(baseFreq * ratios[1]);
|
||||
waves[2]->setFreq(baseFreq * ratios[2]);
|
||||
waves[3]->setFreq(baseFreq * ratios[3]);
|
||||
}
|
||||
|
||||
void HeavyMtl :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
gains[0] = amp * __FM4Op_gains[92];
|
||||
gains[1] = amp * __FM4Op_gains[76];
|
||||
gains[2] = amp * __FM4Op_gains[91];
|
||||
gains[3] = amp * __FM4Op_gains[68];
|
||||
this->setFreq(freq);
|
||||
this->keyOn();
|
||||
#if defined(_debug_)
|
||||
printf("HeavyMtl : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
22
HeavyMtl.h
Normal file
22
HeavyMtl.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/******************************************/
|
||||
/* Heavy Metal Synth Subclass */
|
||||
/* of Algorithm 3 (TX81Z) Subclass of */
|
||||
/* 3 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__HeavyMtl_h)
|
||||
#define __HeavyMtl_h
|
||||
|
||||
#include "FM4Alg3.h"
|
||||
|
||||
class HeavyMtl : public FM4Alg3
|
||||
{
|
||||
public:
|
||||
HeavyMtl();
|
||||
~HeavyMtl();
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
};
|
||||
|
||||
#endif
|
||||
35
Instrmnt.cpp
Normal file
35
Instrmnt.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/******************************************/
|
||||
/* Instrument SuperClass for Toolkit96 */
|
||||
/* Perry R. Cook, Princeton University */
|
||||
/******************************************/
|
||||
|
||||
#include "Instrmnt.h"
|
||||
|
||||
Instrmnt :: Instrmnt()
|
||||
{
|
||||
}
|
||||
|
||||
void Instrmnt :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
}
|
||||
|
||||
void Instrmnt :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
}
|
||||
|
||||
void Instrmnt :: setFreq(MY_FLOAT freq)
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT Instrmnt :: tick()
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT Instrmnt :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void Instrmnt :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
}
|
||||
25
Instrmnt.h
Normal file
25
Instrmnt.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/******************************************/
|
||||
/* Instrument SuperClass for Toolkit96 */
|
||||
/* Perry R. Cook, Princeton University */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__Instrmnt_h)
|
||||
#define __Instrmnt_h
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class Instrmnt : public Object
|
||||
{
|
||||
protected:
|
||||
MY_FLOAT lastOutput;
|
||||
public:
|
||||
Instrmnt();
|
||||
MY_FLOAT lastOut();
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
virtual void noteOff(MY_FLOAT amp);
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
virtual MY_FLOAT tick();
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
};
|
||||
|
||||
#endif
|
||||
36
JetTabl.cpp
Normal file
36
JetTabl.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/**********************************************/
|
||||
/* Jet Table Object by Perry R. Cook, 1995-96 */
|
||||
/* Consult Fletcher and Rossing, Karjalainen, */
|
||||
/* Cook, more, for information. */
|
||||
/* This, as with many other of my "tables", */
|
||||
/* is not a table, but is computed by poly- */
|
||||
/* nomial calculation. */
|
||||
/**********************************************/
|
||||
|
||||
#include "JetTabl.h"
|
||||
|
||||
JetTabl :: JetTabl()
|
||||
{
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
|
||||
JetTabl :: ~JetTabl()
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT JetTabl :: lookup(double sample) /* Perform "Table Lookup" */
|
||||
{ /* By Polynomial Calculation */
|
||||
lastOutput = sample *
|
||||
(sample*sample - 1.0); /* (x^3 - x) approximates sigmoid of jet */
|
||||
if (lastOutput > 1.0)
|
||||
lastOutput = 1.0; /* Saturation at +/- 1.0 */
|
||||
if (lastOutput < -1.0)
|
||||
lastOutput = -1.0;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT JetTabl :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
22
JetTabl.h
Normal file
22
JetTabl.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/**********************************************/
|
||||
/* Jet Table Object by Perry R. Cook, 1995-96 */
|
||||
/* Consult Fletcher and Rossing, Karjalainen, */
|
||||
/* Cook, more, for information. */
|
||||
/* This, as with many other of my "tables", */
|
||||
/* is not a table, but is computed by poly- */
|
||||
/* nomial calculation. */
|
||||
/**********************************************/
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class JetTabl : public Object
|
||||
{
|
||||
protected:
|
||||
double lastOutput;
|
||||
public:
|
||||
JetTabl();
|
||||
~JetTabl();
|
||||
double lookup(double deltaP);
|
||||
double lastOut();
|
||||
};
|
||||
|
||||
1
Lacrymosa
Executable file
1
Lacrymosa
Executable file
@@ -0,0 +1 @@
|
||||
time textVoic =100.00 lll ahh ...... =133 .... xxx rrr + + eee .. mmm + ohh ..... sss ahh ..... ddd - eee .. - - ... + + ehh .. + ... sss - - - eee ..... lll =100.0 ahh .......
|
||||
66
LipFilt.cpp
Normal file
66
LipFilt.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/**********************************************/
|
||||
/* Lip Filter Object by Perry R. Cook, 1995-96*/
|
||||
/* The lip of the brass player has dynamics */
|
||||
/* which are controlled by the mass, spring */
|
||||
/* constant, and damping of the lip. This */
|
||||
/* filter simulates that behavior and the */
|
||||
/* transmission/reflection properties as */
|
||||
/* well. See Cook TBone and HosePlayer */
|
||||
/* instruments and articles. */
|
||||
/**********************************************/
|
||||
|
||||
#include "LipFilt.h"
|
||||
|
||||
LipFilt :: LipFilt()
|
||||
{
|
||||
MY_FLOAT coeffs[2];
|
||||
filter = new BiQuad;
|
||||
coeffs[0] = 0.0;
|
||||
coeffs[1] = 0.0;
|
||||
filter->setZeroCoeffs(coeffs);
|
||||
this->clear();
|
||||
}
|
||||
|
||||
LipFilt :: ~LipFilt()
|
||||
{
|
||||
delete filter;
|
||||
}
|
||||
|
||||
void LipFilt :: clear()
|
||||
{
|
||||
filter->clear();
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
|
||||
void LipFilt :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT coeffs[2];
|
||||
coeffs[0] = 2.0 * 0.997 *
|
||||
cos(TWO_PI * frequency / SRATE); /* damping should change with */
|
||||
coeffs[1] = -0.997 * 0.997; /* lip parameters, but not yet.*/
|
||||
filter->setPoleCoeffs(coeffs);
|
||||
filter->setGain(0.03);
|
||||
}
|
||||
|
||||
/* NOTE: Here we should add lip tension */
|
||||
/* settings based on Mass/Spring/Damping */
|
||||
/* Maybe in TookKit97 */
|
||||
|
||||
MY_FLOAT LipFilt :: tick(MY_FLOAT mouthSample,MY_FLOAT boreSample)
|
||||
/* Perform "Table Lookup" By Polynomial Calculation */
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
temp = mouthSample - boreSample; /* Differential pressure */
|
||||
temp = filter->tick(temp); /* Force -> position */
|
||||
temp = temp*temp; /* Simple position to area mapping */
|
||||
if (temp > 1.0) temp = 1.0; /* Saturation at + 1.0 */
|
||||
lastOutput = temp * mouthSample; /* Assume mouth input = area */
|
||||
lastOutput += (1.0 - temp) * boreSample; /* and Bore reflection is compliment. */
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT LipFilt :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
28
LipFilt.h
Normal file
28
LipFilt.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/**********************************************/
|
||||
/* Lip Filter Object by Perry R. Cook, 1995-96*/
|
||||
/* The lip of the brass player has dynamics */
|
||||
/* which are controlled by the mass, spring */
|
||||
/* constant, and damping of the lip. This */
|
||||
/* filter simulates that behavior and the */
|
||||
/* transmission/reflection properties as */
|
||||
/* well. See Cook TBone and HosePlayer */
|
||||
/* instruments and articles. */
|
||||
/**********************************************/
|
||||
|
||||
#include "Object.h"
|
||||
#include "BiQuad.h"
|
||||
|
||||
class LipFilt : public Object
|
||||
{
|
||||
protected:
|
||||
BiQuad *filter;
|
||||
MY_FLOAT lastOutput;
|
||||
public:
|
||||
LipFilt();
|
||||
~LipFilt();
|
||||
void clear();
|
||||
void setFreq(MY_FLOAT frequency);
|
||||
MY_FLOAT tick(MY_FLOAT mouthSample,MY_FLOAT boreSample);
|
||||
MY_FLOAT lastOut();
|
||||
};
|
||||
|
||||
188
MIDIInpt.cpp
Normal file
188
MIDIInpt.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
/******************************************/
|
||||
/* Simple RealTime MIDI Input Object, */
|
||||
/* by Perry R. Cook, 1996 */
|
||||
/* */
|
||||
/* This object takes MIDI from the input */
|
||||
/* , parses it, turns it into TSIDI */
|
||||
/* messages, and buffers it up for use by*/
|
||||
/* any object that asks for it later. */
|
||||
/* */
|
||||
/* TSIDI (ToolKit Synthesis Instrument */
|
||||
/* Digital Interfaceis like MIDI, but */
|
||||
/* allows for floating point control */
|
||||
/* changes, note numbers, etc. Example: */
|
||||
/* noteOn(1,60.01,111.132) plays a sharp */
|
||||
/* middle C with a velocity of 111.132 */
|
||||
/* */
|
||||
/******************************************/
|
||||
|
||||
#include "MIDIInpt.h"
|
||||
|
||||
int onePending;
|
||||
MDport inport;
|
||||
MDevent lastEvent;
|
||||
|
||||
|
||||
// void pollMessage(void *)
|
||||
// {
|
||||
// int status;
|
||||
// while (1) {
|
||||
// while (onePending == 0) {
|
||||
// mdReceive(inport, &lastEvent, 1);
|
||||
// status = mdGetStatus(lastEvent.msg);
|
||||
// if (status==MD_NOTEON || status==MD_NOTEOFF)
|
||||
// onePending = 1;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
MIDIInpt :: MIDIInpt()
|
||||
{
|
||||
int nports;
|
||||
nports = mdInit();
|
||||
printf("%d MIDI devices available\n", nports);
|
||||
inport = mdOpenInPort(0);
|
||||
if (inport == NULL) {
|
||||
printf("open failed\n");
|
||||
exit(0);
|
||||
}
|
||||
mdSetStampMode(inport, MD_NOSTAMP);
|
||||
onePending = 0;
|
||||
// midi_pid = sproc(pollMessage, PR_SALL);
|
||||
// if (midi_pid == -1)
|
||||
// {
|
||||
// fprintf(stderr, "unable to create midi input thread...aborting.\n");
|
||||
// exit(-1);
|
||||
// }
|
||||
}
|
||||
|
||||
#define _BSD_SIGNALS
|
||||
#include <signal.h>
|
||||
|
||||
MIDIInpt :: ~MIDIInpt()
|
||||
{
|
||||
mdClosePort(inport);
|
||||
// kill(midi_pid, SIGKILL);
|
||||
}
|
||||
|
||||
/* MIDI File Code
|
||||
if (byte > 15) {
|
||||
if (byte == 248) printf("MIDI Clock,");
|
||||
else if (byte == 249) printf("Undefined,");
|
||||
else if (byte == 250) printf("Song Start,");
|
||||
else if (byte == 251) printf("Continue,");
|
||||
else if (byte == 252) printf("Song Stop,");
|
||||
else if (byte == 253) printf("Undefined,");
|
||||
else if (byte == 254) printf("ActiveSen,");
|
||||
else if (byte == 255) printf("SystReset,");
|
||||
else printf("BEATSME");
|
||||
}
|
||||
else {
|
||||
if (byte == 8) printf("NoteOff");
|
||||
if (byte == 9) printf("NoteOn");
|
||||
if (byte == 10) printf("Poly Pressure");
|
||||
if (byte == 11) printf("Control Change");
|
||||
if (byte == 12) printf("Program Change");
|
||||
if (byte == 13) printf("Channel Pressure");
|
||||
if (byte == 14) printf("Pitch Wheel");
|
||||
}
|
||||
*/
|
||||
|
||||
int MIDIInpt :: nextMessage()
|
||||
{
|
||||
int status;
|
||||
int byte1;
|
||||
int byte2;
|
||||
|
||||
messageType = -1;
|
||||
|
||||
mdReceive(inport, &lastEvent, 1);
|
||||
|
||||
// if (onePending == 1) {
|
||||
|
||||
status = mdGetStatus(lastEvent.msg);
|
||||
byte1 = mdGetByte1(lastEvent.msg);
|
||||
byte2 = mdGetByte2(lastEvent.msg);
|
||||
channel = mdGetChannel(lastEvent.msg);
|
||||
|
||||
if (status==MD_NOTEON) {
|
||||
byteTwo = (float) byte1;
|
||||
byteThree = (float) byte2;
|
||||
if (byte2==0)
|
||||
messageType = 8;
|
||||
else
|
||||
messageType = 9;
|
||||
}
|
||||
else if (status==MD_NOTEOFF) {
|
||||
byteTwo = (float) byte1;
|
||||
byteThree = (float) byte2;
|
||||
messageType = 8;
|
||||
}
|
||||
else if (status==MD_CONTROLCHANGE) {
|
||||
byteTwo = (float) byte1;
|
||||
byteThree = (float) byte2;
|
||||
messageType = 11;
|
||||
}
|
||||
else if (status==MD_PROGRAMCHANGE) {
|
||||
byteTwo = (float) byte1;
|
||||
messageType = 12;
|
||||
}
|
||||
else if (status==MD_CHANNELPRESSURE) {
|
||||
byteTwo = (float) byte1;
|
||||
messageType = 13;
|
||||
}
|
||||
else if (status==MD_PITCHBENDCHANGE) {
|
||||
byteTwo = (float) byte1;
|
||||
byteTwo += (float) byte2 * NORM_7;
|
||||
messageType = 14;
|
||||
}
|
||||
else {
|
||||
messageType = -1;
|
||||
}
|
||||
// onePending = 0;
|
||||
|
||||
// }
|
||||
|
||||
return messageType;
|
||||
}
|
||||
|
||||
void MIDIInpt :: printMessage()
|
||||
{
|
||||
char buffer[128];
|
||||
mdPrintEvent(buffer,&lastEvent,1);
|
||||
printf(buffer);
|
||||
}
|
||||
|
||||
int MIDIInpt :: getType()
|
||||
{
|
||||
return messageType;
|
||||
}
|
||||
|
||||
int MIDIInpt :: getChannel()
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
|
||||
MY_FLOAT MIDIInpt :: getByteTwo()
|
||||
{
|
||||
return byteTwo;
|
||||
}
|
||||
|
||||
MY_FLOAT MIDIInpt :: getByteThree()
|
||||
{
|
||||
return byteThree;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
void main(int argc,char *argv[])
|
||||
{
|
||||
MIDIInpt testMIDI;
|
||||
|
||||
while(1) {
|
||||
if (testMIDI.nextMessage() > 0)
|
||||
testMIDI.printMessage();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
48
MIDIInpt.h
Normal file
48
MIDIInpt.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/******************************************/
|
||||
/* Simple MIDI Text File Reader Class, */
|
||||
/* by Perry R. Cook, 1996 */
|
||||
/* This Object can open a MIDI Text File */
|
||||
/* and parse it. The file spec is mine */
|
||||
/* and mine alone, but it's all text so */
|
||||
/* you should be able to figure it out. */
|
||||
/* */
|
||||
/* TSIDI (ToolKit Synthesis Instrument */
|
||||
/* Digital Interfaceis like MIDI, but */
|
||||
/* allows for floating point control */
|
||||
/* changes, note numbers, etc. Example: */
|
||||
/* noteOn(1,60.01,111.132) plays a sharp */
|
||||
/* middle C with a velocity of 111.132 */
|
||||
/* */
|
||||
/* Warning: Obey column spacing in the */
|
||||
/* text file if you try to edit it or */
|
||||
/* create your own files. */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__MIDIInpt_h)
|
||||
#define __MIDIInpt_h
|
||||
|
||||
#include "Object.h"
|
||||
#include "dmedia/midi.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/prctl.h>
|
||||
|
||||
class MIDIInpt : public Object
|
||||
{
|
||||
protected:
|
||||
int midi_pid;
|
||||
int messageType;
|
||||
int channel;
|
||||
float byteTwo;
|
||||
float byteThree;
|
||||
public:
|
||||
MIDIInpt();
|
||||
~MIDIInpt();
|
||||
void printMessage();
|
||||
int nextMessage();
|
||||
int getType();
|
||||
int getChannel();
|
||||
MY_FLOAT getByteTwo();
|
||||
MY_FLOAT getByteThree();
|
||||
};
|
||||
|
||||
#endif
|
||||
133
MIDIText.cpp
Normal file
133
MIDIText.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
/******************************************/
|
||||
/* Simple MIDI Text File Reader Class, */
|
||||
/* by Perry R. Cook, 1996 */
|
||||
/* This Object can open a MIDI Text File */
|
||||
/* and parse it. The file spec is mine */
|
||||
/* and mine alone, but it's all text so */
|
||||
/* you should be able to figure it out. */
|
||||
/* */
|
||||
/* SKINI (Synthesis toolKit Instrument */
|
||||
/* Network Interface) is like MIDI, but */
|
||||
/* allows for floating point control */
|
||||
/* changes, note numbers, etc. Example: */
|
||||
/* noteOn 60.01 111.132 plays a sharp */
|
||||
/* middle C with a velocity of 111.132 */
|
||||
/* See SKINI.txt for more information */
|
||||
/* Warning: Obey columns in the text */
|
||||
/* file if you try to edit it or create */
|
||||
/* your own files. */
|
||||
/******************************************/
|
||||
|
||||
#include "MIDIText.h"
|
||||
|
||||
MIDIText :: MIDIText(char *fileName)
|
||||
{
|
||||
myFile = fopen(fileName,"r");
|
||||
this->nextMessage();
|
||||
}
|
||||
|
||||
MIDIText :: ~MIDIText()
|
||||
{
|
||||
}
|
||||
|
||||
/* MIDI File Codes
|
||||
if (byte > 15) {
|
||||
if (byte == 248) printf("MIDI Clock,");
|
||||
else if (byte == 249) printf("Undefined,");
|
||||
else if (byte == 250) printf("Song Start,");
|
||||
else if (byte == 251) printf("Continue,");
|
||||
else if (byte == 252) printf("Song Stop,");
|
||||
else if (byte == 253) printf("Undefined,");
|
||||
else if (byte == 254) printf("ActiveSen,");
|
||||
else if (byte == 255) printf("SystReset,");
|
||||
else printf("BEATSME");
|
||||
}
|
||||
else { // these are all nybbles of status bytes //
|
||||
if (byte == 8) printf("NoteOff");
|
||||
if (byte == 9) printf("NoteOn");
|
||||
if (byte == 10) printf("Poly Pressure");
|
||||
if (byte == 11) printf("Control Change");
|
||||
if (byte == 12) printf("Program Change");
|
||||
if (byte == 13) printf("Channel Pressure");
|
||||
if (byte == 14) printf("Pitch Wheel");
|
||||
}
|
||||
*/
|
||||
|
||||
int MIDIText :: nextMessage()
|
||||
{
|
||||
int notDone = 1,point;
|
||||
char inputString[1024];
|
||||
char tempString[32];
|
||||
|
||||
while (notDone) {
|
||||
notDone = 0;
|
||||
if (fgets(inputString,1000,myFile)) {
|
||||
sscanf(inputString,"%s %lf %i %f %f",tempString,&deltaTime,&channel,&byteTwo,&byteThree);
|
||||
point = 5;
|
||||
if (tempString[0]=='%') point = 1;
|
||||
if (tempString[point] == 'n') { // NoteO'n'
|
||||
messageType = 9;
|
||||
}
|
||||
else if (inputString[point] == 'f') { // NoteO'f'f
|
||||
messageType = 8;
|
||||
}
|
||||
else if (inputString[point] == 'B') { // Pitch'B'end
|
||||
byteThree = byteTwo;
|
||||
messageType = 14;
|
||||
}
|
||||
else if (inputString[point] == 'a') { // Progr'a'mChange
|
||||
messageType = 12;
|
||||
}
|
||||
else if (inputString[point] == 'T') { // After'T'ouch
|
||||
messageType = 11;
|
||||
}
|
||||
else if (inputString[point] == 'o') { // Contr'o'lChange
|
||||
messageType = 11;
|
||||
}
|
||||
else if (inputString[0] == '/' || inputString[0] == ' ') {
|
||||
notDone = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
messageType = -1;
|
||||
}
|
||||
}
|
||||
return messageType;
|
||||
}
|
||||
|
||||
int MIDIText :: getType()
|
||||
{
|
||||
return messageType;
|
||||
}
|
||||
|
||||
int MIDIText :: getChannel()
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
|
||||
MY_FLOAT MIDIText :: getDelta()
|
||||
{
|
||||
return deltaTime;
|
||||
}
|
||||
|
||||
MY_FLOAT MIDIText :: getByteTwo()
|
||||
{
|
||||
return byteTwo;
|
||||
}
|
||||
|
||||
MY_FLOAT MIDIText :: getByteThree()
|
||||
{
|
||||
return byteThree;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
void main(int argc,char *argv[])
|
||||
{
|
||||
MIDIText testFile(argv[1]);
|
||||
|
||||
while(testFile.nextMessage() > 0) ;
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
46
MIDIText.h
Normal file
46
MIDIText.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/******************************************/
|
||||
/* Simple MIDI Text File Reader Class, */
|
||||
/* by Perry R. Cook, 1996 */
|
||||
/* This Object can open a MIDI Text File */
|
||||
/* and parse it. The file spec is mine */
|
||||
/* and mine alone, but it's all text so */
|
||||
/* you should be able to figure it out. */
|
||||
/* */
|
||||
/* SKINI (Synthesis toolKit Instrument */
|
||||
/* Network Interface) is like MIDI, but */
|
||||
/* allows for floating point control */
|
||||
/* changes, note numbers, etc. Example: */
|
||||
/* noteOn 60.01 111.132 plays a sharp */
|
||||
/* middle C with a velocity of 111.132 */
|
||||
/* See SKINI.txt for more information */
|
||||
/* Warning: Obey columns in the text */
|
||||
/* file if you try to edit it or create */
|
||||
/* your own files. */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__MIDIText_h)
|
||||
#define __MIDIText_h
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class MIDIText : public Object
|
||||
{
|
||||
protected:
|
||||
FILE *myFile;
|
||||
int messageType;
|
||||
int channel;
|
||||
MY_FLOAT deltaTime;
|
||||
float byteTwo;
|
||||
float byteThree;
|
||||
public:
|
||||
MIDIText(char *fileName);
|
||||
~MIDIText();
|
||||
int nextMessage();
|
||||
int getType();
|
||||
int getChannel();
|
||||
MY_FLOAT getDelta();
|
||||
MY_FLOAT getByteTwo();
|
||||
MY_FLOAT getByteThree();
|
||||
};
|
||||
|
||||
#endif
|
||||
247
Makefile
Normal file
247
Makefile
Normal file
@@ -0,0 +1,247 @@
|
||||
O_FILES = Object.o Envelope.o ADSR.o Noise.o SubNoise.o RawWave.o RawLoop.o \
|
||||
NIWave1S.o Modulatr.o SingWave.o RawWvOut.o RawWvIn.o Filter.o \
|
||||
OneZero.o OnePole.o TwoZero.o TwoPole.o DCBlock.o BiQuad.o AllPass1.o \
|
||||
DLineA.o DLineL.o DLineN.o FormSwep.o BowTabl.o JetTabl.o ReedTabl.o \
|
||||
LipFilt.o Modal4.o FM4Op.o FM4Alg3.o FM4Alg4.o FM4Alg5.o FM4Alg6.o \
|
||||
FM4Alg8.o Plucked2.o SamplFlt.o Sampler.o VoicForm.o\
|
||||
MIDIText.o Reverb.o VoicMang.o \
|
||||
\
|
||||
Instrmnt.o Marimba.o Vibraphn.o AgogoBel.o Plucked.o Mandolin.o \
|
||||
Clarinet.o Flute.o Brass.o Bowed.o Rhodey.o Wurley.o TubeBell.o \
|
||||
HeavyMtl.o PercFlut.o BeeThree.o FMVoices.o Moog1.o
|
||||
|
||||
RM = /bin/rm
|
||||
|
||||
# This is for NeXT
|
||||
# CC = cc -O
|
||||
# INSTR = testMono testMult DrumSynt textVoic
|
||||
|
||||
|
||||
# These are for SGI
|
||||
INSTR = testTextIn testMono testMIDI testMult DrumSynt textVoic
|
||||
CC = gcc -O
|
||||
MEDIALINK = -lmd
|
||||
TCLLIB = /usr/local/lib/libtcl.so.7.4 /usr/local/lib/libtk.so.4.0 /usr/lib/libX11.so
|
||||
LIBRARY = /usr/lib/libmx.so /usr/lib/libaudio.a
|
||||
|
||||
# .cpp.o:
|
||||
# $(CC) -c $*.cpp
|
||||
|
||||
all: $(INSTR)
|
||||
|
||||
testTextIn: $(LIBRARY) testTextIn.cpp $(O_FILES) MIDIInpt.o
|
||||
$(CC) $(MEDIALINK) -o testTextIn testTextIn.cpp $(O_FILES) $(LIBRARY)
|
||||
|
||||
testMono: $(LIBRARY) testMono.cpp $(O_FILES)
|
||||
$(CC) $(MEDIALINK) -o testMono testMono.cpp $(O_FILES) $(LIBRARY)
|
||||
|
||||
testMIDI: $(LIBRARY) testMIDI.cpp Object.o MIDIInpt.o
|
||||
$(CC) $(MEDIALINK) -o testMIDI testMIDI.cpp Object.o MIDIInpt.o $(LIBRARY) /usr/lib/libmidi.so
|
||||
|
||||
testMult: $(LIBRARY) testMult.cpp $(O_FILES)
|
||||
$(CC) $(MEDIALINK) -o testMult testMult.cpp $(O_FILES) $(LIBRARY)
|
||||
|
||||
textVoic: $(LIBRARY) textVoic.cpp $(O_FILES)
|
||||
$(CC) $(MEDIALINK) -o textVoic textVoic.cpp $(O_FILES) $(LIBRARY)
|
||||
|
||||
Instrmnt.o: Instrmnt.cpp
|
||||
$(CC) -c Instrmnt.cpp
|
||||
|
||||
Marimba.o: Marimba.cpp
|
||||
$(CC) -c Marimba.cpp
|
||||
|
||||
Vibraphn.o: Vibraphn.cpp
|
||||
$(CC) -c Vibraphn.cpp
|
||||
|
||||
AgogoBel.o: AgogoBel.cpp
|
||||
$(CC) -c AgogoBel.cpp
|
||||
|
||||
Plucked.o: Plucked.cpp
|
||||
$(CC) -c Plucked.cpp
|
||||
|
||||
Mandolin.o: Mandolin.cpp
|
||||
$(CC) -c Mandolin.cpp
|
||||
|
||||
Clarinet.o: Clarinet.cpp
|
||||
$(CC) -c Clarinet.cpp
|
||||
|
||||
Flute.o: Flute.cpp
|
||||
$(CC) -c Flute.cpp
|
||||
|
||||
Brass.o: Brass.cpp
|
||||
$(CC) -c Brass.cpp
|
||||
|
||||
Bowed.o: Bowed.cpp
|
||||
$(CC) -c Bowed.cpp
|
||||
|
||||
Rhodey.o: Rhodey.cpp
|
||||
$(CC) -c Rhodey.cpp
|
||||
|
||||
Wurley.o: Wurley.cpp
|
||||
$(CC) -c Wurley.cpp
|
||||
|
||||
TubeBell.o: TubeBell.cpp
|
||||
$(CC) -c TubeBell.cpp
|
||||
|
||||
HeavyMtl.o: HeavyMtl.cpp
|
||||
$(CC) -c HeavyMtl.cpp
|
||||
|
||||
PercFlut.o: PercFlut.cpp
|
||||
$(CC) -c PercFlut.cpp
|
||||
|
||||
BeeThree.o: BeeThree.cpp
|
||||
$(CC) -c BeeThree.cpp
|
||||
|
||||
FMVoices.o: FMVoices.cpp
|
||||
$(CC) -c FMVoices.cpp
|
||||
|
||||
Moog1.o: Moog1.cpp
|
||||
$(CC) -c Moog1.cpp
|
||||
|
||||
DrumSynt: $(LIBRARY) DrumSynt.cpp $(O_FILES)
|
||||
$(CC) -o DrumSynt DrumSynt.cpp $(O_FILES) $(LIBRARY)
|
||||
|
||||
testVoic: $(LIBRARY) testVoic.cpp $(O_FILES)
|
||||
$(CC) -o testVoic testVoic.cpp $(O_FILES) $(LIBRARY)
|
||||
|
||||
# $(O_FILES) :
|
||||
# $(CC) -c -o $@ $*.cpp
|
||||
|
||||
Object.o : Object.cpp
|
||||
$(CC) -c Object.cpp
|
||||
|
||||
Envelope.o : Envelope.cpp
|
||||
$(CC) -c Envelope.cpp
|
||||
|
||||
ADSR.o : ADSR.cpp
|
||||
$(CC) -c ADSR.cpp
|
||||
|
||||
Noise.o : Noise.cpp
|
||||
$(CC) -c Noise.cpp
|
||||
|
||||
SubNoise.o : SubNoise.cpp
|
||||
$(CC) -c SubNoise.cpp
|
||||
|
||||
RawWave.o : RawWave.cpp
|
||||
$(CC) -c RawWave.cpp
|
||||
|
||||
RawLoop.o : RawLoop.cpp
|
||||
$(CC) -c RawLoop.cpp
|
||||
|
||||
NIWave1S.o : NIWave1S.cpp
|
||||
$(CC) -c NIWave1S.cpp
|
||||
|
||||
Modulatr.o : Modulatr.cpp
|
||||
$(CC) -c Modulatr.cpp
|
||||
|
||||
SingWave.o : SingWave.cpp
|
||||
$(CC) -c SingWave.cpp
|
||||
|
||||
RawWvOut.o : RawWvOut.cpp
|
||||
$(CC) -c RawWvOut.cpp
|
||||
|
||||
RawWvIn.o : RawWvIn.cpp
|
||||
$(CC) -c RawWvIn.cpp
|
||||
|
||||
Filter.o : Filter.cpp
|
||||
$(CC) -c Filter.cpp
|
||||
|
||||
OneZero.o : OneZero.cpp
|
||||
$(CC) -c OneZero.cpp
|
||||
|
||||
OnePole.o : OnePole.cpp
|
||||
$(CC) -c OnePole.cpp
|
||||
|
||||
TwoZero.o : TwoZero.cpp
|
||||
$(CC) -c TwoZero.cpp
|
||||
|
||||
TwoPole.o : TwoPole.cpp
|
||||
$(CC) -c TwoPole.cpp
|
||||
|
||||
DCBlock.o : DCBlock.cpp
|
||||
$(CC) -c DCBlock.cpp
|
||||
|
||||
BiQuad.o : BiQuad.cpp
|
||||
$(CC) -c BiQuad.cpp
|
||||
|
||||
AllPass1.o : AllPass1.cpp
|
||||
$(CC) -c AllPass1.cpp
|
||||
|
||||
DLineA.o : DLineA.cpp
|
||||
$(CC) -c DLineA.cpp
|
||||
|
||||
DLineL.o : DLineL.cpp
|
||||
$(CC) -c DLineL.cpp
|
||||
|
||||
DLineN.o : DLineN.cpp
|
||||
$(CC) -c DLineN.cpp
|
||||
|
||||
FormSwep.o : FormSwep.cpp
|
||||
$(CC) -c FormSwep.cpp
|
||||
|
||||
BowTabl.o : BowTabl.cpp
|
||||
$(CC) -c BowTabl.cpp
|
||||
|
||||
JetTabl.o : JetTabl.cpp
|
||||
$(CC) -c JetTabl.cpp
|
||||
|
||||
ReedTabl.o : ReedTabl.cpp
|
||||
$(CC) -c ReedTabl.cpp
|
||||
|
||||
LipFilt.o : LipFilt.cpp
|
||||
$(CC) -c LipFilt.cpp
|
||||
|
||||
Modal4.o : Modal4.cpp
|
||||
$(CC) -c Modal4.cpp
|
||||
|
||||
FM4Op.o : FM4Op.cpp
|
||||
$(CC) -c FM4Op.cpp
|
||||
|
||||
FM4Alg3.o : FM4Alg3.cpp
|
||||
$(CC) -c FM4Alg3.cpp
|
||||
|
||||
FM4Alg4.o : FM4Alg4.cpp
|
||||
$(CC) -c FM4Alg4.cpp
|
||||
|
||||
FM4Alg5.o : FM4Alg5.cpp
|
||||
$(CC) -c FM4Alg5.cpp
|
||||
|
||||
FM4Alg6.o : FM4Alg6.cpp
|
||||
$(CC) -c FM4Alg6.cpp
|
||||
|
||||
FM4Alg8.o : FM4Alg8.cpp
|
||||
$(CC) -c FM4Alg8.cpp
|
||||
|
||||
Plucked2.o : Plucked2.cpp
|
||||
$(CC) -c Plucked2.cpp
|
||||
|
||||
SamplFlt.o : SamplFlt.cpp
|
||||
$(CC) -c SamplFlt.cpp
|
||||
|
||||
Sampler.o : Sampler.cpp
|
||||
$(CC) -c Sampler.cpp
|
||||
|
||||
VoicForm.o : VoicForm.cpp
|
||||
$(CC) -c VoicForm.cpp
|
||||
|
||||
MIDIText.o : MIDIText.cpp
|
||||
$(CC) -c MIDIText.cpp
|
||||
|
||||
MIDIInpt.o : MIDIInpt.cpp
|
||||
$(CC) -c MIDIInpt.cpp
|
||||
|
||||
VoicMang.o : VoicMang.cpp
|
||||
$(CC) -c VoicMang.cpp
|
||||
|
||||
Reverb.o : Reverb.cpp
|
||||
$(CC) -c Reverb.cpp
|
||||
|
||||
clean :
|
||||
rm $(INSTR)
|
||||
rm *.o
|
||||
|
||||
cleanIns :
|
||||
rm $(INSTR)
|
||||
|
||||
strip :
|
||||
strip $(INSTR)
|
||||
116
Mandolin.cpp
Normal file
116
Mandolin.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/********************************************/
|
||||
/* Commuted Mandolin Subclass of enhanced */
|
||||
/* dual plucked-string model */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* Controls: CONTROL1 = bodySize */
|
||||
/* CONTROL2 = pluckPosition */
|
||||
/* CONTROL3 = loopGain */
|
||||
/* MOD_WHEEL= deTuning */
|
||||
/* */
|
||||
/* Note: Commuted Synthesis, as with many */
|
||||
/* other WaveGuide techniques, is covered */
|
||||
/* by patents, granted, pending, and/or */
|
||||
/* applied-for. Many are assigned to the */
|
||||
/* Board of Trustees, Stanford University. */
|
||||
/* For information, contact the Office of */
|
||||
/* Technology Licensing, Stanford U. */
|
||||
/********************************************/
|
||||
|
||||
#include "Mandolin.h"
|
||||
|
||||
Mandolin :: Mandolin(MY_FLOAT lowestFreq) : Plucked2(lowestFreq)
|
||||
{
|
||||
soundfile = new RawWave("rawwaves/mandpluk.raw");
|
||||
soundfile->normalize(0.05); /* Empirical hack here */
|
||||
soundfile->setLooping(0);
|
||||
dampTime = 0;
|
||||
waveDone = 1;
|
||||
}
|
||||
|
||||
void Mandolin :: pluck(MY_FLOAT amplitude)
|
||||
{ /* this function gets interesting here, */
|
||||
soundfile->reset(); /* because pluck may be longer than */
|
||||
pluckAmp = amplitude; /* string length, so we just reset the */
|
||||
/* soundfile and add in the pluck in */
|
||||
/* the tick method. */
|
||||
combDelay->setDelay(
|
||||
0.5 * pluckPos * lastLength); /* Set Pick Position */
|
||||
/* which puts zeroes at pos*length */
|
||||
dampTime = (long) lastLength; /* See tick method below */
|
||||
waveDone = 0;
|
||||
}
|
||||
|
||||
void Mandolin :: pluck(MY_FLOAT amplitude, MY_FLOAT position)
|
||||
{
|
||||
pluckPos = position; /* pluck position is zeroes at pos*length */
|
||||
this->pluck(amplitude);
|
||||
}
|
||||
|
||||
void Mandolin :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->setFreq(freq);
|
||||
this->pluck(amp);
|
||||
#if defined(_debug_)
|
||||
printf("Mandolin : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Mandolin :: setBodySize(MY_FLOAT size)
|
||||
{
|
||||
soundfile->setRate(size);
|
||||
}
|
||||
|
||||
MY_FLOAT Mandolin :: tick()
|
||||
{
|
||||
MY_FLOAT temp = 0;
|
||||
if (!waveDone) {
|
||||
waveDone = soundfile->informTick(); /* as long as it goes . . . */
|
||||
temp = soundfile->lastOut() * pluckAmp; /* scaled pluck excitation */
|
||||
temp = temp - combDelay->tick(temp); /* with comb filtering */
|
||||
}
|
||||
if (dampTime>=0) { /* Damping hack to help avoid */
|
||||
dampTime -= 1; /* overflow on replucking */
|
||||
lastOutput = delayLine->tick( /* Calculate 1st delay */
|
||||
filter->tick( /* filterered reflection */
|
||||
temp + /* plus pluck excitation */
|
||||
(delayLine->lastOut() * 0.7)));
|
||||
lastOutput += delayLine2->tick( /* and 2nd delay */
|
||||
filter2->tick( /* just like the 1st */
|
||||
temp +
|
||||
(delayLine2->lastOut() * 0.7))); /* that's the whole thing!! */
|
||||
}
|
||||
else { /* No damping hack after 1 period */
|
||||
lastOutput = delayLine->tick( /* Calculate 1st delay */
|
||||
filter->tick( /* filtered reflection */
|
||||
temp + /* plus pluck excitation */
|
||||
(delayLine->lastOut()
|
||||
* loopGain)));
|
||||
lastOutput += delayLine2->tick( /* and 2nd delay */
|
||||
filter2->tick( /* just like the 1st */
|
||||
temp +
|
||||
(delayLine2->lastOut()
|
||||
* loopGain)));
|
||||
}
|
||||
lastOutput *= 2.0;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
void Mandolin :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Mandolin : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == MIDI_control1)
|
||||
this->setBodySize(value * NORM_7 * 2.0);
|
||||
else if (number == MIDI_control2)
|
||||
this->setPluckPos(value * NORM_7);
|
||||
else if (number == MIDI_control3)
|
||||
this->setBaseLoopGain(0.97 + (value * NORM_7 * 0.03));
|
||||
else if (number == MIDI_mod_wheel)
|
||||
this->setDetune(1.0 - (value * NORM_7 * 0.1));
|
||||
else if (number == MIDI_after_touch)
|
||||
this->pluck(value * NORM_7);
|
||||
else {
|
||||
printf("Mandolin : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
41
Mandolin.h
Normal file
41
Mandolin.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/********************************************/
|
||||
/* Commuted Mandolin Subclass of enhanced */
|
||||
/* dual plucked-string model */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* Controls: CONTROL1 = bodySize */
|
||||
/* CONTROL2 = pluckPosition */
|
||||
/* CONTROL3 = loopGain */
|
||||
/* MOD_WHEEL= deTuning */
|
||||
/* */
|
||||
/* Note: Commuted Synthesis, as with many */
|
||||
/* other WaveGuide techniques, is covered */
|
||||
/* by patents, granted, pending, and/or */
|
||||
/* applied-for. All are assigned to the */
|
||||
/* Board of Trustees, Stanford University. */
|
||||
/* For information, contact the Office of */
|
||||
/* Technology Licensing, Stanford U. */
|
||||
/********************************************/
|
||||
|
||||
#if !defined(__Mandolin_h)
|
||||
#define __Mandolin_h
|
||||
|
||||
#include "Plucked2.h"
|
||||
#include "RawWave.h"
|
||||
|
||||
class Mandolin : public Plucked2
|
||||
{
|
||||
protected:
|
||||
RawWave *soundfile;
|
||||
long dampTime;
|
||||
int waveDone;
|
||||
public:
|
||||
Mandolin(MY_FLOAT lowestFreq);
|
||||
void pluck(MY_FLOAT amplitude);
|
||||
void pluck(MY_FLOAT amplitude,MY_FLOAT position);
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
void setBodySize(MY_FLOAT size);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
virtual MY_FLOAT tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
111
Marimba.cpp
Normal file
111
Marimba.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/*******************************************/
|
||||
/* Marimba SubClass of Modal4 Instrument, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Controls: CONTROL1 = stickHardness */
|
||||
/* CONTROL2 = strikePosition*/
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/*******************************************/
|
||||
|
||||
#include "Marimba.h"
|
||||
|
||||
Marimba :: Marimba() : Modal4()
|
||||
{
|
||||
wave = new RawWave("rawwaves/marmstk1.raw");
|
||||
wave->normalize();
|
||||
wave->setRate(0.5); /* normal stick */
|
||||
this->setRatioAndReson(0, 1.00,0.9996); /* Set all 132.0 */
|
||||
this->setRatioAndReson(1, 3.99,0.9994); /* of our 523.0 */
|
||||
this->setRatioAndReson(2,10.65,0.9994); /* default 1405.0 */
|
||||
this->setRatioAndReson(3,-18.50,0.999); /* resonances 2443.0 */
|
||||
this->setFiltGain(0,0.08); /* and */
|
||||
this->setFiltGain(1,0.02); /* gains */
|
||||
this->setFiltGain(2,0.02); /* for each */
|
||||
this->setFiltGain(3,0.015); /* resonance */
|
||||
directGain = 0.1;
|
||||
multiStrike = 0;
|
||||
}
|
||||
|
||||
Marimba :: ~Marimba()
|
||||
{
|
||||
}
|
||||
|
||||
void Marimba :: setStickHardness(MY_FLOAT hardness)
|
||||
{
|
||||
stickHardness = hardness;
|
||||
wave->setRate(0.25 * pow(4.0,stickHardness));
|
||||
masterGain = 0.1 + (1.8 * stickHardness);
|
||||
}
|
||||
|
||||
void Marimba :: setStrikePosition(MY_FLOAT position)
|
||||
{
|
||||
MY_FLOAT temp,temp2;
|
||||
temp2 = position * PI;
|
||||
strikePosition = position; /* Hack only first three modes */
|
||||
temp = sin(temp2);
|
||||
this->setFiltGain(0,0.12 * temp); /* 1st mode function of pos. */
|
||||
temp = sin(0.05 + (3.9 * temp2));
|
||||
this->setFiltGain(1,-0.03 * temp); /* 2nd mode function of pos. */
|
||||
temp = sin(-0.05 + (11 * temp2));
|
||||
this->setFiltGain(2,0.11 * temp); /* 3rd mode function of pos. */
|
||||
}
|
||||
|
||||
void Marimba :: setModulationSpeed(MY_FLOAT mSpeed)
|
||||
{
|
||||
/* don't bother here, marimba decay so fast, mod doesn't make sense */
|
||||
}
|
||||
|
||||
void Marimba :: setModulationDepth(MY_FLOAT mDepth)
|
||||
{
|
||||
}
|
||||
|
||||
void Marimba :: strike(MY_FLOAT amplitude)
|
||||
{
|
||||
int temp;
|
||||
temp = random() >> 26;
|
||||
if (temp < 2) {
|
||||
multiStrike = 1;
|
||||
#if defined(_debug_)
|
||||
printf("striking twice here!!\n");
|
||||
#endif
|
||||
}
|
||||
else if (temp < 1) {
|
||||
multiStrike = 2;
|
||||
#if defined(_debug_)
|
||||
printf("striking three times here!!!\n");
|
||||
#endif
|
||||
}
|
||||
else multiStrike = 0;
|
||||
Modal4::strike(amplitude);
|
||||
}
|
||||
|
||||
void Marimba :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Marimba : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == MIDI_control1)
|
||||
this->setStickHardness(value * NORM_7);
|
||||
else if (number == MIDI_control2)
|
||||
this->setStrikePosition(value * NORM_7);
|
||||
else if (number == MIDI_control3)
|
||||
vibr->setFreq((value * NORM_7 * 12.0));
|
||||
else if (number == MIDI_mod_wheel)
|
||||
vibrGain = (value * NORM_7);
|
||||
else if (number == MIDI_after_touch)
|
||||
this->strike(value * NORM_7);
|
||||
else {
|
||||
printf("Marimba : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
MY_FLOAT Marimba :: tick()
|
||||
{
|
||||
if (multiStrike>0)
|
||||
if (wave->isAllDone()) {
|
||||
wave->reset();
|
||||
multiStrike -= 1;
|
||||
}
|
||||
return Modal4::tick();
|
||||
}
|
||||
32
Marimba.h
Normal file
32
Marimba.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*******************************************/
|
||||
/* Marimba SubClass of Modal4 Instrument, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Controls: CONTROL1 = stickHardness */
|
||||
/* CONTROL2 = strikePosition*/
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__Marimba_h)
|
||||
#define __Marimba_h
|
||||
|
||||
#include "Modal4.h"
|
||||
|
||||
class Marimba : public Modal4
|
||||
{
|
||||
private:
|
||||
int multiStrike;
|
||||
public:
|
||||
Marimba();
|
||||
~Marimba();
|
||||
void setStickHardness(MY_FLOAT hardness);
|
||||
void setStrikePosition(MY_FLOAT position);
|
||||
void setModulationSpeed(MY_FLOAT mSpeed);
|
||||
void setModulationDepth(MY_FLOAT mDepth);
|
||||
virtual void strike(MY_FLOAT amplitude);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
virtual MY_FLOAT tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
187
Modal4.cpp
Normal file
187
Modal4.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
/*******************************************/
|
||||
/* 4 Resonance Modal Synthesis Instrument */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This instrument contains an excitation */
|
||||
/* wavetable, an envelope, and four reso- */
|
||||
/* nances (Non-Sweeping BiQuad Filters). */
|
||||
/*******************************************/
|
||||
|
||||
#include "Modal4.h"
|
||||
|
||||
Modal4 :: Modal4()
|
||||
{
|
||||
envelope = new Envelope;
|
||||
/* We don't make the excitation wave here yet, */
|
||||
/* because we don't know what it's going to be. */
|
||||
filters[0] = new BiQuad;
|
||||
filters[1] = new BiQuad;
|
||||
filters[2] = new BiQuad;
|
||||
filters[3] = new BiQuad;
|
||||
onepole = new OnePole;
|
||||
|
||||
vibr = new RawLoop("rawwaves/sinewave.raw");
|
||||
vibr->normalize();
|
||||
vibr->setFreq(6.0);
|
||||
vibrGain = 0.05;
|
||||
|
||||
directGain = 0.0;
|
||||
masterGain = 1.0;
|
||||
baseFreq = 440.0;
|
||||
this->setRatioAndReson(0,1.00,0.9997); /* Set some */
|
||||
this->setRatioAndReson(1,1.30,0.9997); /* silly */
|
||||
this->setRatioAndReson(2,1.77,0.9997); /* default */
|
||||
this->setRatioAndReson(3,2.37,0.9997); /* values here */
|
||||
this->setFiltGain(0,0.01);
|
||||
this->setFiltGain(1,0.01);
|
||||
this->setFiltGain(2,0.01);
|
||||
this->setFiltGain(3,0.01);
|
||||
this->clear();
|
||||
filters[0]->setEqualGainZeroes();
|
||||
filters[1]->setEqualGainZeroes();
|
||||
filters[2]->setEqualGainZeroes();
|
||||
filters[3]->setEqualGainZeroes();
|
||||
stickHardness = 0.5;
|
||||
strikePosition = 0.561;
|
||||
}
|
||||
|
||||
Modal4 :: ~Modal4()
|
||||
{
|
||||
delete envelope;
|
||||
delete wave;
|
||||
delete filters[0];
|
||||
delete filters[1];
|
||||
delete filters[2];
|
||||
delete filters[3];
|
||||
delete onepole;
|
||||
delete vibr;
|
||||
}
|
||||
|
||||
void Modal4 :: clear()
|
||||
{
|
||||
onepole->clear();
|
||||
filters[0]->clear();
|
||||
filters[1]->clear();
|
||||
filters[2]->clear();
|
||||
filters[3]->clear();
|
||||
}
|
||||
|
||||
void Modal4 :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
this->setRatioAndReson(0,ratios[0],resons[0]);
|
||||
this->setRatioAndReson(1,ratios[1],resons[1]);
|
||||
this->setRatioAndReson(2,ratios[2],resons[2]);
|
||||
this->setRatioAndReson(3,ratios[3],resons[3]);
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void Modal4 :: setRatioAndReson(int whichOne, MY_FLOAT ratio,MY_FLOAT reson)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
if (ratio*baseFreq < SRATE_OVER_TWO) {
|
||||
ratios[whichOne] = ratio;
|
||||
}
|
||||
else {
|
||||
temp = ratio;
|
||||
while (temp*baseFreq > SRATE_OVER_TWO) temp *= 0.5;
|
||||
ratios[whichOne] = temp;
|
||||
#if defined(_debug_)
|
||||
printf("Modal4 : Aliasing would occur here, correcting.\n");
|
||||
#endif
|
||||
}
|
||||
resons[whichOne] = reson;
|
||||
if (ratio<0)
|
||||
temp = -ratio;
|
||||
else
|
||||
temp = ratio*baseFreq;
|
||||
filters[whichOne]->setFreqAndReson(temp,reson);
|
||||
}
|
||||
|
||||
void Modal4 :: setMasterGain(MY_FLOAT aGain)
|
||||
{
|
||||
masterGain = aGain;
|
||||
}
|
||||
|
||||
void Modal4 :: setDirectGain(MY_FLOAT aGain)
|
||||
{
|
||||
directGain = aGain;
|
||||
}
|
||||
|
||||
void Modal4 :: setFiltGain(int whichOne, MY_FLOAT gain)
|
||||
{
|
||||
filters[whichOne]->setGain(gain);
|
||||
}
|
||||
|
||||
void Modal4 :: strike(MY_FLOAT amplitude)
|
||||
{
|
||||
int i;
|
||||
MY_FLOAT temp;
|
||||
envelope->setRate(1.0);
|
||||
envelope->setTarget(amplitude);
|
||||
onepole->setPole(1.0 - amplitude);
|
||||
envelope->tick();
|
||||
wave->reset();
|
||||
for (i=0;i<4;i++) {
|
||||
if (ratios[i] < 0)
|
||||
temp = -ratios[i];
|
||||
else
|
||||
temp = ratios[i] * baseFreq;
|
||||
filters[i]->setFreqAndReson(temp,resons[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Modal4 :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->strike(amp);
|
||||
this->setFreq(freq);
|
||||
#if defined(_debug_)
|
||||
printf("Modal4 : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Modal4 :: noteOff(MY_FLOAT amp) /* This calls damp, but inverts the */
|
||||
{ /* meaning of amplitude. */
|
||||
this->damp(1.0 - (amp * 0.03)); /* (high amplitude means fast damping) */
|
||||
#if defined(_debug_)
|
||||
printf("Modal4 : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Modal4 :: damp(MY_FLOAT amplitude)
|
||||
{
|
||||
int i;
|
||||
MY_FLOAT temp;
|
||||
for (i=0;i<4;i++) {
|
||||
if (ratios[i] < 0)
|
||||
temp = -ratios[i];
|
||||
else
|
||||
temp = ratios[i] * baseFreq;
|
||||
filters[i]->setFreqAndReson(temp,resons[i]*amplitude);
|
||||
}
|
||||
}
|
||||
|
||||
void Modal4 :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT Modal4 :: tick()
|
||||
{
|
||||
MY_FLOAT temp,temp2;
|
||||
temp = masterGain * onepole->tick(wave->tick() * envelope->tick());
|
||||
temp2 = filters[0]->tick(temp);
|
||||
temp2 += filters[1]->tick(temp);
|
||||
temp2 += filters[2]->tick(temp);
|
||||
temp2 += filters[3]->tick(temp);
|
||||
temp2 = temp2 - (temp2 * directGain);
|
||||
temp2 += directGain * temp;
|
||||
|
||||
if (vibrGain != 0.0) {
|
||||
temp = 1.0 + (vibr->tick() * vibrGain); /* Calculate AM */
|
||||
temp2 = temp * temp2; /* and apply to master out */
|
||||
}
|
||||
|
||||
lastOutput = temp2 * 2.0;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
52
Modal4.h
Normal file
52
Modal4.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*******************************************/
|
||||
/* 4 Resonance Modal Synthesis Instrument */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This instrument contains an excitation */
|
||||
/* wavetable, an envelope, and four reso- */
|
||||
/* nances (Non-Sweeping BiQuad Filters). */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__Modal4_h)
|
||||
#define __Modal4_h
|
||||
|
||||
#include "Instrmnt.h"
|
||||
#include "Envelope.h"
|
||||
#include "RawWave.h"
|
||||
#include "RawLoop.h"
|
||||
#include "BiQuad.h"
|
||||
#include "OnePole.h"
|
||||
|
||||
class Modal4 : public Instrmnt
|
||||
{
|
||||
protected:
|
||||
Envelope *envelope;
|
||||
RawWave *wave;
|
||||
BiQuad *filters[4];
|
||||
OnePole *onepole;
|
||||
RawLoop *vibr;
|
||||
MY_FLOAT vibrGain;
|
||||
MY_FLOAT masterGain;
|
||||
MY_FLOAT directGain;
|
||||
MY_FLOAT stickHardness;
|
||||
MY_FLOAT strikePosition;
|
||||
MY_FLOAT baseFreq;
|
||||
MY_FLOAT ratios[4];
|
||||
MY_FLOAT resons[4];
|
||||
public:
|
||||
Modal4();
|
||||
~Modal4();
|
||||
void clear();
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
void setRatioAndReson(int whichOne, MY_FLOAT ratio, MY_FLOAT reson);
|
||||
void setMasterGain(MY_FLOAT aGain);
|
||||
void setDirectGain(MY_FLOAT aGain);
|
||||
void setFiltGain(int whichOne, MY_FLOAT gain);
|
||||
virtual void strike(MY_FLOAT amplitude);
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
virtual void noteOff(MY_FLOAT amp);
|
||||
void damp(MY_FLOAT amplitude);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
virtual MY_FLOAT tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
84
Modulatr.cpp
Normal file
84
Modulatr.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/*******************************************/
|
||||
/* Modulator Class, Perry R. Cook, 1995-96*/
|
||||
/* This Object combines random and */
|
||||
/* periodic modulations to give a nice */
|
||||
/* natural human modulation function. */
|
||||
/*******************************************/
|
||||
|
||||
#define POLE_POS 0.999
|
||||
#define RND_SCALE 10.0
|
||||
|
||||
#include "Modulatr.h"
|
||||
|
||||
Modulatr :: Modulatr()
|
||||
{
|
||||
vibwave = new RawWave("rawwaves/sinewave.raw");
|
||||
vibwave->normalize();
|
||||
vibwave->setFreq(6.0);
|
||||
vibwave->setLooping(1);
|
||||
vibAmt = 0.04;
|
||||
noise = new SubNoise(330);
|
||||
rndAmt = 0.005;
|
||||
onepole = new OnePole;
|
||||
onepole->setPole(POLE_POS);
|
||||
onepole->setGain(rndAmt * RND_SCALE);
|
||||
}
|
||||
|
||||
Modulatr :: ~Modulatr()
|
||||
{
|
||||
delete vibwave;
|
||||
delete noise;
|
||||
delete onepole;
|
||||
}
|
||||
|
||||
void Modulatr :: reset()
|
||||
{
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
|
||||
void Modulatr :: setVibFreq(double vibFreq)
|
||||
{
|
||||
vibwave->setFreq(vibFreq);
|
||||
}
|
||||
|
||||
void Modulatr :: setVibAmt(double vibAmount)
|
||||
{
|
||||
vibAmt = vibAmount;
|
||||
}
|
||||
|
||||
void Modulatr :: setRndAmt(double rndAmount)
|
||||
{
|
||||
rndAmt = rndAmount;
|
||||
onepole->setGain(RND_SCALE * rndAmt);
|
||||
}
|
||||
|
||||
double Modulatr :: tick()
|
||||
{
|
||||
lastOutput = vibAmt * vibwave->tick(); /* Compute periodic and */
|
||||
lastOutput += onepole->tick(noise->tick()); /* random modulations */
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
double Modulatr :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
void main()
|
||||
{
|
||||
Modulatr testMod;
|
||||
FILE *fd;
|
||||
short data;
|
||||
long i;
|
||||
|
||||
fd = fopen("test.raw","wb");
|
||||
|
||||
for (i=0;i<20000;i++) {
|
||||
data = testMod.tick() * 32000.0;
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
36
Modulatr.h
Normal file
36
Modulatr.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*******************************************/
|
||||
/* Modulator Class, Perry R. Cook, 1995-96*/
|
||||
/* This Object combines random and */
|
||||
/* periodic modulations to give a nice */
|
||||
/* natural human modulation function. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__Modulatr_h)
|
||||
#define __Modulatr_h
|
||||
|
||||
#include "Object.h"
|
||||
#include "RawWave.h"
|
||||
#include "SubNoise.h"
|
||||
#include "OnePole.h"
|
||||
|
||||
class Modulatr : public Object
|
||||
{
|
||||
protected:
|
||||
RawWave *vibwave;
|
||||
SubNoise *noise;
|
||||
OnePole *onepole;
|
||||
double vibAmt;
|
||||
double rndAmt;
|
||||
double lastOutput;
|
||||
public:
|
||||
Modulatr();
|
||||
~Modulatr();
|
||||
void reset();
|
||||
void setVibFreq(double vibFreq);
|
||||
void setVibAmt(double vibAmount);
|
||||
void setRndAmt(double rndAmount);
|
||||
double tick();
|
||||
double lastOut();
|
||||
};
|
||||
|
||||
#endif
|
||||
108
Moog1.cpp
Normal file
108
Moog1.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
/******************************************/
|
||||
/* Test Sampler Subclass of */
|
||||
/* Sampling Synthesizer Class */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Controls: CONTROL1 = filterQ */
|
||||
/* CONTROL2 = filterRate */
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/******************************************/
|
||||
|
||||
#include "Moog1.h"
|
||||
|
||||
Moog1 :: Moog1() : SamplFlt()
|
||||
{
|
||||
attacks[0] = new RawWave("rawwaves/mandpluk.raw");
|
||||
loops[0] = new RawWave("rawwaves/impuls20.raw");
|
||||
loops[1] = new RawWave("rawwaves/sinewave.raw"); /* Steal one for vibrato */
|
||||
attacks[0]->normalize();
|
||||
loops[0]->normalize();
|
||||
loops[0]->setLooping(1);
|
||||
loops[1]->normalize();
|
||||
loops[1]->setLooping(1);
|
||||
loops[1]->setFreq(6.122);
|
||||
adsr->setAll(0.05,0.00003,0.6,0.0002);
|
||||
filterQ = 0.85;
|
||||
filterRate = 0.0001;
|
||||
modDepth = 0.0;
|
||||
}
|
||||
|
||||
Moog1 :: ~Moog1()
|
||||
{
|
||||
delete attacks[0];
|
||||
delete loops[0];
|
||||
delete loops[1];
|
||||
}
|
||||
|
||||
void Moog1 :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
attacks[0]->setFreq(baseFreq * 0.01);
|
||||
loops[0]->setFreq(baseFreq);
|
||||
}
|
||||
|
||||
void Moog1 :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
|
||||
this->setFreq(freq);
|
||||
this->keyOn();
|
||||
attackGain = amp * 0.5;
|
||||
loopGain = amp;
|
||||
|
||||
temp = filterQ+0.05;
|
||||
filters[0]->setStates(2000,temp,2.0 * (1.0 - temp));
|
||||
filters[1]->setStates(2000,temp,2.0 * (1.0 - temp));
|
||||
temp = filterQ+0.099;
|
||||
filters[0]->setTargets( 0,temp,2.0 * (1.0 - temp));
|
||||
filters[1]->setTargets( 0,temp,2.0 * (1.0 - temp));
|
||||
filters[0]->setSweepRate(filterRate * RATE_NORM);
|
||||
filters[1]->setSweepRate(filterRate * RATE_NORM);
|
||||
#if defined(_debug_)
|
||||
printf("Moog1 : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Moog1 :: setModulationSpeed(MY_FLOAT mSpeed)
|
||||
{
|
||||
loops[1]->setFreq(mSpeed);
|
||||
}
|
||||
|
||||
void Moog1 :: setModulationDepth(MY_FLOAT mDepth)
|
||||
{
|
||||
modDepth = mDepth * 0.5;
|
||||
}
|
||||
|
||||
void Moog1 :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Moog1 : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == MIDI_control1)
|
||||
filterQ = 0.80 + (0.1 * value * NORM_7);
|
||||
else if (number == MIDI_control2)
|
||||
filterRate = (value * NORM_7 * 0.0002);
|
||||
else if (number == MIDI_control3)
|
||||
this->setModulationSpeed(value * NORM_7 * 12.0);
|
||||
else if (number == MIDI_mod_wheel)
|
||||
this->setModulationDepth(value * NORM_7);
|
||||
else if (number == MIDI_after_touch)
|
||||
adsr->setTarget(value * NORM_7);
|
||||
else {
|
||||
printf("Moog1 : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
MY_FLOAT Moog1 :: tick()
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
|
||||
if (modDepth!=0.0) {
|
||||
temp = loops[1]->tick() * modDepth;
|
||||
loops[0]->setFreq(baseFreq * (1.0 + temp));
|
||||
}
|
||||
lastOutput = SamplFlt :: tick();
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
34
Moog1.h
Normal file
34
Moog1.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/******************************************/
|
||||
/* Moog1 Subclass of */
|
||||
/* Sampling Synthesizer Class */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Controls: CONTROL1 = filterQ */
|
||||
/* CONTROL2 = filterRate */
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__Moog1_h)
|
||||
#define __Moog1_h
|
||||
|
||||
#include "SamplFlt.h"
|
||||
|
||||
class Moog1 : public SamplFlt
|
||||
{
|
||||
private:
|
||||
MY_FLOAT modDepth;
|
||||
MY_FLOAT filterQ;
|
||||
MY_FLOAT filterRate;
|
||||
public:
|
||||
Moog1();
|
||||
~Moog1();
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
void setModulationSpeed(MY_FLOAT mSpeed);
|
||||
void setModulationDepth(MY_FLOAT mDepth);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
virtual MY_FLOAT tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
163
NIFileIn.cpp
Normal file
163
NIFileIn.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
/*******************************************/
|
||||
/* NonInterpolating One-Shot Raw Sound- */
|
||||
/* file Class, by Perry R. Cook, 1995-96 */
|
||||
/* This Object can open a raw 16bit data */
|
||||
/* (signed integers) file, and play back */
|
||||
/* the data once, with no interpolation */
|
||||
/* on playback. Once finished, it closes */
|
||||
/* the file, the file is reopened with */
|
||||
/* the reset() method. */
|
||||
/* This is useful for small memory model, */
|
||||
/* applications, or for streaming from */
|
||||
/* disk (and generally non real-time */
|
||||
/* applications). */
|
||||
/*******************************************/
|
||||
|
||||
#include "NIFileIn.h"
|
||||
|
||||
NIFileIn :: NIFileIn(char *fileName)
|
||||
{
|
||||
long i;
|
||||
|
||||
strcpy(fileNm,fileName);
|
||||
|
||||
myFile = fopen(fileNm,"rb");
|
||||
if (!myFile) {
|
||||
printf("Couldn't find soundfile %s !!!!!!!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (fread(&data,2,1,myFile)) i++;
|
||||
length = i;
|
||||
fseek(myFile,0,0);
|
||||
time = 0.0;
|
||||
rate = 1.0;
|
||||
lastTime = 0;
|
||||
finished = 0;
|
||||
gain = 1.0;
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
|
||||
NIFileIn :: ~NIFileIn()
|
||||
{
|
||||
this->finish();
|
||||
}
|
||||
|
||||
void NIFileIn :: reset()
|
||||
{
|
||||
if (finished) {
|
||||
myFile = fopen(fileNm,"rb");
|
||||
}
|
||||
fseek(myFile,0,0);
|
||||
|
||||
printf("Resetting\n");
|
||||
time = 0.0;
|
||||
lastTime = 0;
|
||||
finished = 0;
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
|
||||
void NIFileIn :: normalize()
|
||||
{
|
||||
this->normalize(1.0);
|
||||
}
|
||||
|
||||
void NIFileIn :: normalize(MY_FLOAT newPeak)
|
||||
{
|
||||
long i;
|
||||
FILE *fd;
|
||||
|
||||
gain = 0.0;
|
||||
|
||||
fd = fopen(fileNm,"rb");
|
||||
for (i=0;i<length;i++) {
|
||||
fread(&data,2,1,fd);
|
||||
if (fabs(data) > gain)
|
||||
gain = fabs(data);
|
||||
}
|
||||
if (gain > 0.0) {
|
||||
gain = newPeak / gain;
|
||||
}
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
void NIFileIn :: setRate(MY_FLOAT aRate)
|
||||
{
|
||||
rate = aRate;
|
||||
}
|
||||
|
||||
void NIFileIn :: finish()
|
||||
{
|
||||
finished = 1;
|
||||
lastOutput = 0.0;
|
||||
if (myFile) {
|
||||
fclose(myFile);
|
||||
myFile = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MY_FLOAT NIFileIn :: tick()
|
||||
{
|
||||
this->informTick();
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
int NIFileIn :: informTick()
|
||||
{
|
||||
long temp;
|
||||
|
||||
if (!finished) {
|
||||
|
||||
time += rate; /* Update current time */
|
||||
|
||||
if (time >= length) { /* Check for end of sound */
|
||||
time = length - 1; /* stick at end */
|
||||
finished = 1; /* Information for one-shot use */
|
||||
fclose(myFile);
|
||||
myFile = 0;
|
||||
}
|
||||
else {
|
||||
temp = (long) time; /* Integer part of time address */
|
||||
if (temp > lastTime) { /* If we cross next sample time */
|
||||
lastTime = temp;
|
||||
fread(&data,2,1,myFile); /* Snarf next sample from file */
|
||||
lastOutput = data * gain; /* And save as non-interpolated data */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return finished;
|
||||
}
|
||||
|
||||
MY_FLOAT NIFileIn :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
void main()
|
||||
{
|
||||
NIFileIn oneShot("rawwaves/mandpluk.raw");
|
||||
FILE *fd;
|
||||
short data;
|
||||
long i;
|
||||
|
||||
fd = fopen("test.raw","wb");
|
||||
oneShot.setRate(1.0);
|
||||
while (!oneShot.informTick()) {
|
||||
data = oneShot.lastOut();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
oneShot.reset();
|
||||
oneShot.setRate(0.5);
|
||||
for (i=0;i<16384;i++) {
|
||||
data = oneShot.tick();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
|
||||
47
NIFileIn.h
Normal file
47
NIFileIn.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*******************************************/
|
||||
/* NonInterpolating One-Shot Raw Sound- */
|
||||
/* file Class, by Perry R. Cook, 1995-96 */
|
||||
/* This Object can open a raw 16bit data */
|
||||
/* (signed integers) file, and play back */
|
||||
/* the data once, with no interpolation */
|
||||
/* on playback. Once finished, it closes */
|
||||
/* the file, the file is reopened with */
|
||||
/* the reset() method. */
|
||||
/* This is useful for small memory model, */
|
||||
/* applications, or for streaming from */
|
||||
/* disk (and generally non real-time */
|
||||
/* applications). */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__NIFileIn_h)
|
||||
#define __NIFileIn_h
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class NIFileIn : public Object
|
||||
{
|
||||
protected:
|
||||
long length;
|
||||
long lastTime;
|
||||
int finished;
|
||||
short data;
|
||||
char fileNm[128];
|
||||
FILE *myFile;
|
||||
MY_FLOAT rate;
|
||||
MY_FLOAT time;
|
||||
MY_FLOAT gain;
|
||||
MY_FLOAT lastOutput;
|
||||
public:
|
||||
NIFileIn(char *fileName);
|
||||
~NIFileIn();
|
||||
void reset();
|
||||
void normalize();
|
||||
void normalize(MY_FLOAT newPeak);
|
||||
void setRate(MY_FLOAT aRate);
|
||||
void finish();
|
||||
MY_FLOAT tick();
|
||||
int informTick();
|
||||
MY_FLOAT lastOut();
|
||||
};
|
||||
|
||||
#endif
|
||||
119
NIWave1S.cpp
Normal file
119
NIWave1S.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
/*******************************************/
|
||||
/* NonInterpolating One-Shot Raw Sound- */
|
||||
/* file Class, by Perry R. Cook, 1995-96 */
|
||||
/* This Object can open a raw 16bit data */
|
||||
/* (signed integers) file, and play back */
|
||||
/* the data once (again when reset), with */
|
||||
/* no interpolation on playback. */
|
||||
/*******************************************/
|
||||
|
||||
#include "NIWave1S.h"
|
||||
|
||||
NIWave1S :: NIWave1S(char *fileName)
|
||||
{
|
||||
long i;
|
||||
short temp;
|
||||
FILE *fd;
|
||||
fd = fopen(fileName,"rb");
|
||||
if (!fd) {
|
||||
printf("Couldn't find soundfile %s !!!!!!!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
i = 0;
|
||||
while (fread(&temp,2,1,fd)) i++;
|
||||
length = i;
|
||||
fseek(fd,0,0);
|
||||
data = (MY_FLOAT *) malloc(MY_FLOAT_SIZE * (length + 1));
|
||||
i = 0;
|
||||
while (fread(&temp,2,1,fd)) {
|
||||
data[i] = temp;
|
||||
i++;
|
||||
}
|
||||
data[length] = data[length-1];
|
||||
fclose(fd);
|
||||
time = 0.0;
|
||||
rate = 1.0;
|
||||
}
|
||||
|
||||
void NIWave1S :: reset()
|
||||
{
|
||||
time = 0.0;
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
|
||||
void NIWave1S :: normalize()
|
||||
{
|
||||
this->normalize(1.0);
|
||||
}
|
||||
|
||||
void NIWave1S :: normalize(MY_FLOAT newPeak)
|
||||
{
|
||||
long i;
|
||||
MY_FLOAT max = 0.0;
|
||||
for (i=0;i<=length;i++)
|
||||
if (fabs(data[i]) > max)
|
||||
max = fabs(data[i]);
|
||||
if (max > 0.0) {
|
||||
max = 1.0 / max;
|
||||
max *= newPeak;
|
||||
for (i=0;i<=length;i++)
|
||||
data[i] *= max;
|
||||
}
|
||||
}
|
||||
|
||||
void NIWave1S :: setRate(MY_FLOAT aRate)
|
||||
{
|
||||
rate = aRate;
|
||||
}
|
||||
|
||||
MY_FLOAT NIWave1S :: tick()
|
||||
{
|
||||
this->informTick();
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
int NIWave1S :: informTick()
|
||||
{
|
||||
int allDone = 0;
|
||||
long temp;
|
||||
|
||||
time += rate; /* Update current time */
|
||||
|
||||
if (time >= length) { /* Check for end of sound */
|
||||
time = length-1; /* stick at end */
|
||||
allDone = 1; /* Information for one-shot use */
|
||||
}
|
||||
temp = (long) time; /* Integer part of time address */
|
||||
lastOutput = data[temp]; /* Get non-interpolated data */
|
||||
|
||||
return allDone;
|
||||
}
|
||||
|
||||
MY_FLOAT NIWave1S :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
void main()
|
||||
{
|
||||
NIWave1S oneShot("rawwaves/mandpluk.raw");
|
||||
FILE *fd;
|
||||
short data;
|
||||
long i;
|
||||
|
||||
fd = fopen("test.raw","wb");
|
||||
for (i=0;i<8192;i++) {
|
||||
data = oneShot.tick();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
oneShot.reset();
|
||||
oneShot.setRate(0.5);
|
||||
for (i=0;i<16384;i++) {
|
||||
data = oneShot.tick();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
34
NIWave1S.h
Normal file
34
NIWave1S.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*******************************************/
|
||||
/* NonInterpolating One-Shot Raw Sound- */
|
||||
/* file Class, by Perry R. Cook, 1995-96 */
|
||||
/* This Object can open a raw 16bit data */
|
||||
/* (signed integers) file, and play back */
|
||||
/* the data once (again when reset), with */
|
||||
/* no interpolation on playback. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__NIWave1S_h)
|
||||
#define __NIWave1S_h
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class NIWave1S : public Object
|
||||
{
|
||||
protected:
|
||||
long length;
|
||||
MY_FLOAT *data;
|
||||
MY_FLOAT rate;
|
||||
MY_FLOAT time;
|
||||
MY_FLOAT lastOutput;
|
||||
public:
|
||||
NIWave1S(char *fileName);
|
||||
void reset();
|
||||
void normalize();
|
||||
void normalize(MY_FLOAT newPeak);
|
||||
void setRate(MY_FLOAT aRate);
|
||||
MY_FLOAT tick();
|
||||
int informTick();
|
||||
MY_FLOAT lastOut();
|
||||
};
|
||||
|
||||
#endif
|
||||
52
Noise.cpp
Normal file
52
Noise.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/*******************************************/
|
||||
/* Noise Generator Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* White noise as often as you like. */
|
||||
/*******************************************/
|
||||
|
||||
#include "Noise.h"
|
||||
|
||||
Noise :: Noise() : Object()
|
||||
{
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
|
||||
Noise :: ~Noise()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* THIS IS FOR TURBO C */
|
||||
/* Constant = 1.0 / 16384.0 */
|
||||
/* #define ONE_OVER_RANDLIMIT 0.00006103516 */
|
||||
|
||||
|
||||
/* THIS IS FOR UNIX, NeXT and SGI */
|
||||
#define ONE_OVER_RANDLIMIT 0.00000000093132258
|
||||
|
||||
MY_FLOAT Noise :: tick()
|
||||
{
|
||||
/* THIS ONE IS TURBO C */
|
||||
/* lastOutput = (MY_FLOAT) random(32767) - 16384.0; */
|
||||
|
||||
/* THIS IS FOR UNIX, NeXT and SGI */
|
||||
|
||||
lastOutput = (MY_FLOAT) random() - 1073741823.0;
|
||||
lastOutput *= ONE_OVER_RANDLIMIT;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT Noise :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main ************************/
|
||||
/*
|
||||
void main()
|
||||
{
|
||||
long i;
|
||||
Noise test;
|
||||
for (i=0;i<20;i++) printf("%lf\n",test.tick());
|
||||
}
|
||||
*/
|
||||
23
Noise.h
Normal file
23
Noise.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*******************************************/
|
||||
/* Noise Generator Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* White noise as often as you like. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__Noise_h)
|
||||
#define __Noise_h
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class Noise : public Object
|
||||
{
|
||||
protected:
|
||||
MY_FLOAT lastOutput;
|
||||
public:
|
||||
Noise();
|
||||
~Noise();
|
||||
virtual MY_FLOAT tick();
|
||||
MY_FLOAT lastOut();
|
||||
};
|
||||
|
||||
#endif
|
||||
29
Object.cpp
Normal file
29
Object.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
/*******************************************/
|
||||
/* Object Class, by Perry R. Cook, 1995-96*/
|
||||
/* This is mostly here for compatibility */
|
||||
/* with Objective C. We'll also stick */
|
||||
/* global defines here, so everyone will */
|
||||
/* see them. */
|
||||
/*******************************************/
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
|
||||
/* This is just here for compatibility and convenience,
|
||||
so there's no need to do any real calculations.
|
||||
I do set up some redefinable variables here. */
|
||||
|
||||
|
||||
Object :: Object()
|
||||
{
|
||||
MIDI_mod_wheel = 1; /* Controller # 1 */
|
||||
MIDI_control1 = 2; /* Breath Pressure */
|
||||
MIDI_control2 = 4; /* Foot Control */
|
||||
MIDI_control3 = 11; /* Expression Pedal */
|
||||
MIDI_after_touch = 128; /* Channel Pressure -> new controller */
|
||||
}
|
||||
|
||||
Object :: ~Object()
|
||||
{
|
||||
}
|
||||
|
||||
91
Object.h
Normal file
91
Object.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*******************************************/
|
||||
/* Object Class, by Perry R. Cook, 1995-96*/
|
||||
/* This is mostly here for compatibility */
|
||||
/* with Objective C. We'll also stick */
|
||||
/* global defines here, so everyone will */
|
||||
/* see them. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__Object_h)
|
||||
#define __Object_h
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
int MIDI_control1;
|
||||
int MIDI_control2;
|
||||
int MIDI_control3;
|
||||
int MIDI_mod_wheel;
|
||||
int MIDI_after_touch;
|
||||
protected:
|
||||
Object();
|
||||
~Object();
|
||||
};
|
||||
|
||||
/* Only use one of __SGI_ __NeXT_ __DOS_ */
|
||||
/* And choice of __SGI_REALTIME or not */
|
||||
|
||||
#define __SGI_
|
||||
#define __SGI_REALTIME
|
||||
/* #define __NeXT_ */
|
||||
|
||||
/* SRATE here is 44100, others are derived accordingly */
|
||||
/* #define SRATE 44100.0
|
||||
#define SRATE_OVER_TWO 22050.0
|
||||
#define ONE_OVER_SRATE 0.00002267573696
|
||||
#define RATE_NORM 0.5
|
||||
*/
|
||||
|
||||
/* SRATE here is 22050, others are derived accordingly */
|
||||
#define SRATE 22050.0
|
||||
#define SRATE_OVER_TWO 11025.0
|
||||
#define ONE_OVER_SRATE 0.00004535147392
|
||||
#define RATE_NORM 1.0
|
||||
|
||||
|
||||
/* SRATE here is 8k, others are derived accordingly */
|
||||
/* #define SRATE 8000.0
|
||||
#define SRATE_OVER_TWO 4000
|
||||
#define ONE_OVER_SRATE 0.00012500000000
|
||||
#define RATE_NORM 2.75625
|
||||
*/
|
||||
/* RATE_NORM is 22050 / 8000 */
|
||||
|
||||
/* Yer Basic Trigonometric constants */
|
||||
#define PI 3.14159265359
|
||||
#define TWO_PI 6.28318530718
|
||||
#define ONE_OVER_TWO_PI 0.15915494309
|
||||
|
||||
/* States for Envelopes, etc. */
|
||||
|
||||
#define ATTACK 0
|
||||
#define DECAY 1
|
||||
#define SUSTAIN 2
|
||||
#define RELEASE 3
|
||||
|
||||
/* Machine dependent stuff, possibly useful for optimization */
|
||||
/* for example, changing double to float here increases */
|
||||
/* performance (speed) by a whopping 4-6% on 486-flavor machines */
|
||||
/* BUT!! a change from float to double here increases speed by */
|
||||
/* 30% or so on SGI machines */
|
||||
/* #define MY_FLOAT float */
|
||||
/* #define MY_FLOAT_SIZE 4 */
|
||||
|
||||
#define MY_FLOAT double
|
||||
#define MY_FLOAT_SIZE 8
|
||||
|
||||
/* Debugging define, causes massive printf's to come out. */
|
||||
/* Also enables timing calculations in WaveOut class, other stuff. */
|
||||
/* #define _debug_ 1 */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define NORM_7 0.0078125
|
||||
/* this is 1/128 for MIDI normalization*/
|
||||
|
||||
#endif
|
||||
81
OnePole.cpp
Normal file
81
OnePole.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/*******************************************/
|
||||
/* One Pole Filter Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* The parameter gain is an additional */
|
||||
/* gain parameter applied to the filter */
|
||||
/* on top of the normalization that takes */
|
||||
/* place automatically. So the net max */
|
||||
/* gain through the system equals the */
|
||||
/* value of gain. sgain is the combina- */
|
||||
/* tion of gain and the normalization */
|
||||
/* parameter, so if you set the poleCoeff */
|
||||
/* to alpha, sgain is always set to */
|
||||
/* gain * (1.0 - fabs(alpha)). */
|
||||
/*******************************************/
|
||||
|
||||
#include "OnePole.h"
|
||||
|
||||
OnePole :: OnePole() : Filter()
|
||||
{
|
||||
poleCoeff = 0.9;
|
||||
gain = 1.0;
|
||||
sgain = 0.1;
|
||||
outputs = (MY_FLOAT *) malloc(MY_FLOAT_SIZE);
|
||||
outputs[0] = 0.0;
|
||||
}
|
||||
|
||||
OnePole :: ~OnePole()
|
||||
{
|
||||
free(outputs);
|
||||
}
|
||||
|
||||
void OnePole :: clear()
|
||||
{
|
||||
outputs[0] = 0.0;
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
|
||||
void OnePole :: setPole(MY_FLOAT aValue)
|
||||
{
|
||||
poleCoeff = aValue;
|
||||
if (poleCoeff > 0.0) /* Normalize gain to 1.0 max */
|
||||
sgain = gain * (1.0 - poleCoeff);
|
||||
else
|
||||
sgain = gain * (1.0 + poleCoeff);
|
||||
}
|
||||
|
||||
void OnePole :: setGain(MY_FLOAT aValue)
|
||||
{
|
||||
gain = aValue;
|
||||
if (poleCoeff > 0.0)
|
||||
sgain = gain * (1.0 - poleCoeff); /* Normalize gain to 1.0 max */
|
||||
else
|
||||
sgain = gain * (1.0 + poleCoeff);
|
||||
}
|
||||
|
||||
MY_FLOAT OnePole :: tick(MY_FLOAT sample) /* Perform Filter Operation */
|
||||
{
|
||||
outputs[0] = (sgain * sample) + (poleCoeff * outputs[0]);
|
||||
lastOutput = outputs[0];
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main ************************/
|
||||
/*
|
||||
#include <stdio.h>
|
||||
|
||||
void main()
|
||||
{
|
||||
long i;
|
||||
OnePole test;
|
||||
test.setPole(0.99);
|
||||
for (i=0;i<150;i++) printf("%lf ",test.tick(1.0));
|
||||
printf("\n\n");
|
||||
|
||||
test.clear();
|
||||
test.setPole(0.9);
|
||||
test.setGain(2.0);
|
||||
for (i=0;i<150;i++) printf("%lf ",test.tick(0.5));
|
||||
printf("\n\n");
|
||||
}
|
||||
*/
|
||||
35
OnePole.h
Normal file
35
OnePole.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*******************************************/
|
||||
/* One Pole Filter Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* The parameter gain is an additional */
|
||||
/* gain parameter applied to the filter */
|
||||
/* on top of the normalization that takes */
|
||||
/* place automatically. So the net max */
|
||||
/* gain through the system equals the */
|
||||
/* value of gain. sgain is the combina- */
|
||||
/* tion of gain and the normalization */
|
||||
/* parameter, so if you set the poleCoeff */
|
||||
/* to alpha, sgain is always set to */
|
||||
/* gain * (1.0 - fabs(alpha)). */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__OnePole_h)
|
||||
#define __OnePole_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class OnePole : public Filter
|
||||
{
|
||||
protected:
|
||||
MY_FLOAT poleCoeff;
|
||||
MY_FLOAT sgain;
|
||||
public:
|
||||
OnePole();
|
||||
~OnePole();
|
||||
void clear();
|
||||
void setPole(MY_FLOAT aValue);
|
||||
void setGain(MY_FLOAT aValue);
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
64
OneZero.cpp
Normal file
64
OneZero.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*******************************************/
|
||||
/* One Zero Filter Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* The parameter gain is an additional */
|
||||
/* gain parameter applied to the filter */
|
||||
/* on top of the normalization that takes */
|
||||
/* place automatically. So the net max */
|
||||
/* gain through the system equals the */
|
||||
/* value of gain. sgain is the combina- */
|
||||
/* tion of gain and the normalization */
|
||||
/* parameter, so if you set the poleCoeff */
|
||||
/* to alpha, sgain is always set to */
|
||||
/* gain / (1.0 - fabs(alpha)). */
|
||||
/*******************************************/
|
||||
|
||||
#include "OneZero.h"
|
||||
|
||||
OneZero :: OneZero()
|
||||
{
|
||||
gain = 1.0;
|
||||
zeroCoeff = 1.0;
|
||||
sgain = 0.5;
|
||||
inputs = (MY_FLOAT *) malloc(MY_FLOAT_SIZE);
|
||||
this->clear();
|
||||
}
|
||||
|
||||
OneZero :: ~OneZero()
|
||||
{
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
void OneZero :: clear()
|
||||
{
|
||||
inputs[0] = 0.0;
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
|
||||
void OneZero :: setGain(MY_FLOAT aValue)
|
||||
{
|
||||
gain = aValue;
|
||||
if (zeroCoeff > 0.0) /* Normalize gain to 1.0 max */
|
||||
sgain = gain / (1.0 + zeroCoeff);
|
||||
else
|
||||
sgain = gain / (1.0 - zeroCoeff);
|
||||
}
|
||||
|
||||
void OneZero :: setCoeff(MY_FLOAT aValue)
|
||||
{
|
||||
zeroCoeff = aValue;
|
||||
if (zeroCoeff > 0.0) /* Normalize gain to 1.0 max */
|
||||
sgain = gain / (1.0 + zeroCoeff);
|
||||
else
|
||||
sgain = gain / (1.0 - zeroCoeff);
|
||||
}
|
||||
|
||||
MY_FLOAT OneZero :: tick(MY_FLOAT sample) /* Perform Filter Operation */
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
temp = sgain * sample;
|
||||
lastOutput = (inputs[0] * zeroCoeff) + temp;
|
||||
inputs[0] = temp;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
35
OneZero.h
Normal file
35
OneZero.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*******************************************/
|
||||
/* One Zero Filter Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* The parameter gain is an additional */
|
||||
/* gain parameter applied to the filter */
|
||||
/* on top of the normalization that takes */
|
||||
/* place automatically. So the net max */
|
||||
/* gain through the system equals the */
|
||||
/* value of gain. sgain is the combina- */
|
||||
/* tion of gain and the normalization */
|
||||
/* parameter, so if you set the poleCoeff */
|
||||
/* to alpha, sgain is always set to */
|
||||
/* gain / (1.0 - fabs(alpha)). */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__OneZero_h)
|
||||
#define __OneZero_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class OneZero : public Filter
|
||||
{
|
||||
protected:
|
||||
MY_FLOAT zeroCoeff;
|
||||
MY_FLOAT sgain;
|
||||
public:
|
||||
OneZero();
|
||||
~OneZero();
|
||||
void clear();
|
||||
void setGain(MY_FLOAT aValue);
|
||||
void setCoeff(MY_FLOAT aValue);
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
50
PercFlut.cpp
Normal file
50
PercFlut.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
/******************************************/
|
||||
/* Percussive Flute Subclass */
|
||||
/* of Algorithm 4 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/******************************************/
|
||||
|
||||
#include "PercFlut.h"
|
||||
|
||||
PercFlut :: PercFlut() : FM4Alg4()
|
||||
{
|
||||
this->loadWaves("rawwaves/sinewave.raw",
|
||||
"rawwaves/sinewave.raw",
|
||||
"rawwaves/sinewave.raw",
|
||||
"rawwaves/sinewave.raw");
|
||||
|
||||
this->setRatio(0,1.50 );
|
||||
this->setRatio(1,3.00 * 0.995);
|
||||
this->setRatio(2,2.99 * 1.005);
|
||||
this->setRatio(3,6.00 * 0.997);
|
||||
gains[0] = __FM4Op_gains[99];
|
||||
gains[1] = __FM4Op_gains[71];
|
||||
gains[2] = __FM4Op_gains[93];
|
||||
gains[3] = __FM4Op_gains[85];
|
||||
adsr[0]->setAll(0.001,0.001,__FM4Op_susLevels[14],0.001);
|
||||
adsr[1]->setAll(0.05,0.0001,__FM4Op_susLevels[13],0.0001);
|
||||
adsr[2]->setAll(0.05,0.0020,__FM4Op_susLevels[11],0.001);
|
||||
adsr[3]->setAll(0.05,0.0010,__FM4Op_susLevels[13],0.005);
|
||||
twozero->setGain(0.0);
|
||||
modDepth = 0.005;
|
||||
}
|
||||
|
||||
void PercFlut :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
}
|
||||
|
||||
void PercFlut :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
gains[0] = amp * __FM4Op_gains[99];
|
||||
gains[1] = amp * __FM4Op_gains[71];
|
||||
gains[2] = amp * __FM4Op_gains[93];
|
||||
gains[3] = amp * __FM4Op_gains[85];
|
||||
this->setFreq(freq);
|
||||
this->keyOn();
|
||||
#if defined(_debug_)
|
||||
printf("PercFlut : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
21
PercFlut.h
Normal file
21
PercFlut.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/******************************************/
|
||||
/* Percussive Flute Subclass */
|
||||
/* of Algorithm 4 (TX81Z) Subclass of */
|
||||
/* 4 Operator FM Synth */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__PercFlut_h)
|
||||
#define __PercFlut_h
|
||||
|
||||
#include "FM4Alg4.h"
|
||||
|
||||
class PercFlut : public FM4Alg4
|
||||
{
|
||||
public:
|
||||
PercFlut();
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
};
|
||||
|
||||
#endif
|
||||
189
PhonTabl.h
Normal file
189
PhonTabl.h
Normal file
@@ -0,0 +1,189 @@
|
||||
double phonGains[32][2] =
|
||||
{{1.0,0.0}, // eee
|
||||
{1.0,0.0}, // ihh
|
||||
{1.5,0.0}, // ehh
|
||||
{1.0,0.0}, // aaa
|
||||
|
||||
{0.5,0.0}, // ahh
|
||||
{0.5,0.0}, // aww
|
||||
{0.5,0.0}, // ohh
|
||||
{0.5,0.0}, // uhh
|
||||
|
||||
{0.5,0.0}, // uuu
|
||||
{0.15,0.0}, // ooo
|
||||
{0.15,0.0}, // rrr
|
||||
{6.0,0.0}, // lll
|
||||
|
||||
{1.0,0.0}, // mmm
|
||||
{1.0,0.0}, // nnn
|
||||
{1.0,0.0}, // nng
|
||||
{1.0,0.0}, // ngg
|
||||
|
||||
{0.0,1.0}, // fff
|
||||
{0.0,1.0}, // sss
|
||||
{0.0,1.0}, // thh
|
||||
{0.0,1.0}, // shh
|
||||
|
||||
{0.0,0.2}, // xxx
|
||||
{0.0,0.003}, // hee
|
||||
{0.0,0.001}, // hoo
|
||||
{0.0,0.002}, // hah
|
||||
|
||||
{1.0,0.4}, // bbb
|
||||
{4.0,0.1}, // ddd
|
||||
{1.0,0.4}, // jjj
|
||||
{1.0,0.4}, // ggg
|
||||
|
||||
{1.0,0.1}, // vvv
|
||||
{1.0,0.1}, // zzz
|
||||
{1.0,0.1}, // thz
|
||||
{1.0,0.1} // zhh
|
||||
};
|
||||
|
||||
double phonParams[32][4][3] =
|
||||
{{ { 273,0.996, 0}, // eee (beet)
|
||||
{2086,0.945, -16},
|
||||
{2754,0.979, -12},
|
||||
{3270,0.440, -17}},
|
||||
{ { 385,0.987, 0}, // ihh (bit)
|
||||
{2056,0.930, -20},
|
||||
{2587,0.890, -20},
|
||||
{3150,0.400, -20}},
|
||||
{ { 515,0.977, 0}, // ehh (bet)
|
||||
{1805,0.810, -10},
|
||||
{2526,0.875, -10},
|
||||
{3103,0.400, -13}},
|
||||
{ { 773,0.950, 0}, // aaa (bat)
|
||||
{1676,0.830, -6},
|
||||
{2380,0.880, -20},
|
||||
{3027,0.600, -20}},
|
||||
|
||||
{ { 770,0.950, 0}, // ahh (father)
|
||||
{1153,0.970, -3},
|
||||
{2450,0.780, -20},
|
||||
{3140,0.800, -32}},
|
||||
{ { 637,0.910, 0}, // aww (bought)
|
||||
{ 895,0.900, -3},
|
||||
{2556,0.950, -17},
|
||||
{3070,0.910, -20}},
|
||||
{ { 637,0.910, 0}, // ohh (bone) NOTE:: same as aww (bought)
|
||||
{ 895,0.900, -3},
|
||||
{2556,0.950, -17},
|
||||
{3070,0.910, -20}},
|
||||
{ { 561,0.965, 0}, // uhh (but)
|
||||
{1084,0.930, -10},
|
||||
{2541,0.930, -15},
|
||||
{3345,0.900, -20}},
|
||||
|
||||
{ { 515,0.976, 0}, // uuu (foot)
|
||||
{1031,0.950, -3},
|
||||
{2572,0.960, -11},
|
||||
{3345,0.960, -20}},
|
||||
{ { 349,0.986, 0}, // ooo (boot)
|
||||
{ 918,0.940, -10},
|
||||
{2350,0.960, -17},
|
||||
{2731,0.950, -23}},
|
||||
{ { 394,0.959, 0}, // rrr (bird)
|
||||
{1297,0.780, -6},
|
||||
{1441,0.980, -6},
|
||||
{2754,0.950, -30}},
|
||||
{ { 462,0.940, 0}, // lll (lull)
|
||||
{2754,0.900, -30},
|
||||
{3406,0.100, -30},
|
||||
{3755,0.100, -30}},
|
||||
|
||||
{ { 265,0.987, 0}, // mmm (mom)
|
||||
{1176,0.940, -22},
|
||||
{2352,0.970, -20},
|
||||
{3277,0.940, -31}},
|
||||
{ { 204,0.980, 0}, // nnn (nun)
|
||||
{1570,0.940, -15},
|
||||
{2481,0.980, -12},
|
||||
{3133,0.800, -30}},
|
||||
{ { 204,0.980, 0}, // nng (sang) NOTE:: same as nnn
|
||||
{1570,0.940, -15},
|
||||
{2481,0.980, -12},
|
||||
{3133,0.800, -30}},
|
||||
{ { 204,0.980, 0}, // ngg (bong) NOTE:: same as nnn
|
||||
{1570,0.940, -15},
|
||||
{2481,0.980, -12},
|
||||
{3133,0.800, -30}},
|
||||
|
||||
{ {1000,0.300, -10}, // fff
|
||||
{2800,0.860, -10},
|
||||
{7425,0.740, 0},
|
||||
{8140,0.860, 0}},
|
||||
{ {2000,0.700, -20}, // sss
|
||||
{5257,0.750, -15},
|
||||
{7171,0.840, -3},
|
||||
{9000,0.900, 0}},
|
||||
{ { 100,0.900, 0}, // thh
|
||||
{4000,0.500, -20},
|
||||
{5500,0.500, -15},
|
||||
{8000,0.400, -20}},
|
||||
{ {2693,0.940, 0}, // shh
|
||||
{4000,0.720, -10},
|
||||
{6123,0.870, -10},
|
||||
{7755,0.750, -18}},
|
||||
|
||||
{ {1000,0.300, -10}, // xxx NOTE:: Not Really Done Yet
|
||||
{2800,0.860, -10},
|
||||
{7425,0.740, 0},
|
||||
{8140,0.860, 0}},
|
||||
{ { 273,0.996, 0}, // hee (beet) (noisy eee)
|
||||
{2086,0.945, -16},
|
||||
{2754,0.979, -12},
|
||||
{3270,0.440, -17}},
|
||||
{ { 349,0.986, 0}, // hoo (boot) (noisy ooo)
|
||||
{ 918,0.940, -10},
|
||||
{2350,0.960, -17},
|
||||
{2731,0.950, -23}},
|
||||
{ { 770,0.950, 0}, // hah (father) (noisy ahh)
|
||||
{1153,0.970, -3},
|
||||
{2450,0.780, -20},
|
||||
{3140,0.800, -32}},
|
||||
|
||||
{ {2000,0.700, -20}, // bbb NOTE:: Not Really Done Yet
|
||||
{5257,0.750, -15},
|
||||
{7171,0.840, -3},
|
||||
{9000,0.900, 0}},
|
||||
{ { 100,0.900, 0}, // ddd NOTE:: Not Really Done Yet
|
||||
{4000,0.500, -20},
|
||||
{5500,0.500, -15},
|
||||
{8000,0.400, -20}},
|
||||
{ {2693,0.940, 0}, // jjj NOTE:: Not Really Done Yet
|
||||
{4000,0.720, -10},
|
||||
{6123,0.870, -10},
|
||||
{7755,0.750, -18}},
|
||||
{ {2693,0.940, 0}, // ggg NOTE:: Not Really Done Yet
|
||||
{4000,0.720, -10},
|
||||
{6123,0.870, -10},
|
||||
{7755,0.750, -18}},
|
||||
|
||||
{ {2000,0.700, -20}, // vvv NOTE:: Not Really Done Yet
|
||||
{5257,0.750, -15},
|
||||
{7171,0.840, -3},
|
||||
{9000,0.900, 0}},
|
||||
{ { 100,0.900, 0}, // zzz NOTE:: Not Really Done Yet
|
||||
{4000,0.500, -20},
|
||||
{5500,0.500, -15},
|
||||
{8000,0.400, -20}},
|
||||
{ {2693,0.940, 0}, // thz NOTE:: Not Really Done Yet
|
||||
{4000,0.720, -10},
|
||||
{6123,0.870, -10},
|
||||
{7755,0.750, -18}},
|
||||
{ {2693,0.940, 0}, // zhh NOTE:: Not Really Done Yet
|
||||
{4000,0.720, -10},
|
||||
{6123,0.870, -10},
|
||||
{7755,0.750, -18}}
|
||||
};
|
||||
|
||||
char phonemes[32][4] =
|
||||
{"eee","ihh","ehh","aaa",
|
||||
"ahh","aww","ohh","uhh",
|
||||
"uuu","ooo","rrr","lll",
|
||||
"mmm","nnn","nng","ngg",
|
||||
"fff","sss","thh","shh",
|
||||
"xxx","hee","hoo","hah",
|
||||
"bbb","ddd","jjj","ggg",
|
||||
"vvv","zzz","thz","zhh"};
|
||||
84
Plucked.cpp
Normal file
84
Plucked.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/******************************************/
|
||||
/* Karplus-Strong plucked string model */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* */
|
||||
/* There exist at least two patents, */
|
||||
/* assigned to Stanford, bearing the */
|
||||
/* names of Karplus and/or Strong. */
|
||||
/******************************************/
|
||||
|
||||
#include "Plucked.h"
|
||||
|
||||
Plucked :: Plucked(MY_FLOAT lowestFreq)
|
||||
{
|
||||
length = (long) (SRATE / lowestFreq + 1);
|
||||
loopGain = 0.999;
|
||||
delayLine = new DLineA(length);
|
||||
loopFilt = new OneZero;
|
||||
pickFilt = new OnePole;
|
||||
noise = new Noise;
|
||||
this->clear();
|
||||
}
|
||||
|
||||
Plucked :: ~Plucked()
|
||||
{
|
||||
delete delayLine;
|
||||
delete loopFilt;
|
||||
delete pickFilt;
|
||||
delete noise;
|
||||
}
|
||||
|
||||
void Plucked :: clear()
|
||||
{
|
||||
delayLine->clear();
|
||||
loopFilt->clear();
|
||||
pickFilt->clear();
|
||||
}
|
||||
|
||||
void Plucked :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
MY_FLOAT delay;
|
||||
delay = ((MY_FLOAT) SRATE / frequency) - 0.5; /* length - delays */
|
||||
delayLine->setDelay(delay);
|
||||
loopGain = 0.995 + (frequency * 0.000005);
|
||||
if (loopGain>1.0) loopGain = 0.99999;
|
||||
}
|
||||
|
||||
void Plucked :: pluck(MY_FLOAT amplitude)
|
||||
{
|
||||
long i;
|
||||
pickFilt->setPole(0.999 - (amplitude*0.15));
|
||||
pickFilt->setGain(amplitude * 0.5);
|
||||
for (i=0;i<length;i++)
|
||||
delayLine->tick(delayLine->lastOut() * 0.6 /* fill delay with noise */
|
||||
+ pickFilt->tick(noise->tick())); /* additively with current */
|
||||
/* contents */
|
||||
}
|
||||
|
||||
void Plucked :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->setFreq(freq);
|
||||
this->pluck(amp);
|
||||
#if defined(_debug_)
|
||||
printf("Plucked : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Plucked :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
loopGain = 1.0 - amp;
|
||||
#if defined(_debug_)
|
||||
printf("Plucked : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
MY_FLOAT Plucked :: tick()
|
||||
{
|
||||
lastOutput = delayLine->tick( /* check this out, */
|
||||
loopFilt->tick( /* here's the whole inner */
|
||||
delayLine->lastOut() /* loop of the instrument!! */
|
||||
* loopGain));
|
||||
lastOutput *= 3.0;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
40
Plucked.h
Normal file
40
Plucked.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/******************************************/
|
||||
/* Karplus-Strong plucked string model */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* */
|
||||
/* There exist at least two patents, */
|
||||
/* assigned to Stanford, bearing the */
|
||||
/* names of Karplus and/or Strong. */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__Plucked_h)
|
||||
#define __Plucked_h
|
||||
|
||||
#include "Instrmnt.h"
|
||||
#include "DLineA.h"
|
||||
#include "OneZero.h"
|
||||
#include "OnePole.h"
|
||||
#include "Noise.h"
|
||||
|
||||
class Plucked : public Instrmnt
|
||||
{
|
||||
protected:
|
||||
DLineA *delayLine;
|
||||
OneZero *loopFilt;
|
||||
OnePole *pickFilt;
|
||||
Noise *noise;
|
||||
long length;
|
||||
MY_FLOAT loopGain;
|
||||
public:
|
||||
Plucked(MY_FLOAT lowestFreq);
|
||||
~Plucked();
|
||||
void clear();
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
void pluck(MY_FLOAT amplitude);
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
virtual void noteOff(MY_FLOAT amp);
|
||||
virtual MY_FLOAT tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
90
Plucked2.cpp
Normal file
90
Plucked2.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/******************************************/
|
||||
/* Enhanced (Jaffe-Smith, Smith, others) */
|
||||
/* Karplus-Strong plucked model */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* This is the super-class, with no */
|
||||
/* excitation specified. So this one by */
|
||||
/* itself doesn't make any sound. */
|
||||
/******************************************/
|
||||
|
||||
#include "Plucked2.h"
|
||||
|
||||
Plucked2 :: Plucked2(MY_FLOAT lowestFreq)
|
||||
{
|
||||
length = (long) (SRATE / lowestFreq + 1);
|
||||
baseLoopGain = 0.995;
|
||||
loopGain = 0.999;
|
||||
delayLine = new DLineA(length);
|
||||
delayLine2 = new DLineA(length);
|
||||
combDelay = new DLineL(length);
|
||||
filter = new OneZero;
|
||||
filter2 = new OneZero;
|
||||
pluckAmp = 0.3;
|
||||
pluckPos = 0.4;
|
||||
detuning = 0.995;
|
||||
lastFreq = lowestFreq * 2.0;
|
||||
lastLength = length * 0.5;
|
||||
}
|
||||
|
||||
Plucked2 :: ~Plucked2()
|
||||
{
|
||||
delete delayLine;
|
||||
delete delayLine2;
|
||||
delete combDelay;
|
||||
delete filter;
|
||||
delete filter2;
|
||||
}
|
||||
|
||||
void Plucked2 :: clear()
|
||||
{
|
||||
delayLine->clear();
|
||||
delayLine2->clear();
|
||||
combDelay->clear();
|
||||
filter->clear();
|
||||
filter2->clear();
|
||||
}
|
||||
|
||||
void Plucked2 :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
lastFreq = frequency;
|
||||
lastLength = ((MY_FLOAT) SRATE / lastFreq); /* length - delays */
|
||||
delayLine->setDelay((lastLength / detuning) - 0.5);
|
||||
delayLine2->setDelay((lastLength * detuning) - 0.5);
|
||||
loopGain = baseLoopGain + (frequency * 0.000005);
|
||||
if (loopGain>1.0) loopGain = 0.99999;
|
||||
}
|
||||
|
||||
void Plucked2 :: setDetune(MY_FLOAT detune)
|
||||
{
|
||||
detuning = detune;
|
||||
delayLine->setDelay((lastLength / detuning) - 0.5);
|
||||
delayLine2->setDelay((lastLength * detuning) - 0.5);
|
||||
}
|
||||
|
||||
void Plucked2 :: setFreqAndDetune(MY_FLOAT frequency,MY_FLOAT detune)
|
||||
{
|
||||
lastFreq = frequency;
|
||||
detuning = detune;
|
||||
this->setFreq(frequency);
|
||||
}
|
||||
|
||||
void Plucked2 :: setPluckPos(MY_FLOAT position)
|
||||
{
|
||||
pluckPos = position;
|
||||
}
|
||||
|
||||
void Plucked2 :: setBaseLoopGain(MY_FLOAT aGain)
|
||||
{
|
||||
baseLoopGain = aGain;
|
||||
loopGain = baseLoopGain + (lastFreq * 0.000005);
|
||||
if (loopGain>1.0) loopGain = 0.99999;
|
||||
}
|
||||
|
||||
void Plucked2 :: noteOff(MY_FLOAT amp)
|
||||
{
|
||||
loopGain = (1.0 - amp) * 0.5;
|
||||
#if defined(_debug_)
|
||||
printf("Plucked2 : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
46
Plucked2.h
Normal file
46
Plucked2.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/******************************************/
|
||||
/* Enhanced (Jaffe-Smith, Smith, others) */
|
||||
/* Karplus-Strong plucked model */
|
||||
/* by Perry Cook, 1995-96 */
|
||||
/* This is the super-class, with no */
|
||||
/* excitation specified. So this one by */
|
||||
/* itself doesn't make any sound. */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__Plucked2_h)
|
||||
#define __Plucked2_h
|
||||
|
||||
#include "Instrmnt.h"
|
||||
#include "DLineL.h"
|
||||
#include "DLineA.h"
|
||||
#include "OneZero.h"
|
||||
|
||||
class Plucked2 : public Instrmnt
|
||||
{
|
||||
protected:
|
||||
DLineA *delayLine;
|
||||
DLineA *delayLine2;
|
||||
DLineL *combDelay;
|
||||
OneZero *filter;
|
||||
OneZero *filter2;
|
||||
long length;
|
||||
MY_FLOAT loopGain;
|
||||
MY_FLOAT baseLoopGain;
|
||||
MY_FLOAT lastFreq;
|
||||
MY_FLOAT lastLength;
|
||||
MY_FLOAT detuning;
|
||||
MY_FLOAT pluckAmp;
|
||||
MY_FLOAT pluckPos;
|
||||
public:
|
||||
Plucked2(MY_FLOAT lowestFreq);
|
||||
~Plucked2();
|
||||
void clear();
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
void setDetune(MY_FLOAT detune);
|
||||
void setFreqAndDetune(MY_FLOAT frequency, MY_FLOAT detune);
|
||||
void setPluckPos(MY_FLOAT position);
|
||||
void setBaseLoopGain(MY_FLOAT aGain);
|
||||
virtual void noteOff(MY_FLOAT amp);
|
||||
};
|
||||
|
||||
#endif
|
||||
117
README.txt
Normal file
117
README.txt
Normal file
@@ -0,0 +1,117 @@
|
||||
TK96CPP
|
||||
A ToolKit of Audio Synthesis Classes
|
||||
and Instruments in C++
|
||||
Perry Cook, 1995-96
|
||||
|
||||
Please read the Legal and Ethical notes at the
|
||||
bottom of this document.
|
||||
|
||||
For instant fun, if you get it to compile (see
|
||||
below) type TestAllNext or TestAllSGIRT. The
|
||||
former makes sound files of each instrument and
|
||||
saves them under the instrument name. The latter
|
||||
plays in real time from a SKINI scorefile.
|
||||
|
||||
For even more potential fun, try the GUI and MIDI
|
||||
interface demos in the directory TCLSpecs. MIDI
|
||||
is SGI specific for today, look for more support
|
||||
later. TCL works on SGI, maybe elsewhere, but
|
||||
you must have and install Tcl/TK.
|
||||
|
||||
For more documentation on this ToolKit, the classes,
|
||||
etc, read the file HIERARCH.txt and the individual
|
||||
class definitions.
|
||||
|
||||
SGI vs. NeXT vs. Intel vs. the world:
|
||||
See Object.h and Makefile for machine-specific
|
||||
items.
|
||||
|
||||
Initial public release. Some objects still beta.
|
||||
|
||||
This whole world was created with no particular
|
||||
hardware in mind. These examples are intended
|
||||
to be tutorial in nature, as a platform for the
|
||||
continuation of my research, and as a possible
|
||||
starting point for a software synthesis system.
|
||||
The basic motivation was to create the necessary
|
||||
unit generators to do the synthesis, processing,
|
||||
and control that I want to do and teach about.
|
||||
Little thought for optimization was given (see
|
||||
Object.cpp), and therefore improvements, especially
|
||||
speed enhancements, should be possible with
|
||||
these classes. It was written with some basic
|
||||
concepts in mind about how to let compilers
|
||||
optimize (see Adrian Freed's home page for some
|
||||
nice experience-based thoughts on that topic).
|
||||
|
||||
Your question at this point might be, "But Perry,
|
||||
with CMix, CMusic, CSound, CShells, CMonkeys, etc.
|
||||
already cluttering the landscape, why a new set
|
||||
of stupid C functions for music synthesis and
|
||||
processing?" The answers lie below.
|
||||
|
||||
1) I needed to port many of the things I've done
|
||||
into something which is generic enough to port
|
||||
further to different machines.
|
||||
|
||||
2) I really plan to document this stuff, so that
|
||||
you don't have to be me to figure out what's
|
||||
going on. (I'll probably be sorry I said this
|
||||
in a couple of years, when even I can't figure
|
||||
out what I was thinking.)
|
||||
|
||||
3) The classic difficulties most people have in
|
||||
trying to implement physical models are:
|
||||
|
||||
A) They have trouble understanding the papers,
|
||||
and/or in turning the theory into practice.
|
||||
|
||||
B) The Physical Model instruments are a pain to get
|
||||
to oscillate, and coming up with stable and
|
||||
meaningful parameter values is required to
|
||||
get the models to work at all.
|
||||
|
||||
This set of C++ unitgenerators and instruments
|
||||
might help to diminish the scores of EMails I
|
||||
get asking what to do with those block diagrams
|
||||
I put in my papers.
|
||||
|
||||
4) I wanted to try some new stuff with modal synthesis,
|
||||
and implement some classic FM patches as well.
|
||||
|
||||
5) I wanted to reimplement, and newly implement
|
||||
more of the intelligent and physical performer
|
||||
models I've talked about in some of my papers.
|
||||
But I wanted to do it in a portable way, and in
|
||||
such a way that I can hook up modules quickly.
|
||||
I also wanted to make these instruments connectable
|
||||
to such player objects, so folks like Brad Garton
|
||||
who really think a lot about the players can connect
|
||||
them to my instruments, a lot about which I think.
|
||||
|
||||
6) More rationalizations to follow . . .
|
||||
|
||||
***********************************************************
|
||||
Legal and Ethical:
|
||||
|
||||
This software was designed and created to be
|
||||
made publicly available for free, primarily for
|
||||
academic purposes, so if you use it, pass it on
|
||||
with this documentation, and for free.
|
||||
|
||||
If you make a million dollars with it, give me some.
|
||||
If you make compositions with it, put me in the
|
||||
program notes.
|
||||
|
||||
Some of the concepts are covered by various patents,
|
||||
some known to me and likely others which are unknown.
|
||||
Many of the ones known to me are administered by the
|
||||
Stanford Office of Technology and Licensing.
|
||||
|
||||
The good news is that large hunks of the techniques
|
||||
used here are public domain. To avoid subtle legal
|
||||
issues, I'll not state what's freely useable here,
|
||||
but I'll try to note within the various classes
|
||||
where certain things are likely to be protected by
|
||||
patents.
|
||||
***********************************************************
|
||||
155
RawLoop.cpp
Normal file
155
RawLoop.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
/*******************************************/
|
||||
/* Raw Looped Soundfile Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This Object can open a raw 16bit data */
|
||||
/* (signed integers) file, and play back */
|
||||
/* the data, looping only, with linear */
|
||||
/* interpolation on playback. */
|
||||
/*******************************************/
|
||||
|
||||
#include "RawLoop.h"
|
||||
|
||||
RawLoop :: RawLoop(char *fileName)
|
||||
{
|
||||
long i;
|
||||
short temp;
|
||||
FILE *fd;
|
||||
fd = fopen(fileName,"rb");
|
||||
if (!fd) {
|
||||
printf("Couldn't find soundfile %s !!!!!!!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
i = 0;
|
||||
while (fread(&temp,2,1,fd)) i++;
|
||||
length = i;
|
||||
fseek(fd,0,0);
|
||||
data = (MY_FLOAT *) malloc(MY_FLOAT_SIZE * (length + 1));
|
||||
i = 0;
|
||||
while (fread(&temp,2,1,fd)) {
|
||||
data[i] = temp;
|
||||
i++;
|
||||
}
|
||||
data[length] = data[0];
|
||||
fclose(fd);
|
||||
time = 0.0;
|
||||
phaseOffset = 0.0;
|
||||
rate = 1.0;
|
||||
}
|
||||
|
||||
RawLoop :: ~RawLoop()
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
|
||||
void RawLoop :: reset()
|
||||
{
|
||||
time = 0.0;
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
|
||||
void RawLoop :: normalize()
|
||||
{
|
||||
this->normalize(1.0);
|
||||
}
|
||||
|
||||
void RawLoop :: normalize(MY_FLOAT newPeak)
|
||||
{
|
||||
long i;
|
||||
MY_FLOAT max = 0.0;
|
||||
for (i=0;i<=length;i++)
|
||||
if (fabs(data[i]) > max)
|
||||
max = fabs(data[i]);
|
||||
if (max > 0.0) {
|
||||
max = 1.0 / max;
|
||||
max *= newPeak;
|
||||
for (i=0;i<=length;i++)
|
||||
data[i] *= max;
|
||||
}
|
||||
}
|
||||
|
||||
void RawLoop :: setRate(MY_FLOAT aRate)
|
||||
{
|
||||
rate = aRate;
|
||||
}
|
||||
|
||||
void RawLoop :: setFreq(MY_FLOAT aFreq)
|
||||
{
|
||||
rate = length * ONE_OVER_SRATE * aFreq;
|
||||
}
|
||||
|
||||
void RawLoop :: addTime(MY_FLOAT aTime) /* Add an absolute time */
|
||||
{ /* in samples */
|
||||
time += aTime;
|
||||
}
|
||||
|
||||
void RawLoop :: addPhase(MY_FLOAT anAngle) /* Add a time in cycles */
|
||||
{ /* Cycles here means */
|
||||
time += length * anAngle; /* 1.0 = length */
|
||||
}
|
||||
|
||||
void RawLoop :: addPhaseOffset(MY_FLOAT anAngle)
|
||||
{ /* Add a phase offset */
|
||||
phaseOffset = length * anAngle; /* in cycles, where */
|
||||
} /* 1.0 = length */
|
||||
|
||||
MY_FLOAT RawLoop :: tick()
|
||||
{
|
||||
long temp;
|
||||
|
||||
MY_FLOAT temp_time, alpha;
|
||||
|
||||
time += rate; /* Update current time */
|
||||
|
||||
while (time >= length) /* Check for end of sound */
|
||||
time -= length; /* loop back to beginning */
|
||||
while (time < 0.0) /* Check for end of sound */
|
||||
time += length; /* loop back to beginning */
|
||||
|
||||
temp_time = time;
|
||||
|
||||
if (phaseOffset != 0.0) {
|
||||
temp_time += phaseOffset; /* Add phase offset */
|
||||
while (temp_time >= length) /* Check for end of sound */
|
||||
temp_time -= length; /* loop back to beginning */
|
||||
while (temp_time < 0.0) /* Check for end of sound */
|
||||
temp_time += length; /* loop back to beginning */
|
||||
}
|
||||
|
||||
temp = (long) temp_time; /* Integer part of time address */
|
||||
alpha = temp_time - (MY_FLOAT) temp; /* fractional part of time address */
|
||||
lastOutput = data[temp]; /* Do linear interpolation */
|
||||
lastOutput = lastOutput + /* same as alpha*data[temp+1] */
|
||||
(alpha * (data[temp+1]
|
||||
- lastOutput)); /* + (1-alpha)data[temp] */
|
||||
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
MY_FLOAT RawLoop :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
void main()
|
||||
{
|
||||
RawLoop loopWave("rawwaves/sinewave.raw");
|
||||
FILE *fd;
|
||||
short data;
|
||||
long i;
|
||||
|
||||
loopWave.setFreq(5500);
|
||||
fd = fopen("test.raw","wb");
|
||||
for (i=0;i<4096;i++) {
|
||||
data = loopWave.tick();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
loopWave.setFreq(2750);
|
||||
for (i=0;i<4096;i++) {
|
||||
data = loopWave.tick();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
39
RawLoop.h
Normal file
39
RawLoop.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*******************************************/
|
||||
/* Raw Looped Soundfile Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This Object can open a raw 16bit data */
|
||||
/* (signed integers) file, and play back */
|
||||
/* the data, looping only, with linear */
|
||||
/* interpolation on playback. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__RawLoop_h)
|
||||
#define __RawLoop_h
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class RawLoop : public Object
|
||||
{
|
||||
protected:
|
||||
long length;
|
||||
MY_FLOAT *data;
|
||||
MY_FLOAT rate;
|
||||
MY_FLOAT time;
|
||||
MY_FLOAT phaseOffset;
|
||||
MY_FLOAT lastOutput;
|
||||
public:
|
||||
RawLoop(char *fileName);
|
||||
~RawLoop();
|
||||
void reset();
|
||||
void normalize();
|
||||
void normalize(MY_FLOAT newPeak);
|
||||
void setRate(MY_FLOAT aRate);
|
||||
void setFreq(MY_FLOAT aFreq);
|
||||
void addTime(MY_FLOAT aTime);
|
||||
void addPhase(MY_FLOAT anAngle);
|
||||
void addPhaseOffset(MY_FLOAT anAngle);
|
||||
MY_FLOAT tick();
|
||||
MY_FLOAT lastOut();
|
||||
};
|
||||
|
||||
#endif
|
||||
235
RawWave.cpp
Normal file
235
RawWave.cpp
Normal file
@@ -0,0 +1,235 @@
|
||||
/*******************************************/
|
||||
/* Raw Soundfile Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This Object can open a raw 16bit data */
|
||||
/* (signed integers) file, and play back */
|
||||
/* the data once or looping, with linear */
|
||||
/* interpolation on playback. */
|
||||
/*******************************************/
|
||||
|
||||
#include "RawWave.h"
|
||||
|
||||
RawWave :: RawWave(char *fileName)
|
||||
{
|
||||
long i;
|
||||
short temp;
|
||||
FILE *fd;
|
||||
fd = fopen(fileName,"rb");
|
||||
if (!fd) {
|
||||
printf("Couldn't find soundfile %s !!!!!!!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
i = 0;
|
||||
while (fread(&temp,2,1,fd)) i++;
|
||||
length = i;
|
||||
fseek(fd,0,0);
|
||||
data = (MY_FLOAT *) malloc(MY_FLOAT_SIZE * (length + 1));
|
||||
myData = 1;
|
||||
i = 0;
|
||||
while (fread(&temp,2,1,fd)) {
|
||||
data[i] = temp;
|
||||
i++;
|
||||
}
|
||||
data[length] = data[length-1];
|
||||
fclose(fd);
|
||||
looping = 0;
|
||||
time = length;
|
||||
phaseOffset = 0.0;
|
||||
rate = 1.0;
|
||||
allDone = 0;
|
||||
}
|
||||
|
||||
RawWave :: RawWave(MY_FLOAT *someData, long aLength)
|
||||
{
|
||||
|
||||
length = aLength;
|
||||
data = someData;
|
||||
myData = 0;
|
||||
looping = 0;
|
||||
time = 0.0;
|
||||
phaseOffset = 0.0;
|
||||
rate = 1.0;
|
||||
}
|
||||
|
||||
RawWave :: ~RawWave()
|
||||
{
|
||||
if (myData) {
|
||||
free(data);
|
||||
data = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RawWave :: reset()
|
||||
{
|
||||
time = 0.0;
|
||||
lastOutput = 0.0;
|
||||
allDone = 0;
|
||||
}
|
||||
|
||||
void RawWave :: normalize()
|
||||
{
|
||||
this->normalize(1.0);
|
||||
}
|
||||
|
||||
void RawWave :: normalize(MY_FLOAT newPeak)
|
||||
{
|
||||
long i;
|
||||
MY_FLOAT max = 0.0;
|
||||
for (i=0;i<=length;i++)
|
||||
if (fabs(data[i]) > max)
|
||||
max = fabs(data[i]);
|
||||
if (max > 0.0) {
|
||||
max = 1.0 / max;
|
||||
max *= newPeak;
|
||||
for (i=0;i<=length;i++)
|
||||
data[i] *= max;
|
||||
}
|
||||
}
|
||||
|
||||
void RawWave :: setRate(MY_FLOAT aRate)
|
||||
{
|
||||
rate = aRate;
|
||||
}
|
||||
|
||||
void RawWave :: setFreq(MY_FLOAT aFreq)
|
||||
{
|
||||
rate = length * ONE_OVER_SRATE * aFreq;
|
||||
}
|
||||
|
||||
void RawWave :: addTime(MY_FLOAT aTime) /* Add an absolute time */
|
||||
{ /* in samples */
|
||||
time += aTime;
|
||||
}
|
||||
|
||||
void RawWave :: addPhase(MY_FLOAT anAngle) /* Add a time in cycles */
|
||||
{ /* Cycles here means */
|
||||
time += length * anAngle; /* 1.0 = length */
|
||||
}
|
||||
|
||||
void RawWave :: addPhaseOffset(MY_FLOAT anAngle)
|
||||
{ /* Add a phase offset */
|
||||
phaseOffset = length * anAngle; /* in cycles, where */
|
||||
} /* 1.0 = length */
|
||||
|
||||
void RawWave :: setLooping(int aLoopStatus)
|
||||
{
|
||||
time = 0;
|
||||
looping = aLoopStatus;
|
||||
if (looping) data[length] = data[0];
|
||||
}
|
||||
|
||||
long RawWave :: getLength()
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
MY_FLOAT* RawWave :: getData()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
MY_FLOAT RawWave :: tick()
|
||||
{
|
||||
this->informTick();
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
int RawWave :: isAllDone()
|
||||
{
|
||||
return allDone;
|
||||
}
|
||||
|
||||
int RawWave :: informTick()
|
||||
{
|
||||
long temp;
|
||||
|
||||
MY_FLOAT temp_time, alpha;
|
||||
|
||||
time += rate; /* Update current time */
|
||||
|
||||
if (looping) {
|
||||
while (time >= length) /* Check for end of sound */
|
||||
time -= length; /* loop back to beginning */
|
||||
while (time < 0.0) /* Check for end of sound */
|
||||
time += length; /* loop back to beginning */
|
||||
}
|
||||
else {
|
||||
if (time >= length) { /* Check for end of sound */
|
||||
time = length-1; /* stick at end */
|
||||
allDone = 1; /* Information for one-shot use */
|
||||
}
|
||||
else if (time < 0.0) /* Check for end of sound */
|
||||
time = 0.0; /* stick at beg */
|
||||
}
|
||||
|
||||
temp_time = time;
|
||||
|
||||
if (phaseOffset != 0.0) {
|
||||
temp_time += phaseOffset; /* Add phase offset */
|
||||
if (looping) {
|
||||
while (temp_time >= length) /* Check for end of sound */
|
||||
temp_time -= length; /* loop back to beginning */
|
||||
while (temp_time < 0.0) /* Check for end of sound */
|
||||
temp_time += length; /* loop back to beginning */
|
||||
}
|
||||
else {
|
||||
if (temp_time >= length) /* Check for end of sound */
|
||||
temp_time = length-1; /* stick at end */
|
||||
else if (temp_time < 0.0) /* check for end of sound */
|
||||
temp_time = 0.0; /* stick at beg */
|
||||
}
|
||||
}
|
||||
|
||||
temp = (long) temp_time; /* Integer part of time address */
|
||||
alpha = temp_time - (MY_FLOAT) temp; /* fractional part of time address */
|
||||
lastOutput = data[temp]; /* Do linear interpolation */
|
||||
lastOutput = lastOutput + /* same as alpha*data[temp+1] */
|
||||
(alpha * (data[temp+1] -
|
||||
lastOutput)); /* + (1-alpha)data[temp] */
|
||||
|
||||
return allDone;
|
||||
}
|
||||
|
||||
MY_FLOAT RawWave :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
|
||||
void main()
|
||||
{
|
||||
RawWave loopWave("rawwaves/sinewave.raw");
|
||||
RawWave oneShot("rawwaves/mandpluk.raw");
|
||||
FILE *fd;
|
||||
short data;
|
||||
long i;
|
||||
|
||||
loopWave.setLooping(1);
|
||||
loopWave.setFreq(5500);
|
||||
fd = fopen("test.raw","wb");
|
||||
for (i=0;i<4096;i++) {
|
||||
data = loopWave.tick();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
loopWave.setFreq(2750);
|
||||
for (i=0;i<4096;i++) {
|
||||
data = loopWave.tick();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
oneShot.setLooping(0);
|
||||
for (i=0;i<8192;i++) {
|
||||
data = oneShot.tick();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
oneShot.reset();
|
||||
oneShot.setRate(0.5);
|
||||
for (i=0;i<16384;i++) {
|
||||
data = oneShot.tick();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
48
RawWave.h
Normal file
48
RawWave.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*******************************************/
|
||||
/* Raw Soundfile Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This Object can open a raw 16bit data */
|
||||
/* (signed integers) file, and play back */
|
||||
/* the data once or looping, with linear */
|
||||
/* interpolation on playback. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__RawWave_h)
|
||||
#define __RawWave_h
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class RawWave : public Object
|
||||
{
|
||||
protected:
|
||||
int looping;
|
||||
int myData;
|
||||
int allDone;
|
||||
long length;
|
||||
MY_FLOAT *data;
|
||||
MY_FLOAT rate;
|
||||
MY_FLOAT time;
|
||||
MY_FLOAT phaseOffset;
|
||||
MY_FLOAT lastOutput;
|
||||
public:
|
||||
RawWave(char *fileName);
|
||||
RawWave(MY_FLOAT *someData,long aLength);
|
||||
~RawWave();
|
||||
void reset();
|
||||
void normalize();
|
||||
void normalize(MY_FLOAT newPeak);
|
||||
void setRate(MY_FLOAT aRate);
|
||||
void setFreq(MY_FLOAT aFreq);
|
||||
void addTime(MY_FLOAT aTime);
|
||||
void addPhase(MY_FLOAT anAngle);
|
||||
void addPhaseOffset(MY_FLOAT anAngle);
|
||||
void setLooping(int aLoopStatus);
|
||||
int isAllDone();
|
||||
long getLength();
|
||||
MY_FLOAT* getData();
|
||||
MY_FLOAT tick();
|
||||
int informTick();
|
||||
MY_FLOAT lastOut();
|
||||
};
|
||||
|
||||
#endif
|
||||
163
RawWvIn.cpp
Normal file
163
RawWvIn.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
/*******************************************/
|
||||
/* NonInterpolating One-Shot Raw Sound- */
|
||||
/* file Class, by Perry R. Cook, 1995-96 */
|
||||
/* This Object can open a raw 16bit data */
|
||||
/* (signed integers) file, and play back */
|
||||
/* the data once, with no interpolation */
|
||||
/* on playback. Once finished, it closes */
|
||||
/* the file, the file is reopened with */
|
||||
/* the reset() method. */
|
||||
/* This is useful for small memory model, */
|
||||
/* applications, or for streaming from */
|
||||
/* disk (and generally non real-time */
|
||||
/* applications). */
|
||||
/*******************************************/
|
||||
|
||||
#include "RawWvIn.h"
|
||||
|
||||
RawWvIn :: RawWvIn(char *fileName)
|
||||
{
|
||||
long i;
|
||||
|
||||
strcpy(fileNm,fileName);
|
||||
|
||||
myFile = fopen(fileNm,"rb");
|
||||
if (!myFile) {
|
||||
printf("Couldn't find soundfile %s !!!!!!!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (fread(&data,2,1,myFile)) i++;
|
||||
length = i;
|
||||
fseek(myFile,0,0);
|
||||
time = 0.0;
|
||||
rate = 1.0;
|
||||
lastTime = 0;
|
||||
finished = 0;
|
||||
gain = 1.0;
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
|
||||
RawWvIn :: ~RawWvIn()
|
||||
{
|
||||
this->finish();
|
||||
}
|
||||
|
||||
void RawWvIn :: reset()
|
||||
{
|
||||
if (finished) {
|
||||
myFile = fopen(fileNm,"rb");
|
||||
}
|
||||
fseek(myFile,0,0);
|
||||
|
||||
printf("Resetting\n");
|
||||
time = 0.0;
|
||||
lastTime = 0;
|
||||
finished = 0;
|
||||
lastOutput = 0.0;
|
||||
}
|
||||
|
||||
void RawWvIn :: normalize()
|
||||
{
|
||||
this->normalize(1.0);
|
||||
}
|
||||
|
||||
void RawWvIn :: normalize(MY_FLOAT newPeak)
|
||||
{
|
||||
long i;
|
||||
FILE *fd;
|
||||
|
||||
gain = 0.0;
|
||||
|
||||
fd = fopen(fileNm,"rb");
|
||||
for (i=0;i<length;i++) {
|
||||
fread(&data,2,1,fd);
|
||||
if (fabs(data) > gain)
|
||||
gain = fabs(data);
|
||||
}
|
||||
if (gain > 0.0) {
|
||||
gain = newPeak / gain;
|
||||
}
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
void RawWvIn :: setRate(MY_FLOAT aRate)
|
||||
{
|
||||
rate = aRate;
|
||||
}
|
||||
|
||||
void RawWvIn :: finish()
|
||||
{
|
||||
finished = 1;
|
||||
lastOutput = 0.0;
|
||||
if (myFile) {
|
||||
fclose(myFile);
|
||||
myFile = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MY_FLOAT RawWvIn :: tick()
|
||||
{
|
||||
this->informTick();
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
int RawWvIn :: informTick()
|
||||
{
|
||||
long temp;
|
||||
|
||||
if (!finished) {
|
||||
|
||||
time += rate; /* Update current time */
|
||||
|
||||
if (time >= length) { /* Check for end of sound */
|
||||
time = length - 1; /* stick at end */
|
||||
finished = 1; /* Information for one-shot use */
|
||||
fclose(myFile);
|
||||
myFile = 0;
|
||||
}
|
||||
else {
|
||||
temp = (long) time; /* Integer part of time address */
|
||||
if (temp > lastTime) { /* If we cross next sample time */
|
||||
lastTime = temp;
|
||||
fread(&data,2,1,myFile); /* Snarf next sample from file */
|
||||
lastOutput = data * gain; /* And save as non-interpolated data */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return finished;
|
||||
}
|
||||
|
||||
MY_FLOAT RawWvIn :: lastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
/************ Test Main Program *****************/
|
||||
/*
|
||||
void main()
|
||||
{
|
||||
RawWvIn oneShot("rawwaves/mandpluk.raw");
|
||||
FILE *fd;
|
||||
short data;
|
||||
long i;
|
||||
|
||||
fd = fopen("test.raw","wb");
|
||||
oneShot.setRate(1.0);
|
||||
while (!oneShot.informTick()) {
|
||||
data = oneShot.lastOut();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
|
||||
oneShot.reset();
|
||||
oneShot.setRate(0.5);
|
||||
for (i=0;i<16384;i++) {
|
||||
data = oneShot.tick();
|
||||
fwrite(&data,2,1,fd);
|
||||
}
|
||||
fclose(fd);
|
||||
}
|
||||
*/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user