TGrains3		buffer granulator with user envelope

Triggers generate grains from a buffer. Each grain has a user-defined rise/decay shape and is panned between two channels of multiple outputs.

TGrains3.ar(numChannels, trigger, bufnum, rate, centerPos, dur, pan, amp, att, dec, window, interp)

numChannels - number of output channels.
trigger - at each trigger, the following arguments are sampled and used 
		as the arguments of a new grain. 
		A trigger occurs when a signal changes from <= 0 to > 0.
		If the trigger is audio rate then the grains will start with sample accuracy.
bufnum - the index of the buffer to use. It must be a one channel (mono) buffer.
rate   -  1.0 is normal, 2.0 is one octave up, 0.5 is one octave down
			-1.0 is backwards normal rate ... etc.
		Unlike PlayBuf, the rate is multiplied by BufRate, so you needn't do that yourself.
centerPos - the position in the buffer in seconds at which the grain envelope will reach 
			maximum amplitude.
dur    -   duration of the grain in seconds.
pan    -   a value from -1 to 1. Determines where to pan the output in the same manner as PanAz.
amp   - amplitude of the grain.
att- attack time of grain in seconds.
dec- decay time of grain in seconds.
window- bufnum of rise/decay shape.
interp - 1,2,or 4. Determines whether the grain uses (1) no interpolation, (2) linear interpolation, 
			or (4) cubic interpolation.

s.sendMsg(\b_allocRead, 10, "sounds/a11wlk01.wav");
c=Buffer.alloc(s, s.sampleRate * 0.2, 1) 
// buffer for rise/decay shape - multiple of sr helps prevent clicks, i think.

(
var y, h;
y=Signal.hanningWindow(s.sampleRate * 0.4); // twice the size of our buffer, 'cause we only use 1/2
h=Array.fill(s.sampleRate * 0.2, {|i| y[i]});
c.loadCollection(h);
)

(
{
	var b = 10, trate, dur, clk;
	trate = MouseY.kr(2,200,1);
	dur = 4 / trate;
	clk = Dust.kr(trate);
	TGrains3.ar(2, clk, 10, 1.0, LFNoise2.kr(0.5).range(0, BufDur.kr(b)) + TRand.kr(0, 0.02, clk), dur, 0, 0.1, MouseX.kr(0.003, 0.01), 0.007, c.bufnum, 4);
}.play;
)

(
var y, h;
y=Signal.hammingWindow(s.sampleRate * 0.4);
h=Array.fill(s.sampleRate * 0.2, {|i| y[i]});
c.loadCollection(h);
)

(
{
	var b = 10, trate, dur, clk, pos, pan;
	trate = MouseY.kr(8,220,1);
	dur = 2/trate;
	clk = Impulse.kr(trate);
	pos = MouseX.kr(0, BufDur.kr(b)) + TRand.kr(0, 0.02, clk);
	pan = WhiteNoise.kr(0.6);
	TGrains3.ar(2, clk, b, 1, pos, dur, pan, 0.1, dur*0.1, dur*0.3, c.bufnum, 4);
}.play;
)