X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=libs%2Fardour%2Fdelivery.cc;h=5a4fbd3e1defe3c1f5bf5cc481f36fefd29ebd60;hb=e125c7807027b31e2fd2fb48ea117bb769c5f678;hp=44782650c16c23904bfe8104ef29dc69d0b1cde4;hpb=37e9a53180877db90e3d9e88ac916a2ed0473ae3;p=ardour.git diff --git a/libs/ardour/delivery.cc b/libs/ardour/delivery.cc index 44782650c1..5a4fbd3e1d 100644 --- a/libs/ardour/delivery.cc +++ b/libs/ardour/delivery.cc @@ -22,33 +22,27 @@ #include "pbd/enumwriter.h" #include "pbd/convert.h" -#include "ardour/midi_buffer.h" - -#include "ardour/debug.h" -#include "ardour/delivery.h" -#include "ardour/audio_buffer.h" -#include "ardour/audio_port.h" #include "ardour/amp.h" +#include "ardour/audioengine.h" #include "ardour/buffer_set.h" -#include "ardour/configuration.h" +#include "ardour/debug.h" +#include "ardour/delivery.h" #include "ardour/io.h" -#include "ardour/meter.h" #include "ardour/mute_master.h" -#include "ardour/panner.h" -#include "ardour/panner_shell.h" #include "ardour/pannable.h" +#include "ardour/panner_shell.h" #include "ardour/port.h" #include "ardour/session.h" -#include "ardour/audioengine.h" #include "i18n.h" +namespace ARDOUR { class Panner; } + using namespace std; using namespace PBD; using namespace ARDOUR; -PBD::Signal1 Delivery::CycleStart; -PBD::Signal0 Delivery::PannersLegal; +PBD::Signal0 Delivery::PannersLegal; bool Delivery::panners_legal = false; /* deliver to an existing IO object */ @@ -58,14 +52,15 @@ Delivery::Delivery (Session& s, boost::shared_ptr io, boost::shared_ptr(), (role_requires_output_ports (r) ? io : boost::shared_ptr()), name) , _role (r) , _output_buffers (new BufferSet()) - , _current_gain (1.0) + , _amp (new Amp (s)) , _no_outs_cuz_we_no_monitor (false) , _mute_master (mm) - , no_panner_reset (false) - , scnt (0) + , _no_panner_reset (false) { if (pannable) { - _panshell = boost::shared_ptr(new PannerShell (_name, _session, pannable)); + bool is_send = false; + if (r & (Delivery::Send|Delivery::Aux)) is_send = true; + _panshell = boost::shared_ptr(new PannerShell (_name, _session, pannable, is_send)); } _display_to_user = false; @@ -74,23 +69,24 @@ Delivery::Delivery (Session& s, boost::shared_ptr io, boost::shared_ptrchanged.connect_same_thread (*this, boost::bind (&Delivery::output_changed, this, _1, _2)); } - CycleStart.connect_same_thread (*this, boost::bind (&Delivery::cycle_start, this, _1)); + _amp->activate (); } /* deliver to a new IO object */ Delivery::Delivery (Session& s, boost::shared_ptr pannable, boost::shared_ptr mm, const string& name, Role r) - : IOProcessor(s, false, (role_requires_output_ports (r) ? true : false), name) + : IOProcessor(s, false, (role_requires_output_ports (r) ? true : false), name, "", DataType::AUDIO, (r == Send)) , _role (r) , _output_buffers (new BufferSet()) - , _current_gain (1.0) + , _amp (new Amp (s)) , _no_outs_cuz_we_no_monitor (false) , _mute_master (mm) - , no_panner_reset (false) - , scnt (0) + , _no_panner_reset (false) { if (pannable) { - _panshell = boost::shared_ptr(new PannerShell (_name, _session, pannable)); + bool is_send = false; + if (r & (Delivery::Send|Delivery::Aux)) is_send = true; + _panshell = boost::shared_ptr(new PannerShell (_name, _session, pannable, is_send)); } _display_to_user = false; @@ -99,13 +95,21 @@ Delivery::Delivery (Session& s, boost::shared_ptr pannable, boost::sha _output->changed.connect_same_thread (*this, boost::bind (&Delivery::output_changed, this, _1, _2)); } - CycleStart.connect_same_thread (*this, boost::bind (&Delivery::cycle_start, this, _1)); + _amp->activate (); } - Delivery::~Delivery() { DEBUG_TRACE (DEBUG::Destruction, string_compose ("delivery %1 destructor\n", _name)); + + /* this object should vanish from any signal callback lists + that it is on before we get any further. The full qualification + of the method name is not necessary, but is here to make it + clear that this call is about signals, not data flow connections. + */ + + ScopedConnectionList::drop_connections (); + delete _output_buffers; } @@ -126,14 +130,8 @@ Delivery::display_name () const } } -void -Delivery::cycle_start (pframes_t /*nframes*/) -{ - _no_outs_cuz_we_no_monitor = false; -} - bool -Delivery::can_support_io_configuration (const ChanCount& in, ChanCount& out) const +Delivery::can_support_io_configuration (const ChanCount& in, ChanCount& out) { if (_role == Main) { @@ -153,7 +151,7 @@ Delivery::can_support_io_configuration (const ChanCount& in, ChanCount& out) con } } else { fatal << "programming error: this should never be reached" << endmsg; - /*NOTREACHED*/ + abort(); /*NOTREACHED*/ } @@ -174,7 +172,7 @@ Delivery::can_support_io_configuration (const ChanCount& in, ChanCount& out) con } } else { fatal << "programming error: this should never be reached" << endmsg; - /*NOTREACHED*/ + abort(); /*NOTREACHED*/ } } else { @@ -188,7 +186,10 @@ Delivery::can_support_io_configuration (const ChanCount& in, ChanCount& out) con bool Delivery::configure_io (ChanCount in, ChanCount out) { - assert (!AudioEngine::instance()->process_lock().trylock()); +#ifndef NDEBUG + bool r = AudioEngine::instance()->process_lock().trylock(); + assert (!r && "trylock inside Delivery::configure_io"); +#endif /* check configuration by comparison with our I/O port configuration, if appropriate. see ::can_support_io_configuration() for comments @@ -212,7 +213,7 @@ Delivery::configure_io (ChanCount in, ChanCount out) if (_input->n_ports() != in) { if (_input->n_ports() != ChanCount::ZERO) { fatal << _name << " programming error: configure_io called with " << in << " and " << out << " with " << _input->n_ports() << " input ports" << endmsg; - /*NOTREACHED*/ + abort(); /*NOTREACHED*/ } else { /* I/O not yet configured */ } @@ -233,12 +234,11 @@ Delivery::configure_io (ChanCount in, ChanCount out) void Delivery::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, bool result_required) { - boost::shared_ptr panner; - assert (_output); PortSet& ports (_output->ports()); gain_t tgain; + bool need_amp = true; if (_output->n_ports ().get (_output->default_type()) == 0) { goto out; @@ -253,7 +253,8 @@ Delivery::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pf processing pathway that wants to use this->output_buffers() for some reason. */ - output_buffers().get_jack_port_addresses (ports, nframes); + // TODO delayline -- latency-compensation + output_buffers().get_backend_port_addresses (ports, nframes); // this Delivery processor is not a derived type, and thus we assume // we really can modify the buffers passed in (it is almost certainly @@ -262,55 +263,80 @@ Delivery::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pf tgain = target_gain (); - if (tgain != _current_gain) { - /* target gain has changed */ + if (tgain < GAIN_COEFF_SMALL && _amp->gain() < GAIN_COEFF_SMALL) { - Amp::apply_gain (bufs, nframes, _current_gain, tgain); - _current_gain = tgain; - - } else if (tgain == 0.0) { - - /* we were quiet last time, and we're still supposed to be quiet. - Silence the outputs, and make sure the buffers are quiet too, - */ + /* special case (but very common) fast path: + * + * if we are supposed to be silent, and we were already silent, + * then short-circuit the computation in Amp and just put silence into + * our output(s) + */ _output->silence (nframes); - if (result_required) { - Amp::apply_simple_gain (bufs, nframes, 0.0); + + if (!result_required) { + /* if !result_required, then the buffers won't actually + * be used. This means we don't actually need to silence + * them, because we've already filled the output ports + * with silence. + * + * but we just noted that result_required is true, + * and so we do need to run the amp to ensure + * that the buffers are silenced. + */ + need_amp = false; } - goto out; + } + + if (need_amp) { + + bufs.set_count (output_buffers().count ()); + + if (_role != Main) { + + /* inserts, external and internal sends have + * automatable gain and the Amp::run() method has + * already been executed by the time we get here. + * + * XXX we do not expose the automatable gain for + * Inserts as of September 2015. + */ - } else if (tgain != 1.0) { + } else { + + /* main outs have no automatable gain, the amp is just + * used for ramping gain changes caused by monitoring + * state changes. + */ + + _amp->set_gain (tgain, this); + _amp->run (bufs, 0, 0, nframes, false); + + } - /* target gain has not changed, but is not unity */ - Amp::apply_simple_gain (bufs, nframes, tgain); + } else { + goto out; } - if (_panshell) { - panner = _panshell->panner(); + // Speed quietning + + if (fabs (_session.transport_speed()) > 1.5 && Config->get_quieten_at_speed ()) { + Amp::apply_simple_gain (bufs, nframes, speed_quietning, false); } -#if 0 - if (_session.transport_rolling()) { - cerr << name() << " first value written : " << scnt << endl; - for (BufferSet::audio_iterator b = bufs.audio_begin(); b != bufs.audio_end(); ++b) { - Sample* p = b->data (); - float s = (float) scnt; - for (pframes_t n = 0; n < nframes; ++n) { - p[n] = s * 0.001; - s += 1.0; - } - } - scnt += nframes; - } -#endif + // Panning - if (panner && !panner->bypassed()) { + if (_panshell && !_panshell->bypassed() && _panshell->panner()) { // Use the panner to distribute audio to output port buffers _panshell->run (bufs, output_buffers(), start_frame, end_frame, nframes); + // MIDI data will not have been delivered by the panner + + if (bufs.count().n_midi() > 0 && ports.count().n_midi () > 0) { + _output->copy_to_outputs (bufs, DataType::MIDI, nframes, 0); + } } else { @@ -349,7 +375,10 @@ Delivery::state (bool full_state) node.add_property("role", enum_2_string(_role)); if (_panshell) { - node.add_child_nocopy (_panshell->state (full_state)); + node.add_child_nocopy (_panshell->get_state ()); + if (_panshell->pannable()) { + node.add_child_nocopy (_panshell->pannable()->get_state ()); + } } return node; @@ -371,7 +400,7 @@ Delivery::set_state (const XMLNode& node, int version) // std::cerr << this << ' ' << _name << " NO ROLE INFO\n"; } - XMLNode* pan_node = node.child (X_("Panner")); + XMLNode* pan_node = node.child (X_("PannerShell")); if (pan_node && _panshell) { _panshell->set_state (*pan_node, version); @@ -379,34 +408,40 @@ Delivery::set_state (const XMLNode& node, int version) reset_panner (); + XMLNode* pannnode = node.child (X_("Pannable")); + if (_panshell && _panshell->panner() && pannnode) { + _panshell->pannable()->set_state (*pannnode, version); + } + return 0; } void -Delivery::reset_panner () +Delivery::unpan () { - if (_role == Listen) { - /* monitor out gets no panner */ - return; - } + /* caller must hold process lock */ - if (panners_legal) { - if (!no_panner_reset) { + _panshell.reset (); +} - uint32_t ntargets; +uint32_t +Delivery::pan_outs () const +{ + if (_output) { + return _output->n_ports().n_audio(); + } - if (_output) { - ntargets = _output->n_ports().n_audio(); - } else { - ntargets = _configured_output.n_audio(); - } + return _configured_output.n_audio(); +} - if (_panshell) { - _panshell->configure_io (ChanCount (DataType::AUDIO, pans_required()), ChanCount (DataType::AUDIO, ntargets)); - - if (_role == Main) { - _panshell->pannable()->set_panner (_panshell->panner()); - } +void +Delivery::reset_panner () +{ + if (panners_legal) { + if (!_no_panner_reset) { + + if (_panshell && _role != Insert && _role != Listen) { + _panshell->configure_io (ChanCount (DataType::AUDIO, pans_required()), ChanCount (DataType::AUDIO, pan_outs())); } } @@ -416,66 +451,57 @@ Delivery::reset_panner () } } -int +void Delivery::panners_became_legal () { - uint32_t ntargets; - - if (_output) { - ntargets = _output->n_ports().n_audio(); - } else { - ntargets = _configured_output.n_audio(); - } - - if (_panshell) { - _panshell->configure_io (ChanCount (DataType::AUDIO, pans_required()), ChanCount (DataType::AUDIO, ntargets)); - - if (_role == Main) { - _panshell->pannable()->set_panner (_panshell->panner()); - } + if (_panshell && _role != Insert) { + _panshell->configure_io (ChanCount (DataType::AUDIO, pans_required()), ChanCount (DataType::AUDIO, pan_outs())); } panner_legal_c.disconnect (); - return 0; } void Delivery::defer_pan_reset () { - no_panner_reset = true; + _no_panner_reset = true; } void Delivery::allow_pan_reset () { - no_panner_reset = false; + _no_panner_reset = false; reset_panner (); } int -Delivery::disable_panners (void) +Delivery::disable_panners () { panners_legal = false; return 0; } -int +void Delivery::reset_panners () { panners_legal = true; - return *PannersLegal (); + PannersLegal (); } void -Delivery::flush_buffers (framecnt_t nframes, framepos_t time) +Delivery::flush_buffers (framecnt_t nframes) { /* io_lock, not taken: function must be called from Session::process() calltree */ + if (!_output) { + return; + } + PortSet& ports (_output->ports()); for (PortSet::iterator i = ports.begin(); i != ports.end(); ++i) { - (*i).flush_buffers (nframes, time); + i->flush_buffers (nframes); } } @@ -492,7 +518,7 @@ Delivery::transport_stopped (framepos_t now) PortSet& ports (_output->ports()); for (PortSet::iterator i = ports.begin(); i != ports.end(); ++i) { - (*i).transport_stopped (); + i->transport_stopped (); } } } @@ -504,7 +530,7 @@ Delivery::realtime_locate () PortSet& ports (_output->ports()); for (PortSet::iterator i = ports.begin(); i != ports.end(); ++i) { - (*i).realtime_locate (); + i->realtime_locate (); } } } @@ -515,15 +541,15 @@ Delivery::target_gain () /* if we've been requested to deactivate, our target gain is zero */ if (!_pending_active) { - return 0.0; + return GAIN_COEFF_ZERO; } /* if we've been told not to output because its a monitoring situation and we're not monitoring, then be quiet. */ - if (_no_outs_cuz_we_no_monitor) { - return 0.0; + if (_role == Main && _session.config.get_use_monitor_fades() && _no_outs_cuz_we_no_monitor) { + return GAIN_COEFF_ZERO; } MuteMaster::MutePoint mp = MuteMaster::Main; // stupid gcc uninit warning @@ -555,7 +581,7 @@ Delivery::target_gain () it gets its signal from the master out. */ - desired_gain = 0.0; + desired_gain = GAIN_COEFF_ZERO; } @@ -573,13 +599,15 @@ Delivery::set_name (const std::string& name) { bool ret = IOProcessor::set_name (name); - if (ret) { + if (ret && _panshell) { ret = _panshell->set_name (name); } return ret; } +bool ignore_output_change = false; + void Delivery::output_changed (IOChange change, void* /*src*/) { @@ -598,3 +626,4 @@ Delivery::panner () const return boost::shared_ptr(); } } +