initial work on livetrax all-mono, direct outs and send-to-(master/monitor?)

This commit is contained in:
Paul Davis 2024-03-25 10:31:57 -06:00
parent 3aaa066652
commit 3f81b73f36
5 changed files with 123 additions and 46 deletions

View file

@ -99,6 +99,7 @@ class MonitorControl;
class TriggerBox; class TriggerBox;
class SurroundReturn; class SurroundReturn;
class SurroundSend; class SurroundSend;
class Send;
class LIBARDOUR_API Route : public Stripable, class LIBARDOUR_API Route : public Stripable,
public GraphNode, public GraphNode,
@ -695,6 +696,7 @@ protected:
std::shared_ptr<PeakMeter> _meter; std::shared_ptr<PeakMeter> _meter;
std::shared_ptr<PolarityProcessor> _polarity; std::shared_ptr<PolarityProcessor> _polarity;
std::shared_ptr<TriggerBox> _triggerbox; std::shared_ptr<TriggerBox> _triggerbox;
std::shared_ptr<InternalSend> _master_send;
bool _volume_applies_to_output; bool _volume_applies_to_output;

View file

@ -1804,6 +1804,7 @@ private:
MidiPortFlags exclude = MidiPortFlags (0)); MidiPortFlags exclude = MidiPortFlags (0));
void auto_connect (const AutoConnectRequest&); void auto_connect (const AutoConnectRequest&);
void livetrax_auto_connect (std::shared_ptr<Route>);
void queue_latency_recompute (); void queue_latency_recompute ();
/* SessionEventManager interface */ /* SessionEventManager interface */
@ -1984,6 +1985,7 @@ private:
bool find_route_name (std::string const &, uint32_t& id, std::string& name, bool); bool find_route_name (std::string const &, uint32_t& id, std::string& name, bool);
void count_existing_track_channels (ChanCount& in, ChanCount& out); void count_existing_track_channels (ChanCount& in, ChanCount& out);
void auto_connect_route (std::shared_ptr<Route>, bool, bool, const ChanCount&, const ChanCount&, const ChanCount& io = ChanCount(), const ChanCount& oo = ChanCount()); void auto_connect_route (std::shared_ptr<Route>, bool, bool, const ChanCount&, const ChanCount&, const ChanCount& io = ChanCount(), const ChanCount& oo = ChanCount());
void livetrax_auto_connect_route (std::shared_ptr<Route>);
void midi_output_change_handler (IOChange change, void* /*src*/, std::weak_ptr<Route> midi_track); void midi_output_change_handler (IOChange change, void* /*src*/, std::weak_ptr<Route> midi_track);
/* track numbering */ /* track numbering */

View file

@ -316,6 +316,11 @@ Route::init ()
panner_shell()->select_panner_by_uri ("http://ardour.org/plugin/panner_balance"); panner_shell()->select_panner_by_uri ("http://ardour.org/plugin/panner_balance");
} }
if (Profile->get_livetrax() && is_track()) {
_master_send.reset (new InternalSend (_session, _pannable, _mute_master, std::dynamic_pointer_cast<Route> (shared_from_this()), std::shared_ptr<Route>(), Delivery::Aux, false));
_master_send->set_display_to_user (false);
}
/* now set up processor chain and invisible processors */ /* now set up processor chain and invisible processors */
{ {
Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
@ -1847,10 +1852,11 @@ Route::try_configure_processors_unlocked (ChanCount in, ProcessorStreams* err)
if ((*p)->can_support_io_configuration(in, out)) { if ((*p)->can_support_io_configuration(in, out)) {
if (std::dynamic_pointer_cast<Delivery> (*p) if (!Profile->get_livetrax()
&& std::dynamic_pointer_cast<Delivery> (*p)->role() == Delivery::Main && std::dynamic_pointer_cast<Delivery> (*p)
&& !is_auditioner() && std::dynamic_pointer_cast<Delivery> (*p)->role() == Delivery::Main
&& (is_monitor() || _strict_io || Profile->get_mixbus ())) { && !is_auditioner()
&& (is_monitor() || _strict_io || Profile->get_mixbus ())) {
/* with strict I/O the panner + output are forced to /* with strict I/O the panner + output are forced to
* follow the last processor's output. * follow the last processor's output.
* *
@ -2522,41 +2528,49 @@ Route::customize_plugin_insert (std::shared_ptr<Processor> proc, uint32_t count,
} }
bool bool
Route::set_strict_io (const bool enable) Route::set_strict_io (bool enable)
{ {
Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
if (_strict_io != enable) { if (Profile->get_livetrax()) {
_strict_io = enable; /* cannot be disabled, and is set to true by default */
Glib::Threads::RWLock::ReaderLock lm (_processor_lock); // enable = true;
}
if (_strict_io == enable) {
return true;
}
_strict_io = enable;
Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p) {
std::shared_ptr<PluginInsert> pi;
if ((pi = std::dynamic_pointer_cast<PluginInsert>(*p)) != 0) {
pi->set_strict_io (_strict_io);
}
}
list<pair<ChanCount, ChanCount> > c = try_configure_processors_unlocked (n_inputs (), 0);
if (c.empty()) {
// not possible
_strict_io = !enable; // restore old value
for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p) { for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p) {
std::shared_ptr<PluginInsert> pi; std::shared_ptr<PluginInsert> pi;
if ((pi = std::dynamic_pointer_cast<PluginInsert>(*p)) != 0) { if ((pi = std::dynamic_pointer_cast<PluginInsert>(*p)) != 0) {
pi->set_strict_io (_strict_io); pi->set_strict_io (_strict_io);
} }
} }
return false;
list<pair<ChanCount, ChanCount> > c = try_configure_processors_unlocked (n_inputs (), 0);
if (c.empty()) {
// not possible
_strict_io = !enable; // restore old value
for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p) {
std::shared_ptr<PluginInsert> pi;
if ((pi = std::dynamic_pointer_cast<PluginInsert>(*p)) != 0) {
pi->set_strict_io (_strict_io);
}
}
return false;
}
lm.release ();
configure_processors (0);
lx.release ();
processors_changed (RouteProcessorChange (RouteProcessorChange::CustomPinChange, false)); /* EMIT SIGNAL */
_session.set_dirty ();
} }
lm.release ();
configure_processors (0);
lx.release ();
processors_changed (RouteProcessorChange (RouteProcessorChange::CustomPinChange, false)); /* EMIT SIGNAL */
_session.set_dirty ();
return true; return true;
} }
@ -5284,6 +5298,12 @@ Route::setup_invisible_processors ()
new_processors.push_back (_surround_send); new_processors.push_back (_surround_send);
} }
if (Profile->get_livetrax() && is_track()) {
assert (_master_send);
assert (!_master_send->display_to_user());
new_processors.push_back (_master_send);
}
/* MAIN OUTS */ /* MAIN OUTS */
assert (_main_outs); assert (_main_outs);

View file

@ -36,6 +36,7 @@
#include "ardour/io.h" #include "ardour/io.h"
#include "ardour/meter.h" #include "ardour/meter.h"
#include "ardour/panner_shell.h" #include "ardour/panner_shell.h"
#include "ardour/profile.h"
#include "ardour/send.h" #include "ardour/send.h"
#include "ardour/session.h" #include "ardour/session.h"
@ -72,9 +73,17 @@ Send::name_and_id_new_send (Session& s, Role r, uint32_t& bitslot, bool ignore_b
return string (); return string ();
} }
switch (r) { switch (r) {
case Delivery::Aux: case Delivery::Aux:
return string_compose (_("aux %1"), (bitslot = s.next_aux_send_id ())); if (Profile->get_livetrax()) {
/* The only type of aux send possible with livetrax */
return _("master");
} else {
return string_compose (_("aux %1"), (bitslot = s.next_aux_send_id ()));
}
case Delivery::Listen: case Delivery::Listen:
bitslot = 0; /* unused */ bitslot = 0; /* unused */
return _("listen"); // no ports, no need for numbering return _("listen"); // no ports, no need for numbering
@ -551,6 +560,10 @@ Send::set_name (const string& new_name)
bool bool
Send::display_to_user () const Send::display_to_user () const
{ {
if (_role == Aux && Profile->get_livetrax()) {
return false;
}
/* we ignore Deliver::_display_to_user */ /* we ignore Deliver::_display_to_user */
if (_role == Listen || _role == Foldback) { if (_role == Listen || _role == Foldback) {

View file

@ -3021,6 +3021,8 @@ Session::new_audio_track (int input_channels, int output_channels, RouteGroup* r
goto failed; goto failed;
} }
std::cerr << "new track with " << output_channels << " channels\n";
if (track->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) { if (track->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) {
error << string_compose ( error << string_compose (
_("cannot configure %1 in/%2 out configuration for new audio track"), _("cannot configure %1 in/%2 out configuration for new audio track"),
@ -3104,7 +3106,7 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
<< endmsg; << endmsg;
goto failure; goto failure;
} }
if (bus->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) { if (bus->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) {
error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"), error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
@ -3524,6 +3526,8 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
{ {
PresentationInfo::ChangeSuspender cs; PresentationInfo::ChangeSuspender cs;
ensure_route_presentation_info_gap (order, new_routes.size()); ensure_route_presentation_info_gap (order, new_routes.size());
ensure_stripable_sort_order ();
reassign_track_numbers ();
for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x, ++added) { for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x, ++added) {
@ -3603,7 +3607,6 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
ARDOUR::GUIIdle (); ARDOUR::GUIIdle ();
} }
ensure_stripable_sort_order ();
} }
if (_monitor_out && !loading()) { if (_monitor_out && !loading()) {
@ -3622,8 +3625,6 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
r->enable_surround_send (); r->enable_surround_send ();
} }
} }
reassign_track_numbers ();
} }
void void
@ -4580,15 +4581,19 @@ Session::reassign_track_numbers ()
StateProtector sp (this); StateProtector sp (this);
for (RouteList::iterator i = r.begin(); i != r.end(); ++i) { for (auto & route : r) {
assert (!(*i)->is_auditioner()); assert (!route->is_auditioner());
if (std::dynamic_pointer_cast<Track> (*i)) { if (std::dynamic_pointer_cast<Track> (route)) {
(*i)->set_track_number(++tn); route->set_track_number(++tn);
} else if (!(*i)->is_main_bus ()) { } else if (!route->is_main_bus ()) {
(*i)->set_track_number(--bn); route->set_track_number(--bn);
} }
std::shared_ptr<TriggerBox> tb = (*i)->triggerbox(); if (Profile->get_livetrax() && !route->is_auditioner() && route->is_track()) {
livetrax_auto_connect_route (route);
}
std::shared_ptr<TriggerBox> tb = (route)->triggerbox();
if (tb) { if (tb) {
tb->set_order (trigger_order); tb->set_order (trigger_order);
trigger_order++; trigger_order++;
@ -4599,8 +4604,8 @@ Session::reassign_track_numbers ()
_track_number_decimals = decimals; _track_number_decimals = decimals;
if (decimals_changed && config.get_track_name_number ()) { if (decimals_changed && config.get_track_name_number ()) {
for (RouteList::iterator i = r.begin(); i != r.end(); ++i) { for (auto & route : r) {
std::shared_ptr<Track> t = std::dynamic_pointer_cast<Track> (*i); std::shared_ptr<Track> t = std::dynamic_pointer_cast<Track> (route);
if (t) { if (t) {
t->resync_take_name (); t->resync_take_name ();
} }
@ -6462,7 +6467,7 @@ Session::write_one_track (Track& track, samplepos_t start, samplepos_t end,
plist.add (Properties::whole_file, true); plist.add (Properties::whole_file, true);
plist.add (Properties::length, len); //ToDo: in nutempo, if the Range is snapped to bbt, this should be in bbt (?) plist.add (Properties::length, len); //ToDo: in nutempo, if the Range is snapped to bbt, this should be in bbt (?)
plist.add (Properties::name, region_name_from_path (srcs.front()->name(), true)); // TODO: allow custom region-name when consolidating plist.add (Properties::name, region_name_from_path (srcs.front()->name(), true)); // TODO: allow custom region-name when consolidating
plist.add (Properties::tags, "(bounce)"); plist.add (Properties::tags, "(bounce)");
result = RegionFactory::create (srcs, plist, true); result = RegionFactory::create (srcs, plist, true);
@ -7669,6 +7674,13 @@ Session::cut_copy_section (timepos_t const& start_, timepos_t const& end_, timep
commit_reversible_command (); commit_reversible_command ();
} }
void
Session::livetrax_auto_connect_route (std::shared_ptr<Route> route)
{
ChanCount ignored;
auto_connect_route (route, true, true, ignored, ignored, ignored, ignored);
}
void void
Session::auto_connect_route (std::shared_ptr<Route> route, Session::auto_connect_route (std::shared_ptr<Route> route,
bool connect_inputs, bool connect_inputs,
@ -7710,6 +7722,27 @@ Session::queue_latency_recompute ()
auto_connect_thread_wakeup (); auto_connect_thread_wakeup ();
} }
void
Session::livetrax_auto_connect (std::shared_ptr<Route> route)
{
vector<string> physinputs;
vector<string> physoutputs;
get_physical_ports (physinputs, physoutputs, DataType::AUDIO);
const vector<string>::size_type n = route->track_number() - 1;
route->input()->disconnect (this);
route->output()->disconnect (this);
route->input()->connect (route->input()->ports().port (DataType::AUDIO, 0), physinputs[n % physinputs.size()], this);
route->output()->connect (route->output()->ports().port (DataType::AUDIO, 0), physoutputs[n % physoutputs.size()], this);
DEBUG_TRACE (DEBUG::PortConnectAuto, string_compose ("livetrax auto connect %1 [%2] to %3 and %4\n", route->name(), route->track_number(),
physinputs[n % physinputs.size()],
physoutputs[n % physoutputs.size()]));
}
void void
Session::auto_connect (const AutoConnectRequest& ar) Session::auto_connect (const AutoConnectRequest& ar)
{ {
@ -7721,6 +7754,11 @@ Session::auto_connect (const AutoConnectRequest& ar)
return; return;
} }
if (Profile->get_livetrax() && !route->is_auditioner() && route->is_track()) {
livetrax_auto_connect (route);
return;
}
/* If both inputs and outputs are auto-connected to physical ports, /* If both inputs and outputs are auto-connected to physical ports,
* use the max of input and output offsets to ensure auto-connected * use the max of input and output offsets to ensure auto-connected
* port numbers always match up (e.g. the first audio input and the * port numbers always match up (e.g. the first audio input and the
@ -7750,7 +7788,6 @@ Session::auto_connect (const AutoConnectRequest& ar)
vector<string> physinputs; vector<string> physinputs;
vector<string> physoutputs; vector<string> physoutputs;
/* for connecting track inputs we only want MIDI ports marked /* for connecting track inputs we only want MIDI ports marked
* for "music". * for "music".
*/ */
@ -7775,6 +7812,8 @@ Session::auto_connect (const AutoConnectRequest& ar)
DEBUG_TRACE (DEBUG::PortConnectAuto, "Failed to auto-connect input."); DEBUG_TRACE (DEBUG::PortConnectAuto, "Failed to auto-connect input.");
break; break;
} }
DEBUG_TRACE (DEBUG::PortConnectAuto, string_compose ("autoconnected input %1/%2 [%4]to %3\n", route->name(), i, port, route->track_number()));
} }
} }
@ -7801,6 +7840,8 @@ Session::auto_connect (const AutoConnectRequest& ar)
DEBUG_TRACE (DEBUG::PortConnectAuto, "Failed to auto-connect output."); DEBUG_TRACE (DEBUG::PortConnectAuto, "Failed to auto-connect output.");
break; break;
} }
DEBUG_TRACE (DEBUG::PortConnectAuto, string_compose ("autoconnected output %1/%2 [%4]to %3\n", route->name(), i, port, route->track_number()));
} }
} }
} }
@ -8132,4 +8173,3 @@ Session::foreach_route (void (Route::*method)())
((r.get())->*method) (); ((r.get())->*method) ();
} }
} }