scide: keyboard navigation - move among documents via Alt-Left/Right
[supercollider.git] / SCClassLibrary / JITLib / ProxySpace / BusPlug.sc
blob724d104b451a5515c9376d9c8f5d150fed2874be
1 BusPlug : AbstractFunction {
3         var <server, <bus;
4         var <>monitor, <>parentGroup; // if nil, uses default group
5         var busArg; // cache for "/s_new" bus arg
6         var busLoaded = false;
8         classvar <>defaultNumAudio=2, <>defaultNumControl=1;
11         *new { | server |
12                 ^super.newCopyArgs(server ? Server.default);
13         }
15         *for { | bus |
16                 bus = bus.asBus;
17                 ^this.new(bus.server).bus_(bus)
18         }
20         *audio { | server, numChannels |
21                 ^this.new(server).defineBus(\audio, numChannels)
22         }
24         *control { | server, numChannels |
25                 ^this.new(server).defineBus(\control, numChannels)
26         }
28         clear {
29                 this.free;
30                 this.stop;
31                 this.freeBus;
32                 monitor = nil;
33         }
38         //  playing and access
41         rate {  ^if(bus.isNil) { \scalar } { bus.rate } }
42         numChannels {  ^if(bus.isNil) { nil } { bus.numChannels } }
43         index { ^if(bus.isNil) { nil } { bus.index } }
45         isNeutral {
46                 ^bus.isNil or: { bus.index.isNil and: { bus.numChannels.isNil } }
47         }
49         isMonitoring {
50                 ^monitor.isPlaying
51         }
53         isPlaying {
54                 ^this.index.notNil and: { server.serverRunning }
55         }
57         prepareOutput { } // see subclass
58         clock { ^nil  }
60         ar { | numChannels, offset = 0 |
61                 if(this.isNeutral) {
62                         this.defineBus(\audio, numChannels)
63                 };
64                 this.prepareOutput;
65                 ^InBus.ar(bus, numChannels ? bus.numChannels, offset)
66         }
68         kr { | numChannels, offset = 0 |
69                 if(this.isNeutral) {
70                         this.defineBus(\control, numChannels)
71                 };
72                 this.prepareOutput;
73                 ^InBus.kr(bus, numChannels ? bus.numChannels, offset)
74         }
77         embedInStream { | inval | // for now, force multichannel expansion in streams early.
78                 ^this.asControlInput.embedInStream(inval);
79         }
81         asControlInput {
82                         if(this.isPlaying.not) {
83                                 if(this.isNeutral) { this.defineBus(\control, 1) };
84                                 this.wakeUp
85                         };
86                         ^this.busArg;
87         }
88         asUGenInput {
89                 ^this.value;
90         }
95         //  math support
97         value { | something |
98                 var n;
99                 if(UGen.buildSynthDef.isNil) { ^this }; // only return when in ugen graph.
100                 something !? {  n = something.numChannels };
101                 ^if(something.respondsTo(\rate) and: { something.rate == 'audio'}) { this.ar(n) } { this.kr(n) }
102         }
104         composeUnaryOp { | aSelector |
105                 ^UnaryOpPlug.new(aSelector, this)
106         }
107         composeBinaryOp { | aSelector, something |
108                 ^BinaryOpPlug.new(aSelector, this, something)
109         }
110         reverseComposeBinaryOp { | aSelector, something |
111                 ^BinaryOpPlug.new(aSelector, something, this)
112         }
113         composeNAryOp { |aSelector, anArgList|
114                 ^thisMethod.notYetImplemented
115                 //^NAryOpPlug.new(aSelector, [this]++anArgList) // nary op ugens are not yet implemented
116         }
121         // bus initialization
123         bus_ { | inBus |
124                 this.freeBus;
125                 bus = inBus;
126                 this.makeBusArg;
127                 busLoaded = bus.server.serverRunning;
128         }
130         // returns false if failed
131         initBus { | rate, numChannels |
132                                 if(rate.isNil or: { rate === 'scalar' }) { ^true }; // this is no problem
133                                 if(this.isNeutral) {
134                                         this.defineBus(rate, numChannels);
135                                         ^true
136                                 } {
137                                         numChannels = numChannels ? this.numChannels;
138                                         ^(bus.rate === rate) and: { numChannels <= bus.numChannels }
139                                 };
140         }
142         defineBus { | rate = \audio, numChannels |
143                 if(numChannels.isNil) {
144                         numChannels = if(rate === \audio) {
145                                                                 this.class.defaultNumAudio
146                                                         } {
147                                                                 this.class.defaultNumControl                                                    }
148                 };
149                 this.bus = Bus.alloc(rate, server, numChannels);
151         }
153         freeBus {
154                 if(bus.notNil) {
155                         if(bus.rate === \control) { bus.setAll(0) }; // clean up
156                         bus.free;
157                         monitor.stop;
158                 };
159                 busArg = bus = nil;
160                 busLoaded = false;
161         }
163         busArg { ^busArg ?? { this.makeBusArg } }
165         makeBusArg {
166                         var index, numChannels, prefix;
167                         if(bus.isNil) { ^busArg = "" }; // still neutral
168                         prefix = if(this.rate == \audio) { "\a" } { "\c" };
169                         index = this.index;
170                         numChannels = this.numChannels;
171                         ^busArg = if(numChannels == 1) {
172                                 prefix ++ index
173                         } {
174                                 { |i| prefix ++ (index + i) }.dup(numChannels)
175                         }
176         }
177         
178         asMap {
179                  ^this.busArg   
180         }
182         wakeUpToBundle {}
183         wakeUp {}
184         asBus { ^if(this.isNeutral) { nil } { bus } }
185         asNodeArg { ^if(this.isNeutral) { nil } { this.busArg } }
191         // monitoring
194         play { | out, numChannels, group, multi=false, vol, fadeTime, addAction |
195                 var bundle = MixedBundle.new;
196                 if(this.homeServer.serverRunning.not) {
197                         ("server not running:" + this.homeServer).warn;
198                         ^this
199                 };
200                 this.playToBundle(bundle, out.asControlInput, numChannels, group, multi, vol, fadeTime, addAction);
201                 // homeServer: multi client support: monitor only locally
202                 bundle.schedSend(this.homeServer, this.clock ? TempoClock.default, this.quant)
203         }
205         playN { | outs, amps, ins, vol, fadeTime, group, addAction |
206                 var bundle = MixedBundle.new;
207                 if(this.homeServer.serverRunning.not) {
208                         ("server not running:" + this.homeServer).warn;
209                         ^this
210                 };
211                 this.playNToBundle(bundle, outs.asControlInput, amps, ins, vol, fadeTime, group, addAction);
212                 bundle.schedSend(this.homeServer, this.clock ? TempoClock.default, this.quant)
213         }
215         fadeTime { ^0.02 }
216         quant { ^nil }
218         vol { ^if(monitor.isNil) { 1.0 } { monitor.vol } }
219         vol_ { arg val; this.initMonitor(val) }
221         monitorIndex { ^if(monitor.isNil) { nil } { monitor.out } }
222         monitorGroup { ^if(monitor.isNil) { nil } { monitor.group } }
224         initMonitor { | vol |
225                 if(this.rate !== 'audio') { Error("can only monitor audio proxy").throw };
226                 if(monitor.isNil) { monitor = Monitor.new };
227                 if (vol.notNil) { monitor.vol_(vol) };
228                 ^monitor
229         }
231         stop { | fadeTime = 0.1, reset = false |
232                 monitor.stop(fadeTime);
233                 if(reset) { monitor = nil };
234         }
236         scope { | bufsize = 4096, zoom |
237                 if(this.isNeutral.not) { ^bus.scope(bufsize, zoom) }
238         }
242         // bundling messages
244         playToBundle { | bundle, out, numChannels,
245                                 group, multi=false, vol, fadeTime, addAction |
246                 this.newMonitorToBundle(bundle, numChannels);
247                 group = group ?? { if(parentGroup.isPlaying) { parentGroup } { this.homeServer.asGroup } };
248                 monitor.usedPlayN = false;
249                 monitor.playToBundle(bundle, bus.index, bus.numChannels, out, numChannels, group,
250                         multi, vol, fadeTime, addAction);
251         }
253         playNToBundle { | bundle, outs, amps, ins, vol, fadeTime, group, addAction |
254                 this.newMonitorToBundle(bundle); // todo: numChannels
255                 monitor.usedPlayN = true;
256                 group = group ?? { if(parentGroup.isPlaying) { parentGroup } { this.homeServer.asGroup } };
257                 monitor.playNBusToBundle(bundle, outs, amps, ins, bus, vol, fadeTime, group, addAction);
259         }
261         newMonitorToBundle { | bundle, numChannels |
262                 this.initBus(\audio, numChannels);
263                 this.initMonitor;
265                 if(this.isPlaying.not) { this.wakeUpToBundle(bundle) };
266         }
271         // netwrk node proxy support
273         shared { ^false }
274         homeServer { ^server }
276         printOn { | stream |
277                 stream  << this.class.name << "." << bus.rate << "("
278                                 << server << ", " << bus.numChannels <<")";
279         }