Reverse parameters to CPPUNIT_ASSERT_EQUAL so its assert
[ardour.git] / libs / ardour / delivery.cc
1 /*
2     Copyright (C) 2009 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify it
5     under the terms of the GNU General Public License as published by the Free
6     Software Foundation; either version 2 of the License, or (at your option)
7     any later version.
8
9     This program is distributed in the hope that it will be useful, but WITHOUT
10     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12     for more details.
13
14     You should have received a copy of the GNU General Public License along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <cmath>
20 #include <algorithm>
21
22 #include "pbd/enumwriter.h"
23 #include "pbd/convert.h"
24
25 #include "ardour/midi_buffer.h"
26
27 #include "ardour/debug.h"
28 #include "ardour/delivery.h"
29 #include "ardour/audio_buffer.h"
30 #include "ardour/audio_port.h"
31 #include "ardour/amp.h"
32 #include "ardour/buffer_set.h"
33 #include "ardour/configuration.h"
34 #include "ardour/io.h"
35 #include "ardour/meter.h"
36 #include "ardour/mute_master.h"
37 #include "ardour/panner.h"
38 #include "ardour/panner_shell.h"
39 #include "ardour/pannable.h"
40 #include "ardour/port.h"
41 #include "ardour/session.h"
42 #include "ardour/audioengine.h"
43
44 #include "i18n.h"
45
46 using namespace std;
47 using namespace PBD;
48 using namespace ARDOUR;
49
50 PBD::Signal1<void, pframes_t> Delivery::CycleStart;
51 PBD::Signal0<int>             Delivery::PannersLegal;
52 bool                          Delivery::panners_legal = false;
53
54 /* deliver to an existing IO object */
55
56 Delivery::Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<Pannable> pannable,
57                     boost::shared_ptr<MuteMaster> mm, const string& name, Role r)
58         : IOProcessor(s, boost::shared_ptr<IO>(), (role_requires_output_ports (r) ? io : boost::shared_ptr<IO>()), name)
59         , _role (r)
60         , _output_buffers (new BufferSet())
61         , _current_gain (1.0)
62         , _no_outs_cuz_we_no_monitor (false)
63         , _mute_master (mm)
64         , _no_panner_reset (false)
65 {
66         if (pannable) {
67                 _panshell = boost::shared_ptr<PannerShell>(new PannerShell (_name, _session, pannable));
68         }
69
70         _display_to_user = false;
71
72         if (_output) {
73                 _output->changed.connect_same_thread (*this, boost::bind (&Delivery::output_changed, this, _1, _2));
74         }
75
76         CycleStart.connect_same_thread (*this, boost::bind (&Delivery::cycle_start, this, _1));
77 }
78
79 /* deliver to a new IO object */
80
81 Delivery::Delivery (Session& s, boost::shared_ptr<Pannable> pannable, boost::shared_ptr<MuteMaster> mm, const string& name, Role r)
82         : IOProcessor(s, false, (role_requires_output_ports (r) ? true : false), name)
83         , _role (r)
84         , _output_buffers (new BufferSet())
85         , _current_gain (1.0)
86         , _no_outs_cuz_we_no_monitor (false)
87         , _mute_master (mm)
88         , _no_panner_reset (false)
89 {
90         if (pannable) {
91                 _panshell = boost::shared_ptr<PannerShell>(new PannerShell (_name, _session, pannable));
92         }
93
94         _display_to_user = false;
95
96         if (_output) {
97                 _output->changed.connect_same_thread (*this, boost::bind (&Delivery::output_changed, this, _1, _2));
98         }
99
100         CycleStart.connect_same_thread (*this, boost::bind (&Delivery::cycle_start, this, _1));
101 }
102
103
104 Delivery::~Delivery()
105 {
106         DEBUG_TRACE (DEBUG::Destruction, string_compose ("delivery %1 destructor\n", _name));   
107
108         /* this object should vanish from any signal callback lists
109            that it is on before we get any further. The full qualification
110            of the method name is not necessary, but is here to make it 
111            clear that this call is about signals, not data flow connections.
112         */
113
114         ScopedConnectionList::drop_connections ();
115
116         delete _output_buffers;
117 }
118
119 std::string
120 Delivery::display_name () const
121 {
122         switch (_role) {
123         case Main:
124                 return _("main outs");
125                 break;
126         case Listen:
127                 return _("listen");
128                 break;
129         case Send:
130         case Insert:
131         default:
132                 return name();
133         }
134 }
135
136 void
137 Delivery::cycle_start (pframes_t /*nframes*/)
138 {
139         _no_outs_cuz_we_no_monitor = false;
140 }
141
142 bool
143 Delivery::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
144 {
145         if (_role == Main) {
146
147                 /* the out buffers will be set to point to the port output buffers
148                    of our output object.
149                 */
150
151                 if (_output) {
152                         if (_output->n_ports() != ChanCount::ZERO) {
153                                 /* increase number of output ports if the processor chain requires it */
154                                 out = ChanCount::max (_output->n_ports(), in);
155                                 return true;
156                         } else {
157                                 /* not configured yet - we will passthru */
158                                 out = in;
159                                 return true;
160                         }
161                 } else {
162                         fatal << "programming error: this should never be reached" << endmsg;
163                         /*NOTREACHED*/
164                 }
165
166
167         } else if (_role == Insert) {
168
169                 /* the output buffers will be filled with data from the *input* ports
170                    of this Insert.
171                 */
172
173                 if (_input) {
174                         if (_input->n_ports() != ChanCount::ZERO) {
175                                 out = _input->n_ports();
176                                 return true;
177                         } else {
178                                 /* not configured yet - we will passthru */
179                                 out = in;
180                                 return true;
181                         }
182                 } else {
183                         fatal << "programming error: this should never be reached" << endmsg;
184                         /*NOTREACHED*/
185                 }
186
187         } else {
188                 fatal << "programming error: this should never be reached" << endmsg;
189         }
190
191         return false;
192 }
193
194 /** Caller must hold process lock */
195 bool
196 Delivery::configure_io (ChanCount in, ChanCount out)
197 {
198         assert (!AudioEngine::instance()->process_lock().trylock());
199
200         /* check configuration by comparison with our I/O port configuration, if appropriate.
201            see ::can_support_io_configuration() for comments
202         */
203
204         if (_role == Main) {
205
206                 if (_output) {
207                         if (_output->n_ports() != out) {
208                                 if (_output->n_ports() != ChanCount::ZERO) {
209                                         _output->ensure_io (out, false, this);
210                                 } else {
211                                         /* I/O not yet configured */
212                                 }
213                         }
214                 }
215
216         } else if (_role == Insert) {
217
218                 if (_input) {
219                         if (_input->n_ports() != in) {
220                                 if (_input->n_ports() != ChanCount::ZERO) {
221                                         fatal << _name << " programming error: configure_io called with " << in << " and " << out << " with " << _input->n_ports() << " input ports" << endmsg;
222                                         /*NOTREACHED*/
223                                 } else {
224                                         /* I/O not yet configured */
225                                 }
226                         }
227                 }
228
229         }
230
231         if (!Processor::configure_io (in, out)) {
232                 return false;
233         }
234
235         reset_panner ();
236
237         return true;
238 }
239
240 void
241 Delivery::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, bool result_required)
242 {
243         assert (_output);
244
245         PortSet& ports (_output->ports());
246         gain_t tgain;
247
248         if (_output->n_ports ().get (_output->default_type()) == 0) {
249                 goto out;
250         }
251
252         if (!_active && !_pending_active) {
253                 _output->silence (nframes);
254                 goto out;
255         }
256
257         /* this setup is not just for our purposes, but for anything that comes after us in the
258            processing pathway that wants to use this->output_buffers() for some reason.
259         */
260
261         output_buffers().get_jack_port_addresses (ports, nframes);
262
263         // this Delivery processor is not a derived type, and thus we assume
264         // we really can modify the buffers passed in (it is almost certainly
265         // the main output stage of a Route). Contrast with Send::run()
266         // which cannot do this.
267
268         tgain = target_gain ();
269
270         if (tgain != _current_gain) {
271                 /* target gain has changed */
272
273                 Amp::apply_gain (bufs, nframes, _current_gain, tgain);
274                 _current_gain = tgain;
275
276         } else if (tgain == 0.0) {
277
278                 /* we were quiet last time, and we're still supposed to be quiet.
279                    Silence the outputs, and make sure the buffers are quiet too,
280                 */
281
282                 _output->silence (nframes);
283                 if (result_required) {
284                         bufs.set_count (output_buffers().count ());
285                         Amp::apply_simple_gain (bufs, nframes, 0.0);
286                 }
287                 goto out;
288
289         } else if (tgain != 1.0) {
290
291                 /* target gain has not changed, but is not unity */
292                 Amp::apply_simple_gain (bufs, nframes, tgain);
293         }
294
295         if (_panshell && !_panshell->bypassed() && _panshell->panner()) {
296
297                 // Use the panner to distribute audio to output port buffers
298
299                 _panshell->run (bufs, output_buffers(), start_frame, end_frame, nframes);
300
301                 // MIDI data will not have been delivered by the panner
302
303                 if (bufs.count().n_midi() > 0 && ports.count().n_midi () > 0) {
304                         _output->copy_to_outputs (bufs, DataType::MIDI, nframes, 0);
305                 }
306
307         } else {
308
309                 // Do a 1:1 copy of data to output ports
310
311                 if (bufs.count().n_audio() > 0 && ports.count().n_audio () > 0) {
312                         _output->copy_to_outputs (bufs, DataType::AUDIO, nframes, 0);
313                 }
314
315                 if (bufs.count().n_midi() > 0 && ports.count().n_midi () > 0) {
316                         _output->copy_to_outputs (bufs, DataType::MIDI, nframes, 0);
317                 }
318         }
319
320         if (result_required) {
321                 bufs.read_from (output_buffers (), nframes);
322         }
323
324   out:
325         _active = _pending_active;
326 }
327
328 XMLNode&
329 Delivery::state (bool full_state)
330 {
331         XMLNode& node (IOProcessor::state (full_state));
332
333         if (_role & Main) {
334                 node.add_property("type", "main-outs");
335         } else if (_role & Listen) {
336                 node.add_property("type", "listen");
337         } else {
338                 node.add_property("type", "delivery");
339         }
340
341         node.add_property("role", enum_2_string(_role));
342
343         if (_panshell) {
344                 node.add_child_nocopy (_panshell->get_state ());
345         }
346
347         return node;
348 }
349
350 int
351 Delivery::set_state (const XMLNode& node, int version)
352 {
353         const XMLProperty* prop;
354
355         if (IOProcessor::set_state (node, version)) {
356                 return -1;
357         }
358
359         if ((prop = node.property ("role")) != 0) {
360                 _role = Role (string_2_enum (prop->value(), _role));
361                 // std::cerr << this << ' ' << _name << " set role to " << enum_2_string (_role) << std::endl;
362         } else {
363                 // std::cerr << this << ' ' << _name << " NO ROLE INFO\n";
364         }
365
366         XMLNode* pan_node = node.child (X_("PannerShell"));
367
368         if (pan_node && _panshell) {
369                 _panshell->set_state (*pan_node, version);
370         }
371
372         reset_panner ();
373
374         return 0;
375 }
376
377 void
378 Delivery::unpan ()
379 {
380         /* caller must hold process lock */
381
382         _panshell.reset ();
383 }
384
385 uint32_t
386 Delivery::pan_outs () const
387 {
388         if (_output) {
389                 return _output->n_ports().n_audio();
390         } 
391
392         return _configured_output.n_audio();
393 }
394
395 void
396 Delivery::reset_panner ()
397 {
398         if (panners_legal) {
399                 if (!_no_panner_reset) {
400
401                         if (_panshell) {
402                                 _panshell->configure_io (ChanCount (DataType::AUDIO, pans_required()), ChanCount (DataType::AUDIO, pan_outs()));
403                                 
404                                 if (_role == Main) {
405                                         _panshell->pannable()->set_panner (_panshell->panner());
406                                 }
407                         }
408                 }
409
410         } else {
411                 panner_legal_c.disconnect ();
412                 PannersLegal.connect_same_thread (panner_legal_c, boost::bind (&Delivery::panners_became_legal, this));
413         }
414 }
415
416 int
417 Delivery::panners_became_legal ()
418 {
419         if (_panshell) {
420                 _panshell->configure_io (ChanCount (DataType::AUDIO, pans_required()), ChanCount (DataType::AUDIO, pan_outs()));
421                 
422                 if (_role == Main) {
423                         _panshell->pannable()->set_panner (_panshell->panner());
424                 }
425         }
426
427         panner_legal_c.disconnect ();
428         return 0;
429 }
430
431 void
432 Delivery::defer_pan_reset ()
433 {
434         _no_panner_reset = true;
435 }
436
437 void
438 Delivery::allow_pan_reset ()
439 {
440         _no_panner_reset = false;
441         reset_panner ();
442 }
443
444
445 int
446 Delivery::disable_panners ()
447 {
448         panners_legal = false;
449         return 0;
450 }
451
452 int
453 Delivery::reset_panners ()
454 {
455         panners_legal = true;
456         return *PannersLegal ();
457 }
458
459 void
460 Delivery::flush_buffers (framecnt_t nframes, framepos_t time)
461 {
462         /* io_lock, not taken: function must be called from Session::process() calltree */
463
464         if (!_output) {
465                 return;
466         }
467         
468         PortSet& ports (_output->ports());
469
470         for (PortSet::iterator i = ports.begin(); i != ports.end(); ++i) {
471                 i->flush_buffers (nframes, time);
472         }
473 }
474
475 void
476 Delivery::transport_stopped (framepos_t now)
477 {
478         Processor::transport_stopped (now);
479
480         if (_panshell) {
481                 _panshell->pannable()->transport_stopped (now);
482         }
483
484         if (_output) {
485                 PortSet& ports (_output->ports());
486
487                 for (PortSet::iterator i = ports.begin(); i != ports.end(); ++i) {
488                         i->transport_stopped ();
489                 }
490         }
491 }
492
493 void
494 Delivery::realtime_locate ()
495 {
496         if (_output) {
497                 PortSet& ports (_output->ports());
498
499                 for (PortSet::iterator i = ports.begin(); i != ports.end(); ++i) {
500                         i->realtime_locate ();
501                 }
502         }
503 }
504
505 gain_t
506 Delivery::target_gain ()
507 {
508         /* if we've been requested to deactivate, our target gain is zero */
509
510         if (!_pending_active) {
511                 return 0.0;
512         }
513
514         /* if we've been told not to output because its a monitoring situation and
515            we're not monitoring, then be quiet.
516         */
517
518         if (_no_outs_cuz_we_no_monitor) {
519                 return 0.0;
520         }
521
522         MuteMaster::MutePoint mp = MuteMaster::Main; // stupid gcc uninit warning
523
524         switch (_role) {
525         case Main:
526                 mp = MuteMaster::Main;
527                 break;
528         case Listen:
529                 mp = MuteMaster::Listen;
530                 break;
531         case Send:
532         case Insert:
533         case Aux:
534                 if (_pre_fader) {
535                         mp = MuteMaster::PreFader;
536                 } else {
537                         mp = MuteMaster::PostFader;
538                 }
539                 break;
540         }
541
542         gain_t desired_gain = _mute_master->mute_gain_at (mp);
543
544         if (_role == Listen && _session.monitor_out() && !_session.listening()) {
545
546                 /* nobody is soloed, and this delivery is a listen-send to the
547                    control/monitor/listen bus, we should be silent since
548                    it gets its signal from the master out.
549                 */
550
551                 desired_gain = 0.0;
552
553         }
554
555         return desired_gain;
556 }
557
558 void
559 Delivery::no_outs_cuz_we_no_monitor (bool yn)
560 {
561         _no_outs_cuz_we_no_monitor = yn;
562 }
563
564 bool
565 Delivery::set_name (const std::string& name)
566 {
567         bool ret = IOProcessor::set_name (name);
568
569         if (ret) {
570                 ret = _panshell->set_name (name);
571         }
572
573         return ret;
574 }
575
576 bool ignore_output_change = false;
577
578 void
579 Delivery::output_changed (IOChange change, void* /*src*/)
580 {
581         if (change.type & IOChange::ConfigurationChanged) {
582                 reset_panner ();
583                 _output_buffers->attach_buffers (_output->ports ());
584         }
585 }
586
587 boost::shared_ptr<Panner>
588 Delivery::panner () const
589 {
590         if (_panshell) {
591                 return _panshell->panner();
592         } else {
593                 return boost::shared_ptr<Panner>();
594         }
595 }
596