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