13
0

T: radically change the logic for auto-connect

This now auto-connects all tracks at once, using a single list of available
ports for input and output.

It also handles a mixture of stereo and mono tracks correctly
This commit is contained in:
Paul Davis 2024-05-08 22:05:22 -06:00
parent 82d786f506
commit b10a5be5be
4 changed files with 93 additions and 101 deletions

View File

@ -1793,11 +1793,12 @@ private:
struct AutoConnectRequest {
public:
AutoConnectRequest (std::shared_ptr <Route> r,
bool ci, bool co,
const ChanCount& is,
const ChanCount& os,
const ChanCount& io,
const ChanCount& oo)
bool ci, bool co,
const ChanCount& is,
const ChanCount& os,
const ChanCount& io,
const ChanCount& oo,
bool a = false)
: route (std::weak_ptr<Route> (r))
, connect_inputs (ci)
, connect_outputs (co)
@ -1805,6 +1806,7 @@ private:
, output_start (os)
, input_offset (io)
, output_offset (oo)
, all (a)
{}
std::weak_ptr <Route> route;
@ -1814,6 +1816,7 @@ private:
ChanCount output_start;
ChanCount input_offset;
ChanCount output_offset;
bool all;
};
Glib::Threads::Mutex _update_latency_lock;
@ -1828,7 +1831,9 @@ private:
MidiPortFlags exclude = MidiPortFlags (0));
void auto_connect (const AutoConnectRequest&);
void livetrax_auto_connect (std::shared_ptr<Route>);
void build_available_physical_audio_io_lists (std::vector<std::string>& physinputs, std::vector<std::string>& physoutputs);
void livetrax_queue_auto_connect ();
void livetrax_auto_connect ();
void queue_latency_recompute ();
/* SessionEventManager interface */

View File

@ -83,6 +83,9 @@ InternalSend::~InternalSend ()
void
InternalSend::propagate_solo ()
{
if (_role == MasterSend) {
return;
}
if (_session.inital_connect_or_deletion_in_progress ()) {
return;
}

View File

@ -277,6 +277,8 @@ Send::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample, do
} else {
_meter->run (*_output_buffers, start_sample, end_sample, speed, nframes, true);
}
} else {
std::cerr << "send not metering\n";
}
_thru_delay->run (bufs, start_sample, end_sample, speed, nframes, true);

View File

@ -4680,16 +4680,17 @@ Session::reassign_track_numbers ()
route->set_track_number(--bn);
}
if (Profile->get_livetrax() && !route->is_auditioner() && route->is_track()) {
livetrax_auto_connect_route (route);
}
std::shared_ptr<TriggerBox> tb = (route)->triggerbox();
if (tb) {
tb->set_order (trigger_order);
trigger_order++;
}
}
if (Profile->get_livetrax()) {
livetrax_queue_auto_connect ();
}
const uint32_t decimals = ceilf (log10f (tn + 1));
const bool decimals_changed = _track_number_decimals != decimals;
_track_number_decimals = decimals;
@ -7804,14 +7805,20 @@ Session::unsuspend_livetrax_auto_connect ()
}
void
Session::livetrax_auto_connect_route (std::shared_ptr<Route> route)
Session::livetrax_queue_auto_connect ()
{
if (_no_livetrax_auto_connect) {
return;
}
ChanCount ignored;
auto_connect_route (route, true, true, ignored, ignored, ignored, ignored);
Glib::Threads::Mutex::Lock lx (_auto_connect_queue_lock);
/* special auto connect request with final argument "all" set to true */
_auto_connect_queue.push (AutoConnectRequest (std::shared_ptr<Route>(), true, true, ignored, ignored, ignored, ignored, true));
lx.release (); // XXX check try-lock + pthread_cond_wait
auto_connect_thread_wakeup ();
}
void
@ -7856,108 +7863,82 @@ Session::queue_latency_recompute ()
}
void
Session::livetrax_auto_connect (std::shared_ptr<Route> route)
Session::build_available_physical_audio_io_lists (vector<string>& physinputs, vector<string>& physoutputs)
{
vector<string> physinputs;
vector<string> physoutputs;
get_physical_ports (physinputs, physoutputs, DataType::AUDIO);
AudioBackend::ChannelMask const & input_channel_mask ( _engine.current_backend()->input_channel_mask());
AudioBackend::ChannelMask const & output_channel_mask ( _engine.current_backend()->output_channel_mask());
route->input()->disconnect (this);
route->output()->disconnect (this);
vector<string>::size_type n;
vector<string>::size_type ichn;
vector<string>::size_type ochn;
vector<string>::size_type i;
vector<string>::size_type start_from;
vector<string>::size_type enabled;
n = route->track_number() - 1;
/* move to the nth enabled input channel */
i = 0;
start_from = 0;
enabled = 0;
while (enabled <= n && i < input_channel_mask.size()) {
if (input_channel_mask[i]) {
start_from = i;
enabled++;
}
++i;
}
n = start_from;
size_t attempts = 0;
size_t limit = physinputs.size();
assert (physinputs.size() <= input_channel_mask.size());
assert (physoutputs.size() <= output_channel_mask.size());
while (attempts < limit) {
ichn = n % physinputs.size();
if (input_channel_mask[ichn]) {
route->input()->connect (route->input()->ports().port (DataType::AUDIO, 0), physinputs[ichn], this);
break;
vector<string>::size_type n = 0;
for (vector<string>::iterator i = physinputs.begin(); i != physinputs.end(); ++i) {
if (!input_channel_mask[n]) {
i = physinputs.erase (i);
} else {
/* reduce limit because we found a channel that can't be used */
--limit;
}
++attempts;
++n;
if (n >= physinputs.size()) {
n = 0;
++i;
}
}
n = route->track_number() - 1;
i = 0;
start_from = 0;
enabled = 0;
while (enabled <= n && i < output_channel_mask.size()) {
if (output_channel_mask[i]) {
start_from = i;
enabled++;
}
++i;
}
n = start_from;
attempts = 0;
limit = physoutputs.size();
while (attempts < limit) {
ochn = n % physoutputs.size();
if (output_channel_mask[ochn]) {
route->output()->connect (route->output()->ports().port (DataType::AUDIO, 0), physoutputs[ochn], this);
break;
n = 0;
for (vector<string>::iterator o = physoutputs.begin(); o != physoutputs.end(); ++o) {
if (!output_channel_mask[n]) {
o = physoutputs.erase (o);
} else {
/* reduce limit because we found a channel that can't be used */
--limit;
++o;
}
}
}
++attempts;
++n;
struct tnsorter {
bool operator()(std::shared_ptr<Track> a, std::shared_ptr<Track> b) {
return a->track_number() < b->track_number();
}
};
if (n >= physinputs.size()) {
n = 0;
void
Session::livetrax_auto_connect ()
{
vector<string> physinputs;
vector<string> physoutputs;
build_available_physical_audio_io_lists (physinputs, physoutputs);
vector<std::shared_ptr<Track>> tracks;
std::shared_ptr<Track> t;
std::shared_ptr<RouteList const> rl (routes.reader());
for (auto & r : *rl) {
if (!r->is_auditioner()) {
if ((t = std::dynamic_pointer_cast<Track> (r))) {
tracks.push_back (t);
}
}
}
DEBUG_TRACE (DEBUG::PortConnectAuto, string_compose ("livetrax auto connect %1 [%2] to %3 and %4\n", route->name(), route->track_number(),
physinputs[ichn],
physoutputs[ochn]));
sort (tracks.begin(), tracks.end(), tnsorter());
vector<string>::iterator ip = physinputs.begin();
vector<string>::iterator op = physoutputs.begin();
for (auto & t : tracks) {
t->input()->disconnect (this);
t->output()->disconnect (this);
uint32_t n;
n = t->input()->n_ports().n_audio();
for (uint32_t c = 0; c < n && ip != physinputs.end(); ++c) {
t->input()->connect (t->input()->ports().port (DataType::AUDIO, c), *ip, this);
++ip;
}
n = t->output()->n_ports().n_audio();
for (uint32_t c = 0; c < n && op != physoutputs.end(); ++c) {
t->output()->connect (t->output()->ports().port (DataType::AUDIO, c), *op, this);
++op;
}
}
}
void
@ -7965,14 +7946,15 @@ Session::auto_connect (const AutoConnectRequest& ar)
{
std::shared_ptr<Route> route = ar.route.lock();
if (!route) { return; }
if (loading()) {
if (!route) {
if (Profile->get_livetrax() && ar.all) {
/* This being LiveTrax, we will connect all tracks at once */
livetrax_auto_connect ();
}
return;
}
if (Profile->get_livetrax() && !route->is_auditioner() && route->is_track()) {
livetrax_auto_connect (route);
if (loading()) {
return;
}