SCDoc: Use proper static string constants instead of comparing string literals.
[supercollider.git] / SCClassLibrary / Common / Streams / Pspawner.sc
blob5652fb0acf1ec0a8e09c590eac5553377cc9f1d1
1 Spawner : Pattern {
2         var <>genStream;
3         var <>priorityQ;
4         var <>now;
5         var <>event;
7         *new { | func, stackSize=64 |
8                 ^super.new.init( func, stackSize)
9         }
11         suspend { | stream |
12                 priorityQ.removeValue(stream);
13         }
15         suspendAll {
16                 priorityQ.clear
17         }
19         init { | func, stackSize |
20                 priorityQ = PriorityQueue.new;
21                 genStream = Routine({func.value(this) }, stackSize);
22                 now = 0;
23                 priorityQ.put(now, genStream);
24         }
26         par { | pattern, delta = 0 |
27                 var stream = pattern.asStream;
28                 priorityQ.put(now + delta, stream);
29                 ^stream;
30         }
32         seq { | pat |
33                 pat.embedInStream(event)
34         }
36         wait { | dur |
37                 Event.silent(dur, event).yield
38         }
40         embedInStream { | inevent, cleanup|
42                 var outevent, stream, nexttime;
43                 event = inevent;                                        // gives genStream access to the event
44                 cleanup ?? { cleanup = EventStreamCleanup.new };
46                 while({
47                         priorityQ.notEmpty
48                 },{
49                         stream = priorityQ.pop;
50                         outevent = stream.next(event).asEvent;
52                         if (outevent.isNil, {
53                                 nexttime = priorityQ.topPriority;
54                                 if (nexttime.notNil, {
55                                         // that child stream ended, so rest until next one
56                                         outevent = Event.silent(nexttime - now, event);
57                                         event = outevent.yield;
58                                         now = nexttime;
59                                 },{
60                                         priorityQ.clear;
61                                         cleanup.exit(event);
62                                 });
63                         },{
64                                 cleanup.update(outevent);
65                                 // requeue stream
66                                 priorityQ.put(now + outevent.delta, stream);
67                                 nexttime = priorityQ.topPriority;
68                                 outevent.put(\delta, nexttime - now);
70                                 event = outevent.yield;
71                                 now = nexttime;
72                         });
73                 });
74                 ^event;
75         }
78 Pspawner : Prout {
79         asStream {
80                 ^Routine({ | ev | this.embedInStream(ev) })
81         }
82         embedInStream { | inevent, cleanup |
83                 ^Spawner(routineFunc).embedInStream(inevent, cleanup ?? { EventStreamCleanup.new });
84         }
87 Pspawn : FilterPattern {
88         var     <>spawnProtoEvent;
90         *new { |pattern, spawnProtoEvent|
91                 ^super.new(pattern)
92                         .spawnProtoEvent_(spawnProtoEvent ?? { Event.default });
93         }
95         embedInStream { |inevent, cleanup|
96                 ^Spawner({ |sp|
97                         var     event, stream = pattern.asStream,
98                                 child;
99                         while { (event = stream.next(spawnProtoEvent.copy.put(\spawner, sp))).notNil } {
100                                 case
101                                         { event.method == \wait } {
102                                                 event.spawner.wait(event.delta)
103                                         }
104                                         { #[seq, par].includes(event.method) } {
105                                                 child = event.pattern;
106                                                 if(child.isKindOf(Symbol)) {
107                                                         child = (event[\dict] ? Pdef).at(child);
108                                                 };
109                                                 event.spawner.perform(event.method, child.value);
110                                                 if(event.delta > 0) {
111                                                         event.spawner.wait(event.delta)
112                                                 }
113                                         }
114                                                 // suspend requires access to the specific stream
115                                                 // don't know how to get it... maybe implement later
116                                         { event.method == \suspendAll } {
117                                                 event.spawner.suspendAll
118                                         }
119                                         { "Unrecognized method % in spawner event."
120                                                 .format(event.method.asCompileString).warn;
121                                         }
122                         };
123                 }).embedInStream(inevent, cleanup ?? { EventStreamCleanup.new })
124         }
129         Pseq([
130                 Pspawner({ | sp |
131                         sp.postln;
132                         sp.par(Pbind(*[degree:  Pwhite(0,12), dur: 0.1, db: -30]) );
133                         sp.seq(Pbind(*[degree:  Pseq((0..4).mirror.mirror, 1) + [-3, 0,2], ctranspose: -12, dur: 0.2 ]) );
134                         "hi".postln;
135                         sp.wait(1);
136                         "bye".postln;
137                         sp.suspendAll;
138                 }),
140                 Pspawner({ | sp |
141                         sp.postln;
142                         sp.par(Pbind(*[degree:  Pwhite(0,12), dur: 0.2, ctranspose: -12]) );
143                         "hi".postln;
144                         sp.wait(4);
145                         "bye".postln;
146                         sp.suspendAll
147                 }),
149         ]).play
151         a = Spawner({ |sp | 100.do{ sp.wait(1) } });
152         a.play;
153         b = a.par(Pbind(*[degree: Pwhite(0, 10), dur: 0.2]));
154         a.suspend(b)
155         a.par(b)
157         Pspawner({ | sp |
158                 5.do {
159                         sp.par(Pbind(*[
160                                 octave: (5.rand + 3).postln,
161                                  degree:        Pwhite(0,12), dur: 0.1, db: -30
162                         ]) );
163                         sp.wait(1);
164                         sp.clear;
165                 }
166         }).play