X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Froute.cc;h=046bf7998e520ca0e557227301e4ac1bb2527431;hb=10933e200369ecceb2c8b3a52be41b930955d269;hp=3f68e266ebbacefcf6eb5ed28c0e74bd9f9d44d3;hpb=0eee85f43b2435277c7cccda8e5145761bcb98a8;p=ardour.git diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 3f68e266eb..046bf7998e 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -26,6 +26,8 @@ #include #include +#include + #include "pbd/xml++.h" #include "pbd/enumwriter.h" #include "pbd/memento_command.h" @@ -33,23 +35,20 @@ #include "pbd/convert.h" #include "pbd/boost_debug.h" -#include "evoral/Curve.hpp" - #include "ardour/amp.h" +#include "ardour/audio_buffer.h" #include "ardour/audio_port.h" #include "ardour/audioengine.h" #include "ardour/buffer.h" #include "ardour/buffer_set.h" -#include "ardour/configuration.h" -#include "ardour/cycle_timer.h" +#include "ardour/capturing_processor.h" #include "ardour/debug.h" #include "ardour/delivery.h" -#include "ardour/dB.h" -#include "ardour/internal_send.h" #include "ardour/internal_return.h" -#include "ardour/ladspa_plugin.h" +#include "ardour/internal_send.h" #include "ardour/meter.h" -#include "ardour/mix.h" +#include "ardour/midi_buffer.h" +#include "ardour/midi_port.h" #include "ardour/monitor_processor.h" #include "ardour/pannable.h" #include "ardour/panner.h" @@ -58,15 +57,12 @@ #include "ardour/port.h" #include "ardour/port_insert.h" #include "ardour/processor.h" -#include "ardour/profile.h" #include "ardour/route.h" #include "ardour/route_group.h" #include "ardour/send.h" #include "ardour/session.h" -#include "ardour/timestamps.h" -#include "ardour/utils.h" #include "ardour/unknown_processor.h" -#include "ardour/capturing_processor.h" +#include "ardour/utils.h" #include "i18n.h" @@ -74,8 +70,7 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -uint32_t Route::order_key_cnt = 0; -PBD::Signal1 Route::SyncOrderKeys; +PBD::Signal0 Route::SyncOrderKeys; PBD::Signal0 Route::RemoteControlIDChange; Route::Route (Session& sess, string name, Flag flg, DataType default_type) @@ -89,6 +84,7 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type) , _flags (flg) , _pending_declick (true) , _meter_point (MeterPostFader) + , _meter_type (MeterPeak) , _self_solo (false) , _soloed_by_others_upstream (0) , _soloed_by_others_downstream (0) @@ -101,20 +97,18 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type) , _have_internal_generator (false) , _solo_safe (false) , _default_type (default_type) + , _order_key (0) + , _has_order_key (false) , _remote_control_id (0) , _in_configure_processors (false) + , _initial_io_setup (false) , _custom_meter_position_noted (false) , _last_custom_meter_was_at_end (false) { - processor_max_streams.reset(); - order_keys[N_("signal")] = order_key_cnt++; - if (is_master()) { - set_remote_control_id (MasterBusRemoteControlID); - } else if (is_monitor()) { - set_remote_control_id (MonitorBusRemoteControlID); + _meter_type = MeterK20; } - + processor_max_streams.reset(); } int @@ -146,6 +140,7 @@ Route::init () _input->PortCountChanging.connect_same_thread (*this, boost::bind (&Route::input_port_count_changing, this, _1)); _output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2)); + _output->PortCountChanging.connect_same_thread (*this, boost::bind (&Route::output_port_count_changing, this, _1)); /* add amp processor */ @@ -156,7 +151,8 @@ Route::init () they will be added to _processors by setup_invisible_processors () */ - _meter.reset (new PeakMeter (_session)); + _meter.reset (new PeakMeter (_session, _name)); + _meter->set_owner (this); _meter->set_display_to_user (false); _meter->activate (); @@ -175,7 +171,7 @@ Route::init () _monitor_control->activate (); } - if (is_master() || is_monitor() || is_hidden()) { + if (is_master() || is_monitor() || is_auditioner()) { _mute_master->set_solo_ignore (true); } @@ -184,8 +180,7 @@ Route::init () Metering::Meter.connect_same_thread (*this, (boost::bind (&Route::meter, this))); { - /* run a configure so that the invisible processors get set up */ - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); configure_processors (0); } @@ -205,7 +200,7 @@ Route::~Route () be half-destroyed by now */ - Glib::RWLock::WriterLock lm (_processor_lock); + Glib::Threads::RWLock::WriterLock lm (_processor_lock); for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { (*i)->drop_references (); } @@ -215,6 +210,16 @@ Route::~Route () void Route::set_remote_control_id (uint32_t id, bool notify_class_listeners) +{ + if (Config->get_remote_model() != UserOrdered) { + return; + } + + set_remote_control_id_internal (id, notify_class_listeners); +} + +void +Route::set_remote_control_id_internal (uint32_t id, bool notify_class_listeners) { /* force IDs for master/monitor busses and prevent any other route from accidentally getting these IDs @@ -229,6 +234,10 @@ Route::set_remote_control_id (uint32_t id, bool notify_class_listeners) id = MonitorBusRemoteControlID; } + if (id < 1) { + return; + } + /* don't allow it to collide */ if (!is_master () && !is_monitor() && @@ -236,9 +245,10 @@ Route::set_remote_control_id (uint32_t id, bool notify_class_listeners) id += MonitorBusRemoteControlID; } - if (id != _remote_control_id) { + if (id != remote_control_id()) { _remote_control_id = id; RemoteControlIDChanged (); + if (notify_class_listeners) { RemoteControlIDChange (); } @@ -248,88 +258,68 @@ Route::set_remote_control_id (uint32_t id, bool notify_class_listeners) uint32_t Route::remote_control_id() const { + if (is_master()) { + return MasterBusRemoteControlID; + } + + if (is_monitor()) { + return MonitorBusRemoteControlID; + } + return _remote_control_id; } -int32_t -Route::order_key (std::string const & name) const +bool +Route::has_order_key () const { - OrderKeys::const_iterator i = order_keys.find (name); - if (i == order_keys.end()) { - return -1; - } + return _has_order_key; +} - return i->second; +uint32_t +Route::order_key () const +{ + return _order_key; } void -Route::set_order_key (std::string const & name, int32_t n) +Route::set_remote_control_id_explicit (uint32_t rid) { - bool changed = false; - - /* This method looks more complicated than it should, but - it's important that we don't emit order_key_changed unless - it actually has, as expensive things happen on receipt of that - signal. - */ - - if (order_keys.find(name) == order_keys.end() || order_keys[name] != n) { - order_keys[name] = n; - changed = true; + if (is_master() || is_monitor() || is_auditioner()) { + /* hard-coded remote IDs, or no remote ID */ + return; } - if (Config->get_sync_all_route_ordering()) { - for (OrderKeys::iterator x = order_keys.begin(); x != order_keys.end(); ++x) { - if (x->second != n) { - x->second = n; - changed = true; - } - } + if (_remote_control_id != rid) { + DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1: set edit-based RID to %2\n", name(), rid)); + _remote_control_id = rid; + RemoteControlIDChanged (); /* EMIT SIGNAL (per-route) */ } - if (changed) { - order_key_changed (); /* EMIT SIGNAL */ - _session.set_dirty (); - } + /* don't emit the class-level RID signal RemoteControlIDChange here, + leave that to the entity that changed the order key, so that we + don't get lots of emissions for no good reasons (e.g. when changing + all route order keys). + + See Session::sync_remote_id_from_order_keys() for the (primary|only) + spot where that is emitted. + */ } -/** Set all order keys to be the same as that for `base', if such a key - * exists in this route. - * @param base Base key. - */ void -Route::sync_order_keys (std::string const & base) +Route::set_order_key (uint32_t n) { - if (order_keys.empty()) { - return; - } - - OrderKeys::iterator i; - int32_t key; + _has_order_key = true; - if ((i = order_keys.find (base)) == order_keys.end()) { - /* key doesn't exist, use the first existing key (during session initialization) */ - i = order_keys.begin(); - key = i->second; - ++i; - } else { - /* key exists - use it and reset all others (actually, itself included) */ - key = i->second; - i = order_keys.begin(); + if (_order_key == n) { + return; } - bool changed = false; + _order_key = n; - for (; i != order_keys.end(); ++i) { - if (i->second != key) { - i->second = key; - changed = true; - } - } + DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("%1 order key set to %2\n", + name(), order_key ())); - if (changed) { - order_key_changed (); /* EMIT SIGNAL */ - } + _session.set_dirty (); } string @@ -429,10 +419,12 @@ Route::process_output_buffers (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick, bool gain_automation_ok) { - bufs.set_is_silent (false); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK); + assert(lm.locked()); /* figure out if we're going to use gain automation */ if (gain_automation_ok) { + _amp->set_gain_automation_buffer (_session.gain_automation_buffer ()); _amp->setup_gain_automation (start_frame, end_frame, nframes); } else { _amp->apply_gain_automation (false); @@ -442,8 +434,8 @@ Route::process_output_buffers (BufferSet& bufs, on a transition between monitoring states we get a de-clicking gain change in the _main_outs delivery. */ - _main_outs->no_outs_cuz_we_no_monitor (monitoring_state () == MonitoringSilence); + _main_outs->no_outs_cuz_we_no_monitor (monitoring_state () == MonitoringSilence); /* ------------------------------------------------------------------------------------------- GLOBAL DECLICK (for transport changes etc.) @@ -524,11 +516,10 @@ Route::process_output_buffers (BufferSet& bufs, if (bufs.count() != (*i)->input_streams()) { DEBUG_TRACE ( DEBUG::Processors, string_compose ( - "%1 bufs = %2 input for %3 = %4\n", + "input port mismatch %1 bufs = %2 input for %3 = %4\n", _name, bufs.count(), (*i)->name(), (*i)->input_streams() ) ); - continue; } } #endif @@ -549,39 +540,27 @@ Route::n_process_buffers () } void -Route::passthru (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick) +Route::monitor_run (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick) { - BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers()); + assert (is_monitor()); + BufferSet& bufs (_session.get_route_buffers (n_process_buffers())); + fill_buffers_with_input (bufs, _input, nframes); + passthru (bufs, start_frame, end_frame, nframes, declick); +} +void +Route::passthru (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick) +{ _silent = false; - assert (bufs.available() >= input_streams()); - - if (_input->n_ports() == ChanCount::ZERO) { - silence_unlocked (nframes); - } - - bufs.set_count (input_streams()); - if (is_monitor() && _session.listening() && !_session.is_auditioning()) { /* control/monitor bus ignores input ports when something is feeding the listen "stream". data will "arrive" into the route from the intreturn processor element. */ - bufs.silence (nframes, 0); - - } else { - - for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { - BufferSet::iterator o = bufs.begin(*t); - PortSet& ports (_input->ports()); - - for (PortSet::iterator i = ports.begin(*t); i != ports.end(*t); ++i, ++o) { - o->read_from (i->get_buffer(nframes), nframes); - } - } + bufs.silence (nframes, 0); } write_out_of_band_data (bufs, start_frame, end_frame, nframes); @@ -591,7 +570,7 @@ Route::passthru (framepos_t start_frame, framepos_t end_frame, pframes_t nframes void Route::passthru_silence (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick) { - BufferSet& bufs (_session.get_silent_buffers (n_process_buffers())); + BufferSet& bufs (_session.get_route_buffers (n_process_buffers(), true)); bufs.set_count (_input->n_ports()); write_out_of_band_data (bufs, start_frame, end_frame, nframes); @@ -654,6 +633,7 @@ void Route::set_solo (bool yn, void *src) { if (_solo_safe) { + DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo change due to solo-safe\n", name())); return; } @@ -662,6 +642,9 @@ Route::set_solo (bool yn, void *src) return; } + DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: set solo => %2, src: %3 grp ? %4 currently self-soloed ? %5\n", + name(), yn, src, (src == _route_group), self_soloed())); + if (self_soloed() != yn) { set_self_solo (yn); set_mute_master_solo (); @@ -673,6 +656,7 @@ Route::set_solo (bool yn, void *src) void Route::set_self_solo (bool yn) { + DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: set SELF solo => %2\n", name(), yn)); _self_solo = yn; } @@ -680,9 +664,13 @@ void Route::mod_solo_by_others_upstream (int32_t delta) { if (_solo_safe) { + DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo-by-upstream due to solo-safe\n", name())); return; } + DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod solo-by-upstream by %2, current up = %3 down = %4\n", + name(), delta, _soloed_by_others_upstream, _soloed_by_others_downstream)); + uint32_t old_sbu = _soloed_by_others_upstream; if (delta < 0) { @@ -736,9 +724,13 @@ void Route::mod_solo_by_others_downstream (int32_t delta) { if (_solo_safe) { + DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo-by-downstream due to solo safe\n", name())); return; } + DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod solo-by-downstream by %2, current up = %3 down = %4\n", + name(), delta, _soloed_by_others_upstream, _soloed_by_others_downstream)); + if (delta < 0) { if (_soloed_by_others_downstream >= (uint32_t) abs (delta)) { _soloed_by_others_downstream += delta; @@ -764,7 +756,7 @@ Route::set_mute_master_solo () void Route::set_solo_isolated (bool yn, void *src) { - if (is_master() || is_monitor() || is_hidden()) { + if (is_master() || is_monitor() || is_auditioner()) { return; } @@ -778,7 +770,7 @@ Route::set_solo_isolated (bool yn, void *src) boost::shared_ptr routes = _session.get_routes (); for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) { - if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_hidden()) { + if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) { continue; } @@ -878,7 +870,7 @@ dump_processors(const string& name, const list >& p boost::shared_ptr Route::before_processor_for_placement (Placement p) { - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); ProcessorList::iterator loc; @@ -903,7 +895,7 @@ Route::before_processor_for_index (int index) return boost::shared_ptr (); } - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); ProcessorList::iterator i = _processors.begin (); int j = 0; @@ -951,12 +943,13 @@ Route::add_processor (boost::shared_ptr processor, boost::shared_ptr< DEBUG_TRACE (DEBUG::Processors, string_compose ( "%1 adding processor %2\n", name(), processor->name())); - if (!_session.engine().connected() || !processor) { + if (!AudioEngine::instance()->connected() || !processor) { return 1; } { - Glib::RWLock::WriterLock lm (_processor_lock); + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); + Glib::Threads::RWLock::WriterLock lm (_processor_lock); ProcessorState pstate (this); boost::shared_ptr pi; @@ -991,13 +984,12 @@ Route::add_processor (boost::shared_ptr processor, boost::shared_ptr< } _processors.insert (loc, processor); + processor->set_owner (this); // Set up processor list channels. This will set processor->[input|output]_streams(), // configure redirect ports properly, etc. { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); - if (configure_processors_unlocked (err)) { pstate.restore (); configure_processors_unlocked (0); // it worked before we tried to add it ... @@ -1014,7 +1006,7 @@ Route::add_processor (boost::shared_ptr processor, boost::shared_ptr< } - if (activation_allowed) { + if (activation_allowed && !_session.get_disable_all_loaded_plugins()) { processor->activate (); } @@ -1023,6 +1015,7 @@ Route::add_processor (boost::shared_ptr processor, boost::shared_ptr< _output->set_user_latency (0); } + reset_instrument_info (); processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ set_processor_positions (); @@ -1062,7 +1055,7 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version) if (prop->value() == "ladspa" || prop->value() == "Ladspa" || prop->value() == "lv2" || - prop->value() == "vst" || + prop->value() == "windows-vst" || prop->value() == "lxvst" || prop->value() == "audiounit") { @@ -1124,7 +1117,8 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr } { - Glib::RWLock::WriterLock lm (_processor_lock); + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); + Glib::Threads::RWLock::WriterLock lm (_processor_lock); ProcessorState pstate (this); for (ProcessorList::const_iterator i = others.begin(); i != others.end(); ++i) { @@ -1140,13 +1134,14 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr } _processors.insert (loc, *i); + (*i)->set_owner (this); if ((*i)->active()) { (*i)->activate (); } + /* Think: does this really need to be called for every processor in the loop? */ { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); if (configure_processors_unlocked (err)) { pstate.restore (); configure_processors_unlocked (0); // it worked before we tried to add it ... @@ -1171,6 +1166,7 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr _output->set_user_latency (0); } + reset_instrument_info (); processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ set_processor_positions (); @@ -1196,7 +1192,7 @@ Route::placement_range(Placement p, ProcessorList::iterator& start, ProcessorLis void Route::disable_processors (Placement p) { - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); ProcessorList::iterator start, end; placement_range(p, start, end); @@ -1213,7 +1209,7 @@ Route::disable_processors (Placement p) void Route::disable_processors () { - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { (*i)->deactivate (); @@ -1228,7 +1224,7 @@ Route::disable_processors () void Route::disable_plugins (Placement p) { - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); ProcessorList::iterator start, end; placement_range(p, start, end); @@ -1247,7 +1243,7 @@ Route::disable_plugins (Placement p) void Route::disable_plugins () { - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { if (boost::dynamic_pointer_cast (*i)) { @@ -1262,7 +1258,7 @@ Route::disable_plugins () void Route::ab_plugins (bool forward) { - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); if (forward) { @@ -1321,7 +1317,8 @@ Route::clear_processors (Placement p) } { - Glib::RWLock::WriterLock lm (_processor_lock); + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); + Glib::Threads::RWLock::WriterLock lm (_processor_lock); ProcessorList new_list; ProcessorStreams err; bool seen_amp = false; @@ -1365,11 +1362,7 @@ Route::clear_processors (Placement p) } _processors = new_list; - - { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); - configure_processors_unlocked (&err); // this can't fail - } + configure_processors_unlocked (&err); // this can't fail } processor_max_streams.reset(); @@ -1377,6 +1370,8 @@ Route::clear_processors (Placement p) processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ set_processor_positions (); + reset_instrument_info (); + if (!already_deleting) { _session.clear_deletion_in_progress(); } @@ -1385,6 +1380,11 @@ Route::clear_processors (Placement p) int Route::remove_processor (boost::shared_ptr processor, ProcessorStreams* err, bool need_process_lock) { + // TODO once the export point can be configured properly, do something smarter here + if (processor == _capturing_processor) { + _capturing_processor.reset(); + } + /* these can never be removed */ if (processor == _amp || processor == _meter || processor == _main_outs) { @@ -1398,7 +1398,11 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream processor_max_streams.reset(); { - Glib::RWLock::WriterLock lm (_processor_lock); + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK); + if (need_process_lock) { + lx.acquire(); + } + Glib::Threads::RWLock::WriterLock lm (_processor_lock); ProcessorState pstate (this); ProcessorList::iterator i; @@ -1419,12 +1423,7 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream boost::shared_ptr iop; if ((iop = boost::dynamic_pointer_cast (*i)) != 0) { - if (iop->input()) { - iop->input()->disconnect (this); - } - if (iop->output()) { - iop->output()->disconnect (this); - } + iop->disconnect (); } i = _processors.erase (i); @@ -1443,22 +1442,11 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream return 1; } - if (need_process_lock) { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); - - if (configure_processors_unlocked (err)) { - pstate.restore (); - /* we know this will work, because it worked before :) */ - configure_processors_unlocked (0); - return -1; - } - } else { - if (configure_processors_unlocked (err)) { - pstate.restore (); - /* we know this will work, because it worked before :) */ - configure_processors_unlocked (0); - return -1; - } + if (configure_processors_unlocked (err)) { + pstate.restore (); + /* we know this will work, because it worked before :) */ + configure_processors_unlocked (0); + return -1; } _have_internal_generator = false; @@ -1473,8 +1461,12 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream } } } + if (need_process_lock) { + lx.release(); + } } + reset_instrument_info (); processor->drop_references (); processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ set_processor_positions (); @@ -1494,7 +1486,8 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams* processor_max_streams.reset(); { - Glib::RWLock::WriterLock lm (_processor_lock); + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); + Glib::Threads::RWLock::WriterLock lm (_processor_lock); ProcessorState pstate (this); ProcessorList::iterator i; @@ -1540,16 +1533,13 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams* _output->set_user_latency (0); - { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); - - if (configure_processors_unlocked (err)) { - pstate.restore (); - /* we know this will work, because it worked before :) */ - configure_processors_unlocked (0); - return -1; - } + if (configure_processors_unlocked (err)) { + pstate.restore (); + /* we know this will work, because it worked before :) */ + configure_processors_unlocked (0); + return -1; } + //lx.unlock(); _have_internal_generator = false; @@ -1571,20 +1561,86 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams* (*i)->drop_references (); } + reset_instrument_info (); processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ set_processor_positions (); return 0; } +#if 0 +/* currently unused (again) -- but will come in handy soon (again) + * once there is an option to link route + delivery panner settings + */ +void +Route::set_custom_panner_uri (std::string const panner_uri) +{ + if (_in_configure_processors) { + DEBUG_TRACE (DEBUG::Panning, string_compose (_("Route::set_custom_panner_uri '%1' -- called while in_configure_processors\n"), name())); + return; + } + + if (!_main_outs->panner_shell()->set_user_selected_panner_uri(panner_uri)) { + DEBUG_TRACE (DEBUG::Panning, string_compose (_("Route::set_custom_panner_uri '%1 '%2' -- no change needed\n"), name(), panner_uri)); + /* no change needed */ + return; + } + + DEBUG_TRACE (DEBUG::Panning, string_compose (_("Route::set_custom_panner_uri '%1 '%2' -- reconfigure I/O\n"), name(), panner_uri)); + + /* reconfigure I/O -- re-initialize panner modules */ + { + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); + Glib::Threads::RWLock::WriterLock lm (_processor_lock); + + for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p) { + boost::shared_ptr dl; + boost::shared_ptr panner; + if ((dl = boost::dynamic_pointer_cast (*p)) == 0) { + continue; + } + if (!dl->panner_shell()) { + continue; + } + if (!(panner = dl->panner_shell()->panner())) { + continue; + } + /* _main_outs has already been set before the loop. + * Ignore the return status here. It need reconfiguration */ + if (dl->panner_shell() != _main_outs->panner_shell()) { + if (!dl->panner_shell()->set_user_selected_panner_uri(panner_uri)) { + continue; + } + } + + ChanCount in = panner->in(); + ChanCount out = panner->out(); + dl->panner_shell()->configure_io(in, out); + dl->panner_shell()->pannable()->set_panner(dl->panner_shell()->panner()); + } + } + + processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + _session.set_dirty (); +} +#endif + +void +Route::reset_instrument_info () +{ + boost::shared_ptr instr = the_instrument(); + if (instr) { + _instrument_info.set_internal_instrument (instr); + } +} + /** Caller must hold process lock */ int Route::configure_processors (ProcessorStreams* err) { assert (!AudioEngine::instance()->process_lock().trylock()); - if (!_in_configure_processors) { - Glib::RWLock::WriterLock lm (_processor_lock); + Glib::Threads::RWLock::WriterLock lm (_processor_lock); return configure_processors_unlocked (err); } @@ -1600,7 +1656,7 @@ Route::input_streams () const list > Route::try_configure_processors (ChanCount in, ProcessorStreams* err) { - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); return try_configure_processors_unlocked (in, err); } @@ -1620,7 +1676,8 @@ Route::try_configure_processors_unlocked (ChanCount in, ProcessorStreams* err) if (boost::dynamic_pointer_cast (*p)) { DEBUG_TRACE (DEBUG::Processors, "--- CONFIGURE ABORTED due to unknown processor.\n"); - break; + DEBUG_TRACE (DEBUG::Processors, "}\n"); + return list > (); } if ((*p)->can_support_io_configuration(in, out)) { @@ -1670,6 +1727,9 @@ Route::configure_processors_unlocked (ProcessorStreams* err) } ChanCount out; + bool seen_mains_out = false; + processor_out_streams = _input->n_ports(); + processor_max_streams.reset(); list< pair >::iterator c = configuration.begin(); for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++c) { @@ -1682,8 +1742,21 @@ Route::configure_processors_unlocked (ProcessorStreams* err) processor_max_streams = ChanCount::max(processor_max_streams, c->first); processor_max_streams = ChanCount::max(processor_max_streams, c->second); out = c->second; + + if (boost::dynamic_pointer_cast (*p) + && boost::dynamic_pointer_cast (*p)->role() == Delivery::Main) { + /* main delivery will increase port count to match input. + * the Delivery::Main is usually the last processor - followed only by + * 'MeterOutput'. + */ + seen_mains_out = true; + } + if (!seen_mains_out) { + processor_out_streams = out; + } } + if (_meter) { _meter->reset_max_channels (processor_max_streams); } @@ -1705,7 +1778,7 @@ Route::configure_processors_unlocked (ProcessorStreams* err) void Route::all_visible_processors_active (bool state) { - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); if (_processors.empty()) { return; @@ -1736,7 +1809,8 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err */ { - Glib::RWLock::WriterLock lm (_processor_lock); + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); + Glib::Threads::RWLock::WriterLock lm (_processor_lock); ProcessorState pstate (this); ProcessorList::iterator oiter; @@ -1797,13 +1871,9 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err /* If the meter is in a custom position, find it and make a rough note of its position */ maybe_note_meter_position (); - { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); - - if (configure_processors_unlocked (err)) { - pstate.restore (); - return -1; - } + if (configure_processors_unlocked (err)) { + pstate.restore (); + return -1; } } @@ -1848,28 +1918,14 @@ Route::state(bool full_state) node->add_property("denormal-protection", _denormal_protection?"yes":"no"); node->add_property("meter-point", enum_2_string (_meter_point)); + node->add_property("meter-type", enum_2_string (_meter_type)); + if (_route_group) { node->add_property("route-group", _route_group->name()); } - string order_string; - OrderKeys::iterator x = order_keys.begin(); - - while (x != order_keys.end()) { - order_string += string ((*x).first); - order_string += '='; - snprintf (buf, sizeof(buf), "%ld", (*x).second); - order_string += buf; - - ++x; - - if (x == order_keys.end()) { - break; - } - - order_string += ':'; - } - node->add_property ("order-keys", order_string); + snprintf (buf, sizeof (buf), "%d", _order_key); + node->add_property ("order-key", buf); node->add_property ("self-solo", (_self_solo ? "yes" : "no")); snprintf (buf, sizeof (buf), "%d", _soloed_by_others_upstream); node->add_property ("soloed-by-upstream", buf); @@ -1912,7 +1968,7 @@ Route::state(bool full_state) boost::shared_ptr is; if ((is = boost::dynamic_pointer_cast (*i)) != 0) { - if (is->role() == Delivery::Aux || is->role() == Delivery::Listen) { + if (is->role() == Delivery::Listen) { continue; } } @@ -1959,6 +2015,7 @@ Route::set_state (const XMLNode& node, int version) } set_id (node); + _initial_io_setup = true; if ((prop = node.property (X_("flags"))) != 0) { _flags = Flag (string_2_enum (prop->value(), _flags)); @@ -1966,7 +2023,7 @@ Route::set_state (const XMLNode& node, int version) _flags = Flag (0); } - if (is_master() || is_monitor() || is_hidden()) { + if (is_master() || is_monitor() || is_auditioner()) { _mute_master->set_solo_ignore (true); } @@ -2005,7 +2062,6 @@ Route::set_state (const XMLNode& node, int version) processor_state.add_child_copy (*child); } - if (child->name() == X_("Pannable")) { if (_pannable) { _pannable->set_state (*child, version); @@ -2023,8 +2079,17 @@ Route::set_state (const XMLNode& node, int version) } } + if ((prop = node.property (X_("meter-type"))) != 0) { + _meter_type = MeterType (string_2_enum (prop->value (), _meter_type)); + } + + _initial_io_setup = false; + set_processor_state (processor_state); + // this looks up the internal instrument in processors + reset_instrument_info(); + if ((prop = node.property ("self-solo")) != 0) { set_self_solo (string_is_affirmative (prop->value())); } @@ -2061,7 +2126,11 @@ Route::set_state (const XMLNode& node, int version) set_active (yn, this); } - if ((prop = node.property (X_("order-keys"))) != 0) { + if ((prop = node.property (X_("order-key"))) != 0) { // New order key (no separate mixer/editor ordering) + set_order_key (atoi(prop->value())); + } + + if ((prop = node.property (X_("order-keys"))) != 0) { // Deprecated order keys int32_t n; @@ -2078,7 +2147,12 @@ Route::set_state (const XMLNode& node, int version) error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining) << endmsg; } else { - set_order_key (remaining.substr (0, equal), n); + string keyname = remaining.substr (0, equal); + + if ((keyname == "EditorSort") || (keyname == "editor")) { + cerr << "Setting " << name() << " order key to " << n << " using saved Editor order." << endl; + set_order_key (n); + } } } @@ -2094,7 +2168,7 @@ Route::set_state (const XMLNode& node, int version) if ((prop = node.property (X_("processor-after-last-custom-meter"))) != 0) { PBD::ID id (prop->value ()); - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); ProcessorList::const_iterator i = _processors.begin (); while (i != _processors.end() && (*i)->id() != id) { ++i; @@ -2123,13 +2197,15 @@ Route::set_state (const XMLNode& node, int version) } else if (child->name() == Controllable::xml_node_name && (prop = child->property("name")) != 0) { if (prop->value() == "solo") { _solo_control->set_state (*child, version); + } else if (prop->value() == "mute") { + _mute_control->set_state (*child, version); } } else if (child->name() == X_("RemoteControl")) { if ((prop = child->property (X_("id"))) != 0) { int32_t x; sscanf (prop->value().c_str(), "%d", &x); - set_remote_control_id (x); + set_remote_control_id_internal (x); } } else if (child->name() == X_("MuteMaster")) { @@ -2160,11 +2236,17 @@ Route::set_state_2X (const XMLNode& node, int version) } if ((prop = node.property (X_("flags"))) != 0) { - _flags = Flag (string_2_enum (prop->value(), _flags)); + string f = prop->value (); + boost::replace_all (f, "ControlOut", "MonitorOut"); + _flags = Flag (string_2_enum (f, _flags)); } else { _flags = Flag (0); } + if (is_master() || is_monitor() || is_auditioner()) { + _mute_master->set_solo_ignore (true); + } + if ((prop = node.property (X_("phase-invert"))) != 0) { boost::dynamic_bitset<> p (_input->n_ports().n_audio ()); if (string_is_affirmative (prop->value ())) { @@ -2270,7 +2352,12 @@ Route::set_state_2X (const XMLNode& node, int version) error << string_compose (_("badly formed order key string in state file! [%1] ... ignored."), remaining) << endmsg; } else { - set_order_key (remaining.substr (0, equal), n); + string keyname = remaining.substr (0, equal); + + if (keyname == "EditorSort" || keyname == "editor") { + info << string_compose(_("Converting deprecated order key for %1 using Editor order %2"), name (), n) << endmsg; + set_order_key (n); + } } } @@ -2377,7 +2464,7 @@ Route::set_state_2X (const XMLNode& node, int version) if ((prop = child->property (X_("id"))) != 0) { int32_t x; sscanf (prop->value().c_str(), "%d", &x); - set_remote_control_id (x); + set_remote_control_id_internal (x); } } @@ -2444,7 +2531,8 @@ Route::set_processor_state (const XMLNode& node) } _monitor_control->set_state (**niter, Stateful::current_state_version); } else if (prop->value() == "capture") { - _capturing_processor.reset (new CapturingProcessor (_session)); + /* CapturingProcessor should never be restored, it's always + added explicitly when needed */ } else { ProcessorList::iterator o; @@ -2465,11 +2553,11 @@ Route::set_processor_state (const XMLNode& node) if (prop->value() == "intsend") { - processor.reset (new InternalSend (_session, _pannable, _mute_master, boost::shared_ptr(), Delivery::Role (0))); + processor.reset (new InternalSend (_session, _pannable, _mute_master, boost::shared_ptr(), Delivery::Aux)); } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" || prop->value() == "lv2" || - prop->value() == "vst" || + prop->value() == "windows-vst" || prop->value() == "lxvst" || prop->value() == "audiounit") { @@ -2512,16 +2600,17 @@ Route::set_processor_state (const XMLNode& node) } { - Glib::RWLock::WriterLock lm (_processor_lock); + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); + Glib::Threads::RWLock::WriterLock lm (_processor_lock); _processors = new_order; if (must_configure) { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); configure_processors_unlocked (0); } for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) { + (*i)->set_owner (this); (*i)->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false)); boost::shared_ptr pi; @@ -2535,6 +2624,7 @@ Route::set_processor_state (const XMLNode& node) } } + reset_instrument_info (); processors_changed (RouteProcessorChange ()); set_processor_positions (); } @@ -2549,7 +2639,7 @@ Route::curve_reallocate () void Route::silence (framecnt_t nframes) { - Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK); if (!lm.locked()) { return; } @@ -2595,7 +2685,7 @@ Route::add_internal_return () void Route::add_send_to_internal_return (InternalSend* send) { - Glib::RWLock::ReaderLock rm (_processor_lock); + Glib::Threads::RWLock::ReaderLock rm (_processor_lock); for (ProcessorList::const_iterator x = _processors.begin(); x != _processors.end(); ++x) { boost::shared_ptr d = boost::dynamic_pointer_cast(*x); @@ -2609,7 +2699,7 @@ Route::add_send_to_internal_return (InternalSend* send) void Route::remove_send_from_internal_return (InternalSend* send) { - Glib::RWLock::ReaderLock rm (_processor_lock); + Glib::Threads::RWLock::ReaderLock rm (_processor_lock); for (ProcessorList::const_iterator x = _processors.begin(); x != _processors.end(); ++x) { boost::shared_ptr d = boost::dynamic_pointer_cast(*x); @@ -2628,6 +2718,7 @@ Route::enable_monitor_send () /* master never sends to monitor section via the normal mechanism */ assert (!is_master ()); + assert (!is_monitor ()); /* make sure we have one */ if (!_monitor_send) { @@ -2649,7 +2740,7 @@ Route::add_aux_send (boost::shared_ptr route, boost::shared_ptr route, boost::shared_ptr listener; { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); listener.reset (new InternalSend (_session, _pannable, _mute_master, route, Delivery::Aux)); } @@ -2687,7 +2778,7 @@ Route::remove_aux_or_listen (boost::shared_ptr route) ProcessorList::iterator tmp; { - Glib::RWLock::ReaderLock rl(_processor_lock); + Glib::Threads::RWLock::ReaderLock rl(_processor_lock); /* have to do this early because otherwise processor reconfig * will put _monitor_send back in the list @@ -2818,16 +2909,12 @@ Route::direct_feeds_according_to_graph (boost::shared_ptr other, bool* vi /** Called from the (non-realtime) butler thread when the transport is stopped */ void -Route::nonrealtime_handle_transport_stopped (bool /*abort_ignored*/, bool did_locate, bool can_flush_processors) +Route::nonrealtime_handle_transport_stopped (bool /*abort_ignored*/, bool /*did_locate*/, bool can_flush_processors) { framepos_t now = _session.transport_frame(); { - Glib::RWLock::ReaderLock lm (_processor_lock); - - if (!did_locate) { - automation_snapshot (now, true); - } + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); Automatable::transport_stopped (now); @@ -2872,12 +2959,17 @@ void Route::output_change_handler (IOChange change, void * /*src*/) { bool need_to_queue_solo_change = true; + if (_initial_io_setup) { + return; + } if ((change.type & IOChange::ConfigurationChanged)) { /* This is called with the process lock held if change contains ConfigurationChanged */ need_to_queue_solo_change = false; + configure_processors (0); + io_changed (); /* EMIT SIGNAL */ } if (!_output->connected() && _soloed_by_others_downstream) { @@ -2914,7 +3006,8 @@ Route::pans_required () const int Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool session_state_changing) { - Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK); + if (!lm.locked()) { return 0; } @@ -2927,6 +3020,7 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, silence_unlocked (nframes); return 0; } + if (session_state_changing) { if (_session.transport_speed() != 0.0f) { /* we're rolling but some state is changing (e.g. our diskstream contents) @@ -2942,8 +3036,16 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, */ } + BufferSet& bufs = _session.get_route_buffers (n_process_buffers()); + + fill_buffers_with_input (bufs, _input, nframes); + + if (_meter_point == MeterInput) { + _meter->run (bufs, start_frame, end_frame, nframes, true); + } + _amp->apply_gain_automation (false); - passthru (start_frame, end_frame, nframes, 0); + passthru (bufs, start_frame, end_frame, nframes, 0); return 0; } @@ -2951,13 +3053,11 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int Route::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick, bool& /* need_butler */) { - Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK); if (!lm.locked()) { return 0; } - automation_snapshot (_session.transport_frame(), false); - if (n_outputs().n_total() == 0) { return 0; } @@ -2975,7 +3075,15 @@ Route::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, in _silent = false; - passthru (start_frame, end_frame, nframes, declick); + BufferSet& bufs = _session.get_route_buffers (n_process_buffers()); + + fill_buffers_with_input (bufs, _input, nframes); + + if (_meter_point == MeterInput) { + _meter->run (bufs, start_frame, end_frame, nframes, true); + } + + passthru (bufs, start_frame, end_frame, nframes, declick); return 0; } @@ -2994,7 +3102,7 @@ Route::flush_processors () this is called from the RT audio thread. */ - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { (*i)->flush (); @@ -3004,8 +3112,6 @@ Route::flush_processors () void Route::set_meter_point (MeterPoint p, bool force) { - /* CAN BE CALLED FROM PROCESS CONTEXT */ - if (_meter_point == p && !force) { return; } @@ -3013,7 +3119,7 @@ Route::set_meter_point (MeterPoint p, bool force) bool meter_was_visible_to_user = _meter->display_to_user (); { - Glib::RWLock::WriterLock lm (_processor_lock); + Glib::Threads::RWLock::WriterLock lm (_processor_lock); maybe_note_meter_position (); @@ -3080,17 +3186,14 @@ void Route::listen_position_changed () { { - Glib::RWLock::WriterLock lm (_processor_lock); + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); + Glib::Threads::RWLock::WriterLock lm (_processor_lock); ProcessorState pstate (this); - { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); - - if (configure_processors_unlocked (0)) { - pstate.restore (); - configure_processors_unlocked (0); // it worked before we tried to add it ... - return; - } + if (configure_processors_unlocked (0)) { + pstate.restore (); + configure_processors_unlocked (0); // it worked before we tried to add it ... + return; } } @@ -3106,10 +3209,7 @@ Route::add_export_point() _capturing_processor.reset (new CapturingProcessor (_session)); _capturing_processor->activate (); - { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); - configure_processors (0); - } + configure_processors (0); } @@ -3169,18 +3269,6 @@ Route::set_latency_compensation (framecnt_t longest_session_latency) } } -void -Route::automation_snapshot (framepos_t now, bool force) -{ - if (_pannable) { - _pannable->automation_snapshot (now, force); - } - - for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - (*i)->automation_snapshot (now, force); - } -} - Route::SoloControllable::SoloControllable (std::string name, boost::shared_ptr r) : AutomationControl (r->session(), Evoral::Parameter (SoloAutomation), boost::shared_ptr(), name) @@ -3279,19 +3367,20 @@ Route::protect_automation () (*i)->protect_automation(); } +/** @param declick 1 to set a pending declick fade-in, + * -1 to set a pending declick fade-out + */ void Route::set_pending_declick (int declick) { if (_declickable) { - /* this call is not allowed to turn off a pending declick unless "force" is true */ + /* this call is not allowed to turn off a pending declick */ if (declick) { _pending_declick = declick; } - // cerr << _name << ": after setting to " << declick << " pending declick = " << _pending_declick << endl; } else { _pending_declick = 0; } - } /** Shift automation forwards from a particular place, thereby inserting time. @@ -3332,7 +3421,7 @@ Route::shift (framepos_t pos, framecnt_t frames) /* redirect automation */ { - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); for (ProcessorList::iterator i = _processors.begin (); i != _processors.end (); ++i) { set parameters = (*i)->what_can_be_automated(); @@ -3432,7 +3521,7 @@ Route::set_name_in_state (XMLNode& node, string const & name) boost::shared_ptr Route::internal_send_for (boost::shared_ptr target) const { - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) { boost::shared_ptr send; @@ -3510,13 +3599,14 @@ Route::set_active (bool yn, void* src) _input->set_active (yn); _output->set_active (yn); active_changed (); // EMIT SIGNAL + _session.set_dirty (); } } void Route::meter () { - Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK); + Glib::Threads::RWLock::ReaderLock rm (_processor_lock, Glib::Threads::TRY_LOCK); assert (_meter); @@ -3571,7 +3661,7 @@ Route::get_control (const Evoral::Parameter& param) /* maybe one of our processors does or ... */ - Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK); + Glib::Threads::RWLock::ReaderLock rm (_processor_lock, Glib::Threads::TRY_LOCK); for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { if ((c = boost::dynamic_pointer_cast((*i)->control (param))) != 0) { break; @@ -3593,7 +3683,7 @@ Route::get_control (const Evoral::Parameter& param) boost::shared_ptr Route::nth_plugin (uint32_t n) { - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); ProcessorList::iterator i; for (i = _processors.begin(); i != _processors.end(); ++i) { @@ -3610,7 +3700,7 @@ Route::nth_plugin (uint32_t n) boost::shared_ptr Route::nth_send (uint32_t n) { - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); ProcessorList::iterator i; for (i = _processors.begin(); i != _processors.end(); ++i) { @@ -3627,7 +3717,7 @@ Route::nth_send (uint32_t n) bool Route::has_io_processor_named (const string& name) { - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); ProcessorList::iterator i; for (i = _processors.begin(); i != _processors.end(); ++i) { @@ -3651,7 +3741,7 @@ Route::mute_points () const void Route::set_processor_positions () { - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); bool had_amp = false; for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { @@ -3678,12 +3768,25 @@ Route::input_port_count_changing (ChanCount to) return false; } +/** Called when there is a proposed change to the output port count */ +bool +Route::output_port_count_changing (ChanCount to) +{ + for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { + if (processor_out_streams.get(*t) > to.get(*t)) { + return true; + } + } + /* The change is ok */ + return false; +} + list Route::unknown_processors () const { list p; - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) { if (boost::dynamic_pointer_cast (*i)) { p.push_back ((*i)->name ()); @@ -3701,13 +3804,13 @@ Route::update_port_latencies (PortSet& from, PortSet& to, bool playback, framecn universally true, but the alternative is way too corner-case to worry about. */ - jack_latency_range_t all_connections; + LatencyRange all_connections; if (from.empty()) { all_connections.min = 0; all_connections.max = 0; } else { - all_connections.min = ~((jack_nframes_t) 0); + all_connections.min = ~((pframes_t) 0); all_connections.max = 0; /* iterate over all "from" ports and determine the latency range for all of their @@ -3716,7 +3819,7 @@ Route::update_port_latencies (PortSet& from, PortSet& to, bool playback, framecn for (PortSet::iterator p = from.begin(); p != from.end(); ++p) { - jack_latency_range_t range; + LatencyRange range; p->get_connected_latency_range (range, playback); @@ -3781,7 +3884,7 @@ Route::set_public_port_latencies (framecnt_t value, bool playback) const latency compensation into account. */ - jack_latency_range_t range; + LatencyRange range; range.min = value; range.max = value; @@ -3808,7 +3911,7 @@ void Route::setup_invisible_processors () { #ifndef NDEBUG - Glib::RWLock::WriterLock lm (_processor_lock, Glib::TRY_LOCK); + Glib::Threads::RWLock::WriterLock lm (_processor_lock, Glib::Threads::TRY_LOCK); assert (!lm.locked ()); #endif @@ -3964,8 +4067,8 @@ Route::setup_invisible_processors () void Route::unpan () { - Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); - Glib::RWLock::ReaderLock lp (_processor_lock); + Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); + Glib::Threads::RWLock::ReaderLock lp (_processor_lock); _pannable.reset (); @@ -4009,7 +4112,7 @@ Route::maybe_note_meter_position () boost::shared_ptr Route::processor_by_id (PBD::ID id) const { - Glib::RWLock::ReaderLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) { if ((*i)->id() == id) { return *i; @@ -4057,12 +4160,129 @@ Route::has_external_redirects () const boost::shared_ptr Route::the_instrument () const { - Glib::RWLock::WriterLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); + return the_instrument_unlocked (); +} + +boost::shared_ptr +Route::the_instrument_unlocked () const +{ for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) { - if ((*i)->input_streams().n_midi() > 0 && - (*i)->output_streams().n_audio() > 0) { - return (*i); + if (boost::dynamic_pointer_cast(*i)) { + if ((*i)->input_streams().n_midi() > 0 && + (*i)->output_streams().n_audio() > 0) { + return (*i); + } } } return boost::shared_ptr(); } + + + +void +Route::non_realtime_locate (framepos_t pos) +{ + if (_pannable) { + _pannable->transport_located (pos); + } + + { + //Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); + Glib::Threads::RWLock::WriterLock lm (_processor_lock); + + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + (*i)->transport_located (pos); + } + } +} + +void +Route::fill_buffers_with_input (BufferSet& bufs, boost::shared_ptr io, pframes_t nframes) +{ + size_t n_buffers; + size_t i; + + /* MIDI + * + * We don't currently mix MIDI input together, so we don't need the + * complex logic of the audio case. + */ + + n_buffers = bufs.count().n_midi (); + + for (i = 0; i < n_buffers; ++i) { + + boost::shared_ptr source_port = io->midi (i); + MidiBuffer& buf (bufs.get_midi (i)); + + if (source_port) { + buf.copy (source_port->get_midi_buffer(nframes)); + } else { + buf.silence (nframes); + } + } + + /* AUDIO */ + + n_buffers = bufs.count().n_audio(); + + size_t n_ports = io->n_ports().n_audio(); + float scaling = 1.0f; + + if (n_ports > n_buffers) { + scaling = ((float) n_buffers) / n_ports; + } + + for (i = 0; i < n_ports; ++i) { + + /* if there are more ports than buffers, map them onto buffers + * in a round-robin fashion + */ + + boost::shared_ptr source_port = io->audio (i); + AudioBuffer& buf (bufs.get_audio (i%n_buffers)); + + + if (i < n_buffers) { + + /* first time through just copy a channel into + the output buffer. + */ + + buf.read_from (source_port->get_audio_buffer (nframes), nframes); + + if (scaling != 1.0f) { + buf.apply_gain (scaling, nframes); + } + + } else { + + /* on subsequent times around, merge data from + * the port with what is already there + */ + + if (scaling != 1.0f) { + buf.accumulate_with_gain_from (source_port->get_audio_buffer (nframes), nframes, 0, scaling); + } else { + buf.accumulate_from (source_port->get_audio_buffer (nframes), nframes); + } + } + } + + /* silence any remaining buffers */ + + for (; i < n_buffers; ++i) { + AudioBuffer& buf (bufs.get_audio (i)); + buf.silence (nframes); + } + + /* establish the initial setup of the buffer set, reflecting what was + copied into it. unless, of course, we are the auditioner, in which + case nothing was fed into it from the inputs at all. + */ + + if (!is_auditioner()) { + bufs.set_count (io->n_ports()); + } +}