class:: TGrains3
summary:: buffer granulator with user envelope
related:: Classes/TGrains, Classes/TGrains2
categories:: UGens>Buffer, UGens>Generators>Granular


Description::

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


classmethods::

method::ar

argument::numChannels
number of output channels.

argument::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.

argument::bufnum
the index of the buffer to use. It must be a one channel (mono) buffer.

argument::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 link::Classes/PlayBuf::, the rate is multiplied by BufRate, so you needn't do that yourself.

argument::centerPos
the position in the buffer in seconds at which the grain envelope will reach maximum amplitude.

argument::dur
duration of the grain in seconds.

argument::pan
determines where to pan the output.
list::
## If numChannels = 1, the pan argument is ignored.
## If numChannels = 2, panning is similar to Pan2.
## If numChannels > 2, panning is the same as PanAz.
::

argument::amp
amplitude of the grain.

argument::att
attack time of grain in seconds.

argument::dec
decay time of grain in seconds.

argument::window
bufnum of rise/decay shape.

argument::interp
1, 2, or 4. Determines whether the grain uses (1) no interpolation, (2) linear interpolation, or (4) cubic interpolation.


Examples::

code::
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;
)
::
