From c4c40340855dff6191a670d3130d65b1e79dc8a0 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 15 Mar 2011 19:32:21 +0000 Subject: [PATCH] fix all manner of things relating to io connections, setting capture alignment, and so on. still needs more tests of actual precise placement of newly recorded material git-svn-id: svn://localhost/ardour2/branches/3.0@9155 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/audio_diskstream.h | 19 ++++--- libs/ardour/ardour/audioengine.h | 3 ++ libs/ardour/ardour/session.h | 2 +- libs/ardour/audio_diskstream.cc | 64 ++++++++++++------------ libs/ardour/audioengine.cc | 30 ++++++++++- libs/ardour/diskstream.cc | 12 +++-- libs/ardour/io.cc | 3 +- libs/ardour/midi_diskstream.cc | 13 +++-- libs/ardour/port.cc | 9 ++-- libs/ardour/route.cc | 43 ---------------- libs/ardour/session.cc | 71 ++++++++++++++------------- libs/ardour/session_transport.cc | 5 +- 12 files changed, 138 insertions(+), 136 deletions(-) diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h index 53dbe5bd9b..12ad418a75 100644 --- a/libs/ardour/ardour/audio_diskstream.h +++ b/libs/ardour/ardour/audio_diskstream.h @@ -66,17 +66,12 @@ class AudioDiskstream : public Diskstream std::string input_source (uint32_t n=0) const { boost::shared_ptr c = channels.reader(); if (n < c->size()) { - return (*c)[n]->source ? (*c)[n]->source->name() : ""; + return (*c)[n]->source.name; } else { return ""; } } - Port *input_source_port (uint32_t n=0) const { - boost::shared_ptr c = channels.reader(); - if (n < c->size()) return (*c)[n]->source; return 0; - } - void set_record_enabled (bool yn); int set_destructive (bool yn); int set_non_layered (bool yn); @@ -179,6 +174,12 @@ class AudioDiskstream : public Diskstream bool commit (framecnt_t nframes); private: + struct ChannelSource { + std::string name; + + bool is_physical () const; + void ensure_monitor_input (bool) const; + }; struct ChannelInfo : public boost::noncopyable { @@ -197,8 +198,10 @@ class AudioDiskstream : public Diskstream boost::shared_ptr fades_source; boost::shared_ptr write_source; - /// the Port that our audio data comes from - Port *source; + /// information the Port that our audio data comes from + + ChannelSource source; + Sample *current_capture_buffer; Sample *current_playback_buffer; diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index e025169f0a..8e68581e12 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -170,6 +170,9 @@ class AudioEngine : public SessionHandlePtr Port *register_output_port (DataType, const std::string& portname); int unregister_port (Port &); + bool port_is_physical (const std::string&) const; + void ensure_monitor_input (const std::string&, bool) const; + void split_cycle (pframes_t offset); int connect (const std::string& source, const std::string& destination); diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index c67e3d10fe..29aae1fbd4 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -1221,7 +1221,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi void route_processors_changed (RouteProcessorChange); bool find_route_name (std::string const &, uint32_t& id, char* name, size_t name_len, bool); - void count_existing_route_channels (ChanCount& in, ChanCount& out); + void count_existing_track_channels (ChanCount& in, ChanCount& out); void auto_connect_route (Route*, ChanCount& existing_inputs, ChanCount& existing_outputs, diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index 36d72ce124..abe75b6ea2 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -162,7 +162,7 @@ AudioDiskstream::non_realtime_input_change () return; } - { + if (input_change_pending.type == IOChange::ConfigurationChanged) { RCUWriter writer (channels); boost::shared_ptr c = writer.get_copy(); @@ -175,9 +175,11 @@ AudioDiskstream::non_realtime_input_change () } } - get_input_sources (); - set_capture_offset (); - set_align_style_from_io (); + if (input_change_pending.type & IOChange::ConnectionsChanged) { + get_input_sources (); + set_capture_offset (); + set_align_style_from_io (); + } input_change_pending = IOChange::NoChange; @@ -223,20 +225,13 @@ AudioDiskstream::get_input_sources () connections.clear (); - cerr << "Getting Nth connection from io " << n << " = " << _io->nth(n) << endl; - if (_io->nth (n)->get_connections (connections) == 0) { - - cerr << "\tThere were NO connections, apparently ...\n"; - if ((*chan)->source) { + if (!(*chan)->source.name.empty()) { // _source->disable_metering (); } - - (*chan)->source = 0; - + (*chan)->source.name = string(); } else { - cerr << "\tThere were some connections, apparently ... to " << connections[0] << endl; - (*chan)->source = dynamic_cast(_session.engine().get_port_by_name (connections[0]) ); + (*chan)->source.name = connections[0]; } } } @@ -1681,9 +1676,7 @@ AudioDiskstream::engage_record_enable () if (Config->get_monitoring_model() == HardwareMonitoring) { for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { - if ((*chan)->source) { - (*chan)->source->ensure_monitor_input (!(_session.config.get_auto_input() && rolling)); - } + (*chan)->source.ensure_monitor_input (!(_session.config.get_auto_input() && rolling)); capturing_sources.push_back ((*chan)->write_source); (*chan)->write_source->mark_streaming_write_started (); } @@ -1705,9 +1698,7 @@ AudioDiskstream::disengage_record_enable () boost::shared_ptr c = channels.reader(); if (Config->get_monitoring_model() == HardwareMonitoring) { for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { - if ((*chan)->source) { - (*chan)->source->ensure_monitor_input (false); - } + (*chan)->source.ensure_monitor_input (false); } } capturing_sources.clear (); @@ -1992,10 +1983,7 @@ AudioDiskstream::monitor_input (bool yn) boost::shared_ptr c = channels.reader(); for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { - - if ((*chan)->source) { - (*chan)->source->ensure_monitor_input (yn); - } + (*chan)->source.ensure_monitor_input (yn); } } @@ -2016,17 +2004,12 @@ AudioDiskstream::set_align_style_from_io () boost::shared_ptr c = channels.reader(); - cerr << "Checking " << c->size() << " for physical connections\n"; - for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { - cerr << "Channel connected via " << (*chan)->source << endl; - if ((*chan)->source && (*chan)->source->flags() & JackPortIsPhysical) { - cerr << "\tchannel has physical connection to " << (*chan)->source->name() << endl; + if ((*chan)->source.is_physical ()) { have_physical = true; break; } } - cerr << "\tphysical? " << have_physical << endl; if (have_physical) { set_align_style (ExistingMaterial); @@ -2312,10 +2295,29 @@ AudioDiskstream::adjust_capture_buffering () } } +bool +AudioDiskstream::ChannelSource::is_physical () const +{ + if (name.empty()) { + return false; + } + + return AudioEngine::instance()->port_is_physical (name); +} + +void +AudioDiskstream::ChannelSource::ensure_monitor_input (bool yn) const +{ + if (name.empty()) { + return; + } + + return AudioEngine::instance()->ensure_monitor_input (name, yn); +} + AudioDiskstream::ChannelInfo::ChannelInfo (framecnt_t playback_bufsize, framecnt_t capture_bufsize, framecnt_t speed_size, framecnt_t wrap_size) { peak_power = 0.0f; - source = 0; current_capture_buffer = 0; current_playback_buffer = 0; curr_capture_cnt = 0; diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index ffa55e453d..6067da55b7 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -1010,7 +1010,7 @@ AudioEngine::get_port_by_name (const string& portname) } } - return 0; + return 0; } const char ** @@ -1484,3 +1484,31 @@ AudioEngine::_start_process_thread (void* arg) return 0; } + +bool +AudioEngine::port_is_physical (const std::string& portname) const +{ + GET_PRIVATE_JACK_POINTER_RET(_jack, false); + + jack_port_t *port = jack_port_by_name (_priv_jack, portname.c_str()); + + if (!port) { + return false; + } + + return jack_port_flags (port) & JackPortIsPhysical; +} + +void +AudioEngine::ensure_monitor_input (const std::string& portname, bool yn) const +{ + GET_PRIVATE_JACK_POINTER(_jack); + + jack_port_t *port = jack_port_by_name (_priv_jack, portname.c_str()); + + if (!port) { + return; + } + + jack_port_request_monitor (port, yn); +} diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc index ae4a8ada3e..affda7b56a 100644 --- a/libs/ardour/diskstream.cc +++ b/libs/ardour/diskstream.cc @@ -180,9 +180,8 @@ Diskstream::set_track (Track* t) ic_connection.disconnect(); _io->changed.connect_same_thread (ic_connection, boost::bind (&Diskstream::handle_input_change, this, _1, _2)); - input_change_pending = IOChange::ConfigurationChanged; + input_change_pending.type = IOChange::Type (IOChange::ConfigurationChanged|IOChange::ConnectionsChanged); non_realtime_input_change (); - set_align_style_from_io (); _track->Destroyed.connect_same_thread (*this, boost::bind (&Diskstream::route_going_away, this)); } @@ -192,7 +191,14 @@ Diskstream::handle_input_change (IOChange change, void * /*src*/) { Glib::Mutex::Lock lm (state_lock); - if (change.type & IOChange::ConfigurationChanged) { + if (change.type & (IOChange::ConfigurationChanged|IOChange::ConnectionsChanged)) { + + /* rather than handle this here on a DS-by-DS basis we defer to the + session transport/butler thread, and let it tackle + as many diskstreams as need it in one shot. this avoids many repeated + takings of the audioengine process lock. + */ + if (!(input_change_pending.type & change.type)) { input_change_pending.type = IOChange::Type (input_change_pending.type | change.type); _session.request_input_change_handling (); diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index 875fca7fa0..27f8ca819d 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -224,7 +224,6 @@ IO::connect (Port* our_port, string other_port, void* src) return -1; } } - changed (IOChange (IOChange::ConnectionsChanged), src); /* EMIT SIGNAL */ _session.set_dirty (); return 0; @@ -912,7 +911,7 @@ IO::make_connections (const XMLNode& node, int version, bool in) } if (prop) { - p->connect (prop->value()); + connect (p, prop->value(), this); } } } diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index 3d2336da3a..3889d79dfb 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -164,14 +164,17 @@ MidiDiskstream::non_realtime_input_change () if (input_change_pending.type & IOChange::ConfigurationChanged) { if (_io->n_ports().n_midi() != _n_channels.n_midi()) { - error << "Can not feed IO " << _io->n_ports() - << " with diskstream " << _n_channels << endl; + error << "Can not feed " << _io->n_ports() + << " ports to " << _n_channels << " channels" + << endmsg; } } - get_input_sources (); - set_capture_offset (); - set_align_style_from_io (); + if (input_change_pending.type & IOChange::ConnectionsChanged) { + get_input_sources (); + set_capture_offset (); + set_align_style_from_io (); + } input_change_pending.type = IOChange::NoChange; diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc index bd3004ba02..c66995bb3c 100644 --- a/libs/ardour/port.cc +++ b/libs/ardour/port.cc @@ -341,11 +341,11 @@ Port::get_connected_latency_range (jack_latency_range_t& range, bool playback) c range.min = ~((jack_nframes_t) 0); range.max = 0; + DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: %2 connections to check for latency range\n", name(), connections.size())); + for (vector::const_iterator c = connections.begin(); c != connections.end(); ++c) { - cerr << "Connection between " << name() << " and " << *c << endl; - jack_port_t* remote_port = jack_port_by_name (_engine->jack(), (*c).c_str()); jack_latency_range_t lr; @@ -359,15 +359,16 @@ Port::get_connected_latency_range (jack_latency_range_t& range, bool playback) c name(), *c, lr.min, lr.max)); range.min = min (range.min, lr.min); range.max = max (range.max, lr.max); - } else { - cerr << "\t NO PORT BY NAME!\n"; } } } else { + DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: not connected to anything\n", name())); range.min = 0; range.max = 0; } + + DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: final connected latency range [ %2 .. %3 ] \n", name(), range.min, range.max)); } int diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index d368198e22..f5fd4a682c 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -137,8 +137,6 @@ Route::init () _output.reset (new IO (_session, _name, IO::Output, _default_type)); _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 */ @@ -2742,47 +2740,6 @@ Route::input_change_handler (IOChange change, void * /*src*/) } } -/** Called with the process lock held if change contains ConfigurationChanged */ -void -Route::output_change_handler (IOChange change, void * /*src*/) -{ - if ((change.type & IOChange::ConfigurationChanged)) { - - /* XXX resize all listeners to match _main_outs? */ - - /* Auto-connect newly-created outputs, unless we're auto-connecting to master - and we are master (as an auto-connect in this situation would cause a - feedback loop) - */ - - AutoConnectOption ac = Config->get_output_auto_connect (); - - if (ac == AutoConnectPhysical || (ac == AutoConnectMaster && !is_master ())) { - - ChanCount start = change.before; - - for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) { - if (change.before.get(*i) < change.after.get(*i)) { - /* the existing ChanCounts don't matter for this call as they are only - to do with matching input and output indices, and we are only changing - outputs here. - */ - ChanCount dummy; - - /* only auto-connect the newly-created outputs, not the ones that were - already there - */ - start.set (*i, start.get (*i) + 1); - - _session.auto_connect_route (this, dummy, dummy, false, false, ChanCount(), change.before); - } - } - } - - // configure_processors (0); - } -} - uint32_t Route::pans_required () const { diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index f08f0589d3..35aebf7eff 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -1399,9 +1399,9 @@ Session::find_route_name (string const & base, uint32_t& id, char* name, size_t return false; } -/** Count the total ins and outs of all non-hidden routes in the session and return them in in and out */ +/** Count the total ins and outs of all non-hidden tracks in the session and return them in in and out */ void -Session::count_existing_route_channels (ChanCount& in, ChanCount& out) +Session::count_existing_track_channels (ChanCount& in, ChanCount& out) { in = ChanCount::ZERO; out = ChanCount::ZERO; @@ -1409,9 +1409,11 @@ Session::count_existing_route_channels (ChanCount& in, ChanCount& out) boost::shared_ptr r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - if (!(*i)->is_hidden()) { - in += (*i)->n_inputs(); - out += (*i)->n_outputs(); + boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); + if (tr && !tr->is_hidden()) { + cerr << "Using track i/o counts for " << tr->name() << endl; + in += tr->n_inputs(); + out += tr->n_outputs(); } } } @@ -1511,6 +1513,7 @@ Session::auto_connect_route (Route* route, ChanCount& existing_inputs, ChanCount bool with_lock, bool connect_inputs, ChanCount input_start, ChanCount output_start) { if (!IO::connecting_legal) { + cerr << "Auto-connect ignored because connecting it not legal\n"; return; } @@ -1528,14 +1531,16 @@ Session::auto_connect_route (Route* route, ChanCount& existing_inputs, ChanCount offset possible. */ - cerr << "ACR: existing in = " << existing_inputs << " out = " << existing_outputs << endl; + cerr << "Auto-connect: existing in = " << existing_inputs << " out = " << existing_outputs << endl; const bool in_out_physical = (Config->get_input_auto_connect() & AutoConnectPhysical) && (Config->get_output_auto_connect() & AutoConnectPhysical) && connect_inputs; - const ChanCount in_offset = existing_inputs; + const ChanCount in_offset = in_out_physical + ? ChanCount::max(existing_inputs, existing_outputs) + : existing_inputs; const ChanCount out_offset = in_out_physical ? ChanCount::max(existing_inputs, existing_outputs) @@ -1896,6 +1901,11 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template void Session::add_routes (RouteList& new_routes, bool auto_connect, bool save) { + ChanCount existing_inputs; + ChanCount existing_outputs; + + count_existing_track_channels (existing_inputs, existing_outputs); + { RCUWriter writer (routes); boost::shared_ptr r = writer.get_copy (); @@ -1948,11 +1958,6 @@ Session::add_routes (RouteList& new_routes, bool auto_connect, bool save) if (auto_connect) { - ChanCount existing_inputs; - ChanCount existing_outputs; - - count_existing_route_channels (existing_inputs, existing_outputs); - auto_connect_route (r, existing_inputs, existing_outputs, true); } } @@ -4160,25 +4165,23 @@ Session::update_latency (bool playback) max_latency = max (max_latency, (*i)->set_private_port_latencies (playback)); } + /* because we latency compensate playback, our published playback latencies should + be the same for all output ports - all material played back by ardour has + the same latency, whether its caused by plugins or by latency compensation. since + these may differ from the values computed above, reset all playback port latencies + to the same value. + */ + + DEBUG_TRACE (DEBUG::Latency, string_compose ("Set public port latencies to %1\n", max_latency)); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + (*i)->set_public_port_latencies (max_latency, playback); + } + if (playback) { post_playback_latency (); - /* because we latency compensate playback, our published playback latencies should - be the same for all output ports - all material played back by ardour has - the same latency, whether its caused by plugins or by latency compensation. since - these may differ from the values computed above, reset all playback port latencies - to the same value. - */ - - DEBUG_TRACE (DEBUG::Latency, string_compose ("Set public port latencies to %1\n", max_latency)); - - for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - (*i)->set_public_port_latencies (max_latency, playback); - } - - - } else { post_capture_latency (); @@ -4275,9 +4278,9 @@ Session::set_worst_capture_latency () void Session::update_latency_compensation (bool force_whole_graph) { - bool update_jack = false; + bool some_track_latency_changed = false; - if (_state_of_the_state & Deletion) { + if (_state_of_the_state & (InitialConnecting|Deletion)) { return; } @@ -4286,21 +4289,21 @@ Session::update_latency_compensation (bool force_whole_graph) _worst_track_latency = 0; boost::shared_ptr r = routes.reader (); - + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (!(*i)->is_hidden() && ((*i)->active())) { framecnt_t tl; if ((*i)->signal_latency () != (tl = (*i)->update_signal_latency ())) { - update_jack = true; + some_track_latency_changed = true; } _worst_track_latency = max (tl, _worst_track_latency); } } DEBUG_TRACE (DEBUG::Latency, string_compose ("worst signal processing latency: %1 (changed ? %2)\n", _worst_track_latency, - (update_jack ? "yes" : "no"))); + (some_track_latency_changed ? "yes" : "no"))); - if (force_whole_graph || update_jack) { + if (force_whole_graph || some_track_latency_changed) { /* trigger a full recompute of latency numbers for the graph. everything else that we need to do will be done in the latency callback. @@ -4309,8 +4312,6 @@ Session::update_latency_compensation (bool force_whole_graph) return; // everything else will be done in the latency callback } - - DEBUG_TRACE(DEBUG::Latency, "---------------------------- DONE update latency compensation\n\n") } diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 248172fcd9..3dc1f9e7b3 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -226,7 +226,7 @@ Session::realtime_stop (bool abort, bool clear_state) /* we rolled past the stop point to pick up data that had not yet arrived. move back to where the stop occured. */ - decrement_transport_position (current_block_size + (worst_playback_latency() - current_block_size)); + decrement_transport_position (current_block_size + (worst_input_latency() - current_block_size)); } else { decrement_transport_position (current_block_size); } @@ -1047,7 +1047,7 @@ Session::stop_transport (bool abort, bool clear_state) return; } - if (actively_recording() && !(transport_sub_state & StopPendingCapture) && worst_playback_latency() > current_block_size) { + if (actively_recording() && !(transport_sub_state & StopPendingCapture) && worst_input_latency() > current_block_size) { boost::shared_ptr rl = routes.reader(); for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { @@ -1075,7 +1075,6 @@ Session::stop_transport (bool abort, bool clear_state) return; } - if ((transport_sub_state & PendingDeclickOut) == 0) { if (!(transport_sub_state & StopPendingCapture)) {