///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// 4. Patterns: which notes to play - Arrays and Control Structures
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

// Let's use a different synth for a change.  Feel free to investigate it, alter it, or choose something else.

(
SynthDef("MyBlip", { 
	arg pitch=69, nharm=4, amp=0.05, decay=1; 
	var snd, env, pos, wobble, freq;
	freq = pitch.midicps;
	wobble = LFNoise1.kr(Rand(2, 5), freq * 0.0025, freq * 0.0025);
	snd = Blip.ar(freq + wobble, nharm);
	env = EnvGen.kr(Env.perc(releaseTime:decay), doneAction:2); 
	pos = Line.kr(-1, 1, decay);
	Out.ar(0, Pan2.ar(snd * env, Rand(-1, 1), amp));
}).send(s);
)

(
	var pitch;
	d = 1/8; // duration in fraction of a second.  Change it and see... You can also use decimals (1/8 = 0.125)
	// A Task is something that can start and stop and that you can return to.
	// Here the task loops around a series of numbers.
	r = Task({

		loop({
						pitch = 60;
						// pitch = [35, 49, 57, 69, 71, 75, 78].choose;
						Synth( "MyBlip", [ \pitch, pitch, \nharm, [2,3,4,5,6,7,8].choose ] );
						d.wait; // this must be set to a non-zero value
				});
		}).play;
)

r.play;
d = 1
d = 0.1 // setting this to zero will crash SC
r.stop;

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// Now using arrays:

(
	var pitch, count = 0;
	d = 1/8; // duration in fraction of a second.  Change it and see... You can also use decimals (1/8 = 0.125)
	// A Task is something that can start and stop and that you can return to.
	// Here the task loops around a series of numbers.
	a = [ 60, 62, 63, 65, 67 ];
	r = Task({

		loop({
				(a.size).do({
						pitch = a[count];
						pitch.postln;
						Synth( "MyBlip", [ \pitch, pitch, \nharm, [2,3,4,5,6,7,8].choose ] );
						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 ]
a = [ 80, 82, 84, 86 ]
a = [ 60, 62, 46 ]
a = a + 2
a = a - 2

///////////////////////////////////////////////////////////////////////////
// Control Structures
// The above has a problem with the loop.  Assume the 'do' is underway 10 times because the array has 	10 items in it.  It has just reached it's fourth iteration.  At that point you change the array so that it only has three items.  At the next iteration, you try to assign the fifth member of the array to 'pitch'.  This doesn't exist so the task will end in an error.  You can get around it like this - see if you can follow it:

(
	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( "MyBlip", [ \pitch, pitch, \nharm, [2,3,4,5,6,7,8].choose ] );
						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 ];

///////////////////////////////////////////////////////
// One level of if:
///////////////////////////////////////////////////////

(
	var pitch, count = 0;
	d = 1/8; // duration in fraction of a second.  Change it and see... You can also use decimals (1/8 = 0.125)
	// A Task is something that can start and stop and that you can return to.
	// Here the task loops around a series of numbers.
	r = Task({
		loop({
					// there's a 50% chance that 0.5.coin will evaluate as 'true'
					// if it does, the first function will be evaluated (pitch will equal 60)
					// otherwise, pitch will be set to 72, an octave higher
					if ( 0.5.coin, { pitch = 60 }, { pitch = 72 });
					Synth( "MyBlip", [ \pitch, pitch ] );
					d.wait;
				});
		}).play;
)

r.play;
r.stop;

///////////////////////////////////////////////////////
// The first if option contains its own array
///////////////////////////////////////////////////////

(
	var pitch, count = 0;
	d = 0.125;
	
	r = Task({
	a = [ 60, 62, 63, 65, 67 ];
	
		loop({
					if ( 0.5.coin, 
						{ // first choice
								while ( { count < a.size }, 
										{
											pitch = a[count];
											pitch.postln;
											Synth( "MyBlip", [ \pitch, pitch ] );
											d.wait;
											count = count + 1;
										});
									count = 0
						 }, // end first choice
						// second choice (notice how frequently this will be chosen
						// many times in a row...)
						{ pitch = [ 72, 79, 84, 86, 87, 89, 91, 96 ].choose } 
						);
						Synth( "MyBlip", [ \pitch, pitch ] );
						d.wait;
				}); // end loop
		}).play; // end task
)

r.play;
r.stop;
d = 0.2;

///////////////////////////////////////////////////////
// Each if option contains its own array
///////////////////////////////////////////////////////

(
	var pitch, count = 0;
	d = 0.125; 
	
	r = Task({
	a = [ 60, 62, 63, 65, 67 ];
	b = [ 59, 61, 62, 64, 66 ];
	
		loop({
					if (0.5.coin, 
						{ // first choice
							while ( { count < a.size }, 
								{
									pitch = a[count];
									Synth( "MyBlip", [ \pitch, pitch ] );
									d.wait;
									count = count + 1;
								})
						 }, 
						{ // second choice
							while ( { count < b.size }, 
								{
								pitch = b[count];
								Synth( "MyBlip", [ \pitch, pitch ] );
								d.wait;
								count = count + 1;
							})
						 } // end second choice 
						);
						Synth( "MyBlip", [ \pitch, pitch ] );
						d.wait;
						count = 0;
				}); // end loop
		}).play; // end task
)

r.play;
r.stop;
d = 0.1;
a = [ 80, 82, 84, 85, 86 ];
a = a - 2;

///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
// Case
///////////////////////////////////////////////////////

(
	var pitch, myCase, myChoices, myChoice;
	d = 0.125; 
	
	r = Task({

		loop({
				myChoices = [ 0, 1 ]; // just two choices - there could be many...
				myChoice = myChoices.choose; // choose one
				
				case // here's the case
				{ myChoice == 0 } { pitch = 60 }
				{ myChoice == 1 } { pitch = 72 };
	
				Synth( "MyBlip", [ \pitch, pitch ]);
				d.wait;
				});
		}).play;
)

r.play;
r.stop;

///////////////////////////////////////////////////////
// Using Case with arrays
///////////////////////////////////////////////////////

(
	var pitch, myCase, myChoices, myChoice;
	var count = 0;
	d = 0.125; 
	a = [ 60, 63, 67, 72, 74 ];
	
	r = Task({

		loop({
				myChoices = [ 0, 1 ]; // just two choices - there could be many...
				myChoice = myChoices.choose; // choose one
				
				case // here's the case
				{ myChoice == 0 } 
				{ 
					count = 0;
					"myChoice is 0!".postln; // you can get rid of this!
					while ( { count < a.size }, 
						{
							pitch = a[count];
							Synth( "MyBlip", [ \pitch, pitch ] );
							d.wait; // try it without the wait here...
							count = count + 1;
					});
				} // note the lack of semicolon;
				// here all the commands are put on one line separated by semicolons.
				// you can remove the postln part if you want.  Go on, try it...
				{ myChoice == 1 } { 	"myChoice is 1!".postln; pitch = 72; Synth( "MyBlip", [ \pitch, pitch ]); 	d.wait; };

				});
		}).play;
)

r.play;
r.stop;

///////////////////////////////////////////////////////
// Using Case with two arrays - you can use any number of cases...
///////////////////////////////////////////////////////
(
	var pitch, myChoices, myChoice;
	var count = 0;
	d = 0.15; 
	a = [ 60, 63, 67, 72, 74 ];
	b = [ 59, 62, 67, 71 ];
	
	r = Task({

		loop({
				myChoices = [ 0, 1 ]; // just two choices - there could be many...
				myChoice = myChoices.choose; // choose one
				
				case // here's the case
				{ myChoice == 0 } 
				{ 
					count = 0;
					while ( { count < a.size }, 
						{
							pitch = a[count];
							Synth( "MyBlip", [ \pitch, pitch ] );
							d.wait; // try it without the wait here...
							count = count + 1;
					})
				} // end of first case
				
				{ // second case
					count = 0;
					while ( { count < b.size }, 
						{
							pitch = b[count];
							Synth( "MyBlip", [ \pitch, pitch ] );
							d.wait; // try it without the wait here.  Try it without either wait, but you must include the one below!
							count = count + 1;
					})
				};
			// 0.1.wait;
			});  // end loop
		}).play; // end task
)

r.play;
r.stop;

d = 0.1

a = a + 12;
b = b + 12;
a = a - 12;
b = b - 2;

///////////////////////////////////////////////////////
// Another example
///////////////////////////////////////////////////////
// is there a problem with the below?

(
	var pitch, myCase, myChoices, myChoice;
	var count = 0;
	d = 0.015; 
	a = [ 60, 63, 67, 72, 74 ];
	b = [ 59, 62, 67, 71 ];
	
	r = Task({

		loop({
				myChoices = [ 0, 1 ]; // just two choices - there could be many...
				myChoice = myChoices.choose; // choose one
				
				case // here's the case
				{ myChoice == 0 } 
				{ 
					count = 0;
					while ( { count < a.size }, 
						{
							pitch = a[count];
							Synth( "MyBlip", [ \pitch, pitch ] );
							d.wait; // try it without the wait here...
							count = count + 1;
						}); // end do
					a = a + 1; //!
				} // end of first case
				
				{ // second case
					count = 0;
					while ( { count < b.size }, 
						{
							pitch = b[count];
							Synth( "MyBlip", [ \pitch, pitch ] );
							d.wait; // try it without the wait here...
							count = count + 1;
						}); // end do
					b = b - 1;
				};
				d = d + 0.001; // !
				d.postln;
				});  // end loop
		}).play; // end task
)

r.play;
r.stop;

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// Arrays with functions

// From above

(
	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( "MyBlip", [ \pitch, pitch, \nharm, [2,3,4,5,6,7,8].choose ] );
						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 ];

///////////////////////////////////////////////////////////////////////////
// Encase in a function:

(
~myAlgorithm = ({ arg arpWait = 0.1, loopWait = 1.0;
	var pitch, count = 0;
	d = 0.1; 
	a = [ 60, 62, 63, 65, 67 ];
	
	r = Task({

		loop({
				while ( { count < a.size }, 
					{
						pitch = a[count];
						pitch.postln;
						Synth( "MyBlip", [ \pitch, pitch, \nharm, [2,3,4,5,6,7,8].choose ] );
						arpWait.wait;
						count = count + 1;
					});
				count = 0;
				loopWait.wait;
		});
	}).play;	

});
)

~myAlgorithm.value;
r.stop;

///////////////////////////////////////////////////////////////////////////
// Develop Arguments

(
~myAlgorithm = ({ arg pitchArray = [ 60, 62, 63, 65, 67 ], myWait = 0.125;
	var pitch = 60, count = 0;
	
	r = Task({

		loop({
				while ( { count < pitchArray.size }, 
					{
						pitch = pitchArray[count];
						pitch.postln;
						Synth( "MyBlip", [ \pitch, pitch, \nharm, [2,3,4,5,6,7,8].choose ] );
						//if ( myWait == 0.0, { 0.01.wait}, { myWait.wait} );
						myWait.wait;
						count = count + 1;
					});
				count = 0
		});
	}).play;	

});
)

// now, because of the defaults above, it works without arguments:
~myAlgorithm.value;
r.stop;

// but you can also include them:
~myAlgorithm.value([ 50, 52, 53, 55, 57 ]);
r.stop;

// and so include various controls:
(
r.stop;
~myAlgorithm.value([ 24, 36, 58, 56 ], 0.2);
)

(
r.stop;
a = 10.rand + 60;
~myAlgorithm.value([ a, a+2, a+3, a+5, a+7 ], 0.3.rand);
)