///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// 6. Synthesis
// Colour your music
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// Additive Synthesis:
// Creating a bell sound

// John-Claude Risset
// Introductory catologue of copmputer-synthesized sounds
// Bell Telephone Laboritories, 1967.
// Data reproduced in Dodge, C. and Jerse, T.A. (1997), Computter Music, 2nd Edn. London: Schirmer, p.105.

(
h = [0.56, 0.56, 0.92, 0.92, 1.19, 1.7, 2, 2.74, 3, 3.76, 4.07];
g = [0, 1, 0 , 1.7, 0, 0, 0, 0, 0, 0, 0]; // g is an added to the freq
d = [1, 0.9, 0.65, 0.55, 0.325, 0.35, 0.25, 0.2, 0.15, 0.1, 0.075];
a = [1, 0.67, 1, 1.8, 2.67, 1.67, 1.46, 1.33, 1.33, 1, 1.33];

(
~out = { 
	Pan2.ar(
		Mix.fill(11, { |i|
			SinOsc.ar(LFNoise0.kr(20.reciprocal, 100, 300) * h[i] + g[i], 0, a[i]/20) * EnvGen.ar(Env.perc(0, 20*d[i], 1, -2), Impulse.kr(2.reciprocal))
		} ), 
		pos: LFNoise0.kr(20.reciprocal)
	)
};
)
)

~out.play; 

///////////////////////////////////////////////////////////////////////////
// Subtractive Synthesis

Noise + Filter model 
Noise are as shown in earlier lessons
What distinguishes noise from other UGens is that noise UGens have no single frequency.

Filters "filter out" certain parts of the frequency spectrum according to their type.

///////////////////////////////////////////////////////////////////////////
// Common filter UGens (see help files)

///////////////////////////////////////////////////////////////////////////
// LPF
{ LPF.ar(Saw.ar(200, 0.1), SinOsc.kr(XLine.kr(0.7, 300, 20), 0, 3600, 4000)) }.play;

///////////////////////////////////////////////////////////////////////////
// HPF
{ HPF.ar(Saw.ar(200,0.1), FSinOsc.kr(XLine.kr(0.7, 300, 20), 0, 3600, 4000), 5) }.play;

///////////////////////////////////////////////////////////////////////////
// BPF
{ BPF.ar(Saw.ar(200, 0.5), SinOsc.kr(XLine.kr(0.7, 300, 20), 0, 3600, 4000), 0.3) }.play;

///////////////////////////////////////////////////////////////////////////
// MidEQ
{ MidEQ.ar(Saw.ar(200,0.2), FSinOsc.kr(1, 0, 24, 84).midicps, 0.3, 12) }.play

///////////////////////////////////////////////////////////////////////////
// RLPF
{ RLPF.ar(Saw.ar(200, 0.1), FSinOsc.kr(XLine.kr(0.7, 300, 20), 0, 3600, 4000), 0.2) }.play;

///////////////////////////////////////////////////////////////////////////
// "Resonant Filters" are 

///////////////////////////////////////////////////////////////////////////
// Resonz
{ Resonz.ar(WhiteNoise.ar(0.5), 2000, 0.1) }.play

// modulate frequency
{ Resonz.ar(WhiteNoise.ar(0.5), XLine.kr(1000,8000,10), 0.05) }.play

// modulate bandwidth
{ Resonz.ar(WhiteNoise.ar(0.5), 2000, XLine.kr(1, 0.001, 8)) }.play

// modulate bandwidth opposite direction
{ Resonz.ar(WhiteNoise.ar(0.5), 2000, XLine.kr(0.001, 1, 8)) }.play

///////////////////////////////////////////////////////////////////////////
// Ringz 
{ Ringz.ar(Dust.ar(3, 0.3), 2000, 2) }.play

{ Ringz.ar(WhiteNoise.ar(0.005), 2000, 0.5) }.play

// modulate frequency
{ Ringz.ar(WhiteNoise.ar(0.005), XLine.kr(100,3000,10), 0.5) }.play

{ Ringz.ar(Impulse.ar(6, 0, 0.3),  XLine.kr(100,3000,10), 0.5) }.play

// modulate ring time
{ Ringz.ar(Impulse.ar(6, 0, 0.3),  2000, XLine.kr(4, 0.04, 8)) }.play

// modulate ring time opposite direction
{ Ringz.ar(Impulse.ar(6, 0, 0.3), 2000, XLine.kr(0.04, 4, 8)) }.play

///////////////////////////////////////////////////////////////////////////
// Klank
{ Klank.ar(`[[800, 1071, 1153, 1723], nil, [1, 1, 1, 1]], Impulse.ar(2, 0, 0.1)) }.play;

{ Klank.ar(`[[800, 1071, 1353, 1723], nil, [1, 1, 1, 1]], Dust.ar(8, 0.1)) }.play;

{ Klank.ar(`[[800, 1071, 1353, 1723], nil, [1, 1, 1, 1]], PinkNoise.ar(0.007)) }.play;

{ Klank.ar(`[[200, 671, 1153, 1723], nil, [1, 1, 1, 1]], PinkNoise.ar([0.007,0.007])) }.play;

(
play({
	Klank.ar(`[ 
		Array.rand(12, 800.0, 4000.0),		// frequencies
		nil,  							// amplitudes (default to 1.0)
		Array.rand(12, 0.1, 2)				// ring times
		], Decay.ar(Impulse.ar(4), 0.03, ClipNoise.ar(0.01)))
})
)

///////////////////////////////////////////////////////////////////////////
// JITLib example
(
Server.default = Server.local;
s = Server.default;
s.boot;
)

//p= ProxySpace.push(s);
//
//p.pop

~out.play

// NB multichannel mul expand
~out = {Resonz.ar(LFNoise0.ar(400), Line.kr(10000, 1000, 10), [0.1, 0.1])} 

~rate = 200

~out = {Resonz.ar(LFNoise0.ar(~rate), Line.kr(10000, 1000, 10), [0.1, 0.1])} 

~rate = {Line.kr(400, 10, 10)}

~rate = {Line.kr(10, 400, 10)}

~out = { Ringz.ar(Dust.ar([3, 4], 0.3), 200, 2) }

~out = { Ringz.ar(Dust.ar([3, 4], 0.3), ~rate * 10, 2) }

~rate = {Line.kr(400, 10, 10)}

~rate.fadeTime = 4

~rate = 200

~out = { Ringz.ar(Dust.ar([3, 4], 0.3), [~rate * 10, ~rate * 11], 2) }

~rate = 250

~out = { Ringz.ar([Impulse.ar(2.5.reciprocal), LFNoise0.ar(4, 0.3)], [~rate * 10, ~rate * 11], 2, 0.3) }

~env = {EnvGen.kr(Env.sine(20), gate: Impulse.kr(20.reciprocal))}

~out = { Ringz.ar([Impulse.ar((~env * 4) + 1), LFNoise0.ar((~env * 4) + 1, 0.3)], [~rate * 10, ~rate * 11], 2, ~env * 0.3) }

///////////////////////////////////////////////////////////////////////////
// PMOsc
// NB for my demonstration only, this document is only available on my own machine.

Document.open("/Users/rich/Documents/Music/HCI2009/Gaggle/GaggleScore/GaggleScore_v0.004.rtf")

// Please see PMOsc Help file for more info.

///////////////////////////////////////////////////////////////////////////
// Simple??? FM example.

(
SynthDef("fm1", { arg bus = 0, freq = 440, carPartial = 1, modPartial = 1, index = 3, mul = 0.05, dur = 1.0;

	// index values usually are between 0 and 24
	// carPartial :: modPartial => car/mod ratio
	
	var mod, car, env;
	
	env = EnvGen.kr(Env.linen(dur*0.1, dur*0.1, dur*0.8, 0.1), 0.1, doneAction: 2);
	
	mod = SinOsc.ar(
		freq * modPartial, 
		0, 
		freq * index * LFNoise1.kr(5.reciprocal).abs
	);
		
	car = SinOsc.ar(
		(freq * carPartial) + mod, 
		0, 
		env
	);
	
	Out.ar( 0, car );
}).send(s); // check
)

(
Synth("fm1", [ \freq, ( 800.rand + 400 ), \carPartial, 2.0.rand, \modPartial, 3.4.rand, \dur, 2.0.rand ]);
)

///////////////////////////////////////////////////////////////////////////
// now a task

(
	var pitch, count = 0;
	d = 0.125; 
	a = [ 60, 62, 63, 65, 67 ];
	r = Task({

		loop({
				while ( { count < a.size }, 
					{
						pitch = a[count];
						pitch.postln;
						Synth( "fm1", [ \freq, pitch.midicps, \carPartial, ( 0.4.rand ) + 1.0, \modPartial, ( 1.4.rand ) + 1.0, \dur, 0.1.rand ] );
						d.wait;
						count = count + 1;
					});
				count = 0
		});
	}).play;	
)

r.play;
d = 1
d = 0.11
d = 0.03
r.stop;
a = [ 45, 46, 47, 48, 50, 60, 62, 63, 65, 67 ]
a = [ 45 ]
a = a + 2.rand
a = a - 2.rand
a = [ 60, 62, 63, 65, 67 ];

///////////////////////////////////////////////////////////////////////////
// now a function

(
~myFMAlg = ({
		var pitch, count = 0;
		d = 0.125; 
		a = [ 60, 62, 63, 65, 67 ];
		r = Task({
	
			loop({
					while ( { count < a.size }, 
						{
							pitch = a[count];
							pitch.postln;
							Synth( "fm1", [ \freq, pitch.midicps, \carPartial, ( 0.4.rand ) + 1.0, \modPartial, ( 1.4.rand ) + 1.0, \dur, 0.1.rand ] );
							d.wait;
							count = count + 1;
						});
					count = 0
			});
		}).play; // end task
});
);

~myFMAlg.value;
r.play;
r.stop;

///////////////////////////////////////////////////////////////////////////
// now arguments

(
~myFMAlg = ({ arg pArray = [ 60, 62, 63, 65, 67 ], myCarPartial = 1.0, myModPartial = 1.0, myDur = 1.0, myWait = 0.125;
		var pitch, count = 0;
		d = 0.125; 
		
		r = Task({
	
			loop({
					while ( { count < pArray.size }, 
						{
							pitch = pArray[count];
							Synth( "fm1", [ \freq, pitch.midicps, \carPartial, myCarPartial, \modPartial, myModPartial, \dur, myDur ] );
							myWait.wait;
							count = count + 1;
						});
					count = 0
			});
		}).play; // end task
});
);

~myFMAlg.value;
r.stop; ~myFMAlg.value( [ 77, 75, 73, 72, 70 ] );
r.stop; ~myFMAlg.value( [ 40, 42, 43, 45, 47 ] );
r.stop; ~myFMAlg.value( [ 77, 75, 73, 72, 70, 68 ], 10.1, 30.4, 0.1, 0.05 );
r.play;
r.stop;

///////////////////////////////////////////////////////////////////////////
// now making choices

(
~myFMAlg = ({ arg pArray = [ 60, 62, 63, 65, 67 ], myCarPartial = 1.0, myModPartial = 1.0, myDur = 1.0, myWait = 0.125, myRand = false;
		var pitch, count = 0;
		var myCPartial, myMPartial;
		
		r = Task({
	
			loop({

					while ( { count < pArray.size }, 
						{	
							if ( myRand == true, { myCPartial = myCarPartial.rand; myMPartial = myModPartial.rand }, { myCPartial = myCarPartial; myMPartial = myModPartial } );
							myMPartial.postln;
							pitch = pArray[count];
							Synth( "fm1", [ \freq, pitch.midicps, \carPartial, myCarPartial, \modPartial, myModPartial, \dur, myDur ] );
							myWait.wait;
							count = count + 1;
						});
					count = 0
			});
		}).play; // end task
});
);

~myFMAlg.value;
r.stop; ~myFMAlg.value( [ 77, 75, 73, 72, 70 ] );
r.stop; ~myFMAlg.value( [ 40, 42, 43, 45, 47 ] );
r.stop; ~myFMAlg.value( [ 77, 75, 73, 72, 70, 68 ], 1.1, 4.4, 0.5, 0.15, true);

a = [ 77, 75, 73, 72, 70, 68 ];

r.stop; ~myFMAlg.value( a, 1.1, 4.4, 0.05, 0.05, true);

a = a + 20

r.play;
r.stop;