Classes | Core>Kernel

# Routine : Thread : Stream : AbstractFunction : Object

Functions that can return in the middle and then resume where they left off
Source: Thread.sc
Subclasses: FuncStreamAsRoutine
See also: Stream

## Description

A Routine runs a 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 Thread. Effectively, Routines can be used to implement co-routines as found in Scheme and some other languages.

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

When a Routine is scheduled on a Clock (e.g. using -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 -awake).

Since Routine inherits from Thread, it has its own associated logical time, etc. When a Routine is started or resumed, it becomes the current thread.

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

## Class Methods

### Routine.new(func, stackSize: 512)

From superclass: Thread

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

#### Arguments:

func | A Function with code for the Thread to run.
stackSize | Call stack size (an Integer).

#### Discussion:

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

### Inherited class methods

### Undocumented class methods

### Routine.run(func, stackSize, clock, quant)

## Instance Methods

### .next(inval)

This method performs differently according to the Routine's state:

- Starts the Routine, if it has not been started yet or it has been reset; i.e runs its Function from the beginning, passing on the `inval` argument.
- Resumes the Routine, if it has been suspended (it has yielded); i.e. resumes its Function from the point where yield was called on an Object, passing the `inval` argument as the return value of `yield`.
- Does nothing if the Routine has stopped (because its Function has returned, or -stop has been called).

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

Synonyms for `next` are -value and -resume.

#### Returns:

- Either the value that the Routine yields (the Object on which yield is called within the Routine Function),
- ...or `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:

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

After the Routine has yielded (it has been suspended at the point in its Function where `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 `yield`. To access that value within the Function, you have to assign it to a variable - typically, the argument of the Function is reused:

    (
    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.

    (
    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.
    }
    )

### .value(inval)

Equivalent to -next.

### .resume(inval)

Equivalent to -next.

### .stop

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

### .reset

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

#### Discussion:

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

A Routine cannot reset itself, except by calling Object: -yieldAndReset.

See also: Object: -yield, Object: -alwaysYield

### .play(clock, quant)

From superclass: Stream

In the SuperCollider application, a Routine can be played using a Clock, as can any 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.

#### Arguments:

clock | a Clock, TempoClock by default
quant | see the Quant helpfile

#### Discussion:

using Object:idle within a routine, return values until this time is over. Time is measured relative to the thread's clock.

    // 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;
        }
    }
    );

### .awake(inBeats, inSeconds, inClock)

This method is called by a Clock on which the Routine was scheduled when its scheduling time is up. It calls -next, passing on the scheduling time in beats as an argument. The value returned by `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.

#### Arguments:

inBeats | The scheduling time in beats. This is equal to the current logical time (Thread: -beats).
inSeconds | The scheduling time in seconds. This is equal to the current logical time (Thread: -seconds).
inClock | The clock which awoke the Routine.

### Accessible instance variables

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

    (
    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;

### .beats

### .beats = inBeats

From superclass: Thread

#### Returns:

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

### .seconds

### .seconds = inSeconds

From superclass: Thread

#### 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.

### .clock

### .clock = inClock

From superclass: Thread

#### Returns:

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

### Inherited instance methods

### Undocumented instance methods

### .p

### .prStart(inval)

### .prStop

### .run(inval)

### .valueArray(inval)

## Examples

    (
    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;
    )

    // 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;
    )

    // 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;
    )

    // 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;
    )

    // 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;

    )

helpfile source: /Applications/SuperCollider.app/Contents/Resources/HelpSource/Classes/Routine.schelp
link::Classes/Routine::