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