TempoClock.default.tempo_(122/60);
(
//Kick
SynthDef(\kick, {
    arg f2 =  200, f1 = 55, decay = 0.3, decayn = 0.02, dist = 7, amp = 1;
    var trig, env, noise, mult, freqenv, ampenv, snd, sig1, freqb, z, del;
    //Amplitude envelope
    decay = Rand(0.5, 0.5);
    ampenv = EnvGen.kr(Env.perc(0, decay), doneAction: 2);
    //Frequency envelope
    freqenv = EnvGen.kr  (Env([f2, f1], [0.05],\exp));
    mult = IRand(1,3) / 1;
    sig1 = SinOsc.ar(freqenv , 0, 1, 0) * ampenv * 0.6;
    snd = sig1;
    //sig = (sig*dist).atan * 0.5;
    snd = Limiter.ar((snd*dist).tanh * 0.5, 0.5);
    snd = snd * amp;
    Out.ar(0, snd!2);
}).add;
//Snare
SynthDef("snare", {
    arg out = 0, amp = 0.3, sinfreq = 220, att = 0.01, rel = 0.3, ffreq = 500, pan = 0;
    var env, snd1, snd2, sum;
    rel = Rand(0.1, 0.2);
    env = Env.perc(att, rel, amp).kr(doneAction: 2);
    snd1 = HPF.ar(
        in: WhiteNoise.ar,
        freq: ffreq,
        mul: env);
    snd1 = LPF.ar(snd1, 9000, 1, 0);
    snd2 = SinOsc.ar(freq: sinfreq, mul: env) * 1;
    sum = snd1 + snd2;
    Out.ar(out, Pan2.ar(sum, pan));
}).add;
SynthDef("hh", {
    arg out = 0, amp = 0.4, att = 0.01, rel = 0.3, ffreq = 6000, panFrac = 0.3;
    var env, snd, pannedPart, dryPart, panPos, comb;
    // Random release time per trigger
    rel = Rand(0.3, 0.5);
    // Envelope
    env = Env.perc(0, rel, amp).kr(doneAction: 2);
    // White noise -> highpass -> envelope
    snd = HPF.ar(WhiteNoise.ar, ffreq) * env;
    // Lowpass
    snd = LPF.ar(snd, 22000);
    // Random pan position between -1 and 1
    panPos = Rand(-1, 1);
    // Split dry and panned parts
    pannedPart = Pan2.ar(snd * panFrac, panPos);
    dryPart = snd * (1 - panFrac);
    comb = pannedPart + [dryPart, dryPart];
    // Combine: dry mono + panned stereo
    Out.ar(out, comb * 0.3);
}).add;
SynthDef(\fm, { arg out=0, amp=0.5, vol = 1, gate=1, pan=0, freq=100;
    var sig, sig1, sig2;
    var env, mult, cutoff;
    var left, right, spread;
    mult = IRand(1, 5);
    cutoff = SinOsc.kr(122/60*1).exprange(200,3000);
    // Envelope
    env = EnvGen.kr(Env.perc(0, 2, amp, -4), gate, doneAction:2);
    // Slightly different frequency modulations for L/R
    sig1 = SinOsc.ar(freq/2 * [0.995, 1.005]); // detune L/R
    sig2 = SinOsc.ar(freq * mult * (sig1 * 2 + 1));
    sig = sig1 +  sig2;
    // Low-pass filter per channel
    sig = LPF.ar(sig * AmpComp.kr(freq), cutoff);
    // Compression
    sig = Compander.ar(sig, sig, 0.6, 1, 0.4, 0.01, 0.1, 1);
    // Final amplitude and stereo spread
    sig = sig * env ;
    // Output as stereo signal
    Out.ar(0, sig);
}).add;
SynthDef("pluck", { |amp = 0.4, amp2 = 3, freq = 440, decay1 = 15, decay2 = 1 |
    var env, snd, v;
    env = EnvGen.kr(Env.perc(0, decay1), doneAction:2);
    snd = Pluck.ar(
        in: WhiteNoise.ar(amp),
        trig: Impulse.kr(1),         // trigger pluck once per second
        maxdelaytime: 1,
        delaytime: 2 / freq, // modulate delaytime slightly around freq
        decaytime:  decay2,
        coef: 0.3);
    snd = snd * amp2;
    Out.ar(0, snd!2 * env);
}).add;
SynthDef(\saw, {
    arg freq = 44, amp = 1, gate = 1, modamp = 1;
    var sig, sin, sigv, saw1,saw2, env1, env2;
    env1 = EnvGen.kr(Env.adsr(6, 3, 0, 2, 1 , -8, 0), gate,  doneAction:2);
    env2 = EnvGen.kr(Env.adsr(4, 3, 0, 2, 1 , -8, 0), gate,  doneAction:2);
    sin  = Saw.ar(freq) * env2;
    saw1 = SinOsc.ar(freq * [0.999, 1.001]) * env1 * 0.5;
    saw2 = SinOsc.ar(freq/2) * env2 * 0.5;
    modamp = LFPulse.kr(3, 0, 0.5,1,0) * 1;
    sig = HPF.ar((sin + saw1 + saw2) * amp, 300);
    sig = sig * modamp * 0.9;
    //mod amplutide
    sigv = FreeVerb.ar(sig, 0.9, 0.8, 0.8, 1, 0);
    Out.ar(0, sigv);
}).add;
)
//pattern
// Kick
(
Pdef(\kickPattern,
    Pbind(
        \instrument, \kick,
        //\dur, Pseq([1/4, Pwrand([1/4, Rest(1/4)], [0.75, 0.25], 1), Rest(2/4), 1/4
        //            Rest(3/4), 1/4, Rest(2/4), 1/4,
        //            Rest(2/4), 1/4, Rest(1/4)], inf)
        \dur, Pseq([1, 0.5, 0.5, 1, 1],  inf),
        \amp, Pxrand([1, 0.5, 1, 0, 1], inf)
    )
).play;
//pattern
// snare
Pdef(\snare,
    Pbind(
        \instrument, \snare,
        //\dur, Pseq([1/4, Pwrand([1/4, Rest(1/4)], [0.75, 0.25], 1), Rest(2/4), 1/4
        //            Rest(3/4), 1/4, Rest(2/4), 1/4,
        //            Rest(2/4), 1/4, Rest(1/4)], inf)
        \dur, Pseq([1, 0.5, 1, 1],  inf),
        \amp, Pseq([0, 0.8, 0, 0, 0.3], inf)
    )
).play;
// hh
Pdef(\hh,
    Pbind(
        \instrument, \hh,
        \dur, Pseq([1/4, 1/4, Rest(1/4)],  inf),
        \amp, Prand([0.3, 0.45], inf)
    )
).play;
// Bass low
Pdef(\fmBassl,
    Pbind(
        \instrument, \fm,
        \root, 9,
        \scale, Scale.phrygian,
        \ctranspose, -24,
        \degree, Pseq([0,1,3] , inf),
        //\midinote, Pseq([64, 68, 71, 64] , inf),
        //
        \dur, Pseq([4],  inf),
        \amp, 0.25
    )
).play;
// Bass high
Pdef(\fmBassh,
    Pbind(
        \instrument, \fm,
        \root, 9,
        \scale, Scale.phrygian,
        \ctranspose, 0,
        \degree, Pseq([0] , inf),
        //\midinote, Pseq([64, 68, 71, 64] , inf),
        \dur, Pseq([4, 3.5, Prand([1, 0.5, 1, 0.5])], inf),
        \amp, Prand([0.1, 0.2, 0.15], inf)
    )
).play;
// FM Pluck
Pdef(\pluck,
    Pbind(
        \instrument, \pluck,
        \root, 9,
        \scale, Scale.phrygian,
        \ctranspose, 0,
        \degree, Pseq([0,1,12,24,5,7] , inf),
        //\midinote, Pseq([64, 68, 71, 64] , inf),
        \dur, Pseq([4, Prand([0.5])], inf)
    )
).play;
// saw
Pdef(\saw,
    Pbind(
        \instrument, \saw,
        \root, 9,
        \scale, Scale.phrygian,
        \ctranspose, 0,
        \degree, Pseq([0, 3, 5, 3], inf),
        //\midinote, Pseq([64, 68, 71, 64] , inf),
        \dur, Pseq([4,6, Rest(2), 8, Rest(2)], inf),
        \amp, 0.5
    )
).play;
)
(
Pdef(\kickPattern).play;
Pdef(\snare).play;
Pdef(\fmBassl).play;
Pdef(\fmBassh).play;
Pdef(\hh).stop
Pdef(\snare).play;
Pdef(\pluck).play;
Pdef(\saw).play;
)
(
Pdef(\fmBassl).stop;
Pdef(\fmBassh).stop;
Pdef(\pluck).stop;
Pdef(\saw).stop;
Pdef(\snare).stop;
Pdef(\kickPattern).stop;
)