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
This commit is contained in:
Paul Davis 2011-03-15 19:32:21 +00:00
parent eee943304c
commit c4c4034085
12 changed files with 138 additions and 136 deletions

View File

@ -66,17 +66,12 @@ class AudioDiskstream : public Diskstream
std::string input_source (uint32_t n=0) const {
boost::shared_ptr<ChannelList> 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<ChannelList> 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<AudioFileSource> fades_source;
boost::shared_ptr<AudioFileSource> 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;

View File

@ -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);

View File

@ -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,

View File

@ -162,7 +162,7 @@ AudioDiskstream::non_realtime_input_change ()
return;
}
{
if (input_change_pending.type == IOChange::ConfigurationChanged) {
RCUWriter<ChannelList> writer (channels);
boost::shared_ptr<ChannelList> 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<AudioPort*>(_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<ChannelList> 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<ChannelList> 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<ChannelList> 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;

View File

@ -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);
}

View File

@ -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 ();

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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<string>::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

View File

@ -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
{

View File

@ -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<RouteList> 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<Track> tr = boost::dynamic_pointer_cast<Track> (*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<RouteList> writer (routes);
boost::shared_ptr<RouteList> 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<RouteList> 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")
}

View File

@ -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<RouteList> 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)) {