#include "ardour/audioengine.h"
#include "ardour/buffer.h"
+#include "ardour/buffer_set.h"
#include "ardour/debug.h"
#include "ardour/io.h"
-#include "ardour/route.h"
#include "ardour/port.h"
-#include "ardour/audio_port.h"
-#include "ardour/midi_port.h"
+#include "ardour/route.h"
#include "ardour/session.h"
-#include "ardour/cycle_timer.h"
-#include "ardour/buffer_set.h"
-#include "ardour/meter.h"
-#include "ardour/amp.h"
#include "ardour/user_bundle.h"
#include "i18n.h"
, _default_type (default_type)
{
_active = true;
+ Port::PostDisconnect.connect_same_thread (*this, boost::bind (&IO::disconnect_check, this, _1, _2));
pending_state_node = 0;
setup_bundle ();
}
{
_active = true;
pending_state_node = 0;
+ Port::PostDisconnect.connect_same_thread (*this, boost::bind (&IO::disconnect_check, this, _1, _2));
set_state (node, Stateful::loading_state_version);
setup_bundle ();
}
}
+void
+IO::disconnect_check (boost::shared_ptr<Port> a, boost::shared_ptr<Port> b)
+{
+ /* this could be called from within our own ::disconnect() method(s)
+ or from somewhere that operates directly on a port. so, we don't
+ know for sure if we can take this lock or not. if we fail,
+ we assume that its safely locked by our own ::disconnect().
+ */
+
+ Glib::Mutex::Lock tm (io_lock, Glib::TRY_LOCK);
+
+ if (tm.locked()) {
+ /* we took the lock, so we cannot be here from inside
+ * ::disconnect()
+ */
+ if (_ports.contains (a) || _ports.contains (b)) {
+ changed (IOChange (IOChange::ConnectionsChanged), this); /* EMIT SIGNAL */
+ }
+ } else {
+ /* we didn't get the lock, so assume that we're inside
+ * ::disconnect(), and it will call changed() appropriately.
+ */
+ }
+}
+
void
IO::increment_port_buffer_offset (pframes_t offset)
{
ChanCount after = before;
after.set (port->type(), after.get (port->type()) - 1);
- bool const r = PortCountChanging (after); /* EMIT SIGNAL */
- if (r) {
+ boost::optional<bool> const r = PortCountChanging (after); /* EMIT SIGNAL */
+ if (r.get_value_or (false)) {
return -1;
}
type = _default_type;
}
+ ChanCount before = _ports.count ();
+ ChanCount after = before;
+ after.set (type, after.get (type) + 1);
+
+ bool const r = PortCountChanging (after); /* EMIT SIGNAL */
+ if (r) {
+ return -1;
+ }
+
IOChange change;
{
return 0;
}
+void
+IO::prepare_for_reset (XMLNode& node, const std::string& name)
+{
+ /* reset name */
+ node.add_property ("name", name);
+
+ /* now find connections and reset the name of the port
+ in one so that when we re-use it it will match
+ the name of the thing we're applying it to.
+ */
+
+ XMLProperty* prop;
+ XMLNodeList children = node.children();
+
+ for (XMLNodeIterator i = children.begin(); i != children.end(); ++i) {
+
+ if ((*i)->name() == "Port") {
+
+ prop = (*i)->property (X_("name"));
+
+ if (prop) {
+ string new_name;
+ string old = prop->value();
+ string::size_type slash = old.find ('/');
+
+ if (slash != string::npos) {
+ /* port name is of form: <IO-name>/<port-name> */
+
+ new_name = name;
+ new_name += old.substr (old.find ('/'));
+
+ prop->set_value (new_name);
+ }
+ }
+ }
+ }
+}
+
int
IO::make_connections_2X (const XMLNode& node, int /*version*/, bool in)
int
IO::enable_connecting ()
{
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock());
connecting_legal = true;
boost::optional<int> r = ConnectingLegal ();
return r.get_value_or (0);
return false;
}
-/** Caller must hold process lock */
+/** Call a processor's ::run() method, giving it our buffers
+ * Caller must hold process lock.
+ */
void
IO::process_input (boost::shared_ptr<Processor> proc, framepos_t start_frame, framepos_t end_frame, pframes_t nframes)
{
/* don't read the data into new buffers - just use the port buffers directly */
+ if (n_ports().n_total() == 0) {
+ /* We have no ports, so nothing to process */
+ return;
+ }
+
_buffers.get_jack_port_addresses (_ports, nframes);
proc->run (_buffers, start_frame, end_frame, nframes, true);
}