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)
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;
16 pairs.pairsDo {|name, value|
19 event[\addAction] = 0; // \addToHead
20 event[\instrument] = fxname;
25 cleanupEvent = (type: \off, parent: event);
27 cleanup.addFunction(event, { |flag|
28 if (flag) { cleanupEvent.play }
31 inevent = event.yield;
33 stream = pattern.asStream;
36 event = stream.next(inevent) ?? { ^cleanup.exit(inevent) };
37 cleanup.update(event);
38 inevent = event.yield;
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)
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
62 inevent[\endTime] ? 2.0,
63 inevent[\fadeTime] ? 0.02,
64 outputData[\numChannels],
66 ).embedInStream(inevent)
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
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;
92 event[\addAction] = 0; // \addToHead
93 event[\type] = eventType;
97 cleanupEvent = (type: \kill, parent: event);
99 cleanup.addFunction(event, { | flag |
100 if (flag) { cleanupEvent.lag_(lag - clock.beats + groupReleaseTime).play }
102 inevent = event.yield;
104 inevent !? { inevent = inevent.copy;
105 inevent[\group] = groupID;
107 stream = pattern.asStream;
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);
116 *embedLoop { arg inevent, stream, groupID, ingroup, cleanup;
119 event = stream.next(inevent) ?? { ^cleanup.exit(inevent) };
121 inevent = event.yield;
122 inevent.put(\group, groupID);
127 Pgroup : PAbstractGroup {
133 PparGroup : PAbstractGroup {
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)
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:
160 bus = server.audioBusAllocator.alloc(numChannels);
161 freeBus = { server.audioBusAllocator.free(bus) };
163 bus = server.controlBusAllocator.alloc(numChannels);
164 freeBus = { server.controlBusAllocator.free(bus) };
167 CmdPeriod.doOnce(freeBus);
169 event = inevent.copy;
170 event[\addAction] = 0; // \addToHead
171 event[\type] = \group;
173 event[\id] = groupID;
174 event[\group] = ingroup;
177 inevent = event = inevent.copy;
180 event[\group] = groupID;
181 event[\addAction] = 3; // \addBefore
184 event[\fadeTime] = fadeTime;
185 event[\instrument] = format("system_link_%_%", rate, numChannels);
187 event[\msgFunc] = #{ |out, in, fadeTime, gate=1|
188 [\out, out, \in, in, \fadeTime, fadeTime, \gate, gate, \doneAction, 3]
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) };
197 cleanup.addFunction(event, { defer({ freeBus.value;}, fadeTime.abs + dur) });
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;
207 event = stream.next(inevent) ?? { ^cleanup.exit(inevent) };
208 cleanup.update(event);
209 inevent = event.yield;