PSrecur Pattern to generate new values with a recursive Function 


Part of: miSCellaneous


Inherits from: PS / PStream


See also: MemoRoutine, PSx stream patterns, PS, PSdup, PSloop



Creation / Class Methods


*new (recurFunc, length, bufSize, start, copyItems, copySets)

Creates a new PSrecur object.

recurFunc - Recursive Function, the PSrecur will be passed as first arg, count as second arg.

length - Number of output items, may be pattern or stream, defaults to inf.

bufSize - Size of buffer to store last values. 

If bufSize is not defined and start is not given or a single item, bufSize gets value 1.

If bufSize is not defined and start is an array bufSize gets its length.

start - Single start item or array ot items used for recursion.

copyItems - Determines if and how to copy items generated by recurFunc,

which are either non-Sets or member of Sets. 

Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true) or 2 (or Symbol \deep). 

Other values are interpreted as 0. Defaults to 0.

0: original item 

1: copy item

2: deepCopy item

copySets - Determines if and how to copy Sets, generated by recurFunc. 

Takes Integer 0 (or false or Symbol \false), 1 (or true or Symbol \true). 

Other values are interpreted as 0. Defaults to 1.

0: original Set 

1: copy Set

NOTE 1: The distinction of copying items and sets makes sense in the case of event streams.

Per default Events are copied (copySets == 1), not their values (copyItems == 0). 

By playing Events those are used to store additional data (synth ids, msgFuncs …) 

which is mostly not of interest when refering to the event stream, e.g. with PSx patterns which use 

MemoRoutine - copied Events will not contain this additional data. 

If values of Events or values returned directly by the stream (being no kind of Sets) are unstructured 

then copying makes no sense, this is the normal case, so copyItems defaults to 0.

When going to alter the ouput, you might want to set copyItems to 1 for a PSx returning 

simple arrays or 2 for nested arrays (deepCopy). For deepCopying Events you'd have to set

copySets to 1 and copyItems to 2 (an option copySets == 2 doesn't exist as

it would be contradictory in combination with copyItems < 2).


NOTE 2: Copy options concern copying into PSrecur's buffer as well as 

the output of a Stream derived from the PSrecur. When such a Stream is outputting copies 

this prevents unintended altering of items stored in the buffer of the source. On the other hand

storing copies in PSrecur's buffer prevents these from being altered unintendedly.



Instance Methods


recurFuncStream, recurFuncStream_(value)

Instance variable getter and setter methods. 



Examples


(

s = Server.local;

Server.default = s;

s.boot;

)

// another way to generate the fibonacci sequence

// the first arg passed to the Function is the PSrecur itself,

// x[0] refers to its last value, x[1] to the value before the last value 


(

a = PSrecur({ |x| x[0] + x[1] }, start: [0, 1]);

b = a.iter;

b.nextN(10);

)


// shorter with partial application


PSrecur(_[0]+_[1], start: [0, 1]).iter.nextN(10);




// recursion with event patterns

// function calculates an iterated average of past event values for all keys,

// events at the end of the array are taken into account most.  


(

u = { |e,f| e.copy.keysValuesChange { |k| e[k]+f[k]/2 } };

v = { |a| a.reduce(u) };

)


(

// three basic Events


e = (midinote: 65, dur: 0.75, amp: 0.1, pan: 0);

f = (midinote: 58, dur: 0.05, amp: 0.3, pan: -1);

g = (midinote: 92, dur: 0.05, amp: 0.4, pan: 1);


// mostly build "blurred" average of last five events, 

// by chance disturbance by choosing a basic event


p = PSrecur({ |x| 0.8.coin.if { v.(x[..4]) }{ [e,f,f,g].choose } }, start: [e,f,e,g,e]);


q = p.trace.play;

)


q.stop;