Merge branch 'master' of https://scm.cri.ensmp.fr/git/Faustine
[Faustine.git] / interpretor / preprocessor / faust-0.9.47mr3 / examples / faust-stk / blowHole.dsp
1 declare name "BlowHole";
2 declare description "Nonlinear WaveGuide Clarinet with one register hole and one tonehole";
3 declare author "Romain Michon";
4 declare copyright "Romain Michon (rmichon@ccrma.stanford.edu)";
5 declare version "1.0";
6 declare licence "STK-4.3"; // Synthesis Tool Kit 4.3 (MIT style license);
7 declare description "A 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.";
8 declare reference "https://ccrma.stanford.edu/~jos/pasp/Woodwinds.html";
9
10 import("music.lib");
11 import("instrument.lib");
12
13 //==================== GUI SPECIFICATION ================
14
15 freq = nentry("h:Basic_Parameters/freq [1][unit:Hz] [tooltip:Tone frequency]",440,20,20000,1);
16 gain = nentry("h:Basic_Parameters/gain [1][tooltip:Gain (value between 0 and 1)]",1,0,1,0.01);
17 gate = button("h:Basic_Parameters/gate [1][tooltip:noteOn = 1, noteOff = 0]");
18
19 reedStiffness = hslider("h:Physical_and_Nonlinearity/v:Physical_Parameters/Reed_Stiffness
20 [2][tooltip:Reed stiffness (value between 0 and 1)]",0.35,0,1,0.01);
21 toneHoleOpenness = hslider("h:Physical_and_Nonlinearity/v:Physical_Parameters/Tone_Hole_Openness
22 [2][tooltip:A value between 0 and 1]",0.12,0,1,0.01);
23 ventOpenness = hslider("h:Physical_and_Nonlinearity/v:Physical_Parameters/Vent_Openness
24 [2][tooltip:A value between 0 and 1]",0,0,1,0.01);
25 noiseGain = hslider("h:Physical_and_Nonlinearity/v:Physical_Parameters/Noise_Gain
26 [2][tooltip:Breath noise gain (value between 0 and 1)]",0,0,1,0.01);
27 pressure = hslider("h:Physical_and_Nonlinearity/v:Physical_Parameters/Pressure
28 [2][tooltip:Breath pressure (value bewteen 0 and 1)]",0.35,0,1,0.01);
29
30 typeModulation = nentry("h:Physical_and_Nonlinearity/v:Nonlinear_Filter_Parameters/Modulation_Type
31 [3][tooltip: 0=theta is modulated by the incoming signal; 1=theta is modulated by the averaged incoming signal;
32 2=theta is modulated by the squared incoming signal; 3=theta is modulated by a sine wave of frequency freqMod;
33 4=theta is modulated by a sine wave of frequency freq;]",0,0,4,1);
34 nonLinearity = hslider("h:Physical_and_Nonlinearity/v:Nonlinear_Filter_Parameters/Nonlinearity
35 [3][tooltip:Nonlinearity factor (value between 0 and 1)]",0,0,1,0.01);
36 frequencyMod = hslider("h:Physical_and_Nonlinearity/v:Nonlinear_Filter_Parameters/Modulation_Frequency
37 [3][unit:Hz][tooltip:Frequency of the sine wave for the modulation of theta (works if Modulation Type=3)]",220,20,1000,0.1);
38 nonLinAttack = hslider("h:Physical_and_Nonlinearity/v:Nonlinear_Filter_Parameters/Nonlinearity_Attack
39 [3][unit:s][Attack duration of the nonlinearity]",0.1,0,2,0.01);
40
41 vibratoFreq = hslider("h:Envelopes_and_Vibrato/v:Vibrato_Parameters/Vibrato_Freq
42 [4][unit:Hz]",5,1,15,0.1);
43 vibratoGain = hslider("h:Envelopes_and_Vibrato/v:Vibrato_Parameters/Vibrato_Gain
44 [4][tooltip:A value between 0 and 1]",0.1,0,1,0.01);
45 vibratoAttack = hslider("h:Envelopes_and_Vibrato/v:Vibrato_Parameters/Vibrato_Attack
46 [4][unit:s][tooltip:Vibrato attack duration]",0.5,0,2,0.01);
47 vibratoRelease = hslider("h:Envelopes_and_Vibrato/v:Vibrato_Parameters/Vibrato_Release
48 [4][unit:s][tooltip:Vibrato release duration]",0.01,0,2,0.01);
49
50 envelopeAttack = hslider("h:Envelopes_and_Vibrato/v:Envelope_Parameters/Envelope_Attack
51 [5][unit:s][tooltip:Envelope attack duration]",0.01,0,2,0.01);
52 envelopeDecay = hslider("h:Envelopes_and_Vibrato/v:Envelope_Parameters/Envelope_Decay
53 [5][unit:s][tooltip:Envelope decay duration]",0.05,0,2,0.01);
54 envelopeRelease = hslider("h:Envelopes_and_Vibrato/v:Envelope_Parameters/Envelope_Release
55 [5][unit:s][tooltip:Envelope release duration]",0.1,0,2,0.01);
56
57 //==================== SIGNAL PROCESSING ================
58
59 //----------------------- Nonlinear filter ----------------------------
60 //nonlinearities are created by the nonlinear passive allpass ladder filter declared in filter.lib
61
62 //nonlinear filter order (problem with compilation time if order is bigger than 2)
63 nlfOrder = 2;
64
65 //attack - sustain - release envelope for nonlinearity (declared in instrument.lib)
66 envelopeMod = asr(nonLinAttack,100,envelopeRelease,gate);
67
68 //nonLinearModultor is declared in instrument.lib, it adapts allpassnn from filter.lib
69 //for using it with waveguide instruments
70 NLFM = nonLinearModulator((nonLinearity : smooth(0.999)),envelopeMod,freq,
71 typeModulation,(frequencyMod : smooth(0.999)),nlfOrder);
72
73 //----------------------- Synthesis parameters computing and functions declaration ----------------------------
74
75 //reed table parameters
76 reedTableOffset = 0.7;
77 reedTableSlope = -0.44 + (0.26*reedStiffness);
78
79 //the reed function is declared in instrument.lib
80 reedTable = reed(reedTableOffset,reedTableSlope);
81
82 // Calculate the initial tonehole three-port scattering coefficient
83 rb = 0.0075; // main bore radius
84 rth = 0.003; // tonehole radius
85 scattering = pow(rth,2)*-1 / (pow(rth,2) + 2*pow(rb,2));
86
87 // Calculate register hole filter coefficients
88 r_rh = 0.0015; // register vent radius
89 teVent = 1.4*r_rh; // effective length of the open hole
90 xi = 0 ; // series resistance term
91 zeta = 347.23 + 2*PI*pow(rb,2)*xi/1.1769;
92 psi = 2*PI*pow(rb,2)*teVent/(PI*pow(r_rh,2));
93 rhCoeff = (zeta - 2*SR*psi)/(zeta + 2*SR*psi);
94 rhGain = -347.23/(zeta + 2*SR*psi);
95 ventFilterGain = rhGain*ventOpenness;
96
97 // Vent filter
98 ventFilter = *(ventFilterGain) : poleZero(1,1,rhCoeff);
99
100 teHole = 1.4*rth; // effective length of the open hole
101 coeff = (teHole*2*SR - 347.23)/(teHole*2*SR + 347.23);
102 scaledCoeff = (toneHoleOpenness*(coeff - 0.9995)) + 0.9995;
103
104 //register hole filter using a poleZero filter (declared in instrument.lib)
105 toneHoleFilter = *(1) : poleZero(b0,-1,a1)
106 with{
107 b0 = scaledCoeff;
108 a1 = -scaledCoeff;
109 };
110
111 //reflexion filter is a one zero filter (delcred in instrument.lib)
112 reflexionFilter = oneZero0(0.5,0.5)*-0.95;
113
114 //delay lengths in number of samples
115 delay0Length = 5*SR/22050;
116 delay2Length = 4*SR/22050;
117 delay1Length = (SR/freq*0.5 - 3.5) - (delay0Length + delay2Length) - (nlfOrder*nonLinearity)*(typeModulation < 2);
118
119 //fractional delay lines
120 delay0 = fdelay(4096,delay0Length);
121 delay1 = fdelay(4096,delay1Length);
122 delay2 = fdelay(4096,delay2Length);
123
124 //stereoizer is declared in instrument.lib and implement a stereo spacialisation in function of
125 //the frequency period in number of samples
126 stereo = stereoizer(SR/freq);
127
128 //----------------------- Algorithm implementation ----------------------------
129
130 //envelope(ADSR) + vibrato + noise
131 envelope = (0.55 + pressure*0.3)*asr(pressure*envelopeAttack,100,pressure*envelopeRelease,gate);
132 vibratoEnvelope = envVibrato(0.1*2*vibratoAttack,0.9*2*vibratoAttack,100,vibratoRelease,gate);
133 vibrato = vibratoGain*osc(vibratoFreq)*vibratoEnvelope;
134 breath = envelope + envelope*noiseGain*noise;
135 breathPressure = breath + (breath*vibrato);
136
137 //two-port junction scattering for register vent
138 twoPortJunction(portB) = (pressureDiff : ((_ <: breathPressure + *(reedTable)) <: (+(portB) : ventFilter <: +(portB),_),_))~
139 delay0 : inverter : + ,_
140 with{
141 pressureDiff = -(breathPressure);
142 inverter(a,b,c) = b,c,a;
143 };
144
145 //three-port junction scattering (under tonehole)
146 threePortJunction(twoPortOutput) = (_ <: junctionScattering(twoPortOutput),_ : +(twoPortOutput), + :
147 reflexionFilter,_)~delay2 : !,_
148 with{
149 toneHole(temp,portA2,portB2) = (portA2 + portB2-_ + temp : toneHoleFilter)~_;
150 junctionScattering(portA2,portB2) = (((portA2+portB2-2*_)*scattering) <: toneHole(_,portA2,portB2),_,_)~_ : !,_,_;
151 };
152
153 process = (twoPortJunction : threePortJunction,_) ~ (delay1 : NLFM) : !,*(gain)*1.5 : stereo : instrReverb;