SCDoc: Use proper static string constants instead of comparing string literals.
[supercollider.git] / SCClassLibrary / Common / Streams / Pfx.sc
blob95d41eed03d4e1423e172e3b9f879d564ca28f7b
1 Pfx : FilterPattern {
2         var <>fxname, <>pairs;
3         *new { arg pattern, fxname ... pairs;
4                 if (pairs.size.odd, { Error("Pfx should have even number of args.\n").throw });
5                 ^super.new(pattern).fxname_(fxname).pairs_(pairs)
6         }
7         storeArgs { ^[pattern, fxname] ++ pairs }
9         embedInStream { arg inevent;
10                 var stream, cleanup = EventStreamCleanup.new;
11                 var server = inevent[\server] ?? { Server.default };
12                 var id = server.nextNodeID;
13                 var event = inevent.copy;
14                 var cleanupEvent;
16                 pairs.pairsDo {|name, value|
17                         event[name] = value;
18                 };
19                 event[\addAction] = 0; // \addToHead
20                 event[\instrument] = fxname;
21                 event[\type] = \on;
22                 event[\id] = id;
23                 event[\delta] = 0;
25                 cleanupEvent = (type: \off, parent: event);
27                 cleanup.addFunction(event, { |flag|
28                         if (flag) { cleanupEvent.play }
29                 });
31                 inevent = event.yield;
33                 stream = pattern.asStream;
35                 loop {
36                         event = stream.next(inevent) ?? { ^cleanup.exit(inevent) };
37                         cleanup.update(event);
38                         inevent = event.yield;
39                 };
40         }
42         isolate {
43                 ^Prout { arg inevent;
44                         var outputData, synthDesc;
46                         synthDesc = (inevent[\synthLib] ?? { SynthDescLib.global }).at(fxname);
47                         if(synthDesc.isNil) { Error("Pfx: SynthDesc not found: %".format(fxname)).throw };
48                         outputData = synthDesc.outputData;
49                         if(outputData.size > 1) { Error("Pfx does not support more than one output UGen.").throw };
51                         if(outputData.isEmpty) {
52                                 this.embedInStream(inevent)
53                         } {
54                                 outputData = outputData.unbubble;
55                                 if(outputData[\numChannels] > SystemSynthDefs.numChannels) {
56                                         Error("Pfx: SynthDef % has too many channels."
57                                                 "Set SystemSynthDefs.numChannels >= %"
58                                                 .format(fxname, outputData[\numChannels])).throw
59                                 };
61                                 Pbus(this,
62                                         inevent[\endTime] ? 2.0,
63                                         inevent[\fadeTime] ? 0.02,
64                                         outputData[\numChannels],
65                                         outputData[\rate]
66                                 ).embedInStream(inevent)
67                         }
68                 }
69         }
72 Pfxb : Pfx {
73         *new { arg pattern, fxname ... pairs;
74                 if (pairs.size.odd, { Error("Pfx should have even number of args.\n").throw });
75                 ^super.new(pattern, fxname, *pairs).isolate
76         }
80 PAbstractGroup : FilterPattern {
81         embedInStream { arg inevent;
82                 var     server, groupID, event, cleanup;
83                 var     stream, lag = 0, clock = thisThread.clock,
84                         groupReleaseTime = inevent[\groupReleaseTime] ? 0.1, cleanupEvent;
85                 var eventType = this.class.eventType;
87                 cleanup = EventStreamCleanup.new;
88                 server = inevent[\server] ?? { Server.default };
89                 groupID = server.nextNodeID;
91                 event = inevent.copy;
92                 event[\addAction] = 0;  // \addToHead
93                 event[\type] = eventType;
94                 event[\delta] = 0;
95                 event[\id] = groupID;
97                 cleanupEvent = (type: \kill, parent: event);
99                 cleanup.addFunction(event, { | flag |
100                         if (flag) { cleanupEvent.lag_(lag - clock.beats + groupReleaseTime).play }
101                 });
102                 inevent = event.yield;
104                 inevent !? { inevent = inevent.copy;
105                         inevent[\group] = groupID;
106                 };
107                 stream = pattern.asStream;
108                 loop {
109                         event = stream.next(inevent) ?? { ^cleanup.exit(inevent) };
110                         lag = max(lag, clock.beats + event.use { ~sustain.value });
111                         inevent = event.yield;
112                         inevent.put(\group, groupID);
113                 }
114         }
116         *embedLoop { arg inevent, stream, groupID, ingroup, cleanup;
117                 var event, lag;
118                  loop {
119                         event = stream.next(inevent) ?? { ^cleanup.exit(inevent) };
120                         lag = event[\dur];
121                         inevent = event.yield;
122                         inevent.put(\group, groupID);
123                 }
124         }
127 Pgroup : PAbstractGroup {
128         *eventType {
129                 ^\group
130         }
133 PparGroup : PAbstractGroup {
134         *eventType {
135                 ^\parGroup
136         }
139 Pbus : FilterPattern {
140         var <>numChannels, <>rate, <>dur=2.0, <>fadeTime;
142         *new { arg pattern, dur=2.0, fadeTime=0.02, numChannels=2, rate=\audio;
143                 ^super.new(pattern).dur_(dur).numChannels_(numChannels).rate_(rate).fadeTime_(fadeTime)
144         }
146         storeArgs { ^[ pattern, dur, fadeTime, numChannels, rate ] }
148         embedInStream { arg inevent;
149                 var server, groupID, linkID, bus, ingroup, cleanup;
150                 var patterns, event, freeBus, stream, cleanupEvent;
152                 cleanup = EventStreamCleanup.new;
153                 server = inevent[\server] ?? { Server.default };
154                 groupID = server.nextNodeID;
155                 linkID = server.nextNodeID;
156                 ingroup = inevent[\group];
158                 // could use a special event type for this:
159                 if(rate == \audio) {
160                         bus = server.audioBusAllocator.alloc(numChannels);
161                         freeBus = { server.audioBusAllocator.free(bus) };
162                 } {
163                         bus = server.controlBusAllocator.alloc(numChannels);
164                         freeBus = { server.controlBusAllocator.free(bus) };
165                 };
167                 CmdPeriod.doOnce(freeBus);
169                 event = inevent.copy;
170                 event[\addAction] = 0; // \addToHead
171                 event[\type] = \group;
172                 event[\delta] = 0;
173                 event[\id] = groupID;
174                 event[\group] = ingroup;
175                 event.yield;
177                 inevent = event = inevent.copy;
179                 event[\type] = \on;
180                 event[\group] = groupID;
181                 event[\addAction] = 3; // \addBefore
182                 event[\delta] = 0;
183                 event[\id] = linkID;
184                 event[\fadeTime] = fadeTime;
185                 event[\instrument] = format("system_link_%_%", rate, numChannels);
186                 event[\in] = bus;
187                 event[\msgFunc] = #{ |out, in, fadeTime, gate=1|
188                         [\out, out, \in, in, \fadeTime, fadeTime, \gate, gate, \doneAction, 3]
189                 };
191                 cleanupEvent = (type: \off, parent: event, fadeTime: fadeTime.abs, hasGate: true, gate: 0);
193                 cleanup.addFunction(event, { | flag |
194                         if(flag) { defer ( {cleanupEvent.play}, dur) };
195                 });
197                 cleanup.addFunction(event, { defer({ freeBus.value;}, fadeTime.abs + dur) });
199                 // doneAction = 3;
200                 // remove and deallocate both this synth and the preceeding node
201                 // (which is the group).
202                 inevent = event.yield;
204                 // now embed the pattern
205                 stream = Pchain(pattern, (group: groupID, out: bus)).asStream;
206                 loop {
207                         event = stream.next(inevent) ?? { ^cleanup.exit(inevent) };
208                         cleanup.update(event);
209                         inevent = event.yield;
210                 }
211         }