#include "ardour/audioengine.h"
#include "ardour/buffer.h"
+#include "ardour/debug.h"
#include "ardour/io.h"
#include "ardour/route.h"
#include "ardour/port.h"
}
void
-IO::silence (nframes_t nframes)
+IO::increment_port_buffer_offset (pframes_t offset)
+{
+ /* io_lock, not taken: function must be called from Session::process() calltree */
+
+ if (_direction == Output) {
+ for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
+ i->increment_port_buffer_offset (offset);
+ }
+ }
+}
+
+void
+IO::silence (framecnt_t nframes)
{
/* io_lock, not taken: function must be called from Session::process() calltree */
return 0;
}
- {
- BLOCK_PROCESS_CALLBACK ();
+ {
+ Glib::Mutex::Lock lm (io_lock);
- {
- Glib::Mutex::Lock lm (io_lock);
-
- /* check that our_port is really one of ours */
+ /* check that our_port is really one of ours */
- if ( ! _ports.contains(our_port)) {
- return -1;
- }
+ if ( ! _ports.contains(our_port)) {
+ return -1;
+ }
- /* disconnect it from the source */
+ /* disconnect it from the source */
- if (our_port->disconnect (other_port)) {
- error << string_compose(_("IO: cannot disconnect port %1 from %2"), our_port->name(), other_port) << endmsg;
- return -1;
- }
+ if (our_port->disconnect (other_port)) {
+ error << string_compose(_("IO: cannot disconnect port %1 from %2"), our_port->name(), other_port) << endmsg;
+ return -1;
+ }
- check_bundles_connected ();
- }
+ 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;
}
{
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;
}
}
-
changed (IOChange (IOChange::ConnectionsChanged), src); /* EMIT SIGNAL */
_session.set_dirty ();
return 0;
if (change.type != IOChange::NoChange) {
changed (change, src);
- _session.set_dirty ();
+ _buffers.attach_buffers (_ports);
}
}
return -1;
}
+ _session.set_dirty ();
+
return 0;
}
/* Create a new port */
string portname = build_legal_port_name (type);
-
+
if (_direction == Input) {
if ((our_port = _session.engine().register_input_port (type, portname)) == 0) {
error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg;
change.before = _ports.count ();
_ports.add (our_port);
}
-
- PortCountChanged (n_ports()); /* EMIT SIGNAL */
- // pan_changed (src); /* EMIT SIGNAL */
+ PortCountChanged (n_ports()); /* EMIT SIGNAL */
change.type = IOChange::ConfigurationChanged;
change.after = _ports.count ();
changed (change, src); /* EMIT SIGNAL */
+ _buffers.attach_buffers (_ports);
}
- if (destination.length()) {
+ if (!destination.empty()) {
if (our_port->connect (destination)) {
return -1;
}
int
IO::disconnect (void* src)
{
- 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 ();
}
-
+
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*/)
+int
+IO::ensure_ports_locked (ChanCount count, bool clear, bool& changed)
{
assert (!AudioEngine::instance()->process_lock().trylock());
-
+
Port* port = 0;
- bool changed = false;
+
+ changed = false;
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
}
}
- return changed;
+ return 0;
}
/** Caller must hold process lock */
IO::ensure_ports (ChanCount count, bool clear, void* src)
{
assert (!AudioEngine::instance()->process_lock().trylock());
-
+
bool changed = false;
if (count == n_ports() && !clear) {
IOChange change;
change.before = _ports.count ();
-
+
{
Glib::Mutex::Lock im (io_lock);
- changed = ensure_ports_locked (count, clear, src);
+ if (ensure_ports_locked (count, clear, changed)) {
+ return -1;
+ }
}
if (changed) {
change.after = _ports.count ();
change.type = IOChange::ConfigurationChanged;
this->changed (change, src); /* EMIT SIGNAL */
+ _buffers.attach_buffers (_ports);
setup_bundle ();
_session.set_dirty ();
}
IO::ensure_io (ChanCount count, bool clear, void* src)
{
assert (!AudioEngine::instance()->process_lock().trylock());
-
+
return ensure_ports (count, clear, src);
}
node->add_child_nocopy (*pnode);
}
+ snprintf (buf, sizeof (buf), "%" PRId64, _user_latency);
+ node->add_property (X_("user-latency"), buf);
+
return *node;
}
ConnectingLegal.connect_same_thread (connection_legal_c, boost::bind (&IO::connecting_became_legal, this));
}
+ if ((prop = node.property ("user-latency")) != 0) {
+ _user_latency = atoi (prop->value ());
+ }
return 0;
}
{
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;
if ((prop = cnode->property (X_("other"))) == 0) {
continue;
}
-
+
if (prop) {
- p->connect (prop->value());
+ connect (p, prop->value(), this);
}
}
- }
+ }
}
}
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-
+
// FIXME: audio-only
if (ensure_ports (ChanCount(DataType::AUDIO, nports), true, this)) {
return -1;
/* replace all colons in the name. i wish we didn't have to do this */
- replace_all (name, ":", "-");
+ replace_all (name, ":", "-");
for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
string current_name = i->name();
return r;
}
-void
-IO::set_port_latency (nframes_t nframes)
-{
- Glib::Mutex::Lock lm (io_lock);
-
- for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
- i->set_latency (nframes);
- }
-}
-
-nframes_t
+framecnt_t
IO::latency () const
{
- nframes_t max_latency;
- nframes_t latency;
+ framecnt_t max_latency;
+ framecnt_t latency;
max_latency = 0;
/* io lock not taken - must be protected by other means */
for (PortSet::const_iterator i = _ports.begin(); i != _ports.end(); ++i) {
- if ((latency = i->total_latency ()) > max_latency) {
+ if ((latency = i->private_latency_range (_direction == Output).max) > max_latency) {
+ DEBUG_TRACE (DEBUG::Latency, string_compose ("port %1 has %2 latency of %3 - use\n",
+ name(),
+ ((_direction == Output) ? "PLAYBACK" : "CAPTURE"),
+ latency));
max_latency = latency;
}
}
+ DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: max %4 latency from %2 ports = %3\n",
+ name(), _ports.num_ports(), max_latency,
+ ((_direction == Output) ? "PLAYBACK" : "CAPTURE")));
return max_latency;
}
-void
-IO::update_port_total_latencies ()
-{
- /* io_lock, not taken: function must be called from Session::process() calltree */
-
- for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
- _session.engine().update_total_latency (*i);
- }
-}
-
int
IO::connect_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
{
char buf1[name_size+1];
char buf2[name_size+1];
- snprintf (buf1, name_size+1, ("%.*s/%s"), limit, _name.val().c_str(), suffix.c_str());
+ /* colons are illegal in port names, so fix that */
+
+ string nom = _name.val();
+ replace_all (nom, ":", ";");
+
+ snprintf (buf1, name_size+1, ("%.*s/%s"), limit, nom.c_str(), suffix.c_str());
int port_number = find_port_hole (buf1);
snprintf (buf2, name_size+1, "%s %d", buf1, port_number);
IO::connected () const
{
/* do we have any connections at all? */
-
+
for (PortSet::const_iterator p = _ports.begin(); p != _ports.end(); ++p) {
if (p->connected()) {
return true;
}
}
-
+
return false;
}
return false;
}
-void
-IO::process_input (boost::shared_ptr<Processor> proc, framepos_t start_frame, framepos_t end_frame, nframes_t nframes)
+bool
+IO::connected_to (const string& str) const
{
- BufferSet bufs;
+ for (PortSet::const_iterator i = _ports.begin(); i != _ports.end(); ++i) {
+ if (i->connected_to (str)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/** 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 */
- bufs.attach_buffers (_ports, nframes, 0);
- proc->run (bufs, start_frame, end_frame, nframes, true);
+ _buffers.get_jack_port_addresses (_ports, nframes);
+ proc->run (_buffers, start_frame, end_frame, nframes, true);
}
void
-IO::collect_input (BufferSet& bufs, nframes_t nframes, ChanCount offset)
+IO::collect_input (BufferSet& bufs, pframes_t nframes, ChanCount offset)
{
assert(bufs.available() >= _ports.count());
}
void
-IO::copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes, nframes_t offset)
+IO::copy_to_outputs (BufferSet& bufs, DataType type, pframes_t nframes, framecnt_t offset)
{
// Copy any buffers 1:1 to outputs
return false;
}
+
+bool
+IO::has_port (Port* p) const
+{
+ Glib::Mutex::Lock lm (io_lock);
+ return _ports.contains (p);
+}