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

@ -468,7 +468,6 @@ ArdourButton::on_button_release_event (GdkEventButton *ev)
if (_act_on_release) {
if (_action) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (_action);
_action->activate ();
return true;
}

View file

@ -250,6 +250,9 @@ Mixer_UI::Mixer_UI ()
Mixer_UI::~Mixer_UI ()
{
if (_monitor_section) {
delete _monitor_section;
}
}
void
@ -323,19 +326,21 @@ Mixer_UI::add_strip (RouteList& routes)
}
if (route->is_monitor()) {
if (!_monitor_section) {
_monitor_section = new MonitorSection (_session);
out_packer.pack_end (_monitor_section->tearoff(), false, false);
} else {
_monitor_section->set_session (_session);
}
XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section"));
if (mnode) {
_monitor_section->tearoff().set_state (*mnode);
}
}
out_packer.pack_end (_monitor_section->tearoff(), false, false);
_monitor_section->set_session (_session);
_monitor_section->tearoff().show_all ();
XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section"));
if (mnode) {
_monitor_section->tearoff().set_state (*mnode);
}
route->DropReferences.connect (*this, invalidator(*this), ui_bind (&Mixer_UI::monitor_section_going_away, this), gui_context());
/* no regular strip shown for control out */
@ -384,25 +389,23 @@ Mixer_UI::remove_strip (MixerStrip* strip)
return;
}
ENSURE_GUI_THREAD (*this, &Mixer_UI::remove_strip, strip);
TreeModel::Children rows = track_model->children();
TreeModel::Children::iterator ri;
list<MixerStrip *>::iterator i;
if ((i = find (strips.begin(), strips.end(), strip)) != strips.end()) {
strips.erase (i);
}
strip_redisplay_does_not_sync_order_keys = true;
for (ri = rows.begin(); ri != rows.end(); ++ri) {
if ((*ri)[track_columns.strip] == strip) {
track_model->erase (ri);
break;
}
}
strip_redisplay_does_not_sync_order_keys = false;
}
@ -1850,3 +1853,12 @@ Mixer_UI::set_route_targets_for_operation ()
_route_targets.insert (ms);
}
}
void
Mixer_UI::monitor_section_going_away ()
{
if (_monitor_section) {
out_packer.remove (_monitor_section->tearoff());
_monitor_section->set_session (0);
}
}

View file

@ -275,6 +275,8 @@ class Mixer_UI : public Gtk::Window, public PBD::ScopedConnectionList, public AR
void follow_editor_selection ();
bool _following_editor_selection;
void monitor_section_going_away ();
};
#endif /* __ardour_mixer_ui_h__ */

View file

@ -214,7 +214,7 @@ MonitorSection::MonitorSection (Session* s)
act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
if (act) {
cut_all_button.set_related_action (act);
}
}
dim_all_button.set_text (_("dim"));
dim_all_button.set_name ("monitor section dim");
@ -549,7 +549,7 @@ MonitorSection::cut_all ()
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
_monitor->set_cut_all (tact->get_active());
}
}
}
void

View file

@ -260,6 +260,13 @@ SessionOptionEditor::SessionOptionEditor (Session* s)
sigc::mem_fun (*_session_config, &SessionConfiguration::set_auto_input)
));
add_option (_("Monitoring"), new BoolOption (
"have-monitor-section",
_("Use monitor section in this session"),
sigc::mem_fun (*this, &SessionOptionEditor::get_use_monitor_section),
sigc::mem_fun (*this, &SessionOptionEditor::set_use_monitor_section)
));
/* Misc */
add_option (_("Misc"), new OptionEditorHeading (_("MIDI Options")));
@ -341,3 +348,27 @@ SessionOptionEditor::parameter_changed (std::string const & p)
_sync_source->set_sensitive (!_session->config.get_external_sync ());
}
}
/* the presence of absence of a monitor section is not really a regular session
* property so we provide these two functions to act as setter/getter slots
*/
bool
SessionOptionEditor::set_use_monitor_section (bool yn)
{
bool had_monitor_section = _session->monitor_out();
if (yn) {
_session->add_monitor_section ();
} else {
_session->remove_monitor_section ();
}
return had_monitor_section != yn;
}
bool
SessionOptionEditor::get_use_monitor_section ()
{
return _session->monitor_out() != 0;
}

View file

@ -35,4 +35,7 @@ private:
ARDOUR::SessionConfiguration* _session_config;
ComboOption<ARDOUR::SyncSource>* _sync_source;
bool set_use_monitor_section (bool);
bool get_use_monitor_section ();
};

View file

@ -162,6 +162,8 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
void set_listen (bool yn, void* src);
bool listening_via_monitor () const;
void enable_monitor_send ();
void disable_monitor_send ();
void set_phase_invert (uint32_t, bool yn);
void set_phase_invert (boost::dynamic_bitset<>);
@ -242,7 +244,7 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
int add_processor_by_index (boost::shared_ptr<Processor>, int, ProcessorStreams* err = 0, bool activation_allowed = true);
int add_processor (boost::shared_ptr<Processor>, ProcessorList::iterator iter, ProcessorStreams* err = 0, bool activation_allowed = true);
int add_processors (const ProcessorList&, boost::shared_ptr<Processor> before, ProcessorStreams* err = 0);
int remove_processor (boost::shared_ptr<Processor>, ProcessorStreams* err = 0);
int remove_processor (boost::shared_ptr<Processor>, ProcessorStreams* err = 0, bool need_process_lock = true);
int remove_processors (const ProcessorList&, ProcessorStreams* err = 0);
int reorder_processors (const ProcessorList& new_order, ProcessorStreams* err = 0);
void disable_processors (Placement);
@ -397,6 +399,15 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
void automation_snapshot (framepos_t now, bool force=false);
void protect_automation ();
enum {
/* These numbers are taken from MIDI Machine Control,
which can only control up to 317 tracks without
doing sysex segmentation.
*/
MasterBusRemoteControlID = 318,
MonitorBusRemoteControlID = 319,
};
void set_remote_control_id (uint32_t id, bool notify_class_listeners = true);
uint32_t remote_control_id () const;

View file

@ -628,7 +628,10 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
PBD::Signal0<void> SoloChanged;
PBD::Signal0<void> IsolatedChanged;
/* control/master out */
/* monitor/master out */
void add_monitor_section ();
void remove_monitor_section ();
boost::shared_ptr<Route> monitor_out() const { return _monitor_out; }
boost::shared_ptr<Route> master_out() const { return _master_out; }
@ -1406,6 +1409,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
boost::shared_ptr<Route> _master_out;
boost::shared_ptr<Route> _monitor_out;
void auto_connect_master_bus ();
/* Windows VST support */
long _windows_vst_callback (
@ -1505,6 +1510,9 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
and solo/mute computations.
*/
GraphEdges _current_route_graph;
uint32_t next_control_id () const;
bool ignore_route_processor_changes;
};
} // namespace ARDOUR

View file

@ -57,14 +57,18 @@ InternalReturn::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*e
void
InternalReturn::add_send (InternalSend* send)
{
Glib::Mutex::Lock lm (_session.engine().process_lock());
/* caller must hold process lock */
assert (!AudioEngine::instance()->process_lock().trylock());
_sends.push_back (send);
}
void
InternalReturn::remove_send (InternalSend* send)
{
Glib::Mutex::Lock lm (_session.engine().process_lock());
/* caller must hold process lock */
assert (!AudioEngine::instance()->process_lock().trylock());
_sends.remove (send);
}

View file

@ -1252,6 +1252,7 @@ IO::disable_connecting ()
int
IO::enable_connecting ()
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock());
connecting_legal = true;
boost::optional<int> r = ConnectingLegal ();
return r.get_value_or (0);

View file

@ -108,6 +108,13 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
{
processor_max_streams.reset();
order_keys[N_("signal")] = order_key_cnt++;
if (is_master()) {
set_remote_control_id (MasterBusRemoteControlID);
} else if (is_monitor()) {
set_remote_control_id (MonitorBusRemoteControlID);
}
}
int
@ -207,6 +214,26 @@ Route::~Route ()
void
Route::set_remote_control_id (uint32_t id, bool notify_class_listeners)
{
/* force IDs for master/monitor busses and prevent
any other route from accidentally getting these IDs
(i.e. legacy sessions)
*/
if (is_master() && id != MasterBusRemoteControlID) {
id = MasterBusRemoteControlID;
}
if (is_monitor() && id != MonitorBusRemoteControlID) {
id = MonitorBusRemoteControlID;
}
/* don't allow it to collide */
if (!is_master () && !is_monitor() &&
(id == MasterBusRemoteControlID || id == MonitorBusRemoteControlID)) {
id += MonitorBusRemoteControlID;
}
if (id != _remote_control_id) {
_remote_control_id = id;
RemoteControlIDChanged ();
@ -1330,7 +1357,7 @@ Route::clear_processors (Placement p)
}
int
Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err)
Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err, bool need_process_lock)
{
/* these can never be removed */
@ -1388,11 +1415,18 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
if (!removed) {
/* what? */
return 1;
}
}
{
if (need_process_lock) {
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
if (configure_processors_unlocked (err)) {
pstate.restore ();
/* we know this will work, because it worked before :) */
configure_processors_unlocked (0);
return -1;
}
} else {
if (configure_processors_unlocked (err)) {
pstate.restore ();
/* we know this will work, because it worked before :) */
@ -2542,11 +2576,13 @@ Route::remove_send_from_internal_return (InternalSend* send)
}
}
/** Add a monitor send (if we don't already have one) but don't activate it */
int
Route::listen_via_monitor ()
void
Route::enable_monitor_send ()
{
/* master never sends to control outs */
/* Caller must hold process lock */
assert (!AudioEngine::instance()->process_lock().trylock());
/* master never sends to monitor section via the normal mechanism */
assert (!is_master ());
/* make sure we have one */
@ -2556,10 +2592,7 @@ Route::listen_via_monitor ()
}
/* set it up */
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
configure_processors (0);
return 0;
}
/** Add an internal send to a route.
@ -2602,31 +2635,34 @@ Route::drop_listen (boost::shared_ptr<Route> route)
ProcessorStreams err;
ProcessorList::iterator tmp;
Glib::RWLock::ReaderLock rl(_processor_lock);
rl.acquire ();
{
Glib::RWLock::ReaderLock rl(_processor_lock);
again:
for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ) {
/* have to do this early because otherwise processor reconfig
* will put _monitor_send back in the list
*/
boost::shared_ptr<InternalSend> d = boost::dynamic_pointer_cast<InternalSend>(*x);
if (d && d->target_route() == route) {
rl.release ();
remove_processor (*x, &err);
rl.acquire ();
/* list could have been demolished while we dropped the lock
so start over.
*/
goto again;
if (route == _session.monitor_out()) {
_monitor_send.reset ();
}
}
rl.release ();
again:
for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ++x) {
boost::shared_ptr<InternalSend> d = boost::dynamic_pointer_cast<InternalSend>(*x);
if (d && d->target_route() == route) {
rl.release ();
remove_processor (*x, &err, false);
rl.acquire ();
if (route == _session.monitor_out()) {
_monitor_send.reset ();
/* list could have been demolished while we dropped the lock
so start over.
*/
goto again;
}
}
}
}

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

View file

@ -57,7 +57,6 @@ Session::click (framepos_t start, framecnt_t nframes)
click_distance = start - _clicks_cleared;
if (!clickm.locked() || _transport_speed != 1.0 || !_clicking || click_data == 0 || ((click_distance + nframes) < _worst_track_latency)) {
_click_io->silence (nframes);
return;

View file

@ -225,6 +225,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
no_questions_about_missing_files = false;
_speakers.reset (new Speakers);
_clicks_cleared = 0;
ignore_route_processor_changes = false;
AudioDiskstream::allocate_working_buffers();
@ -570,7 +571,6 @@ Session::create (const string& session_template, BusProfile* bus_profile)
if (bus_profile) {
RouteList rl;
int control_id = 1;
ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
if (bus_profile->master_out_channels) {
@ -586,28 +586,9 @@ Session::create (const string& session_template, BusProfile* bus_profile)
r->input()->ensure_io (count, false, this);
r->output()->ensure_io (count, false, this);
}
r->set_remote_control_id (control_id++);
rl.push_back (r);
if (Config->get_use_monitor_bus()) {
boost::shared_ptr<Route> r (new Route (*this, _("monitor"), Route::MonitorOut, DataType::AUDIO));
if (r->init ()) {
return -1;
}
#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 (count, false, this);
r->output()->ensure_io (count, false, this);
}
r->set_remote_control_id (control_id);
rl.push_back (r);
}
} else {
/* prohibit auto-connect to master, because there isn't one */
bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
@ -629,6 +610,10 @@ Session::create (const string& session_template, BusProfile* bus_profile)
Config->set_output_auto_connect (bus_profile->output_ac);
}
if (Config->get_use_monitor_bus() && bus_profile) {
add_monitor_section ();
}
save_state ("");
return 0;

View file

@ -1503,6 +1503,10 @@ Session::xrun_recovery ()
void
Session::route_processors_changed (RouteProcessorChange c)
{
if (ignore_route_processor_changes) {
return;
}
if (c.type == RouteProcessorChange::MeterPointChange) {
return;
}

View file

@ -344,8 +344,7 @@ path_expand (string path)
if (realpath (path.c_str(), buf)) {
return buf;
} else {
error << string_compose (_("programming error: realpath(%1) failed, errcode %2"), path, errno) << endmsg;
return path;
return string();
}
}
@ -362,7 +361,10 @@ search_path_expand (string path)
split (path, s, ':');
for (vector<string>::iterator i = s.begin(); i != s.end(); ++i) {
n.push_back (path_expand (*i));
string exp = path_expand (*i);
if (!exp.empty()) {
n.push_back (exp);
}
}
string r;