2 Copyright (C) 2009 Paul Davis
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)
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
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.
22 #include "pbd/enumwriter.h"
23 #include "pbd/convert.h"
25 #include "ardour/amp.h"
26 #include "ardour/audioengine.h"
27 #include "ardour/buffer_set.h"
28 #include "ardour/debug.h"
29 #include "ardour/delivery.h"
30 #include "ardour/io.h"
31 #include "ardour/mute_master.h"
32 #include "ardour/pannable.h"
33 #include "ardour/panner_shell.h"
34 #include "ardour/port.h"
35 #include "ardour/session.h"
39 namespace ARDOUR { class Panner; }
43 using namespace ARDOUR;
45 PBD::Signal0<void> Delivery::PannersLegal;
46 bool Delivery::panners_legal = false;
48 /* deliver to an existing IO object */
50 Delivery::Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<Pannable> pannable,
51 boost::shared_ptr<MuteMaster> mm, const string& name, Role r)
52 : IOProcessor(s, boost::shared_ptr<IO>(), (role_requires_output_ports (r) ? io : boost::shared_ptr<IO>()), name)
54 , _output_buffers (new BufferSet())
55 , _current_gain (GAIN_COEFF_UNITY)
56 , _no_outs_cuz_we_no_monitor (false)
58 , _no_panner_reset (false)
62 if (r & (Delivery::Send|Delivery::Aux)) is_send = true;
63 _panshell = boost::shared_ptr<PannerShell>(new PannerShell (_name, _session, pannable, is_send));
66 _display_to_user = false;
69 _output->changed.connect_same_thread (*this, boost::bind (&Delivery::output_changed, this, _1, _2));
73 /* deliver to a new IO object */
75 Delivery::Delivery (Session& s, boost::shared_ptr<Pannable> pannable, boost::shared_ptr<MuteMaster> mm, const string& name, Role r)
76 : IOProcessor(s, false, (role_requires_output_ports (r) ? true : false), name, "", DataType::AUDIO, (r == Send))
78 , _output_buffers (new BufferSet())
79 , _current_gain (GAIN_COEFF_UNITY)
80 , _no_outs_cuz_we_no_monitor (false)
82 , _no_panner_reset (false)
86 if (r & (Delivery::Send|Delivery::Aux)) is_send = true;
87 _panshell = boost::shared_ptr<PannerShell>(new PannerShell (_name, _session, pannable, is_send));
90 _display_to_user = false;
93 _output->changed.connect_same_thread (*this, boost::bind (&Delivery::output_changed, this, _1, _2));
100 DEBUG_TRACE (DEBUG::Destruction, string_compose ("delivery %1 destructor\n", _name));
102 /* this object should vanish from any signal callback lists
103 that it is on before we get any further. The full qualification
104 of the method name is not necessary, but is here to make it
105 clear that this call is about signals, not data flow connections.
108 ScopedConnectionList::drop_connections ();
110 delete _output_buffers;
114 Delivery::display_name () const
118 return _("main outs");
131 Delivery::can_support_io_configuration (const ChanCount& in, ChanCount& out)
135 /* the out buffers will be set to point to the port output buffers
136 of our output object.
140 if (_output->n_ports() != ChanCount::ZERO) {
141 /* increase number of output ports if the processor chain requires it */
142 out = ChanCount::max (_output->n_ports(), in);
145 /* not configured yet - we will passthru */
150 fatal << "programming error: this should never be reached" << endmsg;
151 abort(); /*NOTREACHED*/
155 } else if (_role == Insert) {
157 /* the output buffers will be filled with data from the *input* ports
162 if (_input->n_ports() != ChanCount::ZERO) {
163 out = _input->n_ports();
166 /* not configured yet - we will passthru */
171 fatal << "programming error: this should never be reached" << endmsg;
172 abort(); /*NOTREACHED*/
176 fatal << "programming error: this should never be reached" << endmsg;
182 /** Caller must hold process lock */
184 Delivery::configure_io (ChanCount in, ChanCount out)
187 bool r = AudioEngine::instance()->process_lock().trylock();
188 assert (!r && "trylock inside Delivery::configure_io");
191 /* check configuration by comparison with our I/O port configuration, if appropriate.
192 see ::can_support_io_configuration() for comments
198 if (_output->n_ports() != out) {
199 if (_output->n_ports() != ChanCount::ZERO) {
200 _output->ensure_io (out, false, this);
202 /* I/O not yet configured */
207 } else if (_role == Insert) {
210 if (_input->n_ports() != in) {
211 if (_input->n_ports() != ChanCount::ZERO) {
212 fatal << _name << " programming error: configure_io called with " << in << " and " << out << " with " << _input->n_ports() << " input ports" << endmsg;
213 abort(); /*NOTREACHED*/
215 /* I/O not yet configured */
222 if (!Processor::configure_io (in, out)) {
232 Delivery::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, double /*speed*/, pframes_t nframes, bool result_required)
236 PortSet& ports (_output->ports());
239 if (ports.num_ports () == 0) {
243 if (!_active && !_pending_active) {
244 _output->silence (nframes);
248 /* this setup is not just for our purposes, but for anything that comes after us in the
249 * processing pathway that wants to use this->output_buffers() for some reason.
252 // TODO delayline -- latency-compensation
253 output_buffers().get_backend_port_addresses (ports, nframes);
255 // this Delivery processor is not a derived type, and thus we assume
256 // we really can modify the buffers passed in (it is almost certainly
257 // the main output stage of a Route). Contrast with Send::run()
258 // which cannot do this.
260 tgain = target_gain ();
262 if (tgain != _current_gain) {
263 /* target gain has changed */
265 _current_gain = Amp::apply_gain (bufs, _session.nominal_frame_rate(), nframes, _current_gain, tgain);
267 } else if (tgain < GAIN_COEFF_SMALL) {
269 /* we were quiet last time, and we're still supposed to be quiet.
270 Silence the outputs, and make sure the buffers are quiet too,
273 _output->silence (nframes);
274 if (result_required) {
275 bufs.set_count (output_buffers().count ());
276 Amp::apply_simple_gain (bufs, nframes, GAIN_COEFF_ZERO);
280 } else if (tgain != GAIN_COEFF_UNITY) {
282 /* target gain has not changed, but is not unity */
283 Amp::apply_simple_gain (bufs, nframes, tgain);
288 if (fabs (_session.transport_speed()) > 1.5 && Config->get_quieten_at_speed ()) {
289 Amp::apply_simple_gain (bufs, nframes, speed_quietning, false);
294 if (_panshell && !_panshell->bypassed() && _panshell->panner()) {
296 // Use the panner to distribute audio to output port buffers
298 _panshell->run (bufs, output_buffers(), start_frame, end_frame, nframes);
300 // non-audio data will not have been delivered by the panner
302 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
303 if (*t != DataType::AUDIO && bufs.count().get(*t) > 0) {
304 _output->copy_to_outputs (bufs, *t, nframes, Port::port_offset());
310 /* Do a 1:1 copy of data to output ports
312 Audio is handled separately because we use 0 for the offset,
313 since the port offset is only used for timestamped events
317 if (bufs.count().n_audio() > 0) {
318 _output->copy_to_outputs (bufs, DataType::AUDIO, nframes, 0);
321 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
322 if (*t != DataType::AUDIO && bufs.count().get(*t) > 0) {
323 _output->copy_to_outputs (bufs, *t, nframes, Port::port_offset());
328 if (result_required) {
330 /* "bufs" are internal, meaning they should never reflect
331 split-cycle offsets. So shift events back in time from where
332 they were for the external buffers associated with Ports.
335 BufferSet& outs (output_buffers());
337 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
340 for (BufferSet::iterator b = bufs.begin (*t); b != bufs.end (*t); ++b) {
341 if (outs.count ().get (*t) <= n) {
344 b->read_from (outs.get (*t, n++), nframes, (*t == DataType::AUDIO ? 0 : -Port::port_offset()));
350 _active = _pending_active;
354 Delivery::state (bool full_state)
356 XMLNode& node (IOProcessor::state (full_state));
359 node.add_property("type", "main-outs");
360 } else if (_role & Listen) {
361 node.add_property("type", "listen");
363 node.add_property("type", "delivery");
366 node.add_property("role", enum_2_string(_role));
369 node.add_child_nocopy (_panshell->get_state ());
370 if (_panshell->pannable()) {
371 node.add_child_nocopy (_panshell->pannable()->get_state ());
379 Delivery::set_state (const XMLNode& node, int version)
381 XMLProperty const * prop;
383 if (IOProcessor::set_state (node, version)) {
387 if ((prop = node.property ("role")) != 0) {
388 _role = Role (string_2_enum (prop->value(), _role));
389 // std::cerr << this << ' ' << _name << " set role to " << enum_2_string (_role) << std::endl;
391 // std::cerr << this << ' ' << _name << " NO ROLE INFO\n";
394 XMLNode* pan_node = node.child (X_("PannerShell"));
396 if (pan_node && _panshell) {
397 _panshell->set_state (*pan_node, version);
402 XMLNode* pannnode = node.child (X_("Pannable"));
403 if (_panshell && _panshell->panner() && pannnode) {
404 _panshell->pannable()->set_state (*pannnode, version);
413 /* caller must hold process lock */
419 Delivery::pan_outs () const
422 return _output->n_ports().n_audio();
425 return _configured_output.n_audio();
429 Delivery::reset_panner ()
432 if (!_no_panner_reset) {
434 if (_panshell && _role != Insert && _role != Listen) {
435 _panshell->configure_io (ChanCount (DataType::AUDIO, pans_required()), ChanCount (DataType::AUDIO, pan_outs()));
440 panner_legal_c.disconnect ();
441 PannersLegal.connect_same_thread (panner_legal_c, boost::bind (&Delivery::panners_became_legal, this));
446 Delivery::panners_became_legal ()
448 if (_panshell && _role != Insert) {
449 _panshell->configure_io (ChanCount (DataType::AUDIO, pans_required()), ChanCount (DataType::AUDIO, pan_outs()));
452 panner_legal_c.disconnect ();
456 Delivery::defer_pan_reset ()
458 _no_panner_reset = true;
462 Delivery::allow_pan_reset ()
464 _no_panner_reset = false;
470 Delivery::disable_panners ()
472 panners_legal = false;
477 Delivery::reset_panners ()
479 panners_legal = true;
484 Delivery::flush_buffers (framecnt_t nframes)
486 /* io_lock, not taken: function must be called from Session::process() calltree */
492 PortSet& ports (_output->ports());
494 for (PortSet::iterator i = ports.begin(); i != ports.end(); ++i) {
495 i->flush_buffers (nframes);
500 Delivery::transport_stopped (framepos_t now)
502 Processor::transport_stopped (now);
505 _panshell->pannable()->transport_stopped (now);
509 PortSet& ports (_output->ports());
511 for (PortSet::iterator i = ports.begin(); i != ports.end(); ++i) {
512 i->transport_stopped ();
518 Delivery::realtime_locate ()
521 PortSet& ports (_output->ports());
523 for (PortSet::iterator i = ports.begin(); i != ports.end(); ++i) {
524 i->realtime_locate ();
530 Delivery::target_gain ()
532 /* if we've been requested to deactivate, our target gain is zero */
534 if (!_pending_active) {
535 return GAIN_COEFF_ZERO;
538 /* if we've been told not to output because its a monitoring situation and
539 we're not monitoring, then be quiet.
542 if (_no_outs_cuz_we_no_monitor) {
543 return GAIN_COEFF_ZERO;
546 MuteMaster::MutePoint mp = MuteMaster::Main; // stupid gcc uninit warning
550 mp = MuteMaster::Main;
553 mp = MuteMaster::Listen;
559 mp = MuteMaster::PreFader;
561 mp = MuteMaster::PostFader;
566 gain_t desired_gain = _mute_master->mute_gain_at (mp);
568 if (_role == Listen && _session.monitor_out() && !_session.listening()) {
570 /* nobody is soloed, and this delivery is a listen-send to the
571 control/monitor/listen bus, we should be silent since
572 it gets its signal from the master out.
575 desired_gain = GAIN_COEFF_ZERO;
583 Delivery::no_outs_cuz_we_no_monitor (bool yn)
585 _no_outs_cuz_we_no_monitor = yn;
589 Delivery::set_name (const std::string& name)
591 bool ret = IOProcessor::set_name (name);
593 if (ret && _panshell) {
594 ret = _panshell->set_name (name);
600 bool ignore_output_change = false;
603 Delivery::output_changed (IOChange change, void* /*src*/)
605 if (change.type & IOChange::ConfigurationChanged) {
607 _output_buffers->attach_buffers (_output->ports ());
611 boost::shared_ptr<Panner>
612 Delivery::panner () const
615 return _panshell->panner();
617 return boost::shared_ptr<Panner>();