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