2 Copyright (C) 2010 Paul Davis
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.
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.
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.
20 #include "pbd/error.h"
21 #include "pbd/xml++.h"
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"
31 using namespace ARDOUR;
35 /* specialize for bool because of set_value() semantics */
38 template<> void MPControl<bool>::set_value (double v, PBD::Controllable::GroupControlDisposition gcd) {
39 bool newval = fabs (v) >= 0.5;
40 if (newval != _value) {
42 Changed (true, gcd); /* EMIT SIGNAL */
47 MonitorProcessor::MonitorProcessor (Session& s)
48 : Processor (s, X_("MonitorOut"))
50 , _monitor_active (false)
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)
69 , _dim_all (*_dim_all_ptr)
70 , _cut_all (*_cut_all_ptr)
72 , _dim_level (*_dim_level_ptr)
73 , _solo_boost_level (*_solo_boost_level_ptr)
78 MonitorProcessor::~MonitorProcessor ()
80 allocate_channels (0);
84 MonitorProcessor::allocate_channels (uint32_t size)
86 while (_channels.size() > size) {
87 if (_channels.back()->soloed) {
92 ChannelRecord* cr = _channels.back();
97 uint32_t n = _channels.size() + 1;
99 while (_channels.size() < size) {
100 _channels.push_back (new ChannelRecord (n));
105 MonitorProcessor::set_state (const XMLNode& node, int version)
107 int ret = Processor::set_state (node, version);
113 std::string type_name;
114 if (!node.get_property (X_("type"), type_name)) {
115 error << string_compose (X_("programming error: %1"), X_("MonitorProcessor XML settings have no type information"))
120 if (type_name != X_("monitor")) {
121 error << string_compose (X_("programming error: %1"), X_("MonitorProcessor given unknown XML settings"))
126 uint32_t channels = 0;
127 if (!node.get_property (X_("channels"), channels)) {
128 error << string_compose (X_("programming error: %1"), X_("MonitorProcessor XML settings are missing a channel cnt"))
133 allocate_channels (channels);
135 // need to check that these conversions are working as expected
137 if (node.get_property (X_("dim-level"), val)) {
141 if (node.get_property (X_("solo-boost-level"), val)) {
142 _solo_boost_level = val;
146 if (node.get_property (X_("cut-all"), bool_val)) {
150 if (node.get_property (X_("dim-all"), bool_val)) {
154 if (node.get_property (X_("mono"), bool_val)) {
158 for (XMLNodeList::const_iterator i = node.children().begin(); i != node.children().end(); ++i) {
160 if ((*i)->name() == X_("Channel")) {
163 if (!(*i)->get_property (X_("id"), chn)) {
164 error << string_compose (X_("programming error: %1"), X_("MonitorProcessor XML settings are missing an ID"))
169 if (chn >= _channels.size()) {
170 error << string_compose (X_("programming error: %1"), X_("MonitorProcessor XML settings has an illegal channel count"))
174 ChannelRecord& cr (*_channels[chn]);
176 bool gain_coeff_zero;
177 if ((*i)->get_property ("cut", gain_coeff_zero)) {
178 if (gain_coeff_zero) {
179 cr.cut = GAIN_COEFF_ZERO;
181 cr.cut = GAIN_COEFF_UNITY;
186 if ((*i)->get_property ("dim", dim)) {
190 bool invert_polarity;
191 if ((*i)->get_property ("invert", invert_polarity)) {
192 if (invert_polarity) {
200 if ((*i)->get_property ("solo", soloed)) {
210 for (vector<ChannelRecord*>::const_iterator x = _channels.begin(); x != _channels.end(); ++x) {
216 update_monitor_state ();
221 MonitorProcessor::state (bool full)
223 XMLNode& node(Processor::state(full));
225 /* this replaces any existing "type" property */
227 node.set_property (X_("type"), X_("monitor"));
229 node.set_property (X_ ("dim-level"), (float)_dim_level.val ());
230 node.set_property (X_ ("solo-boost-level"), (float)_solo_boost_level.val ());
232 node.set_property (X_("cut-all"), _cut_all.val());
233 node.set_property (X_("dim-all"), _dim_all.val());
234 node.set_property (X_("mono"), _mono.val());
236 node.set_property (X_("channels"), (uint32_t)_channels.size ());
241 for (vector<ChannelRecord*>::const_iterator x = _channels.begin (); x != _channels.end ();
243 chn_node = new XMLNode (X_("Channel"));
245 chn_node->set_property ("id", chn);
247 // implicitly cast these to bool
248 chn_node->set_property (X_("cut"), (*x)->cut != GAIN_COEFF_UNITY);
249 chn_node->set_property (X_("invert"), (*x)->polarity != GAIN_COEFF_UNITY);
250 chn_node->set_property (X_("dim"), (*x)->dim == true);
251 chn_node->set_property (X_("solo"), (*x)->soloed == true);
253 node.add_child_nocopy (*chn_node);
260 MonitorProcessor::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_frame*/, double /*speed*/, pframes_t nframes, bool /*result_required*/)
264 gain_t dim_level_this_time = _dim_level;
265 gain_t global_cut = (_cut_all ? GAIN_COEFF_ZERO : GAIN_COEFF_UNITY);
266 gain_t global_dim = (_dim_all ? dim_level_this_time : GAIN_COEFF_UNITY);
269 if (_session.listening() || _session.soloing()) {
270 solo_boost = _solo_boost_level;
272 solo_boost = GAIN_COEFF_UNITY;
275 for (BufferSet::audio_iterator b = bufs.audio_begin(); b != bufs.audio_end(); ++b) {
277 /* don't double-scale by both track dim and global dim coefficients */
279 gain_t dim_level = (global_dim == GAIN_COEFF_UNITY ? (_channels[chn]->dim ? dim_level_this_time : GAIN_COEFF_UNITY) : GAIN_COEFF_UNITY);
281 if (_channels[chn]->soloed) {
282 target_gain = _channels[chn]->polarity * _channels[chn]->cut * dim_level * global_cut * global_dim * solo_boost;
285 target_gain = _channels[chn]->polarity * _channels[chn]->cut * dim_level * global_cut * global_dim * solo_boost;
287 target_gain = GAIN_COEFF_ZERO;
291 if (target_gain != _channels[chn]->current_gain || target_gain != GAIN_COEFF_UNITY) {
293 _channels[chn]->current_gain = Amp::apply_gain (*b, _session.nominal_frame_rate(), nframes, _channels[chn]->current_gain, target_gain);
300 DEBUG_TRACE (DEBUG::Monitor, "mono-izing\n");
302 /* chn is now the number of channels, use as a scaling factor when mixing
304 gain_t scale = 1.f / (float)chn;
305 BufferSet::audio_iterator b = bufs.audio_begin();
306 AudioBuffer& ab (*b);
307 Sample* buf = ab.data();
309 /* scale the first channel */
311 for (pframes_t n = 0; n < nframes; ++n) {
315 /* add every other channel into the first channel's buffer */
318 for (; b != bufs.audio_end(); ++b) {
319 AudioBuffer& ob (*b);
320 Sample* obuf = ob.data ();
321 for (pframes_t n = 0; n < nframes; ++n) {
322 buf[n] += obuf[n] * scale;
326 /* copy the first channel to every other channel's buffer */
328 b = bufs.audio_begin();
330 for (; b != bufs.audio_end(); ++b) {
331 AudioBuffer& ob (*b);
332 Sample* obuf = ob.data ();
333 memcpy (obuf, buf, sizeof (Sample) * nframes);
339 MonitorProcessor::configure_io (ChanCount in, ChanCount out)
341 allocate_channels (in.n_audio());
342 return Processor::configure_io (in, out);
346 MonitorProcessor::can_support_io_configuration (const ChanCount& in, ChanCount& out)
353 MonitorProcessor::set_polarity (uint32_t chn, bool invert)
356 _channels[chn]->polarity = -1.0f;
358 _channels[chn]->polarity = 1.0f;
360 update_monitor_state ();
364 MonitorProcessor::set_dim (uint32_t chn, bool yn)
366 _channels[chn]->dim = yn;
367 update_monitor_state ();
371 MonitorProcessor::set_cut (uint32_t chn, bool yn)
374 _channels[chn]->cut = GAIN_COEFF_ZERO;
376 _channels[chn]->cut = GAIN_COEFF_UNITY;
378 update_monitor_state ();
382 MonitorProcessor::set_solo (uint32_t chn, bool solo)
384 if (solo != _channels[chn]->soloed) {
385 _channels[chn]->soloed = solo;
395 update_monitor_state ();
399 MonitorProcessor::set_mono (bool yn)
402 update_monitor_state ();
406 MonitorProcessor::set_cut_all (bool yn)
409 update_monitor_state ();
413 MonitorProcessor::set_dim_all (bool yn)
416 update_monitor_state ();
420 MonitorProcessor::display_to_user () const
426 MonitorProcessor::soloed (uint32_t chn) const
428 return _channels[chn]->soloed;
433 MonitorProcessor::inverted (uint32_t chn) const
435 return _channels[chn]->polarity < 0.0f;
440 MonitorProcessor::cut (uint32_t chn) const
442 return _channels[chn]->cut == GAIN_COEFF_ZERO;
446 MonitorProcessor::dimmed (uint32_t chn) const
448 return _channels[chn]->dim;
452 MonitorProcessor::mono () const
458 MonitorProcessor::dim_all () const
464 MonitorProcessor::cut_all () const
470 MonitorProcessor::update_monitor_state ()
474 if (_cut_all || _dim_all || _mono) {
478 const uint32_t nchans = _channels.size();
479 for (uint32_t i = 0; i < nchans && !en; ++i) {
480 if (cut (i) || dimmed (i) || soloed (i) || inverted (i)) {
486 if (_monitor_active != en) {
487 _monitor_active = en;
488 _session.MonitorChanged();
492 boost::shared_ptr<Controllable>
493 MonitorProcessor::channel_cut_control (uint32_t chn) const
495 if (chn < _channels.size()) {
496 return _channels[chn]->cut_control;
498 return boost::shared_ptr<Controllable>();
501 boost::shared_ptr<Controllable>
502 MonitorProcessor::channel_dim_control (uint32_t chn) const
504 if (chn < _channels.size()) {
505 return _channels[chn]->dim_control;
507 return boost::shared_ptr<Controllable>();
510 boost::shared_ptr<Controllable>
511 MonitorProcessor::channel_polarity_control (uint32_t chn) const
513 if (chn < _channels.size()) {
514 return _channels[chn]->polarity_control;
516 return boost::shared_ptr<Controllable>();
519 boost::shared_ptr<Controllable>
520 MonitorProcessor::channel_solo_control (uint32_t chn) const
522 if (chn < _channels.size()) {
523 return _channels[chn]->soloed_control;
525 return boost::shared_ptr<Controllable>();
528 MonitorProcessor::ChannelRecord::ChannelRecord (uint32_t chn)
529 : current_gain (GAIN_COEFF_UNITY)
530 , cut_ptr (new MPControl<gain_t> (1.0, string_compose (_("cut control %1"), chn), PBD::Controllable::GainLike))
531 , dim_ptr (new MPControl<bool> (false, string_compose (_("dim control"), chn), PBD::Controllable::Toggle))
532 , polarity_ptr (new MPControl<gain_t> (1.0, string_compose (_("polarity control"), chn), PBD::Controllable::Toggle, -1, 1))
533 , soloed_ptr (new MPControl<bool> (false, string_compose (_("solo control"), chn), PBD::Controllable::Toggle))
535 , cut_control (cut_ptr)
536 , dim_control (dim_ptr)
537 , polarity_control (polarity_ptr)
538 , soloed_control (soloed_ptr)
542 , polarity (*polarity_ptr)
543 , soloed (*soloed_ptr)