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:
parent
82d786f506
commit
b10a5be5be
@ -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 */
|
||||
|
@ -83,6 +83,9 @@ InternalSend::~InternalSend ()
|
||||
void
|
||||
InternalSend::propagate_solo ()
|
||||
{
|
||||
if (_role == MasterSend) {
|
||||
return;
|
||||
}
|
||||
if (_session.inital_connect_or_deletion_in_progress ()) {
|
||||
return;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user