From a8b6affd8c2c1c5a2d3bc0caaded1b7c194d061e Mon Sep 17 00:00:00 2001 From: Gary Scavone Date: Sun, 15 Mar 2020 16:45:30 -0400 Subject: [PATCH] New default argument to keyOn and keyOff in Envelope, fix in setTime function, updates to Guitar string coupling, EGuitar tcl interface, reordering of operations in Flute algorithm. --- include/Envelope.h | 13 ++++--- include/Flute.h | 5 ++- include/Guitar.h | 7 +++- projects/demo/tcl/Physical.tcl | 2 +- projects/eguitar/tcl/EGuitar.tcl | 63 ++++++++++++++++++++++++-------- src/Envelope.cpp | 6 ++- 6 files changed, 67 insertions(+), 29 deletions(-) diff --git a/include/Envelope.h b/include/Envelope.h index 743c829..dcef86b 100644 --- a/include/Envelope.h +++ b/include/Envelope.h @@ -12,7 +12,8 @@ namespace stk { This class implements a simple linear line envelope generator which is capable of ramping to an arbitrary target value by a specified \e rate. It also responds to simple \e keyOn and \e - keyOff messages, ramping to 1.0 on keyOn and to 0.0 on keyOff. + keyOff messages, ramping to a specified target (default = 1.0) on + keyOn and to a specified target (default = 0.0) on keyOff. by Perry R. Cook and Gary P. Scavone, 1995--2019. */ @@ -31,11 +32,11 @@ class Envelope : public Generator //! Assignment operator. Envelope& operator= ( const Envelope& e ); - //! Set target = 1. - void keyOn( void ) { this->setTarget( 1.0 ); }; + //! Start ramping to specified target (default = 1). + void keyOn( StkFloat target = 1.0 ) { this->setTarget( target ); }; - //! Set target = 0. - void keyOff( void ) { this->setTarget( 0.0 ); }; + //! Start ramping to specified target (default = 0). + void keyOff( StkFloat target = 0.0 ) { this->setTarget( target ); }; //! Set the \e rate. /*! @@ -46,7 +47,7 @@ class Envelope : public Generator //! Set the \e rate based on a positive time duration (seconds). /*! The \e rate is calculated such that the envelope will ramp from - a value of 0.0 to 1.0 in the specified time duration. + the current value to the current target in the specified time duration. */ void setTime( StkFloat time ); diff --git a/include/Flute.h b/include/Flute.h index 4fdb532..888264f 100644 --- a/include/Flute.h +++ b/include/Flute.h @@ -123,11 +123,12 @@ inline StkFloat Flute :: tick( unsigned int ) breathPressure += breathPressure * ( noiseGain_ * noise_.tick() + vibratoGain_ * vibrato_.tick() ); StkFloat temp = -filter_.tick( boreDelay_.lastOut() ); - temp = dcBlock_.tick( temp ); // Block DC on reflection. + //temp = dcBlock_.tick( temp ); // Block DC on reflection. pressureDiff = breathPressure - (jetReflection_ * temp); pressureDiff = jetDelay_.tick( pressureDiff ); - pressureDiff = jetTable_.tick( pressureDiff ) + (endReflection_ * temp); + //pressureDiff = jetTable_.tick( pressureDiff ) + (endReflection_ * temp); + pressureDiff = dcBlock_.tick(jetTable_.tick( pressureDiff )) + (endReflection_ * temp); // moved the DC blocker to after the jet non-linearity (GPS, 29 Jan. 2020) lastFrame_[0] = (StkFloat) 0.3 * boreDelay_.tick( pressureDiff ); lastFrame_[0] *= outputGain_; diff --git a/include/Guitar.h b/include/Guitar.h index aa1bfab..7b653b5 100644 --- a/include/Guitar.h +++ b/include/Guitar.h @@ -132,17 +132,20 @@ class Guitar : public Stk StkFrames lastFrame_; }; +// NOTE: It is not possible to implement the Smith coupled string model here because the Twang class does +// not currently offer the chance to have access to a traveling-wave component. Thus, the coupling +// implemented here is approximate. inline StkFloat Guitar :: tick( StkFloat input ) { StkFloat temp, output = 0.0; - lastFrame_[0] /= strings_.size(); // evenly spread coupling across strings + lastFrame_[0] = couplingGain_ * couplingFilter_.tick( lastFrame_[0] ) / strings_.size(); for ( unsigned int i=0; i 0.2 ) temp += pluckGains_[i] * excitation_[filePointer_[i]++]; - temp += couplingGain_ * couplingFilter_.tick( lastFrame_[0] ); // bridge coupling + temp += lastFrame_[0]; // bridge coupling output += strings_[i].tick( temp ); // Check if string energy has decayed sufficiently to turn it off. if ( stringState_[i] == 1 ) { diff --git a/projects/demo/tcl/Physical.tcl b/projects/demo/tcl/Physical.tcl index c3bc946..b615ae9 100644 --- a/projects/demo/tcl/Physical.tcl +++ b/projects/demo/tcl/Physical.tcl @@ -100,7 +100,7 @@ scale .left.bPressure -from 0 -to 128 -length 200 \ -tickinterval 32 -showvalue true -bg grey66 scale .left.pitch -from 0 -to 128 -length 200 \ - -command {changePitch } -variable pitch \ + -command {changePitch } -variable pitch -resolution 0.1 \ -orient horizontal -label "MIDI Note Number" \ -tickinterval 32 -showvalue true -bg grey66 diff --git a/projects/eguitar/tcl/EGuitar.tcl b/projects/eguitar/tcl/EGuitar.tcl index 3690709..38f7244 100644 --- a/projects/eguitar/tcl/EGuitar.tcl +++ b/projects/eguitar/tcl/EGuitar.tcl @@ -19,6 +19,12 @@ array set stringNote { 5 59 6 64 } +array set powerNote { + 1 40 + 2 47 + 3 52 + 4 59 +} #array set stringAmp { 1 64 2 64 3 64 4 64 5 64 6 64 } array set stringAmp { 1 64 @@ -53,10 +59,12 @@ pack .message -padx 5 -pady 10 # Configure "note on" buttons frame .top -button .top.on -text Strum -bg grey66 -command strum -button .top.off -text "All Off" -bg grey66 -command allOff -button .top.exit -text "Quit" -bg grey66 -command quit +button .top.on -text Strum -padx 5 -bg grey66 -command strum +button .top.power -text "Power Chord" -padx 5 -bg grey66 -command powerchord +button .top.off -text "All Off" -padx 5 -bg grey66 -command allOff +button .top.exit -text "Quit" -padx 5 -bg grey66 -command quit pack .top.on -side left -padx 5 +pack .top.power -side left -padx 5 -padx 5 pack .top.off -side left -padx 5 -pady 10 pack .top.exit -side left -padx 5 -pady 10 pack .top @@ -117,13 +125,26 @@ proc quit {} { } proc strum {} { - global stringNote stringAmp + global stringAmp stringNote for {set n 1} {$n < 7} {incr n} { puts [format "NoteOn %2.3f %d %3.2f %3.2f" [expr rand()*0.04] $n $stringNote($n) $stringAmp($n)] } flush stdout } +proc powerchord {} { + global stringNote powerNote stringAmp cont28 cont72 + set cont72 80 + set cont28 90 + puts [format "ControlChange 0.0 0 72 %3.2f" $cont72] + puts [format "ControlChange 0.0 0 28 %3.2f" $cont28] + for {set n 1} {$n < 5} {incr n} { + set stringNote($n) $powerNote($n) + puts [format "NoteOn %2.3f %d %3.2f %3.2f" [expr rand()*0.01] $n $powerNote($n) $stringAmp($n)] + } + flush stdout +} + proc allOff {} { global stringNote stringAmp for {set n 1} {$n < 7} {incr n} { @@ -167,32 +188,32 @@ proc setStringAmp {value} { frame .strings -bg grey88 -borderwidth 5 -relief groove scale .strings.s1 -from $stringMin(1) -to [expr $stringMin(1)+$stringRange] \ -length 350 -orient horizontal -label "String 1: Note Number" \ - -tickinterval 5 -showvalue true -variable $stringNote(1) \ + -tickinterval 5 -showvalue true -variable stringNote(1) \ -command {setNote 1} scale .strings.s2 -from $stringMin(2) -to [expr $stringMin(2)+$stringRange] \ -length 350 -orient horizontal -label "String 2: Note Number" \ - -tickinterval 5 -showvalue true -variable $stringNote(2) \ + -tickinterval 5 -showvalue true -variable stringNote(2) \ -command {setNote 2} scale .strings.s3 -from $stringMin(3) -to [expr $stringMin(3)+$stringRange] \ -length 350 -orient horizontal -label "String 3: Note Number" \ - -tickinterval 5 -showvalue true -variable $stringNote(3) \ + -tickinterval 5 -showvalue true -variable stringNote(3) \ -command {setNote 3} scale .strings.s4 -from $stringMin(4) -to [expr $stringMin(4)+$stringRange] \ -length 350 -orient horizontal -label "String 4: Note Number" \ - -tickinterval 5 -showvalue true -variable $stringNote(4) \ + -tickinterval 5 -showvalue true -variable stringNote(4) \ -command {setNote 4} scale .strings.s5 -from $stringMin(5) -to [expr $stringMin(5)+$stringRange] \ -length 350 -orient horizontal -label "String 5: Note Number" \ - -tickinterval 5 -showvalue true -variable $stringNote(5) \ + -tickinterval 5 -showvalue true -variable stringNote(5) \ -command {setNote 5} scale .strings.s6 -from $stringMin(6) -to [expr $stringMin(6)+$stringRange] \ -length 350 -orient horizontal -label "String 6: Note Number" \ - -tickinterval 5 -showvalue true -variable $stringNote(6) \ + -tickinterval 5 -showvalue true -variable stringNote(6) \ -command {setNote 6} button .strings.b1 -text Pluck -command { pluckOne 1 } @@ -202,7 +223,6 @@ button .strings.b4 -text Pluck -command { pluckOne 4 } button .strings.b5 -text Pluck -command { pluckOne 5 } button .strings.b6 -text Pluck -command { pluckOne 6 } -grid .strings -column 0 -row 0 grid .strings.b1 -column 1 -row 0 -padx 5 -pady 5 grid .strings.b2 -column 1 -row 1 grid .strings.b3 -column 1 -row 2 @@ -218,9 +238,20 @@ grid .strings.s5 -column 0 -row 4 -padx 5 -pady 5 grid .strings.s6 -column 0 -row 5 -padx 5 -pady 5 set stringSelect "All" -ttk::combobox .strings.combo \ - -values [ list "All" "String 1" "String 2" "String 3" "String 4" "String 5" "String 6" ] \ - -width 8 -textvariable stringSelect -justify center +set values [ list "All" "String 1" "String 2" "String 3" "String 4" "String 5" "String 6" ] +ttk::combobox .strings.combo -values $values \ + -width 10 -state readonly -textvariable stringSelect -justify center +bind .strings.combo <> { + global stringAmp velocity + switch [%W get] { + "String 1" { set velocity $stringAmp(1) } + "String 2" { set velocity $stringAmp(2) } + "String 3" { set velocity $stringAmp(3) } + "String 4" { set velocity $stringAmp(4) } + "String 5" { set velocity $stringAmp(5) } + "String 6" { set velocity $stringAmp(6) } + } +} scale .strings.velocity -from 0 -to 128 -length 350 \ -orient horizontal -label "Note Velocity" \ @@ -229,7 +260,7 @@ scale .strings.velocity -from 0 -to 128 -length 350 \ grid .strings.combo -column 1 -row 7 grid .strings.velocity -column 0 -row 7 -padx 5 -pady 10 -pack .strings +pack .strings -side right set cbpath .strings.combo @@ -261,4 +292,4 @@ proc center_the_toplevel { w } { } return -} \ No newline at end of file +} diff --git a/src/Envelope.cpp b/src/Envelope.cpp index 9030ded..0ba1a76 100644 --- a/src/Envelope.cpp +++ b/src/Envelope.cpp @@ -5,7 +5,8 @@ This class implements a simple linear line envelope generator which is capable of ramping to an arbitrary target value by a specified \e rate. It also responds to simple \e keyOn and \e - keyOff messages, ramping to 1.0 on keyOn and to 0.0 on keyOff. + keyOff messages, ramping to a specified target (default = 1.0) on + keyOn and to a specified target (default = 0.0) on keyOff. by Perry R. Cook and Gary P. Scavone, 1995--2019. */ @@ -64,7 +65,8 @@ void Envelope :: setTime( StkFloat time ) handleError( StkError::WARNING ); return; } - rate_ = 1.0 / ( time * Stk::sampleRate() ); + //rate_ = 1.0 / ( time * Stk::sampleRate() ); + rate_ = fabs(target_ - value_) / ( time * Stk::sampleRate() ); } void Envelope :: setTarget( StkFloat target )