#lang scribble/manual @(require (for-label racket)) @title{Pspawner} dynamic control of multiple event streams from a Routine@section{related} Classes/Pspawn @section{categories} Streams-Patterns-Events>Patterns>Parallel @section{description} Pspawner allows a routine to dynamically start and stop subpatterns. @section{ClassMethods} @section{method} new @section{argument} routineFunc The function defines a link::Classes/Routine:: that receives a link::Classes/Spawner:: as its sole argument. All control of subpatterns is through the spawner. link::Classes/Spawner:: responds to the messages: @section{definitionlist} ## par || Begin an event stream in parallel to the routine. If delta is non-zero, the pattern will begin that many beats after 'now', provided that now + delta is later than the next event that the Spawner will generate. The method returns the stream. This may be called from any object. ## seq || Run the entire pattern and then return control to the routine. ## wait || Wait strong::dur:: seconds and then return control to the routine. ## suspend || Find the stream in the Spawner and stop it, returns nil if the stream is not found, the stream otherwise. ## suspendAll || Stop all substreams of the Spawner. :: @section{note} We should move the documentation of above methods to the link::Classes/Spawner:: helpfile... :: @section{Examples} @racketblock[ // example 1: a simple Pspawner ( Pspawner({ | sp | // parallel in-c'ish pulses will run throughout the example sp.par(Pbind(*[ degree: [0,7], octave: 7, dur: 0.2, db: Pseq([-20, -24, -22, -24], inf)]) ); // scales in sequence with pauses sp.seq( Pbind(*[ degree: Pseq((0..7).mirror), dur: 0.2]) ); sp.wait(0.4); sp.seq( Ppar([ Pbind(*[ degree: Pseq((0..7).mirror), dur: 0.2, octave: 4]), Pbind(*[ degree: Pseq((0..7).reverse.mirror), dur: 0.2]) ]) ); sp.wait(3); sp.seq( Pbind(*[ degree: Pseq((0..7).mirror), dur: 0.2, mtranspose: (0,2..14)]) ); // scales overlaped at 0.4 second intervals 10.do { sp.par( Pbind(*[ degree: Pseq((0..7).mirror), dur: 0.2]) ); sp.wait(0.4) }; sp.wait(1.6); sp.suspendAll; }).play ) ( // example 2: create 6 streams at 4 second intervals // then delete them in the order they were created Pspawner({ | sp | var streams, stream; // start patterns, collect the resultant event streams streams = [2, 3, 4, 6, 7, 8].collect { | i | stream = sp.par(Pbind(*[ harmonic: i, ctranspose: [0, 1, 3]/40, octave: Pbrown(2,8,2), dur: 1/i, db: -30 ]) ); sp.wait(4); stream; }; // now stop those streams one by one streams.do { | s | sp.suspend(s); sp.wait(4) }; }).play ) ( // example 3: define a Pspawner and use Pattern manipulations p = Pspawner({ | sp | var pat = Pbrown( -7, 7, 3); sp.par(Pbind(*[octave: 5, degree: pat, dur: 1/4]) ); sp.wait(2); sp.par(Pbind(*[octave: 6, degree: pat, dur: 1/8]) ); sp.wait(3); sp.par(Pbind(*[octave: 7, degree: pat, dur: 1/6, db: -20]) ); sp.wait(4); sp.par(Pbind(*[octave: 4, degree: pat, dur: 1/4]) ); sp.wait(8); sp.suspendAll; }); ) // play the basic patten p.play; ( // manipulate basic pattern with Pchain Pchain( Pbind(*[mtranspose: Pkey(\mtranspose) + Pstutter(8, Prand([0,[0,3,-2],[0,2,4]], inf)) ] ), //make some notes into triads Pbind(*[ctranspose: Pwhite(-0.1, 0.1)]), //add random detuning to notes Pbind(*[\scale, Scale.minor]), //alter the scale Pn(Pseq([p, (type:\rest, dur: 1.0)]) ), //repeat the pattern after a 1 second pause Pbind(*[ db: Pstep(Pseq([-10, -13, -13, -11, -13, -13], inf), 0.1) - 10, mtranspose: Pstep(Pwhite(-7,7), Prand([5,4,2],inf) ) //random modal transposition ]) ).play(protoEvent: Event.default) ) // example 4: altering the contents of the Pspawner from separate code ( a = Pspawner({ |sp | c = sp; // store the Spawner in a global variable 100.do{ sp.wait(1) } }); a.play; ) ( // c will not be valid until the Pspawner has run b = c.par( // now start a pattern in spawner Pbind(*[degree: Pseq((0..6) ++ (7..1), inf), dur: 0.2]) ); ) c.suspend(b) // we can suspend and resume the stream c.par(b) c.suspend(b) ( b = c.par( // or just start up a new pattern Pbind(*[degree: Pseq((0..6) ++ (7..1), inf), dur: 0.2]) ); ) // example 5: Spawner can be used directly in the manner of Pspawner. // This allows external code to access to the spawner whether or not it has run ( c = Spawner({ |sp | 100.do{ sp.wait(1) } }); b = c.par( // now start a pattern in spawner Pbind(*[degree: Pseq((0..6) ++ (7..1), inf), dur: 0.2]) ); c.play; // in this case, c is always valid ) c.suspend(b) // we can suspend and resume the stream c.par(b) c.suspend(b) ( b = c.par( // or just start up a new pattern Pbind(*[degree: Pseq((0..6) ++ (7..1), inf), dur: 0.2]) ); ) ( Pspawner({ | sp | (1..5).do { | i | sp.par(Pbind(*[ octave: i + 2, degree: Pwhite(0,7), dur: 1/i, db: -30 ]) ); sp.wait(4); }; sp.suspendAll; }).play ) :: ]