Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / SCClassLibrary / Common / Streams / Pproto.sc
blob4138dd3cb2c58e4a9608588fcc3ba348f8382ead
1 Pfpar : ListPattern {
2         initStreams { arg priorityQ;
3                 list.do({ arg pattern, i;
4                         priorityQ.put(0.0, pattern.asStream);
5                 });
6         }
7         asStream { | cleanup| ^Routine({ arg inval; this.embedInStream(inval, cleanup) }) }
9         embedInStream { arg inval, cleanup;
10                 var assn;
11                 var priorityQ = PriorityQueue.new;
12                 cleanup ?? { cleanup = EventStreamCleanup.new };
14                 repeats.value(inval).do({ arg j;
15                         var outval, stream, nexttime, now = 0.0;
17                         this.initStreams(priorityQ);
19                         // if first event not at time zero
20                         if (priorityQ.notEmpty and: { (nexttime = priorityQ.topPriority) > 0.0 }, {
21                                 inval = Event.silent(nexttime, inval).yield;
22                                 now = nexttime;
23                         });
25                         while({
26                                 priorityQ.notEmpty
27                         },{
28                                 stream = priorityQ.pop;
29                                 outval = stream.next(inval).asEvent;
30                                 if (outval.isNil, {
31                                         priorityQ.clear;
32                                         ^cleanup.exit(inval);
33                                 },{
34                                         cleanup.update(outval);
35                                         // requeue stream
36                                         priorityQ.put(now + outval.delta, stream);
37                                         nexttime = priorityQ.topPriority;
38                                         outval.put(\delta, nexttime - now);
40                                         inval = outval.yield;
41                                         // inval ?? { this.purgeQueue(priorityQ); ^nil.yield };
42                                         now = nexttime;
43                                 });
44                         });
45                 });
46                 ^inval;
47         }
50 Pproto  : Pattern {
52         var <>makeFunction, <>pattern, <>cleanupFunc;
54         *new { | makeFunction, pattern, cleanupFunc|
55                 ^super.newCopyArgs( makeFunction, pattern, cleanupFunc)
56         }
57         storeArgs { ^[makeFunction,pattern,cleanupFunc] }
58         embedInStream { | event |
59                 var stream,  ev, evType;
60                 var cleanup, cleanupList, eventCleanupFunc;
61                 var proto;                                                      // temporary proto event used in allocation
62                 var makeRoutine;                                                // routine wrapper for function that makes protoEvent
63                 var protoEvent;                                         // protoEvent created by function
65 // Step 1: generate resources from function
66                 proto = (
67                         delta: 0,                                               // events occur simultaneously
68                         finish: { ev = currentEnvironment}      // get copy of event object actually played
69                 );
70                 protoEvent = ();
71                 makeRoutine = Routine({ protoEvent.make (makeFunction) });
73                 while {
74                         (ev = makeRoutine.next(ev)).notNil;
75                 } {
76                         event = ev.proto_(proto).yield;
77                         ev.proto = nil;
78                         cleanupList = cleanupList.add(ev)
79                 };
81                 cleanup = EventStreamCleanup.new;
82                 eventCleanupFunc = { | flag |
83                         cleanupList.do { | ev |
84                                 EventTypesWithCleanup.cleanup(ev, flag)
85                         }
86                 };
87                 cleanupFunc = eventCleanupFunc ?? { { | flag | eventCleanupFunc.value(proto, flag) } };
88                 cleanup.addFunction(event, cleanupFunc);
90                 stream = Pfpar(pattern.asArray).asStream(cleanup);
91                 loop {
92                         ev = event.copy.putAll(protoEvent);
93                         ev = stream.next(ev) ?? { ^cleanup.exit(event) };
94                         event = ev.yield;
95                 };
96                 ^event
97         }