Version 4.0

This commit is contained in:
Gary Scavone
2013-09-25 14:50:19 +02:00
committed by Stephen Sinclair
parent 3f126af4e5
commit 81475b04c5
473 changed files with 36355 additions and 28396 deletions

View File

@@ -1,26 +1,53 @@
/***********************************************/
/*
Waveguide "reed" instrument model with a
register hole and one tonehole
/***************************************************/
/*! \class BlowHole
\brief STK clarinet physical model with one
register hole and one tonehole.
by Gary P. Scavone, 2000.
This class is based on the clarinet model,
with the addition of a two-port register hole
and a three-port dynamic tonehole
implementation, as discussed by Scavone and
Cook (1998).
In this implementation, the distances between
the reed/register hole and tonehole/bell are
fixed. As a result, both the tonehole and
register hole will have variable influence on
the playing frequency, which is dependent on
the length of the air column. In addition,
the highest playing freqeuency is limited by
these fixed lengths.
This is a digital waveguide model, making its
use possibly subject to patents held by Stanford
University, Yamaha, and others.
Control Change Numbers:
- Reed Stiffness = 2
- Noise Gain = 4
- Tonehole State = 11
- Register State = 1
- Breath Pressure = 128
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
*/
/***********************************************/
/***************************************************/
#include "BlowHole.h"
#include "SKINI11.msg"
#include "SKINI.msg"
#include <math.h>
#include <string.h>
BlowHole :: BlowHole(MY_FLOAT lowestFreq)
BlowHole :: BlowHole(MY_FLOAT lowestFrequency)
{
length = (long) (SRATE / lowestFreq + 1);
delays = (DLineL *) new DLineL[3];
// delays[0] is the delay line between the reed and the register vent
delays[0].setDelay(5.0);
// delays[1] is the delay line between the register vent and the tonehole
delays[1].setDelay(length >> 1);
// delays[2] is the delay line between the tonehole and the end of the bore
delays[2].setDelay(4.0);
reedTable = new ReedTabl;
length = (long) (Stk::sampleRate() / lowestFrequency + 1);
// delays[0] is the delay line between the reed and the register vent.
delays[0] = (DelayL *) new DelayL( 5.0 * Stk::sampleRate() / 22050.0, 100 );
// delays[1] is the delay line between the register vent and the tonehole.
delays[1] = (DelayL *) new DelayL( length >> 1, length );
// delays[2] is the delay line between the tonehole and the end of the bore.
delays[2] = (DelayL *) new DelayL( 4.0 * Stk::sampleRate() / 22050.0, 100 );
reedTable = new ReedTabl();
reedTable->setOffset((MY_FLOAT) 0.7);
reedTable->setSlope((MY_FLOAT) -0.3);
filter = new OneZero;
@@ -28,13 +55,13 @@ BlowHole :: BlowHole(MY_FLOAT lowestFreq)
noise = new Noise;
// Calculate the initial tonehole three-port scattering coefficient
double r_b = 0.0075; /* main bore radius */
r_th = 0.003; /* tonehole radius */
double r_b = 0.0075; // main bore radius
r_th = 0.003; // tonehole radius
scatter = -pow(r_th,2) / ( pow(r_th,2) + 2*pow(r_b,2) );
// Calculate tonehole coefficients
MY_FLOAT te = 1.4 * r_th; /* effective length of the open hole */
th_coeff = (te*2*SRATE - 347.23) / (te*2*SRATE + 347.23);
MY_FLOAT te = 1.4 * r_th; // effective length of the open hole
th_coeff = (te*2*Stk::sampleRate() - 347.23) / (te*2*Stk::sampleRate() + 347.23);
tonehole = new PoleZero;
// Start with tonehole open
tonehole->setA1(-th_coeff);
@@ -42,13 +69,13 @@ BlowHole :: BlowHole(MY_FLOAT lowestFreq)
tonehole->setB1(-1.0);
// Calculate register hole filter coefficients
double r_rh = 0.0015; /* register vent radius */
te = 1.4 * r_rh; /* effective length of the open hole */
double xi = 0.0; /* series resistance term */
double r_rh = 0.0015; // register vent radius
te = 1.4 * r_rh; // effective length of the open hole
double xi = 0.0; // series resistance term
double zeta = 347.23 + 2*PI*pow(r_b,2)*xi/1.1769;
double psi = 2*PI*pow(r_b,2)*te / (PI*pow(r_rh,2));
rh_coeff = (zeta - 2*SRATE*psi) / (zeta + 2*SRATE*psi);
rh_gain = -347.23 / (zeta + 2*SRATE*psi);
rh_coeff = (zeta - 2 * Stk::sampleRate() * psi) / (zeta + 2 * Stk::sampleRate() * psi);
rh_gain = -347.23 / (zeta + 2 * Stk::sampleRate() * psi);
vent = new PoleZero;
vent->setA1(rh_coeff);
vent->setB0(1.0);
@@ -59,51 +86,59 @@ BlowHole :: BlowHole(MY_FLOAT lowestFreq)
// Concatenate the STK RAWWAVE_PATH to the rawwave file
char file[128];
strcpy(file, RAWWAVE_PATH);
vibr = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping");
vibr->setFreq((MY_FLOAT) 5.735);
vibrato = new WaveLoop( strcat(file,"rawwaves/sinewave.raw"), TRUE );
vibrato->setFrequency((MY_FLOAT) 5.735);
outputGain = (MY_FLOAT) 1.0;
noiseGain = (MY_FLOAT) 0.2;
vibrGain = (MY_FLOAT) 0.01;
vibratoGain = (MY_FLOAT) 0.01;
}
BlowHole :: ~BlowHole()
{
delete [] delays;
delete delays[0];
delete delays[1];
delete delays[2];
delete reedTable;
delete filter;
delete tonehole;
delete vent;
delete envelope;
delete noise;
delete vibr;
delete vibrato;
}
void BlowHole :: clear()
{
delays[0].clear();
delays[1].clear();
delays[0]->clear();
delays[1]->clear();
delays[2]->clear();
filter->tick((MY_FLOAT) 0.0);
tonehole->tick((MY_FLOAT) 0.0);
vent->tick((MY_FLOAT) 0.0);
}
void BlowHole :: setFreq(MY_FLOAT frequency)
void BlowHole :: setFrequency(MY_FLOAT frequency)
{
MY_FLOAT new_length = (SRATE / frequency) * (MY_FLOAT) 0.5 - (MY_FLOAT) 1.5;
new_length -= 9;
MY_FLOAT freakency = frequency;
if ( frequency <= 0.0 ) {
cerr << "BlowHole: setFrequency parameter is less than or equal to zero!" << endl;
freakency = 220.0;
}
if (new_length <= 1.0) new_length = 1.0;
else if (new_length >= length) new_length = length;
delays[1].setDelay(new_length);
// Delay = length - approximate filter delay.
MY_FLOAT delay = (Stk::sampleRate() / freakency) * 0.5 - 3.5;
delay -= delays[0]->getDelay() + delays[2]->getDelay();
if (delay <= 0.0) delay = 0.3;
else if (delay > length) delay = length;
delays[1]->setDelay(delay);
}
void BlowHole :: setVent(MY_FLOAT newValue)
{
/*
This method allows setting of the register vent "open-ness" at
any point between "Open" (newValue = 1) and "Closed"
(newValue = 0).
*/
// This method allows setting of the register vent "open-ness" at
// any point between "Open" (newValue = 1) and "Closed"
// (newValue = 0).
MY_FLOAT gain;
@@ -115,11 +150,9 @@ void BlowHole :: setVent(MY_FLOAT newValue)
void BlowHole :: setTonehole(MY_FLOAT newValue)
{
/*
This method allows setting of the tonehole "open-ness" at
any point between "Open" (newValue = 1) and "Closed"
(newValue = 0).
*/
// This method allows setting of the tonehole "open-ness" at
// any point between "Open" (newValue = 1) and "Closed"
// (newValue = 0).
MY_FLOAT new_coeff;
if (newValue <= 0.0) new_coeff = 0.9995;
@@ -129,7 +162,7 @@ void BlowHole :: setTonehole(MY_FLOAT newValue)
tonehole->setB0(new_coeff);
}
void BlowHole :: startBlowing(MY_FLOAT amplitude,MY_FLOAT rate)
void BlowHole :: startBlowing(MY_FLOAT amplitude, MY_FLOAT rate)
{
envelope->setRate(rate);
envelope->setTarget(amplitude);
@@ -141,16 +174,24 @@ void BlowHole :: stopBlowing(MY_FLOAT rate)
envelope->setTarget((MY_FLOAT) 0.0);
}
void BlowHole :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
void BlowHole :: noteOn(MY_FLOAT frequency, MY_FLOAT amplitude)
{
this->setFreq(freq);
this->startBlowing((MY_FLOAT) 0.55 + (amp * (MY_FLOAT) 0.30),amp * (MY_FLOAT) 0.005);
outputGain = amp + (MY_FLOAT) 0.001;
setFrequency(frequency);
startBlowing((MY_FLOAT) 0.55 + (amplitude * 0.30), amplitude * 0.005);
outputGain = amplitude + 0.001;
#if defined(_STK_DEBUG_)
cerr << "BlowHole: NoteOn frequency = " << frequency << ", amplitude = " << amplitude << endl;
#endif
}
void BlowHole :: noteOff(MY_FLOAT amp)
void BlowHole :: noteOff(MY_FLOAT amplitude)
{
this->stopBlowing(amp * (MY_FLOAT) 0.01);
this->stopBlowing(amplitude * 0.01);
#if defined(_STK_DEBUG_)
cerr << "BlowHole: NoteOff amplitude = " << amplitude << endl;
#endif
}
MY_FLOAT BlowHole :: tick()
@@ -159,30 +200,30 @@ MY_FLOAT BlowHole :: tick()
MY_FLOAT breathPressure;
MY_FLOAT temp;
// Calculate the breath pressure (envelope + noise + vibrator)
// Calculate the breath pressure (envelope + noise + vibrato)
breathPressure = envelope->tick();
breathPressure += breathPressure * noiseGain * noise->tick();
breathPressure += breathPressure * vibrGain * vibr->tick();
breathPressure += breathPressure * vibratoGain * vibrato->tick();
// Calculate the differential pressure = reflected - mouthpiece pressures
pressureDiff = delays[0].lastOut() - breathPressure;
pressureDiff = delays[0]->lastOut() - breathPressure;
// Do two-port junction scattering for register vent
MY_FLOAT pa = breathPressure + pressureDiff * reedTable->lookup(pressureDiff);
MY_FLOAT pb = delays[1].lastOut();
MY_FLOAT pa = breathPressure + pressureDiff * reedTable->tick(pressureDiff);
MY_FLOAT pb = delays[1]->lastOut();
vent->tick(pa+pb);
lastOutput = delays[0].tick(vent->lastOut()+pb);
lastOutput = delays[0]->tick(vent->lastOut()+pb);
lastOutput *= outputGain;
// Do three-port junction scattering (under tonehole)
pa += vent->lastOut();
pb = delays[2].lastOut();
pb = delays[2]->lastOut();
MY_FLOAT pth = tonehole->lastOut();
temp = scatter * (pa + pb - 2 * pth);
delays[2].tick(filter->tick(pa + temp) * -0.95);
delays[1].tick(pb + temp);
delays[2]->tick(filter->tick(pa + temp) * -0.95);
delays[1]->tick(pb + temp);
tonehole->tick(pa + pb - pth + temp);
return lastOutput;
@@ -190,20 +231,30 @@ MY_FLOAT BlowHole :: tick()
void BlowHole :: controlChange(int number, MY_FLOAT value)
{
if (number == __SK_ReedStiffness_)
reedTable->setSlope((MY_FLOAT) -0.44 + ((MY_FLOAT) 0.26 * value * NORM_7));
else if (number == __SK_NoiseLevel_)
noiseGain = (value * NORM_7 * (MY_FLOAT) 0.4);
else if (number == __SK_ModFrequency_)
//vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
this->setTonehole(value * NORM_7);
else if (number == __SK_ModWheel_)
//vibrGain = (value * NORM_7 * (MY_FLOAT) 0.5);
this->setVent(value * NORM_7);
else if (number == __SK_AfterTouch_Cont_) {
envelope->setValue(value * NORM_7);
MY_FLOAT norm = value * ONE_OVER_128;
if ( norm < 0 ) {
norm = 0.0;
cerr << "Clarinet: Control value less than zero!" << endl;
}
else {
printf("BlowHole : Undefined Control Number!!\n");
else if ( norm > 1.0 ) {
norm = 1.0;
cerr << "Clarinet: Control value greater than 128.0!" << endl;
}
if (number == __SK_ReedStiffness_) // 2
reedTable->setSlope( -0.44 + (0.26 * norm) );
else if (number == __SK_NoiseLevel_) // 4
noiseGain = ( norm * 0.4);
else if (number == __SK_ModFrequency_) // 11
this->setTonehole( norm );
else if (number == __SK_ModWheel_) // 1
this->setVent( norm );
else if (number == __SK_AfterTouch_Cont_) // 128
envelope->setValue( norm );
else
cerr << "BlowHole: Undefined Control Number (" << number << ")!!" << endl;
#if defined(_STK_DEBUG_)
cerr << "BlowHole: controlChange number = " << number << ", value = " << value << endl;
#endif
}