cmake build system: visiblity support for clang
[supercollider.git] / SCClassLibrary / Common / GUI / ServerMeter.sc
blobd0e3e0487927aafc3bb7228529ac7bfdf3f51619
1 ServerMeterView{
3         classvar serverMeterViews,      updateFreq = 10, dBLow = -80, meterWidth = 15, gapWidth = 4, <height = 230;
5         var <view;
6         var inresp, outresp, insynth, outsynth, synthFunc, responderFunc, server, numIns, numOuts, inmeters, outmeters;
8         *new{ |aserver,parent,leftUp,numIns,numOuts|
9                 ^super.new.init(aserver,parent,leftUp,numIns,numOuts)
10         }
12         *getWidth{ arg numIns,numOuts, server;
13                 ^20+((numIns + numOuts + 2) * (meterWidth + gapWidth))
14         }
16         init { arg aserver, parent, leftUp, anumIns,anumOuts;
17                 var innerView, viewWidth;
19                 numIns = anumIns ?? { server.options.numInputBusChannels };
20                 numOuts = anumOuts ?? { server.options.numOutputBusChannels };
22                 viewWidth= this.class.getWidth(anumIns,anumOuts);
24                 leftUp = leftUp ? (0@0);
26                 server = aserver;
28                 view = CompositeView(parent, Rect(leftUp.x,leftUp.y, viewWidth, height) );
29                 view.onClose_({ this.stop });
30                 innerView = CompositeView(view, Rect(10,25, viewWidth, height) );
31                 innerView.addFlowLayout(0@0, gapWidth@gapWidth);
33                 // dB scale
34                 UserView(innerView, Rect(0,0,meterWidth,195)).drawFunc_({
35                         Pen.color = Color.white;
36                         Pen.font = Font.sansSerif(10).boldVariant;
37                         Pen.stringCenteredIn("0", Rect(0, 0, meterWidth, 12));
38                         Pen.stringCenteredIn("-80", Rect(0, 170, meterWidth, 12));
39                 });
41                 (numIns > 0).if({
42                         // ins
43                         StaticText(view, Rect(10, 5, 100, 15))
44                                 .font_(Font.sansSerif(10).boldVariant)
45                                 .stringColor_(Color.white)
46                                 .string_("Inputs");
47                         inmeters = Array.fill( numIns, { arg i;
48                                 var comp;
49                                 comp = CompositeView(innerView, Rect(0,0,meterWidth,195)).resize_(5);
50                                 StaticText(comp, Rect(0, 180, meterWidth, 15))
51                                         .font_(Font.sansSerif(9).boldVariant)
52                                         .stringColor_(Color.white)
53                                         .string_(i.asString);
54                                 LevelIndicator( comp, Rect(0,0,meterWidth,180) ).warning_(0.9).critical_(1.0)
55                                         .drawsPeak_(true)
56                                         .numTicks_(9)
57                                         .numMajorTicks_(3);
58                         });
59                 });
61                 if((numIns > 0) && (numOuts > 0)){
62                         // divider
63                         UserView(innerView, Rect(0,0,meterWidth,180)).drawFunc_({
64                                 Pen.color = Color.white;
65                                 Pen.line(((meterWidth + gapWidth) * 0.5)@0, ((meterWidth + gapWidth) * 0.5)@180);
66                                 Pen.stroke;
67                         });
68                 };
70                 // outs
71                 (numOuts > 0).if({
72                         StaticText(view, Rect(10 + if(numIns > 0 , ((numIns + 2) * (meterWidth + gapWidth)), 0), 5, 100, 15))
73                                 .font_(Font.sansSerif(10).boldVariant)
74                                 .stringColor_(Color.white)
75                                 .string_("Outputs");
76                         outmeters = Array.fill( numOuts, { arg i;
77                                 var comp;
78                                 comp = CompositeView(innerView, Rect(0,0,meterWidth,195));
79                                 StaticText(comp, Rect(0, 180, meterWidth, 15))
80                                         .font_(Font.sansSerif(9).boldVariant)
81                                         .stringColor_(Color.white)
82                                         .string_(i.asString);
83                                 LevelIndicator( comp, Rect(0,0,meterWidth,180) ).warning_(0.9).critical_(1.0)
84                                         .drawsPeak_(true)
85                                         .numTicks_(9)
86                                         .numMajorTicks_(3);
87                         });
88                 });
90                 this.setSynthFunc(inmeters, outmeters);
91                 this.start;
93         }
95         setSynthFunc{
96                 var numRMSSamps, numRMSSampsRecip;
98                 synthFunc = {
99                         //responders and synths are started only once per server
100                         var numIns = server.options.numInputBusChannels;
101                         var numOuts = server.options.numOutputBusChannels;
102                         numRMSSamps = server.sampleRate / updateFreq;
103                         numRMSSampsRecip = 1 / numRMSSamps;
105                         server.bind({
106                                 (numIns > 0).if({
107                                         insynth = SynthDef(server.name ++ "InputLevels", {
108                                                 var in = In.ar(NumOutputBuses.ir, numIns);
109                                                 SendPeakRMS.kr(in, updateFreq, 3, "/" ++ server.name ++ "InLevels")
110                                         }).play(RootNode(server), nil, \addToHead);
111                                 });
112                                 (numOuts > 0).if({
113                                         outsynth = SynthDef(server.name ++ "OutputLevels", {
114                                                 var in = In.ar(0, numOuts);
115                                                 SendPeakRMS.kr(in, updateFreq, 3, "/" ++ server.name ++ "OutLevels")
116                                         }).play(RootNode(server), nil, \addToTail);
117                                 });
118                         });
119                 };
120         }
122         startResponders{
123                 var numRMSSamps, numRMSSampsRecip;
125                 //responders and synths are started only once per server
126                 numRMSSamps = server.sampleRate / updateFreq;
127                 numRMSSampsRecip = 1 / numRMSSamps;
128                 (numIns > 0).if({
129                         inresp = OSCFunc({|msg|
130                                 {
131                                         try {
132                                                 var channelCount = msg.size - 3 / 2;
134                                                 channelCount.do {|channel|
135                                                         var baseIndex = 3 + (2*channel);
136                                                         var peakLevel = msg.at(baseIndex);
137                                                         var rmsValue  = msg.at(baseIndex + 1);
138                                                         var meter = inmeters.at(channel);
139                                                         if (meter.isClosed.not) {
140                                                                 meter.peakLevel = peakLevel.ampdb.linlin(dBLow, 0, 0, 1);
141                                                                 meter.value = rmsValue.ampdb.linlin(dBLow, 0, 0, 1);
142                                                         }
143                                                 }
144                                         } { |error|
145                                                 if(error.isKindOf(PrimitiveFailedError).not) { error.throw }
146                                         };
147                                 }.defer;
148                         }, ("/" ++ server.name ++ "InLevels").asSymbol, server.addr).fix;
149                 });
150                 (numOuts > 0).if({
151                         outresp = OSCFunc({|msg|
152                                 {
153                                         try {
154                                                 var channelCount = msg.size - 3 / 2;
156                                                 channelCount.do {|channel|
157                                                         var baseIndex = 3 + (2*channel);
158                                                         var peakLevel = msg.at(baseIndex);
159                                                         var rmsValue  = msg.at(baseIndex + 1);
160                                                         var meter = outmeters.at(channel);
161                                                         if (meter.isClosed.not) {
162                                                                 meter.peakLevel = peakLevel.ampdb.linlin(dBLow, 0, 0, 1);
163                                                                 meter.value = rmsValue.ampdb.linlin(dBLow, 0, 0, 1);
164                                                         }
165                                                 }
166                                         } { |error|
167                                                 if(error.isKindOf(PrimitiveFailedError).not) { error.throw }
168                                         };
169                                 }.defer;
170                         }, ("/" ++ server.name ++ "OutLevels").asSymbol, server.addr).fix;
171                 });
172         }
174         start{
175                 if(serverMeterViews.isNil){
176                         serverMeterViews = IdentityDictionary.new;
177                 };
178                 if(serverMeterViews[server].isNil){
179                         serverMeterViews.put(server,List[this]);
180                         ServerTree.add(synthFunc);
181                         if(server.serverRunning, synthFunc); // otherwise starts when booted
182                         server.doWhenBooted({this.startResponders});
183                 }{
184                         if(serverMeterViews[server].size == 0){
185                                 ServerTree.add(synthFunc);
186                                 if(server.serverRunning, synthFunc); // otherwise starts when booted
189                         };
190                         serverMeterViews[server].add(this);
191                         server.doWhenBooted({this.startResponders});
192                 }
194         }
196         stop{
197                 serverMeterViews[server].remove(this);
199                 if(serverMeterViews[server].size == 0){
200                         (numIns > 0).if({ insynth.free; });
201                         (numOuts > 0).if({outsynth.free; });
202                         ServerTree.remove(synthFunc);
203                 };
205                 (numIns > 0).if({ inresp.free; });
206                 (numOuts > 0).if({ outresp.free; });
207         }
209         remove{
210                 view.remove
211         }
214 ServerMeter{
216         var <window, <meterView;
218         *new{ |server, numIns, numOuts|
220                 var window, meterView;
222                 numIns = numIns ?? { server.options.numInputBusChannels };
223                 numOuts = numOuts ?? { server.options.numOutputBusChannels };
225                 window = Window.new(server.name ++ " levels (dBFS)",
226                                                         Rect(5, 305, ServerMeterView.getWidth(numIns,numOuts), ServerMeterView.height),
227                                                         false);
228                 window.view.background = Color.grey(0.4);
230                 meterView = ServerMeterView(server, window, 0@0, numIns, numOuts);
231                 meterView.view.keyDownAction_({ arg view, char, modifiers;
232                         if(modifiers & 16515072 == 0) {
233                                 case
234                                 {char === 27.asAscii } { window.close };
235                         };
236                 });
238                 window.front;
240                 ^super.newCopyArgs(window,meterView)
242         }