class::Routine
categories::Core>Kernel
summary:: Functions that can return in the middle and then resume where they left off
related:: Classes/Stream

description::
A Routine runs a link::Classes/Function:: and allows it to be suspended in the middle
and be resumed again where it left off. This functionality is supported by the Routine's
superclass link::Classes/Thread::. Effectively, Routines can be used to implement
co-routines as found in Scheme and some other languages.

A Routine is strong::started:: the first time link::#-next:: is called, which will run
the Function from the beginning. It is strong::suspended:: when it "yields"
(using link::Classes/Object#-yield:: within the Function), and then strong::resumed::
 using link::#-next:: again. When the Function returns, the Routine is considered
strong::stopped::, and calling link::#-next:: will have no effect - unless the Routine is
strong::reset:: using link::#-reset::, which will rewind the Function to the beginning.
You can stop a Routine before its Function returns using link::#-stop::.

When a Routine is strong::scheduled:: on a link::Classes/Clock:: (e.g. using
link::#-play::), it will be started or resumed at the scheduled time. The value yielded
by the Routine will be used as the time difference for rescheduling the Routine. (See
link::#-awake::).

Since Routine inherits from link::Classes/Thread::, it has its own associated
link::Classes/Thread#-beats#logical time::, etc. When a Routine is started or
resumed, it becomes the link::Classes/Thread#.thisThread#current thread::.

Routine also inherits from link::Classes/Stream::, and thus shares its ability to be
combined using math operations and "filtered".


classMethods::

method::new

Creates an instance of Routine, passing it the Function with code to run.

argument::func
A Function with code for the Thread to run.

argument::stackSize
Call stack size (an Integer).

discussion::
code::
a = Routine.new({ 1.yield; 2.yield; });
a.next.postln;
a.next.postln;
a.next.postln;
::

instanceMethods::

method::next

This method performs differently according to the Routine's state:
list::
## Starts the Routine, if it has not been started yet or it has been
link::#-reset#reset::; i.e runs its Function from the beginning, passing on the
code::inval:: argument.
## Resumes the Routine, if it has been suspended (it has yielded); i.e. resumes its
Function from the point where link::Classes/Object#-yield#yield:: was called on an Object,
passing the code::inval:: argument as the return value of code::yield::.
## Does nothing if the Routine has stopped (because its Function has returned, or
link::#-stop:: has been called).
::

Since Routine inherits from link::Classes/Thread::, it will become the
emphasis::current thread:: when it is started or resumed; i.e.
link::Classes/Thread#.thisThread#thisThread:: used in the Routine Function will return
the Routine. It will inherit the parent thread's logical time and clock
(see link::Classes/Thread#-parent::).

Synonyms for code::next:: are link::#-value:: and link::#-resume::.

returns::
list::
## Either the value that the Routine yields (the Object on which
link::Classes/Object#-yield#yield:: is called within the Routine Function),
## ...or code::nil::, if the Routine has stopped.
::

discussion::

When a Routine is started by a call to this method (or one of its synonyms), the method's
argument is passed on as the argument to the Routine Function:

code::
Routine { arg inval;
	inval.postln;
}.value("hello routine");
::

After the Routine has yielded (it has been suspended at the point in its Function where
code::yield:: is called on an Object), a call to this method (or its synonyms) resumes
executing the Function and the argument to this method becomes the return value of
code::yield::. To access that value within the Function, you have to assign it to a
variable - typically, the argument of the Function is reused:

code::
(
r = Routine { arg inval;
	inval.postln;
	inval = 123.yield;
	inval.postln;
}
)

r.value("hello routine");
r.value("goodbye routine");
::

Typically, a Routine yields multiple times, and each time the result of the yield is
reassigning to the argument of its Function.

code::
(
r = Routine { arg inval;
	inval.postln; // Post the value passed in when started.
	5.do { arg i;
		inval = (i + 10).yield;
		inval.postln; // Post the value passed in when resumed.
	}
}
)
(
5.do {
	r.value("hello routine").postln; // Post the value that the Routine yields.
}
)
::

method::value

Equivalent to link::#-next::.

method::resume

Equivalent to link::#-next::.

method::stop

Equivalent to the Routine Function reaching its end or returning: after this, the Routine
will never run again (the link::#-next:: method has no effect and returns code::nil::),
unless link::#-reset:: is called.

method::reset

Causes the Routine to start from the beginning next time link::#-next:: is called.

discussion::

If a Routine is stopped (its Function has returned or link::#-stop:: has been called), it
will never run again (the link::#-next:: method has no effect and returns code::nil::),
unless this method is called.

A Routine cannot reset itself, except by calling link::Classes/Object#-yieldAndReset::.

See also: link::Classes/Object#-yield::, link::Classes/Object#-alwaysYield::


method::play

In the SuperCollider application, a Routine can be played using a link::Classes/Clock::, as can any link::Classes/Stream::.
every time the Routine yields, it should do so with a float, the clock will interpret that, usually
pausing for that many seconds, and then resume the routine, passing it the clock's current time.

argument::clock
a Clock, TempoClock by default

argument::quant
see the link::Classes/Quant:: helpfile

discussion::
using link::Classes/Object#idle#Object:idle:: within a routine, return values until this time is over. Time is measured relative to the thread's clock.
code::
// for 6 seconds, return 200, then continue
(
r = Routine {
		199.yield;
		189.yield;
		200.idle(6);
		199.yield;
		189.yield;
};

fork {
	loop {
		r.value.postln;
		1.wait;
	}
}
);

// the value can also be a stream or a function
(
r = Routine {
		199.yield;
		189.yield;
		Routine { 100.do { |i| i.yield } }.idle(6);
		199.yield;
		189.yield;
};

fork {
	loop {
		r.value.postln;
		1.wait;
	}
}
);
::

method:: awake

This method is called by a link::Classes/Clock:: on which the Routine was scheduled
when its scheduling time is up. It calls link::#-next::, passing on the scheduling
time in beats as an argument. The value returned by code::next:: (the value yielded
by the Routine) will in turn be returned by this method, thus determining the time
which the Routine will be rescheduled for.

argument:: inBeats
The scheduling time in beats. This is equal to the current logical time
(link::Classes/Thread#-beats::).

argument:: inSeconds
The scheduling time in seconds. This is equal to the current logical time
(link::Classes/Thread#-seconds::).

argument:: inClock
The clock which awoke the Routine.



subsection::Accessible instance variables

Routine inherits from link::Classes/Thread::, which allows access to some of its state:

code::
(
r = Routine { arg inval;
	loop {
		// thisThread refers to the routine.
		postf("beats: % seconds: % time: % \n",
			thisThread.beats, thisThread.seconds, Main.elapsedTime
		);
		1.0.yield;

	}
}.play;
)

r.stop;
r.beats;
r.seconds;
r.clock;
::

method::beats

returns:: The elapsed beats (logical time) of the routine. The beats do not proceed when the routine is not playing.

method::seconds

returns:: The elapsed seconds (logical time) of the routine. The seconds do not proceed when the routine is not playing, it is the converted beat value.

method::clock

returns:: The thread's clock. If it has not played, it is the SystemClock.

examples::

code::
(
var r, outval;
r = Routine.new({ arg inval;
	("->inval was " ++ inval).postln;
	inval = 1.yield;
	("->inval was " ++ inval).postln;
	inval = 2.yield;
	("->inval was " ++ inval).postln;
	inval = 99.yield;
});

outval = r.next('a');
("<-outval was " ++ outval).postln;
outval = r.next('b');
("<-outval was " ++ outval).postln;
r.reset; "reset".postln;
outval = r.next('c');
("<-outval was " ++ outval).postln;
outval = r.next('d');
("<-outval was " ++ outval).postln;
outval = r.next('e');
("<-outval was " ++ outval).postln;
outval = r.next('f');
("<-outval was " ++ outval).postln;
)
::

code::
// wait

(
var r;
r = Routine {
	10.do({ arg a;
		a.postln;
		// Often you might see Wait being used to pause a routine
		// This waits for one second between each number
		1.wait;
	});
	// Wait half second before saying we're done
	0.5.wait;
	"done".postln;
}.play;
)
::

code::
// waitUntil

(
var r;
r = Routine {
	var times = { rrand(1.0, 10.0) }.dup(10) + thisThread.beats;
	times = times.sort;
	times.do({ arg a;
		waitUntil(a);
		a.postln;
	});
	// Wait half second before saying we're done
	0.5.wait;
	"done".postln;
}.play;
)
::

code::
// Using Routine to set button states on the fly.
(
var update, w, b;
w = SCWindow.new("State Window", Rect(150,SCWindow.screenBounds.height-140,380,60));

// a convenient way to set the button label
update = {
	|but, string| but.states = [[string.asString, Color.black, Color.red]];
	but.refresh;
};

b = SCButton(w, Rect(10,10,360,40));
b.font_(Font("Impact", 24));

update.value(b, "there is only one state");

// if an action should do something different each time it is called, a routine is the
// right thing to use. This is better than creating variables outside and setting them
// from the action function to keep state from one action to the next

b.action_(Routine { |butt|
	rrand(15, 45).do { |i|
		update.value(butt, "%. there is still only 1 state".format(i + 2));
		0.yield; // stop here
	};
	w.close;
});

w.front;
)
::

code::
// drawing in a window dynamically with Pen
(
var w, much = 0.02, string, synth;

w = Window.new("swing", Rect(100, 100, 300, 500)).front;
w.view.background_(Color.new255(153, 255, 102).vary);

string = "swing ".dup(24).join;

w.drawFunc = Routine {
	var i = 0;
	var size = 40;
	var func = { |i, j| sin(i * 0.07 + (j * 0.0023) + 1.5pi) * much + 1 };
	var scale;
	Pen.font = Font("Helvetica-Bold", 40);
	loop {
		i = i + 1;
		string.do {	|char, j|

			scale = func.value(i, j).dup(6);

			Pen.fillColor = Color.new255(0, 120, 120).vary;
			Pen.matrix = scale * #[1, 0, 0, 1, 1, 0];
			Pen.stringAtPoint(char.asString,
				((size * (j % 9)) - 10) @ (size * (j div: 9))
			);
		};
		0.yield // stop here, return something unimportant
	}
};

fork { while { w.isClosed.not } { defer { w.refresh }; 0.04.wait; } };

w.front;

)
::

