make monitor section an optional feature than can be added/removed as needed. this is a big commit, and breakage is possible. it has been moderately tested. this commit also locks the remote control ID of the master bus to 318 and the monitor section (if any) to 319. the numbers are based on MIDI Machine Control limits

git-svn-id: svn://localhost/ardour2/branches/3.0@11256 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2012-01-18 01:30:44 +00:00
parent 4b95a7912a
commit 508c5eb5bd
16 changed files with 409 additions and 218 deletions

View file

@ -45,6 +45,8 @@
#include "pbd/file_utils.h"
#include "pbd/convert.h"
#include "pbd/strsplit.h"
#include "pbd/strsplit.h"
#include "pbd/unwind.h"
#include "ardour/amp.h"
#include "ardour/analyser.h"
@ -539,110 +541,8 @@ Session::when_engine_running ()
hookup_io ();
if (_is_new && !no_auto_connect()) {
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock());
/* don't connect the master bus outputs if there is a monitor bus */
if (_master_out && Config->get_auto_connect_standard_busses() && !_monitor_out) {
/* if requested auto-connect the outputs to the first N physical ports.
*/
uint32_t limit = _master_out->n_outputs().n_total();
for (uint32_t n = 0; n < limit; ++n) {
boost::shared_ptr<Port> p = _master_out->output()->nth (n);
string connect_to;
if (outputs[p->type()].size() > n) {
connect_to = outputs[p->type()][n];
}
if (!connect_to.empty() && p->connected_to (connect_to) == false) {
if (_master_out->output()->connect (p, connect_to, this)) {
error << string_compose (_("cannot connect master output %1 to %2"), n, connect_to)
<< endmsg;
break;
}
}
}
}
if (_monitor_out) {
/* AUDIO ONLY as of june 29th 2009, because listen semantics for anything else
are undefined, at best.
*/
/* control out listens to master bus (but ignores it
under some conditions)
*/
uint32_t limit = _monitor_out->n_inputs().n_audio();
if (_master_out) {
for (uint32_t n = 0; n < limit; ++n) {
boost::shared_ptr<AudioPort> p = _monitor_out->input()->ports().nth_audio_port (n);
boost::shared_ptr<AudioPort> o = _master_out->output()->ports().nth_audio_port (n);
if (o) {
string connect_to = o->name();
if (_monitor_out->input()->connect (p, connect_to, this)) {
error << string_compose (_("cannot connect control input %1 to %2"), n, connect_to)
<< endmsg;
break;
}
}
}
}
/* if control out is not connected, connect control out to physical outs
*/
if (!_monitor_out->output()->connected ()) {
if (!Config->get_monitor_bus_preferred_bundle().empty()) {
boost::shared_ptr<Bundle> b = bundle_by_name (Config->get_monitor_bus_preferred_bundle());
if (b) {
_monitor_out->output()->connect_ports_to_bundle (b, this);
} else {
warning << string_compose (_("The preferred I/O for the monitor bus (%1) cannot be found"),
Config->get_monitor_bus_preferred_bundle())
<< endmsg;
}
} else {
/* Monitor bus is audio only */
uint32_t mod = n_physical_outputs.get (DataType::AUDIO);
uint32_t limit = _monitor_out->n_outputs().get (DataType::AUDIO);
if (mod != 0) {
for (uint32_t n = 0; n < limit; ++n) {
boost::shared_ptr<Port> p = _monitor_out->output()->ports().port(DataType::AUDIO, n);
string connect_to;
if (outputs[DataType::AUDIO].size() > (n % mod)) {
connect_to = outputs[DataType::AUDIO][n % mod];
}
if (!connect_to.empty()) {
if (_monitor_out->output()->connect (p, connect_to, this)) {
error << string_compose (
_("cannot connect control output %1 to %2"),
n, connect_to)
<< endmsg;
break;
}
}
}
}
}
}
}
auto_connect_master_bus ();
}
_state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
@ -657,6 +557,226 @@ Session::when_engine_running ()
_engine.set_session (this);
}
void
Session::auto_connect_master_bus ()
{
if (!_master_out || !Config->get_auto_connect_standard_busses() || _monitor_out) {
return;
}
/* if requested auto-connect the outputs to the first N physical ports.
*/
uint32_t limit = _master_out->n_outputs().n_total();
vector<string> outputs[DataType::num_types];
for (uint32_t i = 0; i < DataType::num_types; ++i) {
_engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]);
}
for (uint32_t n = 0; n < limit; ++n) {
boost::shared_ptr<Port> p = _master_out->output()->nth (n);
string connect_to;
if (outputs[p->type()].size() > n) {
connect_to = outputs[p->type()][n];
}
if (!connect_to.empty() && p->connected_to (connect_to) == false) {
if (_master_out->output()->connect (p, connect_to, this)) {
error << string_compose (_("cannot connect master output %1 to %2"), n, connect_to)
<< endmsg;
break;
}
}
}
}
void
Session::remove_monitor_section ()
{
if (!_monitor_out) {
return;
}
/* force reversion to Solo-In-Pace */
Config->set_solo_control_is_listen_control (false);
{
/* Hold process lock while doing this so that we don't hear bits and
* pieces of audio as we work on each route.
*/
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
/* Connect tracks to monitor section. Note that in an
existing session, the internal sends will already exist, but we want the
routes to notice that they connect to the control out specifically.
*/
boost::shared_ptr<RouteList> r = routes.reader ();
PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
for (RouteList::iterator x = r->begin(); x != r->end(); ++x) {
if ((*x)->is_monitor()) {
/* relax */
} else if ((*x)->is_master()) {
/* relax */
} else {
(*x)->drop_listen (_monitor_out);
}
}
}
remove_route (_monitor_out);
auto_connect_master_bus ();
}
void
Session::add_monitor_section ()
{
RouteList rl;
if (_monitor_out || !_master_out) {
return;
}
boost::shared_ptr<Route> r (new Route (*this, _("monitor"), Route::MonitorOut, DataType::AUDIO));
if (r->init ()) {
return;
}
#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
// boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
#endif
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
r->input()->ensure_io (_master_out->output()->n_ports(), false, this);
r->output()->ensure_io (_master_out->output()->n_ports(), false, this);
}
rl.push_back (r);
add_routes (rl, false, false);
assert (_monitor_out);
/* AUDIO ONLY as of june 29th 2009, because listen semantics for anything else
are undefined, at best.
*/
uint32_t limit = _monitor_out->n_inputs().n_audio();
if (_master_out) {
/* connect the inputs to the master bus outputs. this
* represents a separate data feed from the internal sends from
* each route. as of jan 2011, it allows the monitor section to
* conditionally ignore either the internal sends or the normal
* input feed, but we should really find a better way to do
* this, i think.
*/
_master_out->output()->disconnect (this);
for (uint32_t n = 0; n < limit; ++n) {
boost::shared_ptr<AudioPort> p = _monitor_out->input()->ports().nth_audio_port (n);
boost::shared_ptr<AudioPort> o = _master_out->output()->ports().nth_audio_port (n);
if (o) {
string connect_to = o->name();
if (_monitor_out->input()->connect (p, connect_to, this)) {
error << string_compose (_("cannot connect control input %1 to %2"), n, connect_to)
<< endmsg;
break;
}
}
}
}
/* if monitor section is not connected, connect it to physical outs
*/
if (Config->get_auto_connect_standard_busses() && !_monitor_out->output()->connected ()) {
if (!Config->get_monitor_bus_preferred_bundle().empty()) {
boost::shared_ptr<Bundle> b = bundle_by_name (Config->get_monitor_bus_preferred_bundle());
if (b) {
_monitor_out->output()->connect_ports_to_bundle (b, this);
} else {
warning << string_compose (_("The preferred I/O for the monitor bus (%1) cannot be found"),
Config->get_monitor_bus_preferred_bundle())
<< endmsg;
}
} else {
/* Monitor bus is audio only */
uint32_t mod = n_physical_outputs.get (DataType::AUDIO);
uint32_t limit = _monitor_out->n_outputs().get (DataType::AUDIO);
vector<string> outputs[DataType::num_types];
for (uint32_t i = 0; i < DataType::num_types; ++i) {
_engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]);
}
if (mod != 0) {
for (uint32_t n = 0; n < limit; ++n) {
boost::shared_ptr<Port> p = _monitor_out->output()->ports().port(DataType::AUDIO, n);
string connect_to;
if (outputs[DataType::AUDIO].size() > (n % mod)) {
connect_to = outputs[DataType::AUDIO][n % mod];
}
if (!connect_to.empty()) {
if (_monitor_out->output()->connect (p, connect_to, this)) {
error << string_compose (
_("cannot connect control output %1 to %2"),
n, connect_to)
<< endmsg;
break;
}
}
}
}
}
}
/* Hold process lock while doing this so that we don't hear bits and
* pieces of audio as we work on each route.
*/
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
/* Connect tracks to monitor section. Note that in an
existing session, the internal sends will already exist, but we want the
routes to notice that they connect to the control out specifically.
*/
boost::shared_ptr<RouteList> rls = routes.reader ();
PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
for (RouteList::iterator x = rls->begin(); x != rls->end(); ++x) {
if ((*x)->is_monitor()) {
/* relax */
} else if ((*x)->is_master()) {
/* relax */
} else {
(*x)->enable_monitor_send ();
}
}
}
void
Session::hookup_io ()
{
@ -701,30 +821,6 @@ Session::hookup_io ()
Delivery::reset_panners ();
/* Connect tracks to monitor/listen bus if there is one. Note that in an
existing session, the internal sends will already exist, but we want the
routes to notice that they connect to the control out specifically.
*/
if (_monitor_out) {
boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator x = r->begin(); x != r->end(); ++x) {
if ((*x)->is_monitor()) {
/* relax */
} else if ((*x)->is_master()) {
/* relax */
} else {
(*x)->listen_via_monitor ();
}
}
}
/* Anyone who cares about input state, wake up and do something */
IOConnectionsComplete (); /* EMIT SIGNAL */
@ -1467,7 +1563,7 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m
list<boost::shared_ptr<MidiTrack> > ret;
uint32_t control_id;
control_id = ntracks() + nbusses();
control_id = next_control_id ();
bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("MIDI");
@ -1683,9 +1779,8 @@ Session::auto_connect_route (boost::shared_ptr<Route> route, ChanCount& existing
* @param name_template string to use for the start of the name, or "" to use "Audio".
*/
list< boost::shared_ptr<AudioTrack> >
Session::new_audio_track (
int input_channels, int output_channels, TrackMode mode, RouteGroup* route_group, uint32_t how_many, string name_template
)
Session::new_audio_track (int input_channels, int output_channels, TrackMode mode, RouteGroup* route_group,
uint32_t how_many, string name_template)
{
char track_name[32];
uint32_t track_id = 0;
@ -1694,7 +1789,7 @@ Session::new_audio_track (
list<boost::shared_ptr<AudioTrack> > ret;
uint32_t control_id;
control_id = ntracks() + nbusses() + 1;
control_id = next_control_id ();
bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Audio");
@ -1813,7 +1908,7 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
RouteList ret;
uint32_t control_id;
control_id = ntracks() + nbusses() + 1;
control_id = next_control_id ();
bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Bus");
@ -1901,7 +1996,7 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
XMLNode* node = tree.root();
control_id = ntracks() + nbusses() + 1;
control_id = next_control_id ();
while (how_many) {
@ -2054,7 +2149,7 @@ Session::add_routes (RouteList& new_routes, bool auto_connect, bool save)
} else if ((*x)->is_master()) {
/* relax */
} else {
(*x)->listen_via_monitor ();
(*x)->enable_monitor_send ();
}
}
@ -2153,7 +2248,7 @@ Session::add_internal_sends (boost::shared_ptr<Route> dest, Placement p, boost::
void
Session::remove_route (boost::shared_ptr<Route> route)
{
if (((route == _master_out) || (route == _monitor_out)) && !Config->get_allow_special_bus_removal()) {
if (route == _master_out) {
return;
}
@ -2175,13 +2270,6 @@ Session::remove_route (boost::shared_ptr<Route> route)
}
if (route == _monitor_out) {
/* cancel control outs for all routes */
for (RouteList::iterator r = rs->begin(); r != rs->end(); ++r) {
(*r)->drop_listen (_monitor_out);
}
_monitor_out.reset ();
}
@ -4564,3 +4652,9 @@ Session::session_name_is_legal (const string& path)
return 0;
}
uint32_t
Session::next_control_id () const
{
return ntracks() + nbusses() + 1;
}