Added new Recorder class, fixed bug in StifKarp.

This commit is contained in:
Gary Scavone
2019-04-16 11:04:41 -04:00
parent 8de7543266
commit ae2bac1601
10 changed files with 736 additions and 184 deletions

167
include/Recorder.h Normal file
View File

@@ -0,0 +1,167 @@
#ifndef STK_RECORDER_H
#define STK_RECORDER_H
#include "Instrmnt.h"
#include "Iir.h"
#include "DelayL.h"
#include "Noise.h"
#include "SineWave.h"
#include "ADSR.h"
namespace stk {
/***************************************************/
/*! \class Recorder
\brief A recorder / flute physical model.
This class implements a physical model of a recorder /
flute instrument, based on the paper "Sound production
in recorderlike instruments. II. A simulation model."
by M.P. Verge, A. Hirschberg and R. Causse, Journal of
the Acoustical Society of America, 1997.
Control Change Numbers:
- Softness = 2
- Noise Gain = 4
- Noise Cutoff = 16
- Vibrato Frequency = 11
- Vibrato Gain = 1
- Breath Pressure = 128
by Mathias Bredholt, McGill University.
Formatted for STK by Gary Scavone, 2019.
*/
/***************************************************/
class Recorder : public Instrmnt
{
public:
//! Class constructor.
Recorder( void );
//! Class destructor.
~Recorder( void );
//! Reset and clear all internal state.
void clear( void );
//! Set instrument parameters for a particular frequency.
void setFrequency( StkFloat val );
//! Apply breath velocity to instrument with given amplitude and rate of increase.
void startBlowing( StkFloat amplitude, StkFloat rate );
//! Decrease breath velocity with given rate of decrease.
void stopBlowing( StkFloat rate );
//! Start a note with the given frequency and amplitude.
void noteOn( StkFloat frequency, StkFloat amplitude );
//! Stop a note with the given amplitude (speed of decay).
void noteOff( StkFloat amplitude );
//! Perform the control change specified by \e number and \e value (0.0 - 128.0).
void controlChange( int number, StkFloat value );
//! Compute and return one output sample.
StkFloat tick( unsigned int channel = 0 );
//! Fill a channel of the StkFrames object with computed outputs.
/*!
The \c channel argument must be less than the number of
channels in the StkFrames argument (the first channel is specified
by 0). However, range checking is only performed if _STK_DEBUG_
is defined during compilation, in which case an out-of-range value
will trigger an StkError exception.
*/
StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
void setBlowPressure( StkFloat val );
void setVibratoGain( StkFloat val );
void setVibratoFrequency( StkFloat val );
void setNoiseGain( StkFloat val );
void setBreathCutoff( StkFloat val );
void setSoftness( StkFloat val );
private:
DelayL pinDelay_;
DelayL poutDelay_;
DelayL jetDelay_;
Iir radiation_filter_;
Iir visco_in_filter_;
Iir visco_out_filter_;
Iir jetFilter_;
Noise turb_;
Iir turbFilter_;
SineWave vibrato_;
ADSR adsr_;
//StkFloat M{ 0 };
//StkFloat maxPressure_( 0 );
double maxPressure_;
//StkFloat blow{ 0 };
StkFloat vibratoGain_;
StkFloat noiseGain_;
StkFloat breathCutoff_;
StkFloat outputGain_;
StkFloat psi_;
StkFloat poutL_;
StkFloat pout_;
StkFloat poutm1_;
StkFloat poutm2_;
StkFloat pin_;
StkFloat pinm1_;
StkFloat pinm2_;
StkFloat b1;
StkFloat b3;
StkFloat b4;
StkFloat Uj_;
StkFloat Ujm1_;
StkFloat Qj_;
StkFloat Qjm1_;
StkFloat Qjm2_;
StkFloat Q1_;
StkFloat Q1m1_;
StkFloat Q1m2_;
StkFloat Qp_;
StkFloat Qpm1_;
StkFloat pm_;
};
inline StkFrames& Recorder :: tick( StkFrames& frames, unsigned int channel )
{
unsigned int nChannels = lastFrame_.channels();
#if defined(_STK_DEBUG_)
if ( channel > frames.channels() - nChannels ) {
oStream_ << "Recorder::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
StkFloat *samples = &frames[channel];
unsigned int j, hop = frames.channels() - nChannels;
if ( nChannels == 1 ) {
for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
*samples++ = tick();
}
else {
for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
*samples++ = tick();
for ( j=1; j<nChannels; j++ )
*samples++ = lastFrame_[j];
}
}
return frames;
}
} // stk namespace
#endif

View File

@@ -37,7 +37,7 @@ class StifKarp : public Instrmnt
{ {
public: public:
//! Class constructor, taking the lowest desired playing frequency. //! Class constructor, taking the lowest desired playing frequency.
StifKarp( StkFloat lowestFrequency = 8.0 ); StifKarp( StkFloat lowestFrequency = 10.0 );
//! Class destructor. //! Class destructor.
~StifKarp( void ); ~StifKarp( void );
@@ -95,7 +95,6 @@ class StifKarp : public Instrmnt
Noise noise_; Noise noise_;
BiQuad biquad_[4]; BiQuad biquad_[4];
unsigned long length_;
StkFloat loopGain_; StkFloat loopGain_;
StkFloat baseLoopGain_; StkFloat baseLoopGain_;
StkFloat lastFrequency_; StkFloat lastFrequency_;

View File

@@ -10,13 +10,13 @@ vpath %.o $(OBJECT_PATH)
OBJECTS = Stk.o Noise.o Envelope.o ADSR.o \ OBJECTS = Stk.o Noise.o Envelope.o ADSR.o \
Modulate.o SingWave.o SineWave.o FileRead.o FileWrite.o \ Modulate.o SingWave.o SineWave.o FileRead.o FileWrite.o \
FileWvIn.o FileLoop.o FileWvOut.o \ FileWvIn.o FileLoop.o FileWvOut.o \
OneZero.o OnePole.o PoleZero.o TwoZero.o Fir.o \ OneZero.o OnePole.o PoleZero.o TwoZero.o Fir.o Iir.o \
BiQuad.o FormSwep.o Delay.o DelayL.o DelayA.o \ BiQuad.o FormSwep.o Delay.o DelayL.o DelayA.o \
ReedTable.o JetTable.o BowTable.o \ ReedTable.o JetTable.o BowTable.o \
JCRev.o \ JCRev.o \
Voicer.o Vector3D.o Sphere.o Twang.o \ Voicer.o Vector3D.o Sphere.o Twang.o \
\ \
Clarinet.o BlowHole.o Saxofony.o Flute.o Brass.o BlowBotl.o \ Clarinet.o BlowHole.o Saxofony.o Flute.o Brass.o BlowBotl.o Recorder.o \
Bowed.o Plucked.o StifKarp.o Sitar.o PluckTwo.o Mandolin.o Mesh2D.o \ Bowed.o Plucked.o StifKarp.o Sitar.o PluckTwo.o Mandolin.o Mesh2D.o \
FM.o Rhodey.o Wurley.o TubeBell.o HevyMetl.o PercFlut.o BeeThree.o FMVoices.o \ FM.o Rhodey.o Wurley.o TubeBell.o HevyMetl.o PercFlut.o BeeThree.o FMVoices.o \
Sampler.o Moog.o Simple.o Drummer.o Shakers.o \ Sampler.o Moog.o Simple.o Drummer.o Shakers.o \

View File

@@ -151,6 +151,8 @@ menu .menu.instrument -tearoff 0
-value 2600 -command { patchChange $patchnum } -value 2600 -command { patchChange $patchnum }
.menu.instrument add radio -label "Police Whistle" -variable patchnum \ .menu.instrument add radio -label "Police Whistle" -variable patchnum \
-value 2700 -command { patchChange $patchnum } -value 2700 -command { patchChange $patchnum }
.menu.instrument add radio -label "Recorder" -variable patchnum \
-value 2800 -command { patchChange $patchnum }
. configure -menu .menu . configure -menu .menu
@@ -744,6 +746,23 @@ proc patchChange {value} {
printWhatz "ControlChange 0.0 1 " 2 $cont2 printWhatz "ControlChange 0.0 1 " 2 $cont2
flush stdout flush stdout
} }
if {$program==28} { # Recorder
.pretty config -bitmap @$bitmappath/KFloot.xbm
.left.bPressure config -state normal -label "Breath Pressure"
.left.pitch config -state normal -label "MIDI Note Number"
.left.cont2 config -state normal -label "Softness"
.right.cont4 config -state normal -label "Breath Noise"
.right.cont11 config -state normal -label "Vibrato Rate"
.right.cont1 config -state normal -label "Vibrato Amount"
set cont1 10.0
set cont2 64.0
set cont4 40.0
set cont11 64.0
printWhatz "ControlChange 0.0 1 " 1 $cont1
printWhatz "ControlChange 0.0 1 " 2 $cont2
printWhatz "ControlChange 0.0 1 " 4 $cont4
printWhatz "ControlChange 0.0 1 " 11 $cont11
}
set oldpatch $value set oldpatch $value
} }
} }

View File

@@ -43,6 +43,8 @@ radiobutton .radios2.sitr -text "Sitar" -bg grey66 \
-variable patchnum -value 9 -command { patchChange $patchnum } -variable patchnum -value 9 -command { patchChange $patchnum }
radiobutton .radios2.mand -text "Mandolin" -bg grey66 \ radiobutton .radios2.mand -text "Mandolin" -bg grey66 \
-variable patchnum -value 10 -command { patchChange $patchnum } -variable patchnum -value 10 -command { patchChange $patchnum }
radiobutton .radios2.recdr -text "Recorder" -bg grey66 \
-variable patchnum -value 28 -command { patchChange $patchnum }
pack .radios1.clar -side left -padx 5 -pady 10 pack .radios1.clar -side left -padx 5 -pady 10
pack .radios1.hole -side left -padx 5 -pady 10 pack .radios1.hole -side left -padx 5 -pady 10
@@ -55,6 +57,7 @@ pack .radios2.pluk -side left -padx 5 -pady 10
pack .radios2.karp -side left -padx 5 -pady 10 pack .radios2.karp -side left -padx 5 -pady 10
pack .radios2.sitr -side left -padx 5 -pady 10 pack .radios2.sitr -side left -padx 5 -pady 10
pack .radios2.mand -side left -padx 5 -pady 10 pack .radios2.mand -side left -padx 5 -pady 10
pack .radios2.recdr -side left -padx 5 -pady 10
pack .radios1 pack .radios1
pack .radios2 pack .radios2
@@ -169,178 +172,195 @@ proc noteOff {pitchVal pressVal} {
proc patchChange {value} { proc patchChange {value} {
global bitmappath cont1 cont2 cont4 cont11 pitch oldpatch global bitmappath cont1 cont2 cont4 cont11 pitch oldpatch
puts [format "ProgramChange 0.0 1 %i" $value] puts [format "ProgramChange 0.0 1 %i" $value]
if {$value==0} { # Clarinet if {$value==0} { # Clarinet
.pretty config -bitmap @$bitmappath/Klar.xbm .pretty config -bitmap @$bitmappath/Klar.xbm
.left.bPressure config -state normal -label "Breath Pressure" .left.bPressure config -state normal -label "Breath Pressure"
.left.pitch config -state normal -label "MIDI Note Number" .left.pitch config -state normal -label "MIDI Note Number"
.left.cont2 config -state normal -label "Reed Stiffness" .left.cont2 config -state normal -label "Reed Stiffness"
.right.cont4 config -state normal -label "Breath Noise" .right.cont4 config -state normal -label "Breath Noise"
.right.cont11 config -state normal -label "Vibrato Rate" .right.cont11 config -state normal -label "Vibrato Rate"
.right.cont1 config -state normal -label "Vibrato Amount" .right.cont1 config -state normal -label "Vibrato Amount"
set cont1 20.0 set cont1 20.0
set cont2 64.0 set cont2 64.0
set cont4 20.0 set cont4 20.0
set cont11 64.0 set cont11 64.0
printWhatz "ControlChange 0.0 1 " 1 $cont1 printWhatz "ControlChange 0.0 1 " 1 $cont1
printWhatz "ControlChange 0.0 1 " 2 $cont2 printWhatz "ControlChange 0.0 1 " 2 $cont2
printWhatz "ControlChange 0.0 1 " 4 $cont4 printWhatz "ControlChange 0.0 1 " 4 $cont4
printWhatz "ControlChange 0.0 1 " 11 $cont11 printWhatz "ControlChange 0.0 1 " 11 $cont11
} }
if {$value==1} { # BlowHole if {$value==1} { # BlowHole
.pretty config -bitmap @$bitmappath/Klar.xbm .pretty config -bitmap @$bitmappath/Klar.xbm
.left.bPressure config -state normal -label "Breath Pressure" .left.bPressure config -state normal -label "Breath Pressure"
.left.pitch config -state normal -label "MIDI Note Number" .left.pitch config -state normal -label "MIDI Note Number"
.left.cont2 config -state normal -label "Reed Stiffness" .left.cont2 config -state normal -label "Reed Stiffness"
.right.cont4 config -state normal -label "Breath Noise" .right.cont4 config -state normal -label "Breath Noise"
.right.cont11 config -state normal -label "Tonehole Openness" .right.cont11 config -state normal -label "Tonehole Openness"
.right.cont1 config -state normal -label "Register Vent Openness" .right.cont1 config -state normal -label "Register Vent Openness"
set cont1 0.0 set cont1 0.0
set cont2 64.0 set cont2 64.0
set cont4 20.0 set cont4 20.0
set cont11 0.0 set cont11 0.0
printWhatz "ControlChange 0.0 1 " 1 $cont1 printWhatz "ControlChange 0.0 1 " 1 $cont1
printWhatz "ControlChange 0.0 1 " 2 $cont2 printWhatz "ControlChange 0.0 1 " 2 $cont2
printWhatz "ControlChange 0.0 1 " 4 $cont4 printWhatz "ControlChange 0.0 1 " 4 $cont4
printWhatz "ControlChange 0.0 1 " 11 $cont11 printWhatz "ControlChange 0.0 1 " 11 $cont11
} }
if {$value==2} { # Saxofony if {$value==2} { # Saxofony
.pretty config -bitmap @$bitmappath/prcFunny.xbm .pretty config -bitmap @$bitmappath/prcFunny.xbm
.left.bPressure config -state normal -label "Breath Pressure" .left.bPressure config -state normal -label "Breath Pressure"
.left.pitch config -state normal -label "MIDI Note Number" .left.pitch config -state normal -label "MIDI Note Number"
.left.cont2 config -state normal -label "Reed Stiffness" .left.cont2 config -state normal -label "Reed Stiffness"
.right.cont4 config -state normal -label "Breath Noise" .right.cont4 config -state normal -label "Breath Noise"
.right.cont11 config -state normal -label "Blow Position" .right.cont11 config -state normal -label "Blow Position"
.right.cont1 config -state normal -label "Vibrato Amount" .right.cont1 config -state normal -label "Vibrato Amount"
set cont1 20.0 set cont1 20.0
set cont2 64.0 set cont2 64.0
set cont4 20.0 set cont4 20.0
set cont11 26.0 set cont11 26.0
printWhatz "ControlChange 0.0 1 " 1 $cont1 printWhatz "ControlChange 0.0 1 " 1 $cont1
printWhatz "ControlChange 0.0 1 " 2 $cont2 printWhatz "ControlChange 0.0 1 " 2 $cont2
printWhatz "ControlChange 0.0 1 " 4 $cont4 printWhatz "ControlChange 0.0 1 " 4 $cont4
printWhatz "ControlChange 0.0 1 " 11 $cont11 printWhatz "ControlChange 0.0 1 " 11 $cont11
} }
if {$value==3} { # Flute if {$value==3} { # Flute
.pretty config -bitmap @$bitmappath/KFloot.xbm .pretty config -bitmap @$bitmappath/KFloot.xbm
.left.bPressure config -state normal -label "Breath Pressure" .left.bPressure config -state normal -label "Breath Pressure"
.left.pitch config -state normal -label "MIDI Note Number" .left.pitch config -state normal -label "MIDI Note Number"
.left.cont2 config -state normal -label "Embouchure Adjustment" .left.cont2 config -state normal -label "Embouchure Adjustment"
.right.cont4 config -state normal -label "Breath Noise" .right.cont4 config -state normal -label "Breath Noise"
.right.cont11 config -state normal -label "Vibrato Rate" .right.cont11 config -state normal -label "Vibrato Rate"
.right.cont1 config -state normal -label "Vibrato Amount" .right.cont1 config -state normal -label "Vibrato Amount"
set cont1 20.0 set cont1 20.0
set cont2 64.0 set cont2 64.0
set cont4 20.0 set cont4 20.0
set cont11 64.0 set cont11 64.0
printWhatz "ControlChange 0.0 1 " 1 $cont1 printWhatz "ControlChange 0.0 1 " 1 $cont1
printWhatz "ControlChange 0.0 1 " 2 $cont2 printWhatz "ControlChange 0.0 1 " 2 $cont2
printWhatz "ControlChange 0.0 1 " 4 $cont4 printWhatz "ControlChange 0.0 1 " 4 $cont4
printWhatz "ControlChange 0.0 1 " 11 $cont11 printWhatz "ControlChange 0.0 1 " 11 $cont11
} }
if {$value==4} { # Brass if {$value==4} { # Brass
.pretty config -bitmap @$bitmappath/KHose.xbm .pretty config -bitmap @$bitmappath/KHose.xbm
.left.bPressure config -state normal -label "Breath Pressure" .left.bPressure config -state normal -label "Breath Pressure"
.left.pitch config -state normal -label "MIDI Note Number" .left.pitch config -state normal -label "MIDI Note Number"
.left.cont2 config -state normal -label "Lip Adjustment" .left.cont2 config -state normal -label "Lip Adjustment"
.right.cont4 config -state normal -label "Slide Length" .right.cont4 config -state normal -label "Slide Length"
.right.cont11 config -state normal -label "Vibrato Rate" .right.cont11 config -state normal -label "Vibrato Rate"
.right.cont1 config -state normal -label "Vibrato Amount" .right.cont1 config -state normal -label "Vibrato Amount"
set cont1 0.0 set cont1 0.0
set cont2 64.0 set cont2 64.0
set cont4 20.0 set cont4 20.0
set cont11 64.0 set cont11 64.0
set press 80.0 set press 80.0
printWhatz "ControlChange 0.0 1 " 1 $cont1 printWhatz "ControlChange 0.0 1 " 1 $cont1
printWhatz "ControlChange 0.0 1 " 2 $cont2 printWhatz "ControlChange 0.0 1 " 2 $cont2
printWhatz "ControlChange 0.0 1 " 4 $cont4 printWhatz "ControlChange 0.0 1 " 4 $cont4
printWhatz "ControlChange 0.0 1 " 11 $cont11 printWhatz "ControlChange 0.0 1 " 11 $cont11
puts [format "NoteOn 0.0 1 %3.2f %3.2f" $pitch $press] puts [format "NoteOn 0.0 1 %3.2f %3.2f" $pitch $press]
} }
if {$value==5} { # Bottle if {$value==5} { # Bottle
.pretty config -bitmap @$bitmappath/prcFunny.xbm .pretty config -bitmap @$bitmappath/prcFunny.xbm
.left.bPressure config -state normal -label "Breath Pressure" .left.bPressure config -state normal -label "Breath Pressure"
.left.pitch config -state normal -label "MIDI Note Number" .left.pitch config -state normal -label "MIDI Note Number"
.left.cont2 config -state disabled -label "Disabled" .left.cont2 config -state disabled -label "Disabled"
.right.cont4 config -state normal -label "Breath Noise" .right.cont4 config -state normal -label "Breath Noise"
.right.cont11 config -state normal -label "Vibrato Rate" .right.cont11 config -state normal -label "Vibrato Rate"
.right.cont1 config -state normal -label "Vibrato Amount" .right.cont1 config -state normal -label "Vibrato Amount"
set cont1 20.0 set cont1 20.0
set cont4 20.0 set cont4 20.0
set cont11 64.0 set cont11 64.0
printWhatz "ControlChange 0.0 1 " 1 $cont1 printWhatz "ControlChange 0.0 1 " 1 $cont1
printWhatz "ControlChange 0.0 1 " 4 $cont4 printWhatz "ControlChange 0.0 1 " 4 $cont4
printWhatz "ControlChange 0.0 1 " 11 $cont11 printWhatz "ControlChange 0.0 1 " 11 $cont11
} }
if {$value==6} { # Bowed String if {$value==6} { # Bowed String
.pretty config -bitmap @$bitmappath/KFiddl.xbm .pretty config -bitmap @$bitmappath/KFiddl.xbm
.left.bPressure config -state normal -label "Volume" .left.bPressure config -state normal -label "Volume"
.left.pitch config -state normal -label "MIDI Note Number" .left.pitch config -state normal -label "MIDI Note Number"
.left.cont2 config -state normal -label "Bow Pressure" .left.cont2 config -state normal -label "Bow Pressure"
.right.cont4 config -state normal -label "Bow Position" .right.cont4 config -state normal -label "Bow Position"
.right.cont11 config -state normal -label "Vibrato Rate" .right.cont11 config -state normal -label "Vibrato Rate"
.right.cont1 config -state normal -label "Vibrato Amount" .right.cont1 config -state normal -label "Vibrato Amount"
set cont1 4.0 set cont1 4.0
set cont2 64.0 set cont2 64.0
set cont4 24.0 set cont4 24.0
set cont11 64.0 set cont11 64.0
printWhatz "ControlChange 0.0 1 " 1 $cont1 printWhatz "ControlChange 0.0 1 " 1 $cont1
printWhatz "ControlChange 0.0 1 " 2 $cont2 printWhatz "ControlChange 0.0 1 " 2 $cont2
printWhatz "ControlChange 0.0 1 " 4 $cont4 printWhatz "ControlChange 0.0 1 " 4 $cont4
printWhatz "ControlChange 0.0 1 " 11 $cont11 printWhatz "ControlChange 0.0 1 " 11 $cont11
} }
if {$value==7} { # Yer Basic Pluck if {$value==7} { # Yer Basic Pluck
.pretty config -bitmap @$bitmappath/KPluk.xbm .pretty config -bitmap @$bitmappath/KPluk.xbm
.left.bPressure config -state normal -label "Pluck Strength" .left.bPressure config -state normal -label "Pluck Strength"
.left.pitch config -state normal -label "MIDI Note Number" .left.pitch config -state normal -label "MIDI Note Number"
.left.cont2 config -state disabled -label "Disabled" .left.cont2 config -state disabled -label "Disabled"
.right.cont4 config -state disabled -label "Disabled" .right.cont4 config -state disabled -label "Disabled"
.right.cont11 config -state disabled -label "Disabled" .right.cont11 config -state disabled -label "Disabled"
.right.cont1 config -state disabled -label "Disabled" .right.cont1 config -state disabled -label "Disabled"
} }
if {$value==8} { # Stiff String if {$value==8} { # Stiff String
.pretty config -bitmap @$bitmappath/KPluk.xbm .pretty config -bitmap @$bitmappath/KPluk.xbm
.left.bPressure config -state normal -label "Pluck Strength" .left.bPressure config -state normal -label "Pluck Strength"
.left.pitch config -state normal -label "MIDI Note Number" .left.pitch config -state normal -label "MIDI Note Number"
.left.cont2 config -state disabled -label "Disabled" .left.cont2 config -state disabled -label "Disabled"
.right.cont4 config -state normal -label "Pickup Position" .right.cont4 config -state normal -label "Pickup Position"
.right.cont11 config -state normal -label "String Sustain" .right.cont11 config -state normal -label "String Sustain"
.right.cont1 config -state normal -label "String Stretch" .right.cont1 config -state normal -label "String Stretch"
set cont1 10.0 set cont1 10.0
set cont4 64.0 set cont4 64.0
set cont11 96.0 set cont11 96.0
printWhatz "ControlChange 0.0 1 " 1 $cont1 printWhatz "ControlChange 0.0 1 " 1 $cont1
printWhatz "ControlChange 0.0 1 " 4 $cont4 printWhatz "ControlChange 0.0 1 " 4 $cont4
printWhatz "ControlChange 0.0 1 " 11 $cont11 printWhatz "ControlChange 0.0 1 " 11 $cont11
} }
if {$value==9} { # Sitar if {$value==9} { # Sitar
.pretty config -bitmap @$bitmappath/KPluk.xbm .pretty config -bitmap @$bitmappath/KPluk.xbm
.left.bPressure config -state normal -label "Pluck Strength" .left.bPressure config -state normal -label "Pluck Strength"
.left.pitch config -state normal -label "MIDI Note Number" .left.pitch config -state normal -label "MIDI Note Number"
.left.cont2 config -state disabled -label "Disabled" .left.cont2 config -state disabled -label "Disabled"
.right.cont4 config -state disabled -label "Disabled" .right.cont4 config -state disabled -label "Disabled"
.right.cont11 config -state disabled -label "Disabled" .right.cont11 config -state disabled -label "Disabled"
.right.cont1 config -state disabled -label "Disabled" .right.cont1 config -state disabled -label "Disabled"
} }
if {$value==10} { # Mandolin if {$value==10} { # Mandolin
.pretty config -bitmap @$bitmappath/KPluk.xbm .pretty config -bitmap @$bitmappath/KPluk.xbm
.left.bPressure config -state normal -label "Microphone Position and Gain" .left.bPressure config -state normal -label "Microphone Position and Gain"
.left.pitch config -state normal -label "MIDI Note Number" .left.pitch config -state normal -label "MIDI Note Number"
.left.cont2 config -state normal -label "Mandolin Body Size" .left.cont2 config -state normal -label "Mandolin Body Size"
.right.cont4 config -state normal -label "Pick Position" .right.cont4 config -state normal -label "Pick Position"
.right.cont11 config -state normal -label "String Sustain" .right.cont11 config -state normal -label "String Sustain"
.right.cont1 config -state normal -label "String Detune" .right.cont1 config -state normal -label "String Detune"
set cont1 10.0 set cont1 10.0
set cont2 64.0 set cont2 64.0
set cont4 64.0 set cont4 64.0
set cont11 96.0 set cont11 96.0
set press 64.0 set press 64.0
printWhatz "ControlChange 0.0 1 " 1 $cont1 printWhatz "ControlChange 0.0 1 " 1 $cont1
printWhatz "ControlChange 0.0 1 " 2 $cont2 printWhatz "ControlChange 0.0 1 " 2 $cont2
printWhatz "ControlChange 0.0 1 " 4 $cont4 printWhatz "ControlChange 0.0 1 " 4 $cont4
printWhatz "ControlChange 0.0 1 " 11 $cont11 printWhatz "ControlChange 0.0 1 " 11 $cont11
changePress $press changePress $press
} }
set oldpatch $value if {$value==28} { # Recorder
.pretty config -bitmap @$bitmappath/KFloot.xbm
.left.bPressure config -state normal -label "Breath Pressure"
.left.pitch config -state normal -label "MIDI Note Number"
.left.cont2 config -state normal -label "Softness"
.right.cont4 config -state normal -label "Breath Noise"
.right.cont11 config -state normal -label "Vibrato Rate"
.right.cont1 config -state normal -label "Vibrato Amount"
set cont1 10.0
set cont2 64.0
set cont4 40.0
set cont11 64.0
printWhatz "ControlChange 0.0 1 " 1 $cont1
printWhatz "ControlChange 0.0 1 " 2 $cont2
printWhatz "ControlChange 0.0 1 " 4 $cont4
printWhatz "ControlChange 0.0 1 " 11 $cont11
}
set oldpatch $value
} }
proc printWhatz {tag value1 value2 } { proc printWhatz {tag value1 value2 } {

View File

@@ -10,6 +10,7 @@
#include "BlowHole.h" #include "BlowHole.h"
#include "Saxofony.h" #include "Saxofony.h"
#include "Flute.h" #include "Flute.h"
#include "Recorder.h"
#include "Brass.h" #include "Brass.h"
#include "BlowBotl.h" #include "BlowBotl.h"
#include "Bowed.h" #include "Bowed.h"
@@ -37,7 +38,7 @@
using namespace stk; using namespace stk;
#define NUM_INSTS 28 #define NUM_INSTS 29
// The order of the following list is important. The location of a particular // The order of the following list is important. The location of a particular
// instrument in the list should correspond to that instrument's ProgramChange // instrument in the list should correspond to that instrument's ProgramChange
@@ -46,7 +47,7 @@ char insts[NUM_INSTS][10] = { "Clarinet", "BlowHole", "Saxofony", "Flute", "Bras
"BlowBotl", "Bowed", "Plucked", "StifKarp", "Sitar", "Mandolin", "BlowBotl", "Bowed", "Plucked", "StifKarp", "Sitar", "Mandolin",
"Rhodey", "Wurley", "TubeBell", "HevyMetl", "PercFlut", "Rhodey", "Wurley", "TubeBell", "HevyMetl", "PercFlut",
"BeeThree", "FMVoices", "VoicForm", "Moog", "Simple", "Drummer", "BeeThree", "FMVoices", "VoicForm", "Moog", "Simple", "Drummer",
"BandedWG", "Shakers", "ModalBar", "Mesh2D", "Resonate", "Whistle" }; "BandedWG", "Shakers", "ModalBar", "Mesh2D", "Resonate", "Whistle", "Recorder" };
int voiceByNumber(int number, Instrmnt **instrument) int voiceByNumber(int number, Instrmnt **instrument)
{ {
@@ -82,6 +83,7 @@ int voiceByNumber(int number, Instrmnt **instrument)
else if (number==25) *instrument = new Mesh2D(10, 10); else if (number==25) *instrument = new Mesh2D(10, 10);
else if (number==26) *instrument = new Resonate; else if (number==26) *instrument = new Resonate;
else if (number==27) *instrument = new Whistle; else if (number==27) *instrument = new Whistle;
else if (number==28) *instrument = new Recorder;
else { else {
printf("\nUnknown instrument or program change requested!\n"); printf("\nUnknown instrument or program change requested!\n");

View File

@@ -47,8 +47,8 @@ Flute :: Flute( StkFloat lowestFrequency )
adsr_.setAllTimes( 0.005, 0.01, 0.8, 0.010 ); adsr_.setAllTimes( 0.005, 0.01, 0.8, 0.010 );
endReflection_ = 0.5; endReflection_ = 0.5;
jetReflection_ = 0.5; jetReflection_ = 0.5;
noiseGain_ = 0.15; // Breath pressure random component. noiseGain_ = 0.15; // Breath pressure random component
vibratoGain_ = 0.05; // Breath periodic vibrato component. vibratoGain_ = 0.05; // Breath periodic vibrato component
jetRatio_ = 0.32; jetRatio_ = 0.32;
maxPressure_ = 0.0; maxPressure_ = 0.0;

View File

@@ -26,7 +26,7 @@ OBJECTS = Stk.o Generator.o Noise.o Blit.o BlitSaw.o BlitSquare.o Granulate.o \
Function.o ReedTable.o JetTable.o BowTable.o Cubic.o \ Function.o ReedTable.o JetTable.o BowTable.o Cubic.o \
Voicer.o Vector3D.o Sphere.o Twang.o Guitar.o \ Voicer.o Vector3D.o Sphere.o Twang.o Guitar.o \
\ \
Instrmnt.o Clarinet.o BlowHole.o Saxofony.o Flute.o Brass.o BlowBotl.o \ Instrmnt.o Clarinet.o BlowHole.o Saxofony.o Flute.o Recorder.o Brass.o BlowBotl.o \
Bowed.o Plucked.o StifKarp.o Sitar.o Mandolin.o Mesh2D.o \ Bowed.o Plucked.o StifKarp.o Sitar.o Mandolin.o Mesh2D.o \
FM.o Rhodey.o Wurley.o TubeBell.o HevyMetl.o PercFlut.o BeeThree.o FMVoices.o \ FM.o Rhodey.o Wurley.o TubeBell.o HevyMetl.o PercFlut.o BeeThree.o FMVoices.o \
Sampler.o Moog.o Simple.o Drummer.o Shakers.o \ Sampler.o Moog.o Simple.o Drummer.o Shakers.o \

345
src/Recorder.cpp Normal file
View File

@@ -0,0 +1,345 @@
/***************************************************/
/*! \class Recorder
\brief A recorder / flute physical model.
This class implements a physical model of a recorder /
flute instrument, based on the paper "Sound production
in recorderlike instruments. II. A simulation model."
by M.P. Verge, A. Hirschberg and R. Causse, Journal of
the Acoustical Society of America, 1997.
Control Change Numbers:
- Softness = 2
- Noise Gain = 4
- Noise Cutoff = 16
- Vibrato Frequency = 11
- Vibrato Gain = 1
- Breath Pressure = 128
by Mathias Bredholt, McGill University.
Formatted for STK by Gary Scavone, 2019.
*/
/***************************************************/
#include "Recorder.h"
#include "SKINImsg.h"
namespace stk {
// Air constants
const stk::StkFloat rho = 1.2041; // density of air
const stk::StkFloat c0 = 343.21; // speed of sound in air
// Flute constants
const stk::StkFloat lc = 0.02; // length of flue canal
const stk::StkFloat h = 0.001; // height of flue exit
const stk::StkFloat H = 0.02; // pipe diameter
const stk::StkFloat W = 4 * h; // width of mouth
const stk::StkFloat Sp = H * H; // cross-section of pipe
const stk::StkFloat Sm = W * H; // cross-section of mouth
const stk::StkFloat din = 0.0030; // end correction
const stk::StkFloat dout = 0.0063; // end correction
const stk::StkFloat dm = din + dout; // end correction of mouth
const stk::StkFloat dd = 0.0035; // acoustic distance between Q1 and Q2
const stk::StkFloat rp = sqrt(Sp / stk::PI);
const stk::StkFloat b = 0.4 * h; // jet width
// Calculation coefficients
const stk::StkFloat b2 = Sp / (rho * c0);
Recorder :: Recorder()
{
vibratoGain_ = 0.0;
noiseGain_ = 0.2;
breathCutoff_ = 0.0;
outputGain_ = 0.0;
psi_ = 1.0;
poutL_ = 0;
pout_ = 0;
poutm1_ = 0;
poutm2_ = 0;
pin_ = 0;
pinm1_ = 0;
pinm2_ = 0;
Uj_ = 0;
Ujm1_ = 0;
Qj_ = 0;
Qjm1_ = 0;
Qjm2_ = 0;
Q1_ = 0;
Q1m1_ = 0;
Q1m2_ = 0;
Qp_ = 0;
Qpm1_ = 0;
pm_ = 0;
pinDelay_.tick( 0 );
poutDelay_.tick( 0 );
jetDelay_.tick( 0 );
jetDelay_.setDelay(200);
vibrato_.setFrequency(4);
// Calculation coefficients ... would need to be recalculated if sample rate changes
StkFloat T = 1.0 / Stk::sampleRate();
b1 = rho / (4.0 * PI * c0 * T * T);
b3 = dm * Sp / (T * Sm * c0);
b4 = rho * dout / (Sm * T);
// Radiation loss filter
StkFloat A = rp * rp / (4 * c0 * c0 * T * T);
StkFloat B = 0.82 * rp / (c0*T);
StkFloat b_rad[3] = { 1 + A - B, B - 2 * A, A };
StkFloat a_rad[3] = { A - B - 1, B - 2 * A, A };
std::vector<StkFloat> b_coeffs( &b_rad[0], &b_rad[0]+3 );
std::vector<StkFloat> a_coeffs( &a_rad[0], &a_rad[0]+3 );
radiation_filter_.setCoefficients(b_coeffs, a_coeffs);
// Visco-thermal loss filter
StkFloat b_visco[4] = { 0.83820223947141, -0.16888603248373, -0.64759781930259, 0.07424498608506 };
StkFloat a_visco[4] = { 1.0, -0.33623476246554, -0.71257915055968, 0.14508304017256 };
b_coeffs.clear();
b_coeffs.assign( &b_visco[0], &b_visco[0]+4 );
a_coeffs.clear();
a_coeffs.assign( &a_visco[0], &a_visco[0]+4 );
visco_in_filter_.setCoefficients(b_coeffs, a_coeffs);
visco_out_filter_.setCoefficients(b_coeffs, a_coeffs);
setBreathCutoff( 500 );
setFrequency( 880 );
}
Recorder :: ~Recorder( void )
{
}
void Recorder :: clear( void )
{
pinDelay_.clear();
poutDelay_.clear();
jetDelay_.clear();
radiation_filter_.clear();
visco_in_filter_.clear();
visco_out_filter_.clear();
turbFilter_.clear();
}
void Recorder :: setFrequency( StkFloat val )
{
#if defined(_STK_DEBUG_)
if ( val <= 0.0 ) {
oStream_ << "Recorder::setFrequency: argument is less than or equal to zero!";
handleError( StkError::WARNING ); return;
}
#endif
StkFloat M = Stk::sampleRate() / val - 4 - 3;
pinDelay_.setDelay( M );
poutDelay_.setDelay( M );
}
void Recorder :: setBlowPressure( StkFloat val )
{
maxPressure_ = val;
}
void Recorder :: setVibratoGain( StkFloat val )
{
vibratoGain_ = val;
}
void Recorder :: setVibratoFrequency( StkFloat val )
{
vibrato_.setFrequency( val );
}
void Recorder :: setNoiseGain( StkFloat val )
{
noiseGain_ = val;
}
void Recorder :: setBreathCutoff( StkFloat val )
{
// The gain of this filter is quite high
breathCutoff_ = val;
StkFloat Q = 0.99;
StkFloat r = 2.0 * sin(PI * val / sampleRate());
StkFloat q = 1.0 - r * Q;
StkFloat as[3] = { 1.0, r * r - q - 1, q };
std::vector<StkFloat> b_turb(1, r*r);
std::vector<StkFloat> a_turb( &as[0], &as[0]+3 );
turbFilter_.setCoefficients(b_turb, a_turb);
}
void Recorder :: setSoftness( StkFloat val )
{
psi_ = val;
}
void Recorder :: startBlowing( StkFloat amplitude, StkFloat rate )
{
if ( amplitude <= 0.0 || rate <= 0.0 ) {
oStream_ << "Recorder::startBlowing: one or more arguments is less than or equal to zero!";
handleError( StkError::WARNING ); return;
}
adsr_.setAttackRate( rate );
//maxPressure_ = amplitude / (StkFloat) 0.8;
maxPressure_ = 35 * amplitude;
adsr_.keyOn();
}
void Recorder :: stopBlowing( StkFloat rate )
{
if ( rate <= 0.0 ) {
oStream_ << "Recorder::stopBlowing: argument is less than or equal to zero!";
handleError( StkError::WARNING ); return;
}
adsr_.setReleaseRate( rate );
adsr_.keyOff();
}
void Recorder :: noteOn( StkFloat frequency, StkFloat amplitude )
{
this->setFrequency( frequency );
this->startBlowing( 1.1 + (amplitude * 0.20), amplitude * 0.02 );
outputGain_ = amplitude / 40.0;
}
void Recorder :: noteOff( StkFloat amplitude )
{
this->stopBlowing( amplitude * 0.02 );
}
void Recorder :: controlChange( int number, StkFloat value )
{
#if defined(_STK_DEBUG_)
if ( Stk::inRange( value, 0.0, 128.0 ) == false ) {
oStream_ << "Recorder::controlChange: value (" << value << ") is out of range!";
handleError( StkError::WARNING ); return;
}
#endif
StkFloat normalizedValue = value * ONE_OVER_128;
if (number == 2) // 2
psi_ = 2.0 * normalizedValue;
else if (number == 16)
setBreathCutoff( normalizedValue * 2000 );
else if (number == __SK_NoiseLevel_) // 4
noiseGain_ = normalizedValue;
else if (number == __SK_ModFrequency_) // 11
vibrato_.setFrequency( normalizedValue * 12.0);
else if (number == __SK_ModWheel_) // 1
vibratoGain_ = ( normalizedValue * 0.4 );
else if (number == __SK_AfterTouch_Cont_) // 128
maxPressure_ = 35.0 * normalizedValue;
#if defined(_STK_DEBUG_)
else {
oStream_ << "Recorder::controlChange: undefined control number (" << number << ")!";
handleError( StkError::WARNING );
}
#endif
}
StkFloat Recorder::tick( unsigned int )
{
// Read in from delay lines
pinm2_ = pinm1_;
pinm1_ = pin_;
pin_ = pinDelay_.lastOut();
poutm2_ = poutm1_;
poutm1_ = pout_;
poutL_ = poutDelay_.lastOut();
// Filter wave components for visco-thermal losses
pin_ = visco_in_filter_.tick(pin_);
poutL_ = visco_out_filter_.tick(poutL_);
// Get input blow pressure
StkFloat pf = maxPressure_ * adsr_.tick() * (vibrato_.tick() * vibratoGain_ + (1 - vibratoGain_));
StkFloat T = 1.0 / sampleRate();
// Jet velocity at flue exit
Ujm1_ = Uj_;
Uj_ = Ujm1_ + T / (rho * lc) * (pf - pm_ - 0.5 * rho * Ujm1_ * Ujm1_);
// Jet flow at flue exit
Qjm2_ = Qjm1_;
Qjm1_ = Qj_;
Qj_ = h * H * Uj_;
// Jet drive
StkFloat Uj_steady = fmax(sqrt(2 * pf / rho), 0.1);
StkFloat fc_jet = 0.36 / W * Uj_steady;
StkFloat g_jet = 0.002004 * exp(-0.06046 * Uj_steady);
StkFloat r_jet = 0.95 - Uj_steady * 0.015;
StkFloat b0_jet = g_jet * (1 - r_jet * r_jet) / 2;
// Calculate coefficients for resonant filter
StkFloat b_jet[3] = { b0_jet, 0, -b0_jet };
StkFloat a_jet[3] = { 1, -2 * r_jet * cos(2 * PI * fc_jet * T), r_jet * r_jet };
std::vector<StkFloat> b_jetcoeffs( &b_jet[0], &b_jet[0]+3 );
std::vector<StkFloat> a_jetcoeffs( &a_jet[0], &a_jet[0]+3 );
jetFilter_.setCoefficients( b_jetcoeffs, a_jetcoeffs );
StkFloat eta = jetFilter_.tick(jetDelay_.lastOut());
// Calculate flow source Q1
Q1m1_ = Q1_;
Q1_ = b * H * Uj_ * (1 + tanh(eta / (psi_ * b)));
// Calculate pressure pulse modeling the jet drive
StkFloat pjd = -rho * dd / Sm * (Q1_ - Q1m1_) / T;
// Vortex shedding
int Qp_sign = 0;
if (Qp_ < 0) Qp_sign = -1;
else if (Qp_ > 0) Qp_sign = 1;
StkFloat pa = -0.5 * rho * (Qp_ / (0.6 * Sm)) * (Qp_ / (0.6 * Sm)) * Qp_sign;
// Turbulence
StkFloat pt = turbFilter_.tick(noiseGain_ * turb_.tick() * 0.5 * rho * Uj_ * Uj_);
// Pressure pulse delta p
StkFloat dp = pjd + pa + pt;
// Calculate outgoing pressure pout
pout_ = ((b3 - b1 * b2 - 1) * pin_ +
(2 * b1 * b2 - b3) * (pinm1_ - poutm1_) +
b1 * b2 * (poutm2_ - pinm2_) -
b1 * (Qj_ - 2 * Qjm1_ + Qjm2_) +
b4 * (Qj_ - Qjm1_) + dp) / (1 - b1 * b2 + b3);
// Flow in the pipe
Qpm1_ = Qp_;
Qp_ = Sp / (rho * c0) * (pout_ - pin_);
// Mouth pressure
pm_ = pout_ + pin_ - dp + rho * din / Sm * (Qp_ - Qpm1_)/T;
// Calculate transverse acoustic velocity
StkFloat Q1d = Q1_ - 0.5 * b * H * Uj_;
StkFloat Vac = 2.0 / PI * Qp_ / Sm - 0.38 * Q1d / Sm;
jetDelay_.tick(Vac);
// Calculate new jet delay line length
//jet_.setDelay(fmin(W / (0.6 * Uj_steady) * sampleRate(), 200.0));
jetDelay_.setDelay(fmin(W / (0.6 * Uj_steady * T), 200.0));
// Radiation loss filtering
StkFloat pin_L = radiation_filter_.tick(poutL_);
// Write to delay lines
poutDelay_.tick(pout_);
pinDelay_.tick(pin_L);
lastFrame_[0] = outputGain_ * (pout_ + pin_);
return lastFrame_[0];
//return (pout_0 + pin_0) * 0.01;
}
} // stk namespace

View File

@@ -89,7 +89,7 @@ void StifKarp :: setStretch( StkFloat stretch )
StkFloat freq = lastFrequency_ * 2.0; StkFloat freq = lastFrequency_ * 2.0;
StkFloat dFreq = ( (0.5 * Stk::sampleRate()) - freq ) * 0.25; StkFloat dFreq = ( (0.5 * Stk::sampleRate()) - freq ) * 0.25;
StkFloat temp = 0.5 + (stretch * 0.5); StkFloat temp = 0.5 + (stretch * 0.5);
if ( temp > 0.9999 ) temp = 0.9999; if ( temp > 0.99999 ) temp = 0.99999;
for ( int i=0; i<4; i++ ) { for ( int i=0; i<4; i++ ) {
coefficient = temp * temp; coefficient = temp * temp;
biquad_[i].setA2( coefficient ); biquad_[i].setA2( coefficient );
@@ -131,7 +131,7 @@ void StifKarp :: pluck( StkFloat amplitude )
} }
pluckAmplitude_ = amplitude; pluckAmplitude_ = amplitude;
for ( unsigned long i=0; i<length_; i++ ) { for ( unsigned long i=0; i<lastLength_; i++ ) {
// Fill delay with noise additively with current contents. // Fill delay with noise additively with current contents.
delayLine_.tick( (delayLine_.lastOut() * 0.6) + 0.4 * noise_.tick() * pluckAmplitude_ ); delayLine_.tick( (delayLine_.lastOut() * 0.6) + 0.4 * noise_.tick() * pluckAmplitude_ );
//delayLine_.tick( combDelay_.tick((delayLine_.lastOut() * 0.6) + 0.4 * noise->tick() * pluckAmplitude_) ); //delayLine_.tick( combDelay_.tick((delayLine_.lastOut() * 0.6) + 0.4 * noise->tick() * pluckAmplitude_) );