class library: DUGen - the server now handles audio-rate inputs correctly
[supercollider.git] / SCClassLibrary / Common / Control / Bus.sc
blob767fbfd9d88c601907b3f025885204e2bb7623c7
1 Bus {
3         var <rate,<index,<numChannels,<server;
4         var mapSymbol;
6         *control { arg server,numChannels=1;
7                 var alloc;
8                 server = server ? Server.default;
9                 alloc = server.controlBusAllocator.alloc(numChannels);
10                 if(alloc.isNil,{
11                         error("Meta_Bus:control: failed to get a control bus allocated."
12                                 + "numChannels:" + numChannels + "server:" + server.name);
13                         ^nil
14                 });
15                 ^this.new(\control,alloc,numChannels,server)
16         }
17         *audio { arg server,numChannels=1;
18                 var alloc;
19                 server = server ? Server.default;
20                 alloc = server.audioBusAllocator.alloc(numChannels);
21                 if(alloc.isNil,{
22                         error("Meta_Bus:audio: failed to get an audio bus allocated."
23                         + "numChannels:" + numChannels + "server:" + server.name);
24                         ^nil
25                 });
26                 ^this.new(\audio,alloc,numChannels,server)
27         }
28         *alloc { arg rate,server,numChannels=1;
29                 ^this.perform(rate ? \audio,server,numChannels);
30         }
32         *new { arg rate=\audio,index=0,numChannels=2,server;
33                 ^super.newCopyArgs(rate,index,numChannels,server ? Server.default)
34         }
36         isSettable {
37                 ^rate != \audio
38         }
40         set { arg ... values; // shouldn't be larger than this.numChannels
41                 if(this.isSettable, {
42                         server.sendBundle(nil,(["/c_set"]
43                                 ++ values.collect({ arg v,i; [index + i ,v] }).flat));
44                 }, {error("Cannot set an audio rate bus")});
45         }
46         setMsg { arg ... values;
47                 if(this.isSettable, {
48                         ^["/c_set"]
49                                 ++ values.collect({ arg v,i; [index + i ,v] }).flat
50                 }, {error("Cannot set an audio rate bus"); ^nil});
51         }
53         setn { arg values;
54                 // could throw an error if values.size > numChannels
55                 if(this.isSettable, {
56                         server.sendBundle(nil,
57                                 ["/c_setn",index,values.size] ++ values);
58                 }, {error("Cannot set an audio rate bus")});
59         }
60         setnMsg { arg values;
61                 if(this.isSettable, {
62                         ^["/c_setn",index,values.size] ++ values;
63                 }, {error("Cannot set an audio rate bus"); ^nil});
64         }
65         setAt { |offset ... values|
66                 // shouldn't be larger than this.numChannels - offset
67                 if(this.isSettable, {
68                         server.sendBundle(nil,(["/c_set"]
69                                 ++ values.collect({ arg v,i; [index + offset + i ,v] }).flat));
70                 }, {error("Cannot set an audio rate bus")});
71         }
72         setnAt { |offset, values|
73                 // could throw an error if values.size > numChannels
74                 if(this.isSettable, {
75                         server.sendBundle(nil,
76                                 ["/c_setn",index + offset, values.size] ++ values);
77                 }, {error("Cannot set an audio rate bus")});
78         }
79         setPairs { | ... pairs|
80                 if(this.isSettable, {
81                         server.sendBundle(nil,(["/c_set"]
82                                 ++ pairs.clump(2).collect({ arg pair; [pair[0] + index, pair[1]] }).flat));
83                 }, {error("Cannot set an audio rate bus")});
84         }
86         get { arg action;
87                 if(numChannels == 1, {
88                         action = action ? { |vals| "Bus % index: % value: %.\n".postf(rate, index, vals); };
89                         OSCpathResponder(server.addr,['/c_set',index], { arg time, r, msg;
90                                 action.value(msg.at(2)); r.remove }).add;
91                         server.listSendMsg(["/c_get",index]);
92                 }, {this.getn(action)});
93         }
95         getn { arg count, action;
96                 action = action ? { |vals| "Bus % index: % values: %.\n".postf(rate, index, vals); };
97                 OSCpathResponder(server.addr,['/c_setn',index],{arg time, r, msg;
98                         action.value(msg.copyToEnd(3)); r.remove } ).add;
99                 server.listSendMsg(this.getnMsg(count));
100         }
101         getMsg {
102                 ^["/c_get",index];
103         }
104         getnMsg { arg count;
105                 ^["/c_getn",index, count ? numChannels];
106         }
108         getSynchronous {
109                 if (not(this.isSettable)) {
110                         Error("Bus-getSynchronous only works for control-rate busses").throw;
111                 } {
112                         ^server.getControlBusValue(index);
113                 }
114         }
116         getnSynchronous {|count|
117                 if (not(this.isSettable)) {
118                         Error("Bus-getnSynchronous only works for control-rate busses").throw;
119                 } {
120                         ^server.getControlBusValues(index, count ? numChannels);
121                 }
122         }
124         setSynchronous { |... values|
125                 if (not(this.isSettable)) {
126                         Error("Bus-setSynchronous only works for control-rate busses").throw;
127                 } {
128                         if (values.size == 1) {
129                                 server.setControlBusValue(index, values[0])
130                         } {
131                                 server.setControlBusValues(index, values)
132                         }
133                 }
134         }
136         setnSynchronous {|values|
137                 if (not(this.isSettable)) {
138                         Error("Bus-setnSynchronous only works for control-rate busses").throw;
139                 } {
140                         server.setControlBusValues(index, values)
141                 }
142         }
144         fill { arg value,numChans;
145                 // could throw an error if numChans > numChannels
146                 server.sendBundle(nil,
147                         ["/c_fill",index,numChans,value]);
148         }
150         fillMsg { arg value;
151                 ^["/c_fill",index,numChannels,value];
152         }
155         free {
156                 if(index.isNil,{ (this.asString + " has already been freed").warn; ^this });
157                 if(rate == \audio,{
158                         server.audioBusAllocator.free(index);
159                 },{
160                         server.controlBusAllocator.free(index);
161                 });
162                 index = nil;
163                 numChannels = nil;
164                 mapSymbol = nil;
165         }
167         // allow reallocation
169         alloc {
170                 if(rate === 'audio', {
171                         index = server.audioBusAllocator.alloc(numChannels);
172                 }, {
173                         index = server.controlBusAllocator.alloc(numChannels);
174                 });
175                 mapSymbol = nil;
176         }
178         realloc {
179                 var r, n;
180                 if(index.notNil, {
181                         r = rate; n = numChannels;
182                         this.free;
183                         rate = r; numChannels = n;
184                         this.alloc;
185                 })
186         }
188         // alternate syntaxes
189         setAll { arg value;
190                 this.fill(value,numChannels);
191         }
193         value_ { arg value;
194                 this.fill(value,numChannels);
195         }
197         printOn { arg stream;
198                 stream << this.class.name << "(" <<*
199                         [rate, index, numChannels, server]  <<")"
200         }
202         storeOn { arg stream;
203                 stream << this.class.name << "(" <<*
204                         [rate.asCompileString, index, numChannels, server.asCompileString]  <<")"
205         }
207         == { arg aBus;
208                 if(aBus === this,{ ^true });
209                 ^aBus respondsTo: #[\index, \numChannels, \rate, \server]
210                 and: { aBus.index == index
211                 and: { aBus.numChannels == numChannels
212                 and: { aBus.rate == rate
213                 and: { aBus.server === server }}}}
214         }
215         hash { ^index.hash bitXor: numChannels.hash bitXor: rate.hash bitXor: server.hash }
217         isAudioOut { // audio interface
218                 ^(rate === \audio and: {index < server.options.firstPrivateBus})
219         }
221         ar { |numChannels=(this.numChannels), offset=0|
222                 if(rate == \audio,{
223                         ^In.ar(index + offset, numChannels)
224                 },{
225                         //"Bus converting control to audio rate".inform;
226                         ^K2A.ar( In.kr(index + offset, numChannels) )
227                 })
228         }
229         kr { |numChannels=(this.numChannels), offset=0|
230                 if(rate == \audio,{
231                         ^A2K.kr( In.ar(index + offset, numChannels) )
232                 },{
233                         ^In.kr(index + offset, numChannels)
234                 })
235         }
237         play { arg target=0, outbus, fadeTime, addAction=\addToTail;
238                 if(this.isAudioOut.not,{ // returns a Synth
239                         ^{ this.ar }.play(target, outbus, fadeTime, addAction);
240                 });
241         }
243         asUGenInput { ^this.index }
244         asControlInput { ^this.index }
246         asMap {
247                 ^mapSymbol ?? {
248                         if(index.isNil) { MethodError("bus not allocated.", this).throw };
249                         mapSymbol = if(rate == \control) { "c" } { "a" };
250                         mapSymbol = (mapSymbol ++ index).asSymbol;
251                 }
252         }
254         // added by nescivi; gets a subbus from another bus
256         *newFrom { |bus, offset, numChannels=1|
257                 if ( offset > bus.numChannels or: {numChannels + offset >
258                         bus.numChannels} )
259                 {
260                         Error( "Bus:newFrom tried to reach outside the channel range of
261 %".format( bus )).throw
262                 };
263                 ^Bus.new( bus.rate, bus.index + offset, numChannels);
264         }
266         subBus{|offset, numChannels=1|
267                 ^Bus.newFrom( this, offset, numChannels );
268         }