1import("stdfaust.lib");
2
3// Port from SuperCollider (SC) to Faust of SOSkick in
4// <SuperCollider>/examples/demonstrations/DrumSynths.scd
5// based on a Sound-on-Sound 'synth secrets' tutorial:
6// http://www.soundonsound.com/sos/jan02/articles/synthsecrets0102.asp
7
8//https://github.com/josmithiii/faust-jos/tree/master/percussion
9
10decay(n,x) = x - (x>0.0)/n;
11release(n) = + ~ decay(n);
12envgate(dur,trigger) = trigger : release(int(dur*float(ma.SR))) : >(0.0);
13
14adsr(a,d,s,r,t) = env ~ (_,_) : (!,_) // the 2 'state' signals are fed back
15with {
16    env (p2,y) =
17        (t>0) & (p2|(y>=1)),          // p2 = decay-sustain phase
18        (y + p1*u - (p2&(y>s))*v*y - p3*w*y)	// y  = envelop signal
19	*((p3==0)|(y>=eps)) // cut off tails to prevent denormals
20    with {
21		p1 = (p2==0) & (t>0) & (y<1);         // p1 = attack phase
22		p3 = (t<=0) & (y>0);                  // p3 = release phase
23		// #samples in attack, decay, release, must be >0
24		na = ma.SR*a+(a==0.0); nd = ma.SR*d+(d==0.0); nr = ma.SR*r+(r==0.0);
25		// correct zero sustain level
26		z = s+(s==0.0)*ba.db2linear(-60);
27		// attack, decay and (-60dB) release rates
28		u = 1/na; v = 1-pow(z, 1/nd); w = 1-1/pow(z*ba.db2linear(60), 1/nr);
29		// values below this threshold are considered zero in the release phase
30		eps = ba.db2linear(-120);
31    };
32};
33
34perc(att,rel,trigger) = adsr(att,0,1.0,rel,envgate(att,trigger));
35pmosc(carfreq,modfreq,index) = os.oscrs(carfreq + (index*modfreq)
36			     * os.oscrs(modfreq));
37
38line(start,end,dur,trigger) = trigger : release(int(dur*float(ma.SR)))
39		    : *(start-end)+end;
40
41lpf(freq) = fi.lowpass(3,freq);
42hpf(freq) = fi.highpass(3,freq);
43
44gate = checkbox(" gate [nomidi:no][alias]");
45ampdb  = vslider("Gain [tooltip: Volume level in decibels]",-20,-60,40,0.1);
46amp = ampdb : si.smooth(0.999) : ba.db2linear;
47freq = 50;
48mod_freq = 5.0;
49mod_index = 5.0;
50sustain = 0.4;
51beater_noise_level = 0.03;
52
53trigger = gate>gate';
54pitch_contour = line(freq*2, freq, 0.02, trigger);
55drum_osc = pmosc(pitch_contour, mod_freq, mod_index/1.3);
56drum_lpf = drum_osc : lpf(1000);
57drum_env = drum_lpf * perc(0.005,sustain,trigger);
58
59beater_source = no.noise * beater_noise_level;
60beater_hpf = beater_source : hpf(500);
61lpf_cutoff_contour = line(6000, 500, 0.03, trigger);
62beater_lpf = beater_hpf : lpf(lpf_cutoff_contour);
63beater_env = beater_lpf * perc(0.01, 1.0, trigger);
64kick_mix = (drum_env + beater_env) * 2 * amp;
65
66process = kick_mix;
67