ardour
monitor_processor.cc
Go to the documentation of this file.
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/convert.h"
21 #include "pbd/error.h"
22 #include "pbd/locale_guard.h"
23 #include "pbd/xml++.h"
24 
25 #include "ardour/amp.h"
26 #include "ardour/debug.h"
27 #include "ardour/audio_buffer.h"
29 #include "ardour/session.h"
30 
31 #include "i18n.h"
32 
33 using namespace ARDOUR;
34 using namespace PBD;
35 using namespace std;
36 
37 /* specialize for bool because of set_value() semantics */
38 
39 namespace ARDOUR {
40  template<> void MPControl<bool>::set_value (double v) {
41  bool newval = fabs (v) >= 0.5;
42  if (newval != _value) {
43  _value = newval;
44  Changed(); /* EMIT SIGNAL */
45  }
46  }
47 }
48 
50  : Processor (s, X_("MonitorOut"))
51  , solo_cnt (0)
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),
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 
80 {
82 }
83 
84 void
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  const XMLProperty* prop;
115 
116  if ((prop = node.property (X_("type"))) == 0) {
117  error << string_compose (X_("programming error: %1"), X_("MonitorProcessor XML settings have no type information"))
118  << endmsg;
119  return -1;
120  }
121 
122  if (prop->value() != X_("monitor")) {
123  error << string_compose (X_("programming error: %1"), X_("MonitorProcessor given unknown XML settings"))
124  << endmsg;
125  return -1;
126  }
127 
128  if ((prop = node.property (X_("channels"))) == 0) {
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 (atoi (prop->value()));
135 
136  if ((prop = node.property (X_("dim-level"))) != 0) {
137  gain_t val = atof (prop->value());
138  _dim_level = val;
139  }
140 
141  if ((prop = node.property (X_("solo-boost-level"))) != 0) {
142  gain_t val = atof (prop->value());
143  _solo_boost_level = val;
144  }
145 
146  if ((prop = node.property (X_("cut-all"))) != 0) {
147  bool val = string_is_affirmative (prop->value());
148  _cut_all = val;
149  }
150  if ((prop = node.property (X_("dim-all"))) != 0) {
151  bool val = string_is_affirmative (prop->value());
152  _dim_all = val;
153  }
154  if ((prop = node.property (X_("mono"))) != 0) {
155  bool val = string_is_affirmative (prop->value());
156  _mono = 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  if ((prop = (*i)->property (X_("id"))) == 0) {
163  error << string_compose (X_("programming error: %1"), X_("MonitorProcessor XML settings are missing an ID"))
164  << endmsg;
165  return -1;
166  }
167 
168  uint32_t chn;
169 
170  if (sscanf (prop->value().c_str(), "%u", &chn) != 1) {
171  error << string_compose (X_("programming error: %1"), X_("MonitorProcessor XML settings has an unreadable channel 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  if ((prop = (*i)->property ("cut")) != 0) {
184  if (string_is_affirmative (prop->value())){
185  cr.cut = GAIN_COEFF_ZERO;
186  } else {
187  cr.cut = GAIN_COEFF_UNITY;
188  }
189  }
190 
191  if ((prop = (*i)->property ("dim")) != 0) {
192  bool val = string_is_affirmative (prop->value());
193  cr.dim = val;
194  }
195 
196  if ((prop = (*i)->property ("invert")) != 0) {
197  if (string_is_affirmative (prop->value())) {
198  cr.polarity = -1.0f;
199  } else {
200  cr.polarity = 1.0f;
201  }
202  }
203 
204  if ((prop = (*i)->property ("solo")) != 0) {
205  bool val = string_is_affirmative (prop->value());
206  cr.soloed = val;
207  }
208  }
209  }
210 
211  /* reset solo cnt */
212 
213  solo_cnt = 0;
214 
215  for (vector<ChannelRecord*>::const_iterator x = _channels.begin(); x != _channels.end(); ++x) {
216  if ((*x)->soloed) {
217  solo_cnt++;
218  }
219  }
220 
221  return 0;
222 }
223 
224 XMLNode&
226 {
227  LocaleGuard lg (X_("C"));
228  XMLNode& node (Processor::state (full));
229  char buf[64];
230 
231  /* this replaces any existing "type" property */
232 
233  node.add_property (X_("type"), X_("monitor"));
234 
235  snprintf (buf, sizeof(buf), "%.12g", _dim_level.val());
236  node.add_property (X_("dim-level"), buf);
237 
238  snprintf (buf, sizeof(buf), "%.12g", _solo_boost_level.val());
239  node.add_property (X_("solo-boost-level"), buf);
240 
241  node.add_property (X_("cut-all"), (_cut_all ? "yes" : "no"));
242  node.add_property (X_("dim-all"), (_dim_all ? "yes" : "no"));
243  node.add_property (X_("mono"), (_mono ? "yes" : "no"));
244 
245  uint32_t limit = _channels.size();
246 
247  snprintf (buf, sizeof (buf), "%u", limit);
248  node.add_property (X_("channels"), buf);
249 
250  XMLNode* chn_node;
251  uint32_t chn = 0;
252 
253  for (vector<ChannelRecord*>::const_iterator x = _channels.begin(); x != _channels.end(); ++x, ++chn) {
254  chn_node = new XMLNode (X_("Channel"));
255 
256  snprintf (buf, sizeof (buf), "%u", chn);
257  chn_node->add_property ("id", buf);
258 
259  chn_node->add_property (X_("cut"), (*x)->cut == GAIN_COEFF_UNITY ? "no" : "yes");
260  chn_node->add_property (X_("invert"), (*x)->polarity == GAIN_COEFF_UNITY ? "no" : "yes");
261  chn_node->add_property (X_("dim"), (*x)->dim ? "yes" : "no");
262  chn_node->add_property (X_("solo"), (*x)->soloed ? "yes" : "no");
263 
264  node.add_child_nocopy (*chn_node);
265  }
266 
267  return node;
268 }
269 
270 void
271 MonitorProcessor::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_frame*/, pframes_t nframes, bool /*result_required*/)
272 {
273  uint32_t chn = 0;
274  gain_t target_gain;
275  gain_t dim_level_this_time = _dim_level;
276  gain_t global_cut = (_cut_all ? GAIN_COEFF_ZERO : GAIN_COEFF_UNITY);
277  gain_t global_dim = (_dim_all ? dim_level_this_time : GAIN_COEFF_UNITY);
278  gain_t solo_boost;
279 
280  if (_session.listening() || _session.soloing()) {
281  solo_boost = _solo_boost_level;
282  } else {
283  solo_boost = GAIN_COEFF_UNITY;
284  }
285 
286  for (BufferSet::audio_iterator b = bufs.audio_begin(); b != bufs.audio_end(); ++b) {
287 
288  /* don't double-scale by both track dim and global dim coefficients */
289 
290  gain_t dim_level = (global_dim == GAIN_COEFF_UNITY ? (_channels[chn]->dim ? dim_level_this_time : GAIN_COEFF_UNITY) : GAIN_COEFF_UNITY);
291 
292  if (_channels[chn]->soloed) {
293  target_gain = _channels[chn]->polarity * _channels[chn]->cut * dim_level * global_cut * global_dim * solo_boost;
294  } else {
295  if (solo_cnt == 0) {
296  target_gain = _channels[chn]->polarity * _channels[chn]->cut * dim_level * global_cut * global_dim * solo_boost;
297  } else {
298  target_gain = GAIN_COEFF_ZERO;
299  }
300  }
301 
302  if (target_gain != _channels[chn]->current_gain || target_gain != GAIN_COEFF_UNITY) {
303 
304  _channels[chn]->current_gain = Amp::apply_gain (*b, _session.nominal_frame_rate(), nframes, _channels[chn]->current_gain, target_gain);
305  }
306 
307  ++chn;
308  }
309 
310  if (_mono) {
311  DEBUG_TRACE (DEBUG::Monitor, "mono-izing\n");
312 
313  /* chn is now the number of channels, use as a scaling factor when mixing
314  */
315  gain_t scale = 1.f / (float)chn;
317  AudioBuffer& ab (*b);
318  Sample* buf = ab.data();
319 
320  /* scale the first channel */
321 
322  for (pframes_t n = 0; n < nframes; ++n) {
323  buf[n] *= scale;
324  }
325 
326  /* add every other channel into the first channel's buffer */
327 
328  ++b;
329  for (; b != bufs.audio_end(); ++b) {
330  AudioBuffer& ob (*b);
331  Sample* obuf = ob.data ();
332  for (pframes_t n = 0; n < nframes; ++n) {
333  buf[n] += obuf[n] * scale;
334  }
335  }
336 
337  /* copy the first channel to every other channel's buffer */
338 
339  b = bufs.audio_begin();
340  ++b;
341  for (; b != bufs.audio_end(); ++b) {
342  AudioBuffer& ob (*b);
343  Sample* obuf = ob.data ();
344  memcpy (obuf, buf, sizeof (Sample) * nframes);
345  }
346  }
347 }
348 
349 bool
351 {
352  allocate_channels (in.n_audio());
353  return Processor::configure_io (in, out);
354 }
355 
356 bool
358 {
359  out = in;
360  return true;
361 }
362 
363 void
364 MonitorProcessor::set_polarity (uint32_t chn, bool invert)
365 {
366  if (invert) {
367  _channels[chn]->polarity = -1.0f;
368  } else {
369  _channels[chn]->polarity = 1.0f;
370  }
371 }
372 
373 void
374 MonitorProcessor::set_dim (uint32_t chn, bool yn)
375 {
376  _channels[chn]->dim = yn;
377 }
378 
379 void
380 MonitorProcessor::set_cut (uint32_t chn, bool yn)
381 {
382  if (yn) {
383  _channels[chn]->cut = GAIN_COEFF_ZERO;
384  } else {
385  _channels[chn]->cut = GAIN_COEFF_UNITY;
386  }
387 }
388 
389 void
390 MonitorProcessor::set_solo (uint32_t chn, bool solo)
391 {
392  if (solo != _channels[chn]->soloed) {
393  _channels[chn]->soloed = solo;
394 
395  if (solo) {
396  solo_cnt++;
397  } else {
398  if (solo_cnt > 0) {
399  solo_cnt--;
400  }
401  }
402  }
403 }
404 
405 void
407 {
408  _mono = yn;
409 }
410 
411 void
413 {
414  _cut_all = yn;
415 }
416 
417 void
419 {
420  _dim_all = yn;
421 }
422 
423 bool
425 {
426  return false;
427 }
428 
429 bool
430 MonitorProcessor::soloed (uint32_t chn) const
431 {
432  return _channels[chn]->soloed;
433 }
434 
435 
436 bool
437 MonitorProcessor::inverted (uint32_t chn) const
438 {
439  return _channels[chn]->polarity < 0.0f;
440 }
441 
442 
443 bool
444 MonitorProcessor::cut (uint32_t chn) const
445 {
446  return _channels[chn]->cut == GAIN_COEFF_ZERO;
447 }
448 
449 bool
450 MonitorProcessor::dimmed (uint32_t chn) const
451 {
452  return _channels[chn]->dim;
453 }
454 
455 bool
457 {
458  return _mono;
459 }
460 
461 bool
463 {
464  return _dim_all;
465 }
466 
467 bool
469 {
470  return _cut_all;
471 }
472 
475 {
476  if (chn < _channels.size()) {
477  return _channels[chn]->cut_control;
478  }
480 }
481 
484 {
485  if (chn < _channels.size()) {
486  return _channels[chn]->dim_control;
487  }
489 }
490 
493 {
494  if (chn < _channels.size()) {
495  return _channels[chn]->polarity_control;
496  }
498 }
499 
502 {
503  if (chn < _channels.size()) {
504  return _channels[chn]->soloed_control;
505  }
507 }
508 
510  : current_gain (GAIN_COEFF_UNITY)
511  , cut_ptr (new MPControl<gain_t> (1.0, string_compose (_("cut control %1"), chn), PBD::Controllable::GainLike))
512  , dim_ptr (new MPControl<bool> (false, string_compose (_("dim control"), chn), PBD::Controllable::Toggle))
513  , polarity_ptr (new MPControl<gain_t> (1.0, string_compose (_("polarity control"), chn), PBD::Controllable::Toggle, -1, 1))
514  , soloed_ptr (new MPControl<bool> (false, string_compose (_("solo control"), chn), PBD::Controllable::Toggle))
515 
516  , cut_control (cut_ptr)
517  , dim_control (dim_ptr)
518  , polarity_control (polarity_ptr)
519  , soloed_control (soloed_ptr)
520 
521  , cut (*cut_ptr)
522  , dim (*dim_ptr)
523  , polarity (*polarity_ptr)
524  , soloed (*soloed_ptr)
525 {
526 
527 }
bool can_support_io_configuration(const ChanCount &in, ChanCount &out)
framecnt_t nominal_frame_rate() const
Definition: session.h:367
ARDOUR::Session & _session
bool inverted(uint32_t chn) const
int atoi(const string &s)
Definition: convert.cc:140
bool soloing() const
Definition: session.h:691
const std::string & value() const
Definition: xml++.h:159
boost::shared_ptr< PBD::Controllable > channel_polarity_control(uint32_t) const
void set_cut(uint32_t, bool cut)
bool apply_gain() const
Definition: amp.h:50
bool configure_io(ChanCount in, ChanCount out)
uint32_t pframes_t
Definition: types.h:61
uint32_t n_audio() const
Definition: chan_count.h:63
boost::shared_ptr< PBD::Controllable > channel_cut_control(uint32_t) const
LIBARDOUR_API uint64_t Monitor
Definition: debug.cc:47
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
const XMLNodeList & children(const std::string &str=std::string()) const
Definition: xml++.cc:329
bool cut(uint32_t chn) const
MPControl< bool > & _dim_all
float gain_t
Definition: types.h:58
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
int set_state(const XMLNode &, int version)
Definition: processor.cc:173
MPControl< volatile gain_t > & _dim_level
#define GAIN_COEFF_ZERO
Definition: dB.h:26
#define _(Text)
Definition: i18n.h:11
bool soloed(uint32_t chn) const
#define X_(Text)
Definition: i18n.h:13
XMLProperty * property(const char *)
Definition: xml++.cc:413
float Sample
Definition: types.h:54
bool string_is_affirmative(const std::string &str)
Definition: convert.cc:282
MPControl< bool > & _cut_all
audio_iterator audio_begin()
Definition: buffer_set.h:173
Definition: amp.h:29
bool dimmed(uint32_t chn) const
void set_solo(uint32_t, bool)
virtual bool configure_io(ChanCount in, ChanCount out)
Definition: processor.cc:246
#define DEBUG_TRACE(bits, str)
Definition: debug.h:55
int64_t framepos_t
Definition: types.h:66
void set_dim(uint32_t, bool dim)
audio_iterator audio_end()
Definition: buffer_set.h:174
MPControl< bool > & _mono
XMLProperty * add_property(const char *name, const std::string &value)
int set_state(const XMLNode &, int)
void allocate_channels(uint32_t)
void add_child_nocopy(XMLNode &)
Definition: xml++.cc:357
std::vector< ChannelRecord * > _channels
LIBARDOUR_API PBD::PropertyDescriptor< bool > solo
Definition: route_group.cc:46
MPControl< volatile gain_t > & _solo_boost_level
void set_value(double v)
Definition: xml++.h:95
void set_polarity(uint32_t, bool invert)
bool listening() const
Definition: session.h:692
Definition: debug.h:30
virtual XMLNode & state(bool full)
Definition: processor.cc:109
static float dB_to_coefficient(float dB)
Definition: dB.h:30
boost::shared_ptr< PBD::Controllable > channel_dim_control(uint32_t) const
const Sample * data(framecnt_t offset=0) const
Definition: audio_buffer.h:187
boost::shared_ptr< PBD::Controllable > channel_solo_control(uint32_t) const
#define GAIN_COEFF_UNITY
Definition: dB.h:28
XMLNode & state(bool full)
void run(BufferSet &, framepos_t, framepos_t, pframes_t, bool)
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
double atof(const string &s)
Definition: convert.cc:158