merge monitor_section branch

This commit is contained in:
Ben Loftis 2015-04-21 08:18:10 -05:00
parent ab4b4934b9
commit f44e2e55fd
8 changed files with 846 additions and 1 deletions

View File

@ -21,6 +21,7 @@
#include "pbd/compose.h"
#include "pbd/error.h"
#include "pbd/replace_all.h"
#include "gtkmm2ext/bindable_button.h"
#include "gtkmm2ext/tearoff.h"
@ -30,7 +31,9 @@
#include <gtkmm/menu.h>
#include <gtkmm/menuitem.h>
#include "ardour/audioengine.h"
#include "ardour/monitor_processor.h"
#include "ardour/port.h"
#include "ardour/route.h"
#include "ardour_ui.h"
@ -320,6 +323,18 @@ MonitorSection::MonitorSection (Session* s)
gain_display->add_controllable_preset(_("-20 dB"), -20.0);
gain_display->add_controllable_preset(_("-30 dB"), -30.0);
Label* output_label = manage (new Label (_("Output")));
output_label->set_name (X_("MonitorSectionLabel"));
output_button = new ArdourButton ();
output_button->set_text (_("Output"));
output_button->set_name (X_("monitor section cut"));
output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
VBox* out_packer = manage (new VBox);
out_packer->set_spacing (6);
out_packer->pack_start (*output_label, false, false);
out_packer->pack_start (*output_button, false, false);
spin_label = manage (new Label (_("Monitor")));
spin_packer = manage (new VBox);
spin_packer->show ();
@ -327,6 +342,7 @@ MonitorSection::MonitorSection (Session* s)
spin_packer->pack_start (*spin_label, false, false);
spin_packer->pack_start (*gain_control, false, false);
spin_packer->pack_start (*gain_display, false, false);
spin_packer->pack_start (*out_packer, false, false, 24);
lower_packer.pack_start (*spin_packer, true, true);
@ -396,6 +412,10 @@ MonitorSection::MonitorSection (Session* s)
map_state ();
assign_controllables ();
output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
output_button->signal_size_allocate().connect (sigc::mem_fun (*this, &MonitorSection::output_button_resized));
_tearoff = new TearOff (hpacker);
/* if torn off, make this a normal window */
@ -403,8 +423,12 @@ MonitorSection::MonitorSection (Session* s)
_tearoff->tearoff_window().set_title (X_("Monitor"));
_tearoff->tearoff_window().signal_key_press_event().connect (sigc::ptr_fun (forward_key_press), false);
/* catch changes that affect us */
update_output_display();
/* catch changes that affect us */
AudioEngine::instance()->PortConnectedOrDisconnected.connect (
*this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
);
Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
}
@ -415,7 +439,9 @@ MonitorSection::~MonitorSection ()
}
_channel_buttons.clear ();
_output_changed_connection.disconnect ();
delete output_button;
delete gain_control;
delete gain_display;
delete dim_control;
@ -425,6 +451,8 @@ MonitorSection::~MonitorSection ()
delete solo_cut_control;
delete solo_cut_display;
delete _tearoff;
delete _output_selector;
_output_selector = 0;
}
void
@ -440,10 +468,16 @@ MonitorSection::set_session (Session* s)
/* session with monitor section */
_monitor = _route->monitor_control ();
assign_controllables ();
_route->output()->changed.connect (_output_changed_connection, invalidator (*this),
boost::bind (&MonitorSection::update_output_display, this),
gui_context());
} else {
/* session with no monitor section */
_output_changed_connection.disconnect();
_monitor.reset ();
_route.reset ();
delete _output_selector;
_output_selector = 0;
}
if (channel_table_scroller.get_parent()) {
@ -484,11 +518,14 @@ MonitorSection::set_session (Session* s)
} else {
/* no session */
_output_changed_connection.disconnect();
_monitor.reset ();
_route.reset ();
control_connections.drop_connections ();
rude_iso_button.unset_active_state ();
rude_solo_button.unset_active_state ();
delete _output_selector;
_output_selector = 0;
assign_controllables ();
}
@ -1154,3 +1191,330 @@ MonitorSection::state_id() const
{
return "monitor-section";
}
void
MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
{
using namespace Menu_Helpers;
if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
return;
}
list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
++i;
}
if (i != output_menu_bundles.end()) {
return;
}
output_menu_bundles.push_back (b);
MenuList& citems = output_menu.items();
std::string n = b->name ();
replace_all (n, "_", " ");
citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
}
void
MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
{
ARDOUR::BundleList current = _route->output()->bundles_connected ();
if (std::find (current.begin(), current.end(), c) == current.end()) {
_route->output()->connect_ports_to_bundle (c, true, this);
} else {
_route->output()->disconnect_ports_from_bundle (c, this);
}
}
gint
MonitorSection::output_release (GdkEventButton *ev)
{
switch (ev->button) {
case 3:
edit_output_configuration ();
break;
}
return false;
}
struct RouteCompareByName {
bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
return a->name().compare (b->name()) < 0;
}
};
gint
MonitorSection::output_press (GdkEventButton *ev)
{
using namespace Menu_Helpers;
if (!_session) {
MessageDialog msg (_("No session - no I/O changes are possible"));
msg.run ();
return true;
}
MenuList& citems = output_menu.items();
switch (ev->button) {
case 3:
return false; //wait for the mouse-up to pop the dialog
case 1:
{
output_menu.set_name ("ArdourContextMenu");
citems.clear ();
output_menu_bundles.clear ();
citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
citems.push_back (SeparatorElem());
uint32_t const n_with_separator = citems.size ();
ARDOUR::BundleList current = _route->output()->bundles_connected ();
boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
/* give user bundles first chance at being in the menu */
for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
maybe_add_bundle_to_output_menu (*i, current);
}
}
for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
maybe_add_bundle_to_output_menu (*i, current);
}
}
boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
RouteList copy = *routes;
copy.sort (RouteCompareByName ());
for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
}
if (citems.size() == n_with_separator) {
/* no routes added; remove the separator */
citems.pop_back ();
}
citems.push_back (SeparatorElem());
citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
output_menu.popup (1, ev->time);
break;
}
default:
break;
}
return TRUE;
}
void
MonitorSection::output_button_resized (Gtk::Allocation& alloc)
{
output_button->set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
}
void
MonitorSection::update_output_display ()
{
if (!_route || !_monitor) {
return;
}
uint32_t io_count;
uint32_t io_index;
boost::shared_ptr<Port> port;
vector<string> port_connections;
uint32_t total_connection_count = 0;
uint32_t io_connection_count = 0;
uint32_t ardour_connection_count = 0;
uint32_t system_connection_count = 0;
uint32_t other_connection_count = 0;
ostringstream label;
bool have_label = false;
bool each_io_has_one_connection = true;
string connection_name;
string ardour_track_name;
string other_connection_type;
string system_ports;
string system_port;
ostringstream tooltip;
char * tooltip_cstr;
io_count = _route->n_outputs().n_total();
tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Glib::Markup::escape_text(_route->name()));
for (io_index = 0; io_index < io_count; ++io_index) {
port = _route->output()->nth (io_index);
//ignore any port connections that don't match our DataType
if (port->type() != DataType::AUDIO) {
continue;
}
port_connections.clear ();
port->get_connections(port_connections);
io_connection_count = 0;
if (!port_connections.empty()) {
for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
string pn = "";
string& connection_name (*i);
if (connection_name.find("system:") == 0) {
pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
}
if (io_connection_count == 0) {
tooltip << endl << Glib::Markup::escape_text(port->name().substr(port->name().find("/") + 1))
<< " -> "
<< Glib::Markup::escape_text( pn.empty() ? connection_name : pn );
} else {
tooltip << ", "
<< Glib::Markup::escape_text( pn.empty() ? connection_name : pn );
}
if (connection_name.find("ardour:") == 0) {
if (ardour_track_name.empty()) {
// "ardour:Master/in 1" -> "ardour:Master/"
string::size_type slash = connection_name.find("/");
if (slash != string::npos) {
ardour_track_name = connection_name.substr(0, slash + 1);
}
}
if (connection_name.find(ardour_track_name) == 0) {
++ardour_connection_count;
}
} else if (!pn.empty()) {
if (system_ports.empty()) {
system_ports += pn;
} else {
system_ports += "/" + pn;
}
if (connection_name.find("system:") == 0) {
++system_connection_count;
}
} else if (connection_name.find("system:") == 0) {
// "system:playback_123" -> "123"
system_port = connection_name.substr(16);
if (system_ports.empty()) {
system_ports += system_port;
} else {
system_ports += "/" + system_port;
}
++system_connection_count;
} else {
if (other_connection_type.empty()) {
// "jamin:in 1" -> "jamin:"
other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
}
if (connection_name.find(other_connection_type) == 0) {
++other_connection_count;
}
}
++total_connection_count;
++io_connection_count;
}
}
if (io_connection_count != 1) {
each_io_has_one_connection = false;
}
}
if (total_connection_count == 0) {
tooltip << endl << _("Disconnected");
}
tooltip_cstr = new char[tooltip.str().size() + 1];
strcpy(tooltip_cstr, tooltip.str().c_str());
ARDOUR_UI::instance()->set_tip (output_button, tooltip_cstr, "");
if (each_io_has_one_connection) {
if (total_connection_count == ardour_connection_count) {
// all connections are to the same track in ardour
// "ardour:Master/" -> "Master"
string::size_type slash = ardour_track_name.find("/");
if (slash != string::npos) {
label << ardour_track_name.substr(7, slash - 7);
have_label = true;
}
} else if (total_connection_count == system_connection_count) {
// all connections are to system ports
label << system_ports;
have_label = true;
} else if (total_connection_count == other_connection_count) {
// all connections are to the same external program eg jamin
// "jamin:" -> "jamin"
label << other_connection_type.substr(0, other_connection_type.size() - 1);
have_label = true;
}
}
if (!have_label) {
if (total_connection_count == 0) {
// Disconnected
label << "-";
} else {
// Odd configuration
label << "*" << total_connection_count << "*";
}
}
output_button->set_text (label.str());
}
void
MonitorSection::disconnect_output ()
{
if (_route) {
_route->output()->disconnect(this);
}
}
void
MonitorSection::edit_output_configuration ()
{
if (_output_selector == 0) {
_output_selector = new MonitorSelectorWindow (_session, _route->output());
}
_output_selector->present ();
}
void
MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
{
if (!_route) {
return;
}
boost::shared_ptr<Port> a = wa.lock ();
boost::shared_ptr<Port> b = wb.lock ();
if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
update_output_display ();
}
}

View File

@ -28,6 +28,7 @@
#include "axis_view.h"
#include "level_meter.h"
#include "route_ui.h"
#include "monitor_selector.h"
namespace Gtkmm2ext {
class TearOff;
@ -85,6 +86,18 @@ class MonitorSection : public RouteUI
ArdourDisplay* solo_boost_display;
ArdourDisplay* solo_cut_display;
std::list<boost::shared_ptr<ARDOUR::Bundle> > output_menu_bundles;
Gtk::Menu output_menu;
MonitorSelectorWindow *_output_selector;
ArdourButton* output_button;
void maybe_add_bundle_to_output_menu (boost::shared_ptr<ARDOUR::Bundle>, ARDOUR::BundleList const &);
void bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle>);
void output_button_resized (Gtk::Allocation&);
void update_output_display ();
void disconnect_output ();
void edit_output_configuration ();
void populate_buttons ();
void map_state ();
@ -107,6 +120,8 @@ class MonitorSection : public RouteUI
void dim_level_changed ();
void solo_boost_changed ();
void gain_value_changed ();
gint output_press (GdkEventButton *);
gint output_release (GdkEventButton *);
ArdourButton solo_in_place_button;
ArdourButton afl_button;
@ -138,8 +153,10 @@ class MonitorSection : public RouteUI
PBD::ScopedConnection config_connection;
PBD::ScopedConnectionList control_connections;
PBD::ScopedConnection _output_changed_connection;
bool _inhibit_solo_model_update;
void assign_controllables ();
void port_connected_or_disconnected (boost::weak_ptr<ARDOUR::Port>, boost::weak_ptr<ARDOUR::Port>);
};

View File

@ -0,0 +1,251 @@
/*
Copyright (C) 2002-2007 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdint.h>
#include <glibmm/objectbase.h>
#include <gtkmm2ext/doi.h>
#include "ardour/audioengine.h"
#include "ardour/bundle.h"
#include "ardour/data_type.h"
#include "ardour/io.h"
#include "ardour/port.h"
#include "ardour/session.h"
#include "monitor_selector.h"
#include "utils.h"
#include "gui_thread.h"
#include "i18n.h"
using namespace ARDOUR;
using namespace ARDOUR_UI_UTILS;
using namespace Gtk;
MonitorSelector::MonitorSelector (Gtk::Window* p, ARDOUR::Session* session, boost::shared_ptr<ARDOUR::IO> io)
: PortMatrix (p, session, DataType::AUDIO)
, _io (io)
{
set_type (DataType::AUDIO);
/* signal flow from 0 to 1 */
_find_inputs_for_io_outputs = (_io->direction() == IO::Output);
if (_find_inputs_for_io_outputs) {
_other = 1;
_ours = 0;
} else {
_other = 0;
_ours = 1;
}
_port_group.reset (new PortGroup (io->name()));
_ports[_ours].add_group (_port_group);
io->changed.connect (_io_connection, invalidator (*this), boost::bind (&MonitorSelector::io_changed_proxy, this), gui_context ());
setup_all_ports ();
init ();
}
void
MonitorSelector::io_changed_proxy ()
{
/* The IO's changed signal is emitted from code that holds its route's processor lock,
so we can't call setup_all_ports (which results in a call to Route::foreach_processor)
without a deadlock unless we break things up with this idle handler.
*/
Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MonitorSelector::io_changed));
}
void
MonitorSelector::io_changed ()
{
setup_all_ports ();
}
void
MonitorSelector::setup_ports (int dim)
{
if (!_session) {
return;
}
_ports[dim].suspend_signals ();
if (dim == _other) {
_ports[_other].gather (_session, type(), _find_inputs_for_io_outputs, false, show_only_bundles ());
} else {
_port_group->clear ();
_port_group->add_bundle (_io->bundle (), _io);
}
_ports[dim].resume_signals ();
}
void
MonitorSelector::set_state (ARDOUR::BundleChannel c[2], bool s)
{
ARDOUR::Bundle::PortList const & our_ports = c[_ours].bundle->channel_ports (c[_ours].channel);
ARDOUR::Bundle::PortList const & other_ports = c[_other].bundle->channel_ports (c[_other].channel);
for (ARDOUR::Bundle::PortList::const_iterator i = our_ports.begin(); i != our_ports.end(); ++i) {
for (ARDOUR::Bundle::PortList::const_iterator j = other_ports.begin(); j != other_ports.end(); ++j) {
boost::shared_ptr<Port> f = _session->engine().get_port_by_name (*i);
if (!f) {
return;
}
if (s) {
if (!f->connected_to (*j)) {
_io->connect (f, *j, 0);
}
} else {
if (f->connected_to (*j)) {
_io->disconnect (f, *j, 0);
}
}
}
}
}
PortMatrixNode::State
MonitorSelector::get_state (ARDOUR::BundleChannel c[2]) const
{
if (c[0].bundle->nchannels() == ChanCount::ZERO || c[1].bundle->nchannels() == ChanCount::ZERO) {
return PortMatrixNode::NOT_ASSOCIATED;
}
ARDOUR::Bundle::PortList const & our_ports = c[_ours].bundle->channel_ports (c[_ours].channel);
ARDOUR::Bundle::PortList const & other_ports = c[_other].bundle->channel_ports (c[_other].channel);
if (!_session || our_ports.empty() || other_ports.empty()) {
/* we're looking at a bundle with no parts associated with this channel,
so nothing to connect */
return PortMatrixNode::NOT_ASSOCIATED;
}
for (ARDOUR::Bundle::PortList::const_iterator i = our_ports.begin(); i != our_ports.end(); ++i) {
for (ARDOUR::Bundle::PortList::const_iterator j = other_ports.begin(); j != other_ports.end(); ++j) {
boost::shared_ptr<Port> f = _session->engine().get_port_by_name (*i);
/* since we are talking about an IO, our ports should all have an associated Port *,
so the above call should never fail */
assert (f);
if (!f->connected_to (*j)) {
/* if any one thing is not connected, all bets are off */
return PortMatrixNode::NOT_ASSOCIATED;
}
}
}
return PortMatrixNode::ASSOCIATED;
}
uint32_t
MonitorSelector::n_io_ports () const
{
if (!_find_inputs_for_io_outputs) {
return _io->n_ports().get (_io->default_type());
} else {
return _io->n_ports().get (_io->default_type());
}
}
bool
MonitorSelector::list_is_global (int dim) const
{
return (dim == _other);
}
std::string
MonitorSelector::disassociation_verb () const
{
return _("Disconnect");
}
std::string
MonitorSelector::channel_noun () const
{
return _("port");
}
MonitorSelectorWindow::MonitorSelectorWindow (ARDOUR::Session* session, boost::shared_ptr<ARDOUR::IO> io, bool /*can_cancel*/)
: ArdourWindow (_("Monitor output selector"))
, _selector (this, session, io)
{
set_name ("IOSelectorWindow2");
add (_selector);
io_name_changed (this);
show_all ();
signal_delete_event().connect (sigc::mem_fun (*this, &MonitorSelectorWindow::wm_delete));
}
bool
MonitorSelectorWindow::wm_delete (GdkEventAny* /*event*/)
{
_selector.Finished (MonitorSelector::Accepted);
return false;
}
void
MonitorSelectorWindow::on_map ()
{
_selector.setup_all_ports ();
Window::on_map ();
}
void
MonitorSelectorWindow::on_show ()
{
Gtk::Window::on_show ();
std::pair<uint32_t, uint32_t> const pm_max = _selector.max_size ();
resize_window_to_proportion_of_monitor (this, pm_max.first, pm_max.second);
}
void
MonitorSelectorWindow::io_name_changed (void*)
{
ENSURE_GUI_THREAD (*this, &MonitorSelectorWindow::io_name_changed, src)
std::string title;
if (!_selector.find_inputs_for_io_outputs()) {
title = string_compose(_("%1 input"), _selector.io()->name());
} else {
title = string_compose(_("%1 output"), _selector.io()->name());
}
set_title (title);
}

View File

@ -0,0 +1,91 @@
/*
Copyright (C) 2002-2007 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __gtkardour_monitor_output_selector_h__
#define __gtkardour_monitor_output_selector_h__
#include "port_matrix.h"
#include "ardour_window.h"
class MonitorSelector : public PortMatrix
{
public:
MonitorSelector (Gtk::Window*, ARDOUR::Session *, boost::shared_ptr<ARDOUR::IO>);
void set_state (ARDOUR::BundleChannel c[2], bool);
PortMatrixNode::State get_state (ARDOUR::BundleChannel c[2]) const;
std::string disassociation_verb () const;
std::string channel_noun () const;
ARDOUR::Session* session() const { return _session; }
uint32_t n_io_ports () const;
boost::shared_ptr<ARDOUR::IO> const io () { return _io; }
void setup_ports (int);
bool list_is_global (int) const;
bool find_inputs_for_io_outputs () const {
return _find_inputs_for_io_outputs;
}
int ours () const {
return _ours;
}
int other () const {
return _other;
}
bool can_add_channels (boost::shared_ptr<ARDOUR::Bundle>) const { return false; }
bool can_remove_channels (boost::shared_ptr<ARDOUR::Bundle>) const { return false; }
bool can_rename_channels (boost::shared_ptr<ARDOUR::Bundle>) const { return false; }
private:
void io_changed ();
void io_changed_proxy ();
int _other;
int _ours;
boost::shared_ptr<ARDOUR::IO> _io;
boost::shared_ptr<PortGroup> _port_group;
bool _find_inputs_for_io_outputs;
PBD::ScopedConnection _io_connection;
};
class MonitorSelectorWindow : public ArdourWindow
{
public:
MonitorSelectorWindow (ARDOUR::Session *, boost::shared_ptr<ARDOUR::IO>, bool can_cancel = false);
MonitorSelector& selector() { return _selector; }
protected:
void on_map ();
void on_show ();
private:
MonitorSelector _selector;
void io_name_changed (void *src);
bool wm_delete (GdkEventAny*);
};
#endif /* __gtkardour_monitor_output_selector_h__ */

View File

@ -144,6 +144,7 @@ gtk2_ardour_sources = [
'meter_strip.cc',
'meter_patterns.cc',
'monitor_section.cc',
'monitor_selector.cc',
'mono_panner.cc',
'mono_panner_editor.cc',
'mouse_cursors.cc',

View File

@ -702,6 +702,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
/* monitor/master out */
void add_monitor_section ();
void reset_monitor_section ();
void remove_monitor_section ();
boost::shared_ptr<Route> monitor_out() const { return _monitor_out; }

View File

@ -3096,6 +3096,11 @@ Route::output_change_handler (IOChange change, void * /*src*/)
*/
need_to_queue_solo_change = false;
configure_processors (0);
if (is_master()) {
_session.reset_monitor_section();
}
io_changed (); /* EMIT SIGNAL */
}

View File

@ -1060,6 +1060,121 @@ Session::add_monitor_section ()
}
}
void
Session::reset_monitor_section ()
{
/* Process lock should be held by the caller.*/
if (!_monitor_out) {
return;
}
uint32_t limit = _master_out->n_outputs().n_audio();
/* 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);
_monitor_out->output()->disconnect (this);
_monitor_out->input()->ensure_io (_master_out->output()->n_ports(), false, this);
_monitor_out->output()->ensure_io (_master_out->output()->n_ports(), false, 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;
}
}
}
/* connect monitor section to physical outs
*/
if (Config->get_auto_connect_standard_busses()) {
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, true, 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 */
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]);
}
uint32_t mod = outputs[DataType::AUDIO].size();
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;
}
}
}
}
}
}
/* 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 ()
{