1declare name "NLFfm";
2declare description "FM synthesizer implemented with a nonlinear passive allpass filter";
3declare author "Romain Michon";
4declare copyright "Romain Michon (rmichon@ccrma.stanford.edu)";
5declare version "1.0";
6
7import("instruments.lib");
8
9//==================== GUI SPECIFICATION ================
10
11freq = nentry("h:Basic_Parameters/freq [1][unit:Hz] [tooltip:Tone frequency]",440,20,20000,1);
12gain = nentry("h:Basic_Parameters/gain [1][tooltip:Gain (value between 0 and 1)]",0.8,0,1,0.01);
13gate = button("h:Basic_Parameters/gate [1][tooltip:noteOn = 1, noteOff = 0]");
14
15typeModulation = nentry("h:Physical_and_Nonlinearity/v:Nonlinear_Filter_Parameters/Modulation_Type
16[2][tooltip: 0=theta is modulated by the incoming signal; 1=theta is modulated by the averaged incoming signal;
172=theta is modulated by the squared incoming signal; 3=theta is modulated by a sine wave of frequency freqMod;
184=theta is modulated by a sine wave of frequency freq;]",0,0,4,1);
19nonLinearity = hslider("h:Physical_and_Nonlinearity/v:Nonlinear_Filter_Parameters/Nonlinearity
20[2][tooltip:Nonlinearity factor (value between 0 and 1)]",0,0,1,0.01);
21frequencyMod = hslider("h:Physical_and_Nonlinearity/v:Nonlinear_Filter_Parameters/Modulation_Frequency
22[2][unit:Hz][tooltip:Frequency of the sine wave for the modulation of theta (works if Modulation Type=3)]",220,20,1000,0.1);
23nonLinAttack = hslider("h:Physical_and_Nonlinearity/v:Nonlinear_Filter_Parameters/Nonlinearity_Attack
24[2][unit:s][Attack duration of the nonlinearity]",0.1,0,2,0.01);
25
26vibratoFreq = hslider("h:Envelopes_and_Vibrato/v:Vibrato_Parameters/Vibrato_Freq
27[3][unit:Hz]",5,1,15,0.1);
28vibratoGain = hslider("h:Envelopes_and_Vibrato/v:Vibrato_Parameters/Vibrato_Gain
29[3][tooltip:A value between 0 and 1]",0.1,0,1,0.01);
30vibratoAttack = hslider("h:Envelopes_and_Vibrato/v:Vibrato_Parameters/Vibrato_Attack
31[3][unit:s][tooltip:Vibrato attack duration]",0.5,0,2,0.01);
32vibratoRelease = hslider("h:Envelopes_and_Vibrato/v:Vibrato_Parameters/Vibrato_Release
33[3][unit:s][tooltip:Vibrato release duration]",0.01,0,2,0.01);
34
35envelopeAttack = hslider("h:Envelopes_and_Vibrato/v:Envelope_Parameters/Envelope_Attack
36[4][unit:s][tooltip:Envelope attack duration]",0.05,0,2,0.01);
37envelopeDecay = hslider("h:Envelopes_and_Vibrato/v:Envelope_Parameters/Envelope_Decay
38[4][unit:s][tooltip:Envelope decay duration]",0.05,0,2,0.01);
39envelopeRelease = hslider("h:Envelopes_and_Vibrato/v:Envelope_Parameters/Envelope_Release
40[4][unit:s][tooltip:Envelope release duration]",0.05,0,2,0.01);
41
42//----------------------- Nonlinear filter ----------------------------
43//nonlinearities are created by the nonlinear passive allpass ladder filter declared in miscfilter.lib
44
45//nonlinear filter order
46nlfOrder = 3;
47
48//attack - sustain - release envelope for nonlinearity (declared in instruments.lib)
49envelopeMod = en.asr(nonLinAttack,1,envelopeRelease,gate);
50
51//nonLinearModultor is declared in instruments.lib, it adapts allpassnn from miscfilter.lib
52//for using it with waveguide instruments
53NLFM =  nonLinearModulator((nonLinearity : si.smoo),envelopeMod,freq,
54     typeModulation,(frequencyMod : si.smoo),nlfOrder);
55
56//----------------------- Algorithm implementation ----------------------------
57
58//stereoizer is declared in instruments.lib and implement a stereo spacialisation in function of
59//the frequency period in number of samples
60stereo = stereoizer(ma.SR/freq);
61
62//vibrato gain is controlled by envVibrato (declared in instruments.lib)
63vibrato = os.osc(vibratoFreq)*vibratoGain*envVibrato(0.1*2*vibratoAttack,0.9*2*vibratoAttack,100,vibratoRelease,gate);
64
65//output gain is controlled by an adsr envelope
66envelope = en.adsr(envelopeAttack,envelopeDecay,0.9,envelopeRelease,gate)*gain;
67breath = envelope + envelope*vibrato;
68
69process = os.osc(freq)*breath : NLFM : stereo : instrReverb;
70
71