much ado about nothing when it comes to gain control
[ardour.git] / libs / ardour / monitor_processor.cc
1 #include "pbd/convert.h"
2 #include "pbd/error.h"
3 #include "pbd/locale_guard.h"
4 #include "pbd/xml++.h"
5
6 #include "ardour/amp.h"
7 #include "ardour/debug.h"
8 #include "ardour/audio_buffer.h"
9 #include "ardour/monitor_processor.h"
10 #include "ardour/session.h"
11
12 #include "i18n.h"
13
14 using namespace ARDOUR;
15 using namespace PBD;
16 using namespace std;
17
18 /* specialize for bool because of set_value() semantics */
19
20 namespace ARDOUR {
21         template<> void MPControl<bool>::set_value (double v) {
22                 bool newval = fabs (v) >= 0.5;
23                 if (newval != _value) {
24                         _value = newval;
25                         Changed(); /* EMIT SIGNAL */
26                 }
27         }
28 }
29
30 MonitorProcessor::MonitorProcessor (Session& s)
31         : Processor (s, X_("MonitorOut"))
32         , solo_cnt (0)
33
34         , _dim_all_ptr (new MPControl<bool> (false, _("monitor dim"), Controllable::Toggle))
35         , _cut_all_ptr (new MPControl<bool> (false, _("monitor cut"), Controllable::Toggle))
36         , _mono_ptr (new MPControl<bool> (false, _("monitor mono"), Controllable::Toggle))
37         , _dim_level_ptr (new MPControl<volatile gain_t> 
38                           /* default is -12dB, range is -20dB to 0dB */
39                           (0.251188635826, _("monitor dim level"), Controllable::Flag (0), 0.100000001490, 1.0))
40         , _solo_boost_level_ptr (new MPControl<volatile gain_t> 
41                                  /* default is 0dB, range is 0dB to +20dB */
42                                  (1.0, _("monitor solo boost level"), Controllable::Flag (0), 1.0, 10.0))
43           
44         , _dim_all_control (_dim_all_ptr)
45         , _cut_all_control (_cut_all_ptr)
46         , _mono_control (_mono_ptr)
47         , _dim_level_control (_dim_level_ptr)
48         , _solo_boost_level_control (_solo_boost_level_ptr)
49
50         , _dim_all (*_dim_all_ptr)
51         , _cut_all (*_cut_all_ptr)
52         , _mono (*_mono_ptr)
53         , _dim_level (*_dim_level_ptr)
54         , _solo_boost_level (*_solo_boost_level_ptr)
55
56 {
57 }
58
59 MonitorProcessor::~MonitorProcessor ()
60 {
61         allocate_channels (0);
62 }
63
64 void
65 MonitorProcessor::allocate_channels (uint32_t size)
66 {
67         while (_channels.size() > size) {
68                 if (_channels.back()->soloed) {
69                         if (solo_cnt > 0) {
70                                 --solo_cnt;
71                         }
72                 }
73                 ChannelRecord* cr = _channels.back();
74                 _channels.pop_back();
75                 delete cr;
76         }
77
78         uint32_t n = _channels.size() + 1;
79
80         while (_channels.size() < size) {
81                 _channels.push_back (new ChannelRecord (n));
82         }
83 }
84
85 int
86 MonitorProcessor::set_state (const XMLNode& node, int version)
87 {
88         int ret = Processor::set_state (node, version);
89
90         if (ret != 0) {
91                 return ret;
92         }
93
94         const XMLProperty* prop;
95
96         if ((prop = node.property (X_("type"))) == 0) {
97                 error << string_compose (X_("programming error: %1"), X_("MonitorProcessor XML settings have no type information"))
98                       << endmsg;
99                 return -1;
100         }
101
102         if (prop->value() != X_("monitor")) {
103                 error << string_compose (X_("programming error: %1"), X_("MonitorProcessor given unknown XML settings"))
104                       << endmsg;
105                 return -1;
106         }
107
108         if ((prop = node.property (X_("channels"))) == 0) {
109                 error << string_compose (X_("programming error: %1"), X_("MonitorProcessor XML settings are missing a channel cnt"))
110                       << endmsg;
111                 return -1;
112         }
113
114         allocate_channels (atoi (prop->value()));
115
116         if ((prop = node.property (X_("dim-level"))) != 0) {
117                 gain_t val = atof (prop->value());
118                 _dim_level = val;
119         }
120
121         if ((prop = node.property (X_("solo-boost-level"))) != 0) {
122                 gain_t val = atof (prop->value());
123                 _solo_boost_level = val;
124         }
125
126         if ((prop = node.property (X_("cut-all"))) != 0) {
127                 bool val = string_is_affirmative (prop->value());
128                 _cut_all = val;
129         }
130         if ((prop = node.property (X_("dim-all"))) != 0) {
131                 bool val = string_is_affirmative (prop->value());
132                 _dim_all = val;
133         }
134         if ((prop = node.property (X_("mono"))) != 0) {
135                 bool val = string_is_affirmative (prop->value());
136                 _mono = val;
137         }
138
139         for (XMLNodeList::const_iterator i = node.children().begin(); i != node.children().end(); ++i) {
140
141                 if ((*i)->name() == X_("Channel")) {
142                         if ((prop = (*i)->property (X_("id"))) == 0) {
143                                 error << string_compose (X_("programming error: %1"), X_("MonitorProcessor XML settings are missing an ID"))
144                                       << endmsg;
145                                 return -1;
146                         }
147
148                         uint32_t chn;
149
150                         if (sscanf (prop->value().c_str(), "%u", &chn) != 1) {
151                                 error << string_compose (X_("programming error: %1"), X_("MonitorProcessor XML settings has an unreadable channel ID"))
152                                       << endmsg;
153                                 return -1;
154                         }
155
156                         if (chn >= _channels.size()) {
157                                 error << string_compose (X_("programming error: %1"), X_("MonitorProcessor XML settings has an illegal channel count"))
158                                       << endmsg;
159                                 return -1;
160                         }
161                         ChannelRecord& cr (*_channels[chn]);
162
163                         if ((prop = (*i)->property ("cut")) != 0) {
164                                 if (string_is_affirmative (prop->value())){
165                                         cr.cut = 0.0f;
166                                 } else {
167                                         cr.cut = 1.0f;
168                                 }
169                         }
170
171                         if ((prop = (*i)->property ("dim")) != 0) {
172                                 bool val = string_is_affirmative (prop->value());
173                                 cr.dim = val;
174                         }
175
176                         if ((prop = (*i)->property ("invert")) != 0) {
177                                 if (string_is_affirmative (prop->value())) {
178                                         cr.polarity = -1.0f;
179                                 } else {
180                                         cr.polarity = 1.0f;
181                                 }
182                         }
183
184                         if ((prop = (*i)->property ("solo")) != 0) {
185                                 bool val = string_is_affirmative (prop->value());
186                                 cr.soloed = val;
187                         }
188                 }
189         }
190
191         /* reset solo cnt */
192
193         solo_cnt = 0;
194
195         for (vector<ChannelRecord*>::const_iterator x = _channels.begin(); x != _channels.end(); ++x) {
196                 if ((*x)->soloed) {
197                         solo_cnt++;
198                 }
199         }
200
201         return 0;
202 }
203
204 XMLNode&
205 MonitorProcessor::state (bool full)
206 {
207         LocaleGuard lg (X_("POSIX"));
208         XMLNode& node (Processor::state (full));
209         char buf[64];
210
211         /* this replaces any existing "type" property */
212
213         node.add_property (X_("type"), X_("monitor"));
214
215         snprintf (buf, sizeof(buf), "%.12g", _dim_level.val());
216         node.add_property (X_("dim-level"), buf);
217
218         snprintf (buf, sizeof(buf), "%.12g", _solo_boost_level.val());
219         node.add_property (X_("solo-boost-level"), buf);
220
221         node.add_property (X_("cut-all"), (_cut_all ? "yes" : "no"));
222         node.add_property (X_("dim-all"), (_dim_all ? "yes" : "no"));
223         node.add_property (X_("mono"), (_mono ? "yes" : "no"));
224
225         uint32_t limit = _channels.size();
226
227         snprintf (buf, sizeof (buf), "%u", limit);
228         node.add_property (X_("channels"), buf);
229
230         XMLNode* chn_node;
231         uint32_t chn = 0;
232
233         for (vector<ChannelRecord*>::const_iterator x = _channels.begin(); x != _channels.end(); ++x, ++chn) {
234                 chn_node = new XMLNode (X_("Channel"));
235
236                 snprintf (buf, sizeof (buf), "%u", chn);
237                 chn_node->add_property ("id", buf);
238
239                 chn_node->add_property (X_("cut"), (*x)->cut == 1.0f ? "no" : "yes");
240                 chn_node->add_property (X_("invert"), (*x)->polarity == 1.0f ? "no" : "yes");
241                 chn_node->add_property (X_("dim"), (*x)->dim ? "yes" : "no");
242                 chn_node->add_property (X_("solo"), (*x)->soloed ? "yes" : "no");
243
244                 node.add_child_nocopy (*chn_node);
245         }
246
247         return node;
248 }
249
250 void
251 MonitorProcessor::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_frame*/, pframes_t nframes, bool /*result_required*/)
252 {
253         uint32_t chn = 0;
254         gain_t target_gain;
255         gain_t dim_level_this_time = _dim_level;
256         gain_t global_cut = (_cut_all ? 0.0f : 1.0f);
257         gain_t global_dim = (_dim_all ? dim_level_this_time : 1.0);
258         gain_t solo_boost;
259
260         if (_session.listening() || _session.soloing()) {
261                 solo_boost = _solo_boost_level;
262         } else {
263                 solo_boost = 1.0;
264         }
265
266         for (BufferSet::audio_iterator b = bufs.audio_begin(); b != bufs.audio_end(); ++b) {
267
268                 /* don't double-scale by both track dim and global dim coefficients */
269
270                 gain_t dim_level = (global_dim == 1.0 ? (_channels[chn]->dim ? dim_level_this_time : 1.0) : 1.0);
271                 
272                 if (_channels[chn]->soloed) {
273                         target_gain = _channels[chn]->polarity * _channels[chn]->cut * dim_level * global_cut * global_dim * solo_boost;
274                 } else {
275                         if (solo_cnt == 0) {
276                                 target_gain = _channels[chn]->polarity * _channels[chn]->cut * dim_level * global_cut * global_dim * solo_boost;
277                         } else {
278                                 target_gain = 0.0;
279                         }
280                 }
281
282                 if (target_gain != _channels[chn]->current_gain || target_gain != 1.0f) {
283
284                         Amp::apply_gain (*b, nframes, _channels[chn]->current_gain, target_gain);
285                         _channels[chn]->current_gain = target_gain;
286                 }
287
288                 ++chn;
289         }
290
291         if (_mono) {
292                 DEBUG_TRACE (DEBUG::Monitor, "mono-izing\n");
293
294                 /* chn is now the number of channels, use as a scaling factor when mixing
295                  */
296                 gain_t scale = 1.0/chn;
297                 BufferSet::audio_iterator b = bufs.audio_begin();
298                 AudioBuffer& ab (*b);
299                 Sample* buf = ab.data();
300
301                 /* scale the first channel */
302
303                 for (pframes_t n = 0; n < nframes; ++n) {
304                         buf[n] *= scale;
305                 }
306
307                 /* add every other channel into the first channel's buffer */
308
309                 ++b;
310                 for (; b != bufs.audio_end(); ++b) {
311                         AudioBuffer& ob (*b);
312                         Sample* obuf = ob.data ();
313                         for (pframes_t n = 0; n < nframes; ++n) {
314                                 buf[n] += obuf[n] * scale;
315                         }
316                 }
317
318                 /* copy the first channel to every other channel's buffer */
319
320                 b = bufs.audio_begin();
321                 ++b;
322                 for (; b != bufs.audio_end(); ++b) {
323                         AudioBuffer& ob (*b);
324                         Sample* obuf = ob.data ();
325                         memcpy (obuf, buf, sizeof (Sample) * nframes);
326                 }
327         }
328 }
329
330 bool
331 MonitorProcessor::configure_io (ChanCount in, ChanCount out)
332 {
333         allocate_channels (in.n_audio());
334         return Processor::configure_io (in, out);
335 }
336
337 bool
338 MonitorProcessor::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
339 {
340         out = in;
341         return true;
342 }
343
344 void
345 MonitorProcessor::set_polarity (uint32_t chn, bool invert)
346 {
347         if (invert) {
348                 _channels[chn]->polarity = -1.0f;
349         } else {
350                 _channels[chn]->polarity = 1.0f;
351         }
352 }
353
354 void
355 MonitorProcessor::set_dim (uint32_t chn, bool yn)
356 {
357         _channels[chn]->dim = yn;
358 }
359
360 void
361 MonitorProcessor::set_cut (uint32_t chn, bool yn)
362 {
363         if (yn) {
364                 _channels[chn]->cut = 0.0f;
365         } else {
366                 _channels[chn]->cut = 1.0f;
367         }
368 }
369
370 void
371 MonitorProcessor::set_solo (uint32_t chn, bool solo)
372 {
373         if (solo != _channels[chn]->soloed) {
374                 _channels[chn]->soloed = solo;
375
376                 if (solo) {
377                         solo_cnt++;
378                 } else {
379                         if (solo_cnt > 0) {
380                                 solo_cnt--;
381                         }
382                 }
383         }
384 }
385
386 void
387 MonitorProcessor::set_mono (bool yn)
388 {
389         _mono = yn;
390 }
391
392 void
393 MonitorProcessor::set_cut_all (bool yn)
394 {
395         _cut_all = yn;
396 }
397
398 void
399 MonitorProcessor::set_dim_all (bool yn)
400 {
401         _dim_all = yn;
402 }
403
404 bool
405 MonitorProcessor::display_to_user () const
406 {
407         return false;
408 }
409
410 bool
411 MonitorProcessor::soloed (uint32_t chn) const
412 {
413         return _channels[chn]->soloed;
414 }
415
416
417 bool
418 MonitorProcessor::inverted (uint32_t chn) const
419 {
420         return _channels[chn]->polarity < 0.0f;
421 }
422
423
424 bool
425 MonitorProcessor::cut (uint32_t chn) const
426 {
427         return _channels[chn]->cut == 0.0f;
428 }
429
430 bool
431 MonitorProcessor::dimmed (uint32_t chn) const
432 {
433         return _channels[chn]->dim;
434 }
435
436 bool
437 MonitorProcessor::mono () const
438 {
439         return _mono;
440 }
441
442 bool
443 MonitorProcessor::dim_all () const
444 {
445         return _dim_all;
446 }
447
448 bool
449 MonitorProcessor::cut_all () const
450 {
451         return _cut_all;
452 }
453
454 boost::shared_ptr<Controllable>
455 MonitorProcessor::channel_cut_control (uint32_t chn) const
456 {
457         if (chn < _channels.size()) {
458                 return _channels[chn]->cut_control;
459         }
460         return boost::shared_ptr<Controllable>();
461 }
462
463 boost::shared_ptr<Controllable>
464 MonitorProcessor::channel_dim_control (uint32_t chn) const
465 {
466         if (chn < _channels.size()) {
467                 return _channels[chn]->dim_control;
468         }
469         return boost::shared_ptr<Controllable>();
470 }
471
472 boost::shared_ptr<Controllable>
473 MonitorProcessor::channel_polarity_control (uint32_t chn) const
474 {
475         if (chn < _channels.size()) {
476                 return _channels[chn]->polarity_control;
477         }
478         return boost::shared_ptr<Controllable>();
479 }
480
481 boost::shared_ptr<Controllable>
482 MonitorProcessor::channel_solo_control (uint32_t chn) const
483 {
484         if (chn < _channels.size()) {
485                 return _channels[chn]->soloed_control;
486         }
487         return boost::shared_ptr<Controllable>();
488 }
489
490 MonitorProcessor::ChannelRecord::ChannelRecord (uint32_t chn)
491         : current_gain (1.0)
492         , cut_ptr (new MPControl<gain_t> (1.0, string_compose (_("cut control %1"), chn), PBD::Controllable::GainLike))
493         , dim_ptr (new MPControl<bool> (false, string_compose (_("dim control"), chn), PBD::Controllable::Toggle))
494         , polarity_ptr (new MPControl<gain_t> (1.0, string_compose (_("polarity control"), chn), PBD::Controllable::Toggle))
495         , soloed_ptr (new MPControl<bool> (false, string_compose (_("solo control"), chn), PBD::Controllable::Toggle))
496
497         , cut_control (cut_ptr)
498         , dim_control (dim_ptr)
499         , polarity_control (polarity_ptr)
500         , soloed_control (soloed_ptr)
501
502         , cut (*cut_ptr)
503         , dim (*dim_ptr)
504         , polarity (*polarity_ptr)
505         , soloed (*soloed_ptr)
506 {
507
508 }