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