first stab at send+route panner link

This commit is contained in:
Robin Gareus
2014-01-13 23:21:30 +01:00
parent 5b0c902997
commit e45151b89c
8 changed files with 121 additions and 27 deletions

View File

@@ -551,6 +551,7 @@
<menuitem action='newaux'/> <menuitem action='newaux'/>
<separator/> <separator/>
<menuitem action='controls'/> <menuitem action='controls'/>
<menuitem action='send_options'/>
<separator/> <separator/>
<menuitem action='clear'/> <menuitem action='clear'/>
<menuitem action='clear_pre'/> <menuitem action='clear_pre'/>

View File

@@ -45,8 +45,8 @@
#include "ardour/audioengine.h" #include "ardour/audioengine.h"
#include "ardour/internal_return.h" #include "ardour/internal_return.h"
#include "ardour/internal_send.h" #include "ardour/internal_send.h"
#include "ardour/panner_shell.h"
#include "ardour/plugin_insert.h" #include "ardour/plugin_insert.h"
#include "ardour/pannable.h"
#include "ardour/port_insert.h" #include "ardour/port_insert.h"
#include "ardour/profile.h" #include "ardour/profile.h"
#include "ardour/return.h" #include "ardour/return.h"
@@ -456,6 +456,34 @@ ProcessorEntry::toggle_control_visibility (Control* c)
_parent->update_gui_object_state (this); _parent->update_gui_object_state (this);
} }
Menu *
ProcessorEntry::build_send_options_menu ()
{
using namespace Menu_Helpers;
Menu* menu = manage (new Menu);
MenuList& items = menu->items ();
boost::shared_ptr<Send> send = boost::dynamic_pointer_cast<Send> (_processor);
if (send) {
items.push_back (CheckMenuElem (_("Link panner controls")));
CheckMenuItem* c = dynamic_cast<CheckMenuItem*> (&items.back ());
c->set_active (send->panner_shell()->is_linked_to_route());
c->signal_toggled().connect (sigc::mem_fun (*this, &ProcessorEntry::toggle_panner_link));
}
return menu;
}
void
ProcessorEntry::toggle_panner_link ()
{
boost::shared_ptr<Send> send = boost::dynamic_pointer_cast<Send> (_processor);
if (send) {
send->panner_shell()->set_linked_to_route(!send->panner_shell()->is_linked_to_route());
}
}
ProcessorEntry::Control::Control (boost::shared_ptr<AutomationControl> c, string const & n) ProcessorEntry::Control::Control (boost::shared_ptr<AutomationControl> c, string const & n)
: _control (c) : _control (c)
, _adjustment (gain_to_slider_position_with_max (1.0, Config->get_max_gain()), 0, 1, 0.01, 0.1) , _adjustment (gain_to_slider_position_with_max (1.0, Config->get_max_gain()), 0, 1, 0.01, 0.1)
@@ -1092,6 +1120,20 @@ ProcessorBox::show_processor_menu (int arg)
} }
} }
Gtk::MenuItem* send_menu_item = dynamic_cast<Gtk::MenuItem*>(ActionManager::get_widget("/ProcessorMenu/send_options"));
if (send_menu_item) {
if (single_selection) {
Menu* m = single_selection->build_send_options_menu ();
if (m && !m->items().empty()) {
send_menu_item->set_submenu (*m);
send_menu_item->set_sensitive (true);
} else {
gtk_menu_item_set_submenu (send_menu_item->gobj(), 0);
send_menu_item->set_sensitive (false);
}
}
}
/* Sensitise actions as approprioate */ /* Sensitise actions as approprioate */
cut_action->set_sensitive (can_cut()); cut_action->set_sensitive (can_cut());
@@ -1403,8 +1445,7 @@ ProcessorBox::choose_insert ()
void void
ProcessorBox::choose_send () ProcessorBox::choose_send ()
{ {
boost::shared_ptr<Pannable> sendpan(new Pannable (*_session)); boost::shared_ptr<Send> send (new Send (*_session, _route->pannable(), _route->mute_master()));
boost::shared_ptr<Send> send (new Send (*_session, sendpan, _route->mute_master()));
/* make an educated guess at the initial number of outputs for the send */ /* make an educated guess at the initial number of outputs for the send */
ChanCount outs = (_session->master_out()) ChanCount outs = (_session->master_out())
@@ -2053,9 +2094,8 @@ ProcessorBox::paste_processor_state (const XMLNodeList& nlist, boost::shared_ptr
continue; continue;
} }
boost::shared_ptr<Pannable> sendpan(new Pannable (*_session));
XMLNode n (**niter); XMLNode n (**niter);
InternalSend* s = new InternalSend (*_session, sendpan, _route->mute_master(), InternalSend* s = new InternalSend (*_session, _route->pannable(), _route->mute_master(),
boost::shared_ptr<Route>(), Delivery::Aux); boost::shared_ptr<Route>(), Delivery::Aux);
IOProcessor::prepare_for_reset (n, s->name()); IOProcessor::prepare_for_reset (n, s->name());
@@ -2069,9 +2109,8 @@ ProcessorBox::paste_processor_state (const XMLNodeList& nlist, boost::shared_ptr
} else if (type->value() == "send") { } else if (type->value() == "send") {
boost::shared_ptr<Pannable> sendpan(new Pannable (*_session));
XMLNode n (**niter); XMLNode n (**niter);
Send* s = new Send (*_session, sendpan, _route->mute_master()); Send* s = new Send (*_session, _route->pannable(), _route->mute_master());
IOProcessor::prepare_for_reset (n, s->name()); IOProcessor::prepare_for_reset (n, s->name());
@@ -2404,6 +2443,7 @@ ProcessorBox::register_actions ()
ActionManager::register_action (popup_act_grp, X_("newaux"), _("New Aux Send ...")); ActionManager::register_action (popup_act_grp, X_("newaux"), _("New Aux Send ..."));
ActionManager::register_action (popup_act_grp, X_("controls"), _("Controls")); ActionManager::register_action (popup_act_grp, X_("controls"), _("Controls"));
ActionManager::register_action (popup_act_grp, X_("send_options"), _("Send Options"));
ActionManager::register_action (popup_act_grp, X_("clear"), _("Clear (all)"), ActionManager::register_action (popup_act_grp, X_("clear"), _("Clear (all)"),
sigc::ptr_fun (ProcessorBox::rb_clear)); sigc::ptr_fun (ProcessorBox::rb_clear));

View File

@@ -138,6 +138,7 @@ public:
void set_control_state (XMLNode const *); void set_control_state (XMLNode const *);
std::string state_id () const; std::string state_id () const;
Gtk::Menu* build_controls_menu (); Gtk::Menu* build_controls_menu ();
Gtk::Menu* build_send_options_menu ();
protected: protected:
ArdourButton _button; ArdourButton _button;
@@ -205,6 +206,7 @@ private:
std::list<Control*> _controls; std::list<Control*> _controls;
void toggle_control_visibility (Control *); void toggle_control_visibility (Control *);
void toggle_panner_link ();
class PortIcon : public Gtk::DrawingArea { class PortIcon : public Gtk::DrawingArea {
public: public:

View File

@@ -49,7 +49,7 @@ class Pannable;
class PannerShell : public SessionObject class PannerShell : public SessionObject
{ {
public: public:
PannerShell (std::string name, Session&, boost::shared_ptr<Pannable>); PannerShell (std::string name, Session&, boost::shared_ptr<Pannable>, bool is_send = false);
virtual ~PannerShell (); virtual ~PannerShell ();
std::string describe_parameter (Evoral::Parameter param); std::string describe_parameter (Evoral::Parameter param);
@@ -63,19 +63,25 @@ public:
XMLNode& get_state (); XMLNode& get_state ();
int set_state (const XMLNode&, int version); int set_state (const XMLNode&, int version);
PBD::Signal0<void> PannableChanged; /* Pannable changed -- l*/
PBD::Signal0<void> Changed; /* panner and/or outputs count and/or bypass state changed */ PBD::Signal0<void> Changed; /* panner and/or outputs count and/or bypass state changed */
boost::shared_ptr<Panner> panner() const { return _panner; } boost::shared_ptr<Panner> panner() const { return _panner; }
boost::shared_ptr<Pannable> pannable() const { return _pannable; } boost::shared_ptr<Pannable> pannable() const { return _panlinked ? _pannable_route : _pannable_internal; }
bool bypassed () const; bool bypassed () const;
void set_bypassed (bool); void set_bypassed (bool);
bool is_send () const { return (_is_send); }
bool is_linked_to_route () const { return (_is_send && _panlinked); }
/* this function takes the process lock: */
void set_linked_to_route (bool);
std::string current_panner_uri() const { return _current_panner_uri; } std::string current_panner_uri() const { return _current_panner_uri; }
std::string user_selected_panner_uri() const { return _user_selected_panner_uri; } std::string user_selected_panner_uri() const { return _user_selected_panner_uri; }
std::string panner_gui_uri() const { return _panner_gui_uri; } std::string panner_gui_uri() const { return _panner_gui_uri; }
/* this function takes the process lock */ /* this function takes the process lock: */
bool select_panner_by_uri (std::string const uri); bool select_panner_by_uri (std::string const uri);
private: private:
@@ -84,7 +90,11 @@ public:
bool set_user_selected_panner_uri (std::string const uri); bool set_user_selected_panner_uri (std::string const uri);
boost::shared_ptr<Panner> _panner; boost::shared_ptr<Panner> _panner;
boost::shared_ptr<Pannable> _pannable;
boost::shared_ptr<Pannable> _pannable_internal;
boost::shared_ptr<Pannable> _pannable_route;
bool _is_send;
bool _panlinked;
bool _bypassed; bool _bypassed;
std::string _current_panner_uri; std::string _current_panner_uri;

View File

@@ -113,6 +113,8 @@ CONFIG_VARIABLE (gain_t, solo_mute_gain, "solo-mute-gain", 0.0)
CONFIG_VARIABLE (std::string, monitor_bus_preferred_bundle, "monitor-bus-preferred-bundle", "") CONFIG_VARIABLE (std::string, monitor_bus_preferred_bundle, "monitor-bus-preferred-bundle", "")
CONFIG_VARIABLE (bool, quieten_at_speed, "quieten-at-speed", true) CONFIG_VARIABLE (bool, quieten_at_speed, "quieten-at-speed", true)
CONFIG_VARIABLE (bool, link_send_and_route_panner, "link-send-and-route-panner", true)
/* click */ /* click */
CONFIG_VARIABLE (bool, clicking, "clicking", false) CONFIG_VARIABLE (bool, clicking, "clicking", false)

View File

@@ -58,7 +58,9 @@ Delivery::Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<Pann
, _no_panner_reset (false) , _no_panner_reset (false)
{ {
if (pannable) { if (pannable) {
_panshell = boost::shared_ptr<PannerShell>(new PannerShell (_name, _session, pannable)); bool is_send = false;
if (r & (Delivery::Send|Delivery::Aux)) is_send = true;
_panshell = boost::shared_ptr<PannerShell>(new PannerShell (_name, _session, pannable, is_send));
} }
_display_to_user = false; _display_to_user = false;
@@ -80,7 +82,9 @@ Delivery::Delivery (Session& s, boost::shared_ptr<Pannable> pannable, boost::sha
, _no_panner_reset (false) , _no_panner_reset (false)
{ {
if (pannable) { if (pannable) {
_panshell = boost::shared_ptr<PannerShell>(new PannerShell (_name, _session, pannable)); bool is_send = false;
if (r & (Delivery::Send|Delivery::Aux)) is_send = true;
_panshell = boost::shared_ptr<PannerShell>(new PannerShell (_name, _session, pannable, is_send));
} }
_display_to_user = false; _display_to_user = false;

View File

@@ -61,21 +61,31 @@ using namespace std;
using namespace ARDOUR; using namespace ARDOUR;
using namespace PBD; using namespace PBD;
PannerShell::PannerShell (string name, Session& s, boost::shared_ptr<Pannable> p) PannerShell::PannerShell (string name, Session& s, boost::shared_ptr<Pannable> p, bool is_send)
: SessionObject (s, name) : SessionObject (s, name)
, _pannable (p) , _pannable_route (p)
, _is_send (is_send)
, _panlinked (true)
, _bypassed (false) , _bypassed (false)
, _current_panner_uri("") , _current_panner_uri("")
, _user_selected_panner_uri("") , _user_selected_panner_uri("")
, _panner_gui_uri("") , _panner_gui_uri("")
, _force_reselect (false) , _force_reselect (false)
{ {
if (is_send) {
_pannable_internal.reset(new Pannable (s));
if (Config->get_link_send_and_route_panner()) {
_panlinked = true;
} else {
_panlinked = false;
}
}
set_name (name); set_name (name);
} }
PannerShell::~PannerShell () PannerShell::~PannerShell ()
{ {
DEBUG_TRACE(DEBUG::Destruction, string_compose ("panner shell %3 for %1 destructor, panner is %4, pannable is %2\n", _name, _pannable, this, _panner)); DEBUG_TRACE(DEBUG::Destruction, string_compose ("panner shell %3 for %1 destructor, panner is %4, pannable is %2\n", _name, _pannable_route, this, _panner));
} }
void void
@@ -122,7 +132,8 @@ PannerShell::configure_io (ChanCount in, ChanCount out)
speakers.reset (s); speakers.reset (s);
} }
Panner* p = pi->descriptor.factory (_pannable, speakers); /* TODO don't allow to link _is_send if internal & route panners are different types */
Panner* p = pi->descriptor.factory (pannable(), speakers);
// boost_debug_shared_ptr_mark_interesting (p, "Panner"); // boost_debug_shared_ptr_mark_interesting (p, "Panner");
_panner.reset (p); _panner.reset (p);
_panner->configure_io (in, out); _panner->configure_io (in, out);
@@ -139,8 +150,9 @@ PannerShell::get_state ()
node->add_property (X_("bypassed"), _bypassed ? X_("yes") : X_("no")); node->add_property (X_("bypassed"), _bypassed ? X_("yes") : X_("no"));
node->add_property (X_("user-panner"), _user_selected_panner_uri); node->add_property (X_("user-panner"), _user_selected_panner_uri);
node->add_property (X_("linked-to-route"), _panlinked ? X_("yes") : X_("no"));
if (_panner) { if (_panner && _is_send) {
node->add_child_nocopy (_panner->get_state ()); node->add_child_nocopy (_panner->get_state ());
} }
@@ -159,6 +171,10 @@ PannerShell::set_state (const XMLNode& node, int version)
set_bypassed (string_is_affirmative (prop->value ())); set_bypassed (string_is_affirmative (prop->value ()));
} }
if ((prop = node.property (X_("linked-to-route"))) != 0) {
_panlinked = string_is_affirmative (prop->value ());
}
if ((prop = node.property (X_("user-panner"))) != 0) { if ((prop = node.property (X_("user-panner"))) != 0) {
_user_selected_panner_uri = prop->value (); _user_selected_panner_uri = prop->value ();
} }
@@ -172,7 +188,8 @@ PannerShell::set_state (const XMLNode& node, int version)
if ((prop = (*niter)->property (X_("uri")))) { if ((prop = (*niter)->property (X_("uri")))) {
PannerInfo* p = PannerManager::instance().get_by_uri(prop->value()); PannerInfo* p = PannerManager::instance().get_by_uri(prop->value());
if (p) { if (p) {
_panner.reset (p->descriptor.factory (_pannable, _session.get_speakers ())); _panner.reset (p->descriptor.factory (
_is_send ? _pannable_internal : _pannable_route, _session.get_speakers ()));
_current_panner_uri = p->descriptor.panner_uri; _current_panner_uri = p->descriptor.panner_uri;
_panner_gui_uri = p->descriptor.gui_uri; _panner_gui_uri = p->descriptor.gui_uri;
if (_panner->set_state (**niter, version) == 0) { if (_panner->set_state (**niter, version) == 0) {
@@ -195,7 +212,8 @@ PannerShell::set_state (const XMLNode& node, int version)
assumption, but it's still an assumption. assumption, but it's still an assumption.
*/ */
_panner.reset ((*p)->descriptor.factory (_pannable, _session.get_speakers ())); _panner.reset ((*p)->descriptor.factory (
_is_send ? _pannable_internal : _pannable_route, _session.get_speakers ()));
_current_panner_uri = (*p)->descriptor.panner_uri; _current_panner_uri = (*p)->descriptor.panner_uri;
_panner_gui_uri = (*p)->descriptor.gui_uri; _panner_gui_uri = (*p)->descriptor.gui_uri;
@@ -413,3 +431,23 @@ PannerShell::select_panner_by_uri (std::string const uri)
} }
return true; return true;
} }
void
PannerShell::set_linked_to_route (bool onoff)
{
if (!_is_send || onoff == _panlinked) {
return;
}
_panlinked = onoff;
_force_reselect = true;
if (_panner) {
Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
ChanCount in = _panner->in();
ChanCount out = _panner->out();
configure_io(in, out);
pannable()->set_panner(_panner);
_session.set_dirty ();
}
PannableChanged();
}

View File

@@ -1069,8 +1069,7 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version)
} else if (node.name() == "Send") { } else if (node.name() == "Send") {
boost::shared_ptr<Pannable> sendpan (new Pannable (_session)); processor.reset (new Send (_session, _pannable, _mute_master));
processor.reset (new Send (_session, sendpan, _mute_master));
} else { } else {
@@ -2553,8 +2552,7 @@ Route::set_processor_state (const XMLNode& node)
if (prop->value() == "intsend") { if (prop->value() == "intsend") {
boost::shared_ptr<Pannable> sendpan (new Pannable (_session)); processor.reset (new InternalSend (_session, _pannable, _mute_master, boost::shared_ptr<Route>(), Delivery::Aux));
processor.reset (new InternalSend (_session, sendpan, _mute_master, boost::shared_ptr<Route>(), Delivery::Role (0)));
} else if (prop->value() == "ladspa" || prop->value() == "Ladspa" || } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
prop->value() == "lv2" || prop->value() == "lv2" ||
@@ -2571,7 +2569,7 @@ Route::set_processor_state (const XMLNode& node)
} else if (prop->value() == "send") { } else if (prop->value() == "send") {
boost::shared_ptr<Pannable> sendpan (new Pannable (_session)); boost::shared_ptr<Pannable> sendpan (new Pannable (_session));
processor.reset (new Send (_session, sendpan, _mute_master)); processor.reset (new Send (_session, _pannable, _mute_master));
} else { } else {
error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg; error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
@@ -2761,8 +2759,7 @@ Route::add_aux_send (boost::shared_ptr<Route> route, boost::shared_ptr<Processor
{ {
Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ()); Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
boost::shared_ptr<Pannable> sendpan (new Pannable (_session)); listener.reset (new InternalSend (_session, _pannable, _mute_master, route, Delivery::Aux));
listener.reset (new InternalSend (_session, sendpan, _mute_master, route, Delivery::Aux));
} }
add_processor (listener, before); add_processor (listener, before);