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
This commit is contained in:
parent
28c004f4fb
commit
54cbc45a5a
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
auto_connect_route (bus.get(), existing_inputs, existing_outputs, false);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
if (route_group) {
|
||||
route_group->add (bus);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue