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