// 1. send the synthdefs to the server
// all tasks in this document use these 2 synthdefs !!

(
// sine grain SynthDef:
SynthDef("sinegrain", { arg freq=400, amp=0.2, dur=0.3, pan=0;
	var env, sig;

	// envelope with 2 s-like segments of the same length:
	env = EnvGen.ar(Env([0, amp, 0], [dur*0.5, dur*0.5], \sine), doneAction: 2);
	sig = SinOsc.ar(freq, 0, env);
	sig = Pan2.ar(sig, pan);
	// OffsetOut for a more precise timing
	OffsetOut.ar(0, sig); 
}).send(s);

// Synthdef for buffer granulation:
SynthDef("bufgrain", { arg buf=0, rate=1, start=0, amp=0.2, dur=0.3, pan=0;
	var env, sig;

	env = EnvGen.ar(Env([0, amp, 0], [dur*0.5, dur*0.5], \sine), doneAction: 2); 
	sig = PlayBuf.ar(1, buf, rate * BufRateScale.ir(buf), 1, start * BufSamples.ir(buf), 0);
	sig = Pan2.ar(sig * env, pan);
	OffsetOut.ar(0, sig);
}).send(s);
)	

// just a test with the defaults:
Synth("sinegrain"); 

// ... and also other values
Synth("sinegrain", [\freq, 2000, \dur, 0.01, \amp, 0.9, \pan, 0]); 

// 2. write and start a Task :

// example 1: harmonic series sucessively
(
t = Task({
	var next, fr, vol, pos, dur;
	20.do({ arg i;
		dur = 0.2;  
		next = dur * 2; // calculation of the inter-onset time
		vol 	= 0.1;
		pos 	= rrand(-1.0, 1.0);
		fr	= (i+1) * 200;
		Synth("sinegrain", [\dur, dur, \freq, fr, \pan, pos, \amp, vol]);
		next.wait;	// wait before doing the next iteration of the do-loop
	});
})
)

// start the Task:
t.start;

// stop it (if not already stopped by itself):
t.stop;

// example 2: granular reconstructed sine tone 
(
t = Task({
	var next, fr, vol, pos, dur;
	inf.do({ arg i;
		dur = 0.2;
		next = dur * 0.5;	// this means an overlap of 2 grains
		vol 	= 0.5;
		pos 	= 0;
		fr	= 300;
		// start the synths in the future but precisely !:
		s.makeBundle(0.1, { Synth("sinegrain", [\dur, dur, \freq, fr, \pan, pos, \amp, vol]) });
		// try it without makeBundle!:
		// Synth("sinegrain", [\dur, dur, \freq, fr, \pan, pos, \amp, vol]) ;
		next.wait;	
	});
})
)

t.start;

t.stop;

// example 3: dens random texture:
(
t = Task({
	var next, fr, vol, pos, dur;
	inf.do({ arg i;
		dur 	= 0.02;
		next = dur * rrand(0.1, 0.4);	// variable overlap
		vol 	= 0.1;
		pos 	= rrand(-1.0, 1.0);
		fr	= rrand(1000.0, 7000.0);
		Synth("sinegrain", [\dur, dur, \freq, fr, \pan, pos, \amp, vol]);
		next.wait;	
	});
})
)

t.start;

t.stop;

// example 4: dense harmonic texture:
(
t = Task({
	var next, fr, vol, pos, dur;
	inf.do({ arg i;
		dur 	= 0.4;
		next = dur * rrand(0.02, 0.04);
		vol 	= 0.1;
		pos 	= rrand(-1.0, 1.0);
		fr	= rrand(1, 20) * 100;	// only integer multiples of 100
		Synth("sinegrain", [\dur, dur, \freq, fr, \pan, pos, \amp, vol]);
		next.wait;	
	});
})
)

t.start;

t.stop;

// 3. load a soundfile into a buffer:

b = Buffer.loadDialog(s);   // only mono soundfiles!

// alternative way (adapt it to your path names) :
b = Buffer.readChannel(s, "/Users/abart/snd/tam-tam.aif", channels: [0]);

// check it if needed:
b.query
b.play

// the duration of the soundfile:
b.duration
// or
b.numFrames / b.sampleRate

// example 5: randomized starting positions (try it with speech sounds):
(
t = Task({
	var next, rate, st, vol, pos, dur;
	inf.do({ arg i;
		dur 	= 0.2;
		next = dur * 0.1;
		vol 	= 0.8;
		pos 	= rrand(-1.0, 1.0);
		rate	= 1;
		st 	= 0.9.rand;	// start position between  0% and 90% of the total duration
		Synth("bufgrain", [\buf, b.bufnum, \dur, dur, \rate, rate, \start, st, \pan, pos, \amp, vol]);
		next.wait;	
	});
})
)

t.start;

t.stop;

// example 6: texture of fifths (try it with a sound which has a clear pitch, i.e. sample of a musical instrument)
(
t = Task({
	var next, rate, st, vol, pos, dur;
	inf.do({ arg i;
		dur 	= 0.1;
		next = dur * 0.03;
		vol 	= 0.3;
		pos 	= rrand(-1.0, 1.0);
		rate	= ([-2, -1, 0, 1, 2, 3].choose * 7).midiratio;
		st 	= 0.9.rand;
		Synth("bufgrain", [\buf, b.bufnum, \dur, dur, \rate, rate, \start, st, \pan, pos, \amp, vol]);
		next.wait;	
	});
})
)

t.start;

t.stop;

// example 7: granular recnstruction of the soundfile,
// constantly rising start position:
(
t = Task({
	var next, rate, st, vol, pos, dur, ovlp, n, totaldur;
	// explizite Angabe des Overlap-Faktors:
	ovlp = 2;
	dur 	= 0.06;
	totaldur = b.numFrames / b.sampleRate;
	// calculation of the number of iterations with the sound durations, the grains duration and the overlap:
	n = ( totaldur / dur * ovlp).asInteger;
	n.do({ arg i;
		next = dur / ovlp;
		vol 	= 0.7;
		pos 	= 0;
		rate	= 1;
		// the start position depends on the iteration number related to the total duration:
		st 	= i * next / totaldur;
		s.makeBundle(0.1, { Synth("bufgrain", [\buf, b.bufnum, \dur, dur, \rate, rate, \start, st, \pan, pos, \amp, vol]) });
		// try also without makeBundle:
		//Synth("bufgrain", [\buf, b.bufnum, \dur, dur, \rate, rate, \start, st, \pan, pos, \amp, vol]);
		next.wait;	
	});
})
)

t.start;

t.stop;

// example 8: time stretching with a ratio of 5:2
(
t = Task({
	var next, rate, st, vol, pos, dur, ovlp, n, totaldur, time;
	time = 5 / 2;
	ovlp = 2;
	dur 	= 0.03;
	totaldur = b.numFrames / b.sampleRate;
	n = (totaldur / dur * ovlp * time).asInteger;
	n.do({ arg i;
		next = dur / ovlp;
		// next = dur / ovlp * rrand(0.98, 1.02);		// slightly randomized overlap
		vol 	= 0.7;
		pos 	= 0;
		rate	= 1 ;
	 	// rate = rrand(0.98, 1.02);		// slightly randomized pitch
		st 	= i * next / totaldur / time;
		// st 	= (n-i) * next / totaldur / time;	// backwards!
		s.makeBundle(0.1, { Synth("bufgrain", [\buf, b.bufnum, \dur, dur, \rate, rate, \start, st, \pan, pos, \amp, vol]) });
		next.wait;	
	});
})
)

t.start;

t.stop;