summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <carl@carlh.net>2010-11-25 23:46:24 +0000
committerCarl Hetherington <carl@carlh.net>2010-11-25 23:46:24 +0000
commit54cbc45a5a40f4eefd64fa41ad9029f5f8f6a84f (patch)
tree558e7cb27683030787fcb4d5654bd4b58ebd8e21
parent28c004f4fb0750b6a4236552bcc8de4946b9b164 (diff)
Prevent removal of route inputs when the plugins cannot be configured with the new number. Rework locking so that the process lock is held from the point that a route input is removed until after the processors are reconfigured; fixes #3548.
git-svn-id: svn://localhost/ardour2/branches/3.0@8089 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--gtk2_ardour/port_matrix.cc13
-rw-r--r--gtk2_ardour/processor_box.cc2
-rw-r--r--libs/ardour/ardour/io.h26
-rw-r--r--libs/ardour/ardour/route.h6
-rw-r--r--libs/ardour/auditioner.cc14
-rw-r--r--libs/ardour/delivery.cc4
-rw-r--r--libs/ardour/io.cc124
-rw-r--r--libs/ardour/port_insert.cc17
-rw-r--r--libs/ardour/route.cc173
-rw-r--r--libs/ardour/send.cc2
-rw-r--r--libs/ardour/session.cc89
-rw-r--r--libs/ardour/session_state.cc15
-rw-r--r--libs/pbd/pbd/signals.h4
13 files changed, 333 insertions, 156 deletions
diff --git a/gtk2_ardour/port_matrix.cc b/gtk2_ardour/port_matrix.cc
index 113a11c116..052a26c25c 100644
--- a/gtk2_ardour/port_matrix.cc
+++ b/gtk2_ardour/port_matrix.cc
@@ -25,6 +25,7 @@
#include <gtkmm/menushell.h>
#include <gtkmm/menu_elems.h>
#include <gtkmm/window.h>
+#include <gtkmm/stock.h>
#include "ardour/bundle.h"
#include "ardour/types.h"
#include "ardour/session.h"
@@ -33,6 +34,7 @@
#include "port_matrix.h"
#include "port_matrix_body.h"
#include "port_matrix_component.h"
+#include "ardour_dialog.h"
#include "i18n.h"
#include "gui_thread.h"
#include "utils.h"
@@ -686,7 +688,16 @@ PortMatrix::remove_channel (ARDOUR::BundleChannel b)
if (io) {
Port* p = io->nth (b.channel);
if (p) {
- io->remove_port (p, this);
+ int const r = io->remove_port (p, this);
+ if (r == -1) {
+ ArdourDialog d (_("Port removal not allowed"));
+ Label l (_("This port cannot be removed, as the first plugin in the track or buss cannot accept the new number of inputs."));
+ d.get_vbox()->pack_start (l);
+ d.add_button (Stock::OK, RESPONSE_ACCEPT);
+ d.set_modal (true);
+ d.show_all ();
+ d.run ();
+ }
}
}
}
diff --git a/gtk2_ardour/processor_box.cc b/gtk2_ardour/processor_box.cc
index 673b3dc1bb..99875a2a47 100644
--- a/gtk2_ardour/processor_box.cc
+++ b/gtk2_ardour/processor_box.cc
@@ -801,6 +801,7 @@ ProcessorBox::choose_insert ()
_route->add_processor (processor, _placement);
}
+/* Caller must not hold process lock */
void
ProcessorBox::choose_send ()
{
@@ -813,6 +814,7 @@ ProcessorBox::choose_send ()
/* XXX need processor lock on route */
try {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock());
send->output()->ensure_io (outs, false, this);
} catch (AudioEngine::PortRegistrationFailure& err) {
error << string_compose (_("Cannot set up new send: %1"), err.what()) << endmsg;
diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h
index a94149e178..9d423f55a5 100644
--- a/libs/ardour/ardour/io.h
+++ b/libs/ardour/ardour/io.h
@@ -133,6 +133,7 @@ class IO : public SessionObject, public Latent
const ChanCount& n_ports () const { return _ports.count(); }
+ /** Emitted with the process lock held */
PBD::Signal2<void,IOChange,void*> changed;
virtual XMLNode& state (bool full);
@@ -140,6 +141,31 @@ class IO : public SessionObject, public Latent
int set_state (const XMLNode&, int version);
int set_state_2X (const XMLNode&, int, bool);
+ class BoolCombiner {
+ public:
+
+ typedef bool result_type;
+
+ template <typename Iter>
+ bool operator() (Iter first, Iter last) const {
+ bool r = false;
+ while (first != last) {
+ if (*first) {
+ r = true;
+ }
+ ++first;
+ }
+
+ return r;
+ }
+ };
+
+ /** Emitted when the port count is about to change. Objects
+ * can attach to this, and return `true' if they want to prevent
+ * the change from happening.
+ */
+ PBD::Signal1<bool, ChanCount, BoolCombiner> PortCountChanging;
+
static int disable_connecting (void);
static int enable_connecting (void);
static int disable_ports (void);
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index 9a874b459d..38300a7de9 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -261,6 +261,8 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
PBD::Signal0<void> signal_latency_changed;
PBD::Signal0<void> initial_delay_changed;
PBD::Signal0<void> order_key_changed;
+
+ /** Emitted with the process lock held */
PBD::Signal0<void> io_changed;
/* gui's call this for their own purposes. */
@@ -473,9 +475,13 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
void input_change_handler (IOChange, void *src);
void output_change_handler (IOChange, void *src);
+ bool input_port_count_changing (ChanCount);
+
bool _in_configure_processors;
int configure_processors_unlocked (ProcessorStreams*);
+ std::list<std::pair<ChanCount, ChanCount> > try_configure_processors (ChanCount, ProcessorStreams *);
+ std::list<std::pair<ChanCount, ChanCount> > try_configure_processors_unlocked (ChanCount, ProcessorStreams *);
bool add_processor_from_xml_2X (const XMLNode&, int);
diff --git a/libs/ardour/auditioner.cc b/libs/ardour/auditioner.cc
index baf97292ec..37df6297da 100644
--- a/libs/ardour/auditioner.cc
+++ b/libs/ardour/auditioner.cc
@@ -176,11 +176,15 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
}
ProcessorStreams ps;
- if (configure_processors (&ps)) {
- error << string_compose (_("Cannot setup auditioner processing flow for %1 channels"),
- _diskstream->n_channels()) << endmsg;
- return;
- }
+ {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+
+ if (configure_processors (&ps)) {
+ error << string_compose (_("Cannot setup auditioner processing flow for %1 channels"),
+ _diskstream->n_channels()) << endmsg;
+ return;
+ }
+ }
/* force a panner reset now that we have all channels */
diff --git a/libs/ardour/delivery.cc b/libs/ardour/delivery.cc
index 4277ee4ed8..700efd8ac1 100644
--- a/libs/ardour/delivery.cc
+++ b/libs/ardour/delivery.cc
@@ -35,6 +35,7 @@
#include "ardour/panner.h"
#include "ardour/port.h"
#include "ardour/session.h"
+#include "ardour/audioengine.h"
#include "i18n.h"
@@ -178,9 +179,12 @@ Delivery::can_support_io_configuration (const ChanCount& in, ChanCount& out) con
return false;
}
+/** Caller must hold process lock */
bool
Delivery::configure_io (ChanCount in, ChanCount out)
{
+ assert (!AudioEngine::instance()->process_lock().trylock());
+
/* check configuration by comparison with our I/O port configuration, if appropriate.
see ::can_support_io_configuration() for comments
*/
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc
index d9a0a3c1e0..de4d658596 100644
--- a/libs/ardour/io.cc
+++ b/libs/ardour/io.cc
@@ -184,38 +184,38 @@ IO::disconnect (Port* our_port, string other_port, void* src)
check_bundles_connected ();
}
+
+ changed (IOChange (IOChange::ConnectionsChanged), src); /* EMIT SIGNAL */
}
- changed (IOChange (IOChange::ConnectionsChanged), src); /* EMIT SIGNAL */
_session.set_dirty ();
return 0;
}
+/** Caller must hold process lock */
int
IO::connect (Port* our_port, string other_port, void* src)
{
+ assert (!AudioEngine::instance()->process_lock().trylock());
+
if (other_port.length() == 0 || our_port == 0) {
return 0;
}
{
- BLOCK_PROCESS_CALLBACK ();
-
- {
- Glib::Mutex::Lock lm (io_lock);
-
- /* check that our_port is really one of ours */
-
- if ( ! _ports.contains(our_port) ) {
- return -1;
- }
-
- /* connect it to the source */
-
- if (our_port->connect (other_port)) {
- return -1;
- }
+ Glib::Mutex::Lock lm (io_lock);
+
+ /* check that our_port is really one of ours */
+
+ if ( ! _ports.contains(our_port) ) {
+ return -1;
+ }
+
+ /* connect it to the source */
+
+ if (our_port->connect (other_port)) {
+ return -1;
}
}
@@ -227,6 +227,15 @@ IO::connect (Port* our_port, string other_port, void* src)
int
IO::remove_port (Port* port, void* src)
{
+ ChanCount before = _ports.count ();
+ ChanCount after = before;
+ after.set (port->type(), after.get (port->type()) - 1);
+
+ bool const r = PortCountChanging (after); /* EMIT SIGNAL */
+ if (r) {
+ return -1;
+ }
+
IOChange change;
{
@@ -235,8 +244,6 @@ IO::remove_port (Port* port, void* src)
{
Glib::Mutex::Lock lm (io_lock);
- ChanCount before = _ports.count ();
-
if (_ports.remove(port)) {
change.type = IOChange::Type (change.type | IOChange::ConfigurationChanged);
change.before = before;
@@ -252,19 +259,22 @@ IO::remove_port (Port* port, void* src)
}
PortCountChanged (n_ports()); /* EMIT SIGNAL */
+
+ if (change.type != IOChange::NoChange) {
+ changed (change, src);
+ _session.set_dirty ();
+ }
}
if (change.type & IOChange::ConfigurationChanged) {
setup_bundle ();
}
- if (change.type != IOChange::NoChange) {
- changed (change, src);
- _session.set_dirty ();
- return 0;
+ if (change.type == IOChange::NoChange) {
+ return -1;
}
- return -1;
+ return 0;
}
/** Add a port.
@@ -312,6 +322,11 @@ IO::add_port (string destination, void* src, DataType type)
}
PortCountChanged (n_ports()); /* EMIT SIGNAL */
+
+ // pan_changed (src); /* EMIT SIGNAL */
+ change.type = IOChange::ConfigurationChanged;
+ change.after = _ports.count ();
+ changed (change, src); /* EMIT SIGNAL */
}
if (destination.length()) {
@@ -320,10 +335,6 @@ IO::add_port (string destination, void* src, DataType type)
}
}
- // pan_changed (src); /* EMIT SIGNAL */
- change.type = IOChange::ConfigurationChanged;
- change.after = _ports.count ();
- changed (change, src); /* EMIT SIGNAL */
setup_bundle ();
_session.set_dirty ();
@@ -333,28 +344,29 @@ IO::add_port (string destination, void* src, DataType type)
int
IO::disconnect (void* src)
{
+ BLOCK_PROCESS_CALLBACK ();
+
{
- BLOCK_PROCESS_CALLBACK ();
-
- {
- Glib::Mutex::Lock lm (io_lock);
-
- for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
- i->disconnect_all ();
- }
-
- check_bundles_connected ();
+ Glib::Mutex::Lock lm (io_lock);
+
+ for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
+ i->disconnect_all ();
}
+
+ check_bundles_connected ();
}
-
+
changed (IOChange (IOChange::ConnectionsChanged), src); /* EMIT SIGNAL */
return 0;
}
+/** Caller must hold process lock */
bool
IO::ensure_ports_locked (ChanCount count, bool clear, void* /*src*/)
{
+ assert (!AudioEngine::instance()->process_lock().trylock());
+
Port* port = 0;
bool changed = false;
@@ -419,10 +431,12 @@ IO::ensure_ports_locked (ChanCount count, bool clear, void* /*src*/)
return changed;
}
-
+/** Caller must hold process lock */
int
IO::ensure_ports (ChanCount count, bool clear, void* src)
{
+ assert (!AudioEngine::instance()->process_lock().trylock());
+
bool changed = false;
if (count == n_ports() && !clear) {
@@ -434,7 +448,6 @@ IO::ensure_ports (ChanCount count, bool clear, void* src)
change.before = _ports.count ();
{
- BLOCK_PROCESS_CALLBACK ();
Glib::Mutex::Lock im (io_lock);
changed = ensure_ports_locked (count, clear, src);
}
@@ -450,9 +463,12 @@ IO::ensure_ports (ChanCount count, bool clear, void* src)
return 0;
}
+/** Caller must hold process lock */
int
IO::ensure_io (ChanCount count, bool clear, void* src)
{
+ assert (!AudioEngine::instance()->process_lock().trylock());
+
return ensure_ports (count, clear, src);
}
@@ -830,9 +846,13 @@ IO::create_ports (const XMLNode& node, int version)
get_port_counts (node, version, n, c);
- if (ensure_ports (n, true, this)) {
- error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
- return -1;
+ {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+
+ if (ensure_ports (n, true, this)) {
+ error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
+ return -1;
+ }
}
/* XXX use c */
@@ -1004,9 +1024,13 @@ IO::set_ports (const string& str)
return 0;
}
- // FIXME: audio-only
- if (ensure_ports (ChanCount(DataType::AUDIO, nports), true, this)) {
- return -1;
+ {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+
+ // FIXME: audio-only
+ if (ensure_ports (ChanCount(DataType::AUDIO, nports), true, this)) {
+ return -1;
+ }
}
string::size_type start, end, ostart;
@@ -1158,8 +1182,9 @@ IO::update_port_total_latencies ()
int
IO::connect_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
{
+ BLOCK_PROCESS_CALLBACK ();
+
{
- BLOCK_PROCESS_CALLBACK ();
Glib::Mutex::Lock lm2 (io_lock);
c->connect (_bundle, _session.engine());
@@ -1189,8 +1214,9 @@ IO::connect_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
int
IO::disconnect_ports_from_bundle (boost::shared_ptr<Bundle> c, void* src)
{
+ BLOCK_PROCESS_CALLBACK ();
+
{
- BLOCK_PROCESS_CALLBACK ();
Glib::Mutex::Lock lm2 (io_lock);
c->disconnect (_bundle, _session.engine());
diff --git a/libs/ardour/port_insert.cc b/libs/ardour/port_insert.cc
index 20c6b127d2..4854c08d8b 100644
--- a/libs/ardour/port_insert.cc
+++ b/libs/ardour/port_insert.cc
@@ -244,17 +244,22 @@ PortInsert::signal_latency() const
}
}
+/** Caller must not hold process lock */
bool
PortInsert::configure_io (ChanCount in, ChanCount out)
{
/* for an insert, processor input corresponds to IO output, and vice versa */
- if (_input->ensure_io (in, false, this) != 0) {
- return false;
- }
-
- if (_output->ensure_io (out, false, this) != 0) {
- return false;
+ {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+
+ if (_input->ensure_io (in, false, this) != 0) {
+ return false;
+ }
+
+ if (_output->ensure_io (out, false, this) != 0) {
+ return false;
+ }
}
return Processor::configure_io (in, out);
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 1bb9c63db5..150d53a1fa 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -120,6 +120,8 @@ Route::init ()
_input->changed.connect_same_thread (*this, boost::bind (&Route::input_change_handler, this, _1, _2));
_output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2));
+ _input->PortCountChanging.connect_same_thread (*this, boost::bind (&Route::input_port_count_changing, this, _1));
+
/* add amp processor */
_amp.reset (new Amp (_session));
@@ -876,13 +878,17 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
// Set up processor list channels. This will set processor->[input|output]_streams(),
// configure redirect ports properly, etc.
- if (configure_processors_unlocked (err)) {
- ProcessorList::iterator ploc = loc;
- --ploc;
- _processors.erase(ploc);
- configure_processors_unlocked (0); // it worked before we tried to add it ...
- cerr << "configure failed\n";
- return -1;
+ {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+
+ if (configure_processors_unlocked (err)) {
+ ProcessorList::iterator ploc = loc;
+ --ploc;
+ _processors.erase(ploc);
+ configure_processors_unlocked (0); // it worked before we tried to add it ...
+ cerr << "configure failed\n";
+ return -1;
+ }
}
if ((pi = boost::dynamic_pointer_cast<PluginInsert>(processor)) != 0) {
@@ -1051,10 +1057,13 @@ Route::add_processors (const ProcessorList& others, ProcessorList::iterator iter
(*i)->activate ();
}
- if (configure_processors_unlocked (err)) {
- _processors.erase (inserted);
- configure_processors_unlocked (0); // it worked before we tried to add it ...
- return -1;
+ {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+ if (configure_processors_unlocked (err)) {
+ _processors.erase (inserted);
+ configure_processors_unlocked (0); // it worked before we tried to add it ...
+ return -1;
+ }
}
(*i)->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false, false));
@@ -1259,7 +1268,11 @@ Route::clear_processors (Placement p)
}
_processors = new_list;
- configure_processors_unlocked (&err); // this can't fail
+
+ {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+ configure_processors_unlocked (&err); // this can't fail
+ }
}
processor_max_streams.reset();
@@ -1333,12 +1346,16 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
return 1;
}
- if (configure_processors_unlocked (err)) {
- /* get back to where we where */
- _processors.insert (i, processor);
- /* we know this will work, because it worked before :) */
- configure_processors_unlocked (0);
- return -1;
+ {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+
+ if (configure_processors_unlocked (err)) {
+ /* get back to where we where */
+ _processors.insert (i, processor);
+ /* we know this will work, because it worked before :) */
+ configure_processors_unlocked (0);
+ return -1;
+ }
}
_have_internal_generator = false;
@@ -1420,12 +1437,16 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
_output->set_user_latency (0);
- if (configure_processors_unlocked (err)) {
- /* get back to where we where */
- _processors = as_we_were;
- /* we know this will work, because it worked before :) */
- configure_processors_unlocked (0);
- return -1;
+ {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+
+ if (configure_processors_unlocked (err)) {
+ /* get back to where we where */
+ _processors = as_we_were;
+ /* we know this will work, because it worked before :) */
+ configure_processors_unlocked (0);
+ return -1;
+ }
}
_have_internal_generator = false;
@@ -1454,10 +1475,12 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
return 0;
}
-
+/** 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);
return configure_processors_unlocked (err);
@@ -1471,22 +1494,20 @@ Route::input_streams () const
return _input->n_ports ();
}
-/** Configure the input/output configuration of each processor in the processors list.
- * Return 0 on success, otherwise configuration is impossible.
- */
-int
-Route::configure_processors_unlocked (ProcessorStreams* err)
+list<pair<ChanCount, ChanCount> >
+Route::try_configure_processors (ChanCount in, ProcessorStreams* err)
{
- if (_in_configure_processors) {
- return 0;
- }
+ Glib::RWLock::ReaderLock lm (_processor_lock);
- _in_configure_processors = true;
+ return try_configure_processors_unlocked (in, err);
+}
+list<pair<ChanCount, ChanCount> >
+Route::try_configure_processors_unlocked (ChanCount in, ProcessorStreams* err)
+{
// Check each processor in order to see if we can configure as requested
- ChanCount in = input_streams ();
ChanCount out;
- list< pair<ChanCount,ChanCount> > configuration;
+ list<pair<ChanCount, ChanCount> > configuration;
uint32_t index = 0;
DEBUG_TRACE (DEBUG::Processors, string_compose ("%1: configure processors\n", _name));
@@ -1507,12 +1528,37 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
err->index = index;
err->count = in;
}
- _in_configure_processors = false;
- return -1;
+ return list<pair<ChanCount, ChanCount> > ();
}
}
- // We can, so configure everything
+ return configuration;
+}
+
+/** Set the input/output configuration of each processor in the processors list.
+ * Caller must hold process lock.
+ * Return 0 on success, otherwise configuration is impossible.
+ */
+int
+Route::configure_processors_unlocked (ProcessorStreams* err)
+{
+ assert (!AudioEngine::instance()->process_lock().trylock());
+
+ if (_in_configure_processors) {
+ return 0;
+ }
+
+ _in_configure_processors = true;
+
+ list<pair<ChanCount, ChanCount> > configuration = try_configure_processors_unlocked (input_streams (), err);
+
+ if (configuration.empty ()) {
+ _in_configure_processors = false;
+ return -1;
+ }
+
+ ChanCount out;
+
list< pair<ChanCount,ChanCount> >::iterator c = configuration.begin();
for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++c) {
(*p)->configure_io(c->first, c->second);
@@ -1527,10 +1573,7 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
/* make sure we have sufficient scratch buffers to cope with the new processor
configuration */
- {
- Glib::Mutex::Lock em (_session.engine().process_lock ());
- _session.ensure_buffers (n_process_buffers ());
- }
+ _session.ensure_buffers (n_process_buffers ());
DEBUG_TRACE (DEBUG::Processors, string_compose ("%1: configuration complete\n", _name));
@@ -1686,10 +1729,14 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err
_processors.insert (oiter, as_it_will_be.begin(), as_it_will_be.end());
- if (configure_processors_unlocked (err)) {
- _processors = as_it_was_before;
- processor_max_streams = old_pms;
- return -1;
+ {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+
+ if (configure_processors_unlocked (err)) {
+ _processors = as_it_was_before;
+ processor_max_streams = old_pms;
+ return -1;
+ }
}
}
@@ -2335,6 +2382,7 @@ Route::set_processor_state (const XMLNode& node)
Glib::RWLock::WriterLock lm (_processor_lock);
_processors = new_order;
if (must_configure) {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
configure_processors_unlocked (0);
}
}
@@ -2647,6 +2695,7 @@ Route::handle_transport_stopped (bool /*abort_ignored*/, bool did_locate, bool c
_roll_delay = _initial_delay;
}
+/** Called with the process lock held */
void
Route::input_change_handler (IOChange change, void * /*src*/)
{
@@ -2657,6 +2706,7 @@ Route::input_change_handler (IOChange change, void * /*src*/)
}
}
+/** Called with the process lock held */
void
Route::output_change_handler (IOChange change, void * /*src*/)
{
@@ -2958,10 +3008,14 @@ Route::put_monitor_send_at (Placement p)
_processors.insert (loc, _monitor_send);
- if (configure_processors_unlocked (0)) {
- _processors = as_it_was;
- configure_processors_unlocked (0); // it worked before we tried to add it ...
- return;
+ {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+
+ if (configure_processors_unlocked (0)) {
+ _processors = as_it_was;
+ configure_processors_unlocked (0); // it worked before we tried to add it ...
+ return;
+ }
}
}
@@ -3456,3 +3510,20 @@ Route::set_processor_positions ()
}
}
+/** Called when there is a proposed change to the input port count */
+bool
+Route::input_port_count_changing (ChanCount to)
+{
+ list<pair<ChanCount, ChanCount> > c = try_configure_processors (to, 0);
+ if (c.empty()) {
+ /* The processors cannot be configured with the new input arrangement, so
+ block the change.
+ */
+ return true;
+ }
+
+ /* The change is ok */
+ return false;
+}
+
+
diff --git a/libs/ardour/send.cc b/libs/ardour/send.cc
index bfbceb49af..74212155ec 100644
--- a/libs/ardour/send.cc
+++ b/libs/ardour/send.cc
@@ -217,6 +217,7 @@ Send::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
return true;
}
+/** Caller must not hold process lock */
bool
Send::configure_io (ChanCount in, ChanCount out)
{
@@ -225,6 +226,7 @@ Send::configure_io (ChanCount in, ChanCount out)
}
if (_output) {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock());
_output->ensure_io (out, false, 0);
}
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index f5df3a0e6b..64c5a173c4 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -1504,6 +1504,7 @@ Session::count_existing_route_channels (ChanCount& in, ChanCount& out)
}
}
+/** Caller must not hold process lock */
list<boost::shared_ptr<MidiTrack> >
Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_many)
{
@@ -1541,15 +1542,17 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m
boost_debug_shared_ptr_mark_interesting (mt, "Track");
track = boost::shared_ptr<MidiTrack>(mt);
- if (track->input()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) {
- error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
- goto failed;
- }
-
+ {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+ if (track->input()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) {
+ error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
+ goto failed;
+ }
- if (track->output()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) {
- error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
- goto failed;
+ if (track->output()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) {
+ error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
+ goto failed;
+ }
}
auto_connect_route (track.get(), existing_inputs, existing_outputs);
@@ -1590,7 +1593,8 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m
return ret;
}
-/** @param connect_inputs true to connect inputs as well as outputs, false to connect just outputs.
+/** Caller must hold process lock.
+ * @param connect_inputs true to connect inputs as well as outputs, false to connect just outputs.
* @param input_start Where to start from when auto-connecting inputs; e.g. if this is 0, auto-connect starting from input 0.
* @param output_start As \a input_start, but for outputs.
*/
@@ -1669,6 +1673,7 @@ Session::auto_connect_route (
existing_outputs += route->n_outputs();
}
+/** Caller must not hold process lock */
list< boost::shared_ptr<AudioTrack> >
Session::new_audio_track (int input_channels, int output_channels, TrackMode mode, RouteGroup* route_group, uint32_t how_many)
{
@@ -1706,23 +1711,27 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
boost_debug_shared_ptr_mark_interesting (at, "Track");
track = boost::shared_ptr<AudioTrack>(at);
- if (track->input()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) {
- error << string_compose (
- _("cannot configure %1 in/%2 out configuration for new audio track"),
- input_channels, output_channels)
- << endmsg;
- goto failed;
- }
+ {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
- if (track->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) {
- error << string_compose (
- _("cannot configure %1 in/%2 out configuration for new audio track"),
- input_channels, output_channels)
- << endmsg;
- goto failed;
- }
+ if (track->input()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) {
+ error << string_compose (
+ _("cannot configure %1 in/%2 out configuration for new audio track"),
+ input_channels, output_channels)
+ << endmsg;
+ goto failed;
+ }
+
+ if (track->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) {
+ error << string_compose (
+ _("cannot configure %1 in/%2 out configuration for new audio track"),
+ input_channels, output_channels)
+ << endmsg;
+ goto failed;
+ }
- auto_connect_route (track.get(), existing_inputs, existing_outputs);
+ auto_connect_route (track.get(), existing_inputs, existing_outputs);
+ }
if (route_group) {
route_group->add (track);
@@ -1787,7 +1796,7 @@ Session::set_remote_control_ids ()
}
}
-
+/** Caller must not hold process lock */
RouteList
Session::new_audio_route (bool aux, int input_channels, int output_channels, RouteGroup* route_group, uint32_t how_many)
{
@@ -1820,23 +1829,27 @@ Session::new_audio_route (bool aux, int input_channels, int output_channels, Rou
boost_debug_shared_ptr_mark_interesting (rt, "Route");
shared_ptr<Route> bus (rt);
- if (bus->input()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) {
- error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
- input_channels, output_channels)
- << endmsg;
- goto failure;
- }
+ {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+ if (bus->input()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) {
+ error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
+ input_channels, output_channels)
+ << endmsg;
+ goto failure;
+ }
+
+
+ if (bus->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) {
+ error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
+ input_channels, output_channels)
+ << endmsg;
+ goto failure;
+ }
- if (bus->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) {
- error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
- input_channels, output_channels)
- << endmsg;
- goto failure;
+ auto_connect_route (bus.get(), existing_inputs, existing_outputs, false);
}
- auto_connect_route (bus.get(), existing_inputs, existing_outputs, false);
-
if (route_group) {
route_group->add (bus);
}
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index 6ceeeb599c..9f87c77009 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -510,6 +510,7 @@ Session::ensure_subdirs ()
return 0;
}
+/** Caller must not hold process lock */
int
Session::create (const string& mix_template, BusProfile* bus_profile)
{
@@ -578,8 +579,11 @@ Session::create (const string& mix_template, BusProfile* bus_profile)
}
boost_debug_shared_ptr_mark_interesting (rt, "Route");
boost::shared_ptr<Route> r (rt);
- r->input()->ensure_io (count, false, this);
- r->output()->ensure_io (count, false, this);
+ {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+ r->input()->ensure_io (count, false, this);
+ r->output()->ensure_io (count, false, this);
+ }
r->set_remote_control_id (control_id++);
rl.push_back (r);
@@ -592,8 +596,11 @@ Session::create (const string& mix_template, BusProfile* bus_profile)
}
boost_debug_shared_ptr_mark_interesting (rt, "Route");
boost::shared_ptr<Route> r (rt);
- r->input()->ensure_io (count, false, this);
- r->output()->ensure_io (count, false, this);
+ {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+ r->input()->ensure_io (count, false, this);
+ r->output()->ensure_io (count, false, this);
+ }
r->set_remote_control_id (control_id);
rl.push_back (r);
diff --git a/libs/pbd/pbd/signals.h b/libs/pbd/pbd/signals.h
index cfbbc949c9..17059ec854 100644
--- a/libs/pbd/pbd/signals.h
+++ b/libs/pbd/pbd/signals.h
@@ -110,11 +110,11 @@ private:
SignalType _signal;
};
-template<typename R, typename A>
+template<typename R, typename A, typename C = boost::signals2::optional_last_value<R> >
class Signal1 {
public:
Signal1 () {}
- typedef boost::signals2::signal<R(A)> SignalType;
+ typedef boost::signals2::signal<R(A), C> SignalType;
void connect_same_thread (ScopedConnectionList& clist,
const typename SignalType::slot_function_type& slot) {