HelpBrowser: path box becomes a more conventional search box
[supercollider.git] / SCClassLibrary / JITLib / ProxySpace / BusPlug.sc
blob1997649e5d3d8e481a05b7c34c27d6233b28b4b3
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.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         }
178         wakeUpToBundle {}
179         wakeUp {}
180         asBus { ^if(this.isNeutral) { nil } { bus } }
181         asNodeArg { ^if(this.isNeutral) { nil } { this.busArg } }
187         // monitoring
190         play { | out, numChannels, group, multi=false, vol, fadeTime, addAction |
191                 var bundle = MixedBundle.new;
192                 if(this.homeServer.serverRunning.not) {
193                         ("server not running:" + this.homeServer).warn;
194                         ^this
195                 };
196                 this.playToBundle(bundle, out.asControlInput, numChannels, group, multi, vol, fadeTime, addAction);
197                 // homeServer: multi client support: monitor only locally
198                 bundle.schedSend(this.homeServer, this.clock ? TempoClock.default, this.quant)
199         }
201         playN { | outs, amps, ins, vol, fadeTime, group, addAction |
202                 var bundle = MixedBundle.new;
203                 if(this.homeServer.serverRunning.not) {
204                         ("server not running:" + this.homeServer).warn;
205                         ^this
206                 };
207                 this.playNToBundle(bundle, outs.asControlInput, amps, ins, vol, fadeTime, group, addAction);
208                 bundle.schedSend(this.homeServer, this.clock ? TempoClock.default, this.quant)
209         }
211         fadeTime { ^0.02 }
212         quant { ^nil }
214         vol { ^if(monitor.isNil) { 1.0 } { monitor.vol } }
215         vol_ { arg val; this.initMonitor(val) }
217         monitorIndex { ^if(monitor.isNil) { nil } { monitor.out } }
218         monitorGroup { ^if(monitor.isNil) { nil } { monitor.group } }
220         initMonitor { | vol |
221                 if(this.rate !== 'audio') { Error("can only monitor audio proxy").throw };
222                 if(monitor.isNil) { monitor = Monitor.new };
223                 if (vol.notNil) { monitor.vol_(vol) };
224                 ^monitor
225         }
227         stop { | fadeTime = 0.1, reset = false |
228                 monitor.stop(fadeTime);
229                 if(reset) { monitor = nil };
230         }
232         scope { | bufsize = 4096, zoom |
233                 if(this.isNeutral.not) { ^bus.scope(bufsize, zoom) }
234         }
236         record { | path, headerFormat = "aiff", sampleFormat = "int16", numChannels |
237                 var rec;
238                 if(server.serverRunning.not) { "server not running".inform; ^nil };
239                 rec = RecNodeProxy.newFrom(this, numChannels);
240                 rec.open(path, headerFormat, sampleFormat);
241                 rec.record;
242                 ^rec
243         }
248         // bundling messages
250         playToBundle { | bundle, out, numChannels,
251                                 group, multi=false, vol, fadeTime, addAction |
252                 this.newMonitorToBundle(bundle, numChannels);
253                 group = group ?? { if(parentGroup.isPlaying) { parentGroup } { this.homeServer.asGroup } };
254                 monitor.usedPlayN = false;
255                 monitor.playToBundle(bundle, bus.index, bus.numChannels, out, numChannels, group,
256                         multi, vol, fadeTime, addAction);
257         }
259         playNToBundle { | bundle, outs, amps, ins, vol, fadeTime, group, addAction |
260                 this.newMonitorToBundle(bundle); // todo: numChannels
261                 monitor.usedPlayN = true;
262                 group = group ?? { if(parentGroup.isPlaying) { parentGroup } { this.homeServer.asGroup } };
263                 monitor.playNBusToBundle(bundle, outs, amps, ins, bus, vol, fadeTime, group, addAction);
265         }
267         newMonitorToBundle { | bundle, numChannels |
268                 this.initBus(\audio, numChannels);
269                 this.initMonitor;
271                 if(this.isPlaying.not) { this.wakeUpToBundle(bundle) };
272         }
277         // netwrk node proxy support
279         shared { ^false }
280         homeServer { ^server }
282         printOn { | stream |
283                 stream  << this.class.name << "." << bus.rate << "("
284                                 << server << ", " << bus.numChannels <<")";
285         }