// Effects tutorial
// dewdrop_world -- http://www.dewdrop-world.net
// code is released under the LGPL, http://creativecommons.org/licenses/LGPL/2.1/

// ducking

s.boot;

(
~master = MixerChannel(\master, s, 2, 2);
~ducker = MixerChannel(\ducker, s, 1, 2, outbus: ~master);
~ducked = MixerChannel(\ducker, s, 1, 2, outbus: ~master);

	// need a bus to hold the control signal
	// WITHOUT panning or level control
~duckbus = Bus.audio(s, 1);
~ducker.newPreSend(~duckbus, 1);
	// presend to bus doesn't fix node order, so:
~ducker.addAsDependantOf(~ducked);

	// play the background signal
~bg = ~ducked.play({
	var	freq, trig, len;
	trig = Impulse.kr(8);
	freq = Demand.kr(trig, 0, Dseq([Dseries(200, 100, 16)], inf));
	len = SinOsc.kr(0.1, 0, 0.04, 0.09);
	SinOsc.ar(freq, 0) * Decay2.kr(trig, 0.005, len);
});
)

	// ducking effect -- basic Instr template 
(
Instr(\ducker, { arg myBus, ctlBus, numChannels, thresh, slopeBelow, slopeAbove, clampTime, relaxTime, postGain;
	var sig, ctl;
	sig = In.ar(myBus, numChannels);
	ctl = In.ar(ctlBus, numChannels);
	Compander.ar(sig, ctl, thresh, slopeBelow, slopeAbove, clampTime, relaxTime, postGain);
}, [\audiobus, \audiobus, nil, [0, 1, \linear, 0, 0.5], [0.01, 10, \exponential, 0, 1], [0.01, 10, \exponential, 0, 1], [0.001, 5, \exponential], [0.001, 5, \exponential], [0.1, 10, \exponential, 0, 1]]);
)

	// gui to tune the effect
~duck = ~ducked.playfx(Instr.at(\ducker), [~ducked.inbus.index, ~duckbus.index, 1]); 
~duck.gui;

	// pretuned, ready to use
(
~duck = ~ducked.playfx(Instr.at(\ducker), [~ducked.inbus.index, ~duckbus.index, 1,
	0.05, 1, 0.01, 0.01, 0.1, 1]);
)

	// control signal: our old friend
(
~buf = Buffer.read(s, "sounds/a11wlk01.wav");

SynthDef(\playbuf, { |out, bufnum, len|
	Out.ar(out, PlayBuf.ar(1, bufnum, BufRateScale.kr(bufnum))
		* EnvGen.kr(Env.linen(0.05, 0.9, 0.05), timeScale:len, doneAction:2)
	)
}).send(s);
)

(
r = Routine({
	{	~ducker.play(\playbuf, [\bufnum, ~buf.bufnum, \len, ~buf.numFrames/~buf.sampleRate]);
		rrand(5, 10).wait;
	}.loop;
}).play;
)

(
r.stop;
[~ducker, ~ducked, ~duckbus, ~buf].free;
)