merge (with conflict fixes) with master (even against rgareus' recommendation)
authorPaul Davis <paul@linuxaudiosystems.com>
Tue, 14 Jan 2014 15:56:17 +0000 (10:56 -0500)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 14 Jan 2014 15:56:17 +0000 (10:56 -0500)
17 files changed:
gtk2_ardour/ardour.menus.in
gtk2_ardour/mixer_strip.cc
gtk2_ardour/panner2d.cc
gtk2_ardour/panner_ui.cc
gtk2_ardour/panner_ui.h
gtk2_ardour/processor_box.cc
gtk2_ardour/processor_box.h
gtk2_ardour/rc_option_editor.cc
gtk2_ardour/send_ui.cc
libs/ardour/ardour/panner_manager.h
libs/ardour/ardour/panner_shell.h
libs/ardour/ardour/rc_configuration_vars.h
libs/ardour/delivery.cc
libs/ardour/panner_manager.cc
libs/ardour/panner_shell.cc
libs/ardour/route.cc
libs/panners/vbap/vbap.cc

index a354df603d4182318c3e8c840a63c294987886b0..b6328963bb1437dce2594d897a03b1172303fb7e 100644 (file)
     <menuitem action='newaux'/>
     <separator/>
     <menuitem action='controls'/>
+    <menuitem action='send_options'/>
     <separator/>
     <menuitem action='clear'/>
     <menuitem action='clear_pre'/>
index 28c4e0745205da86420662c1271e5207cf0afeb9..80548ea20b71c60a4b6d2fd525ed13fefadc269c 100644 (file)
@@ -1041,29 +1041,13 @@ MixerStrip::update_panner_choices ()
        ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
        if (!_route->panner_shell()) { return; }
 
-       int in = _route->output()->n_ports().n_audio();
-       int out = in;
-
+       uint32_t in = _route->output()->n_ports().n_audio();
+       uint32_t out = in;
        if (_route->panner()) {
                in = _route->panner()->in().n_audio();
        }
 
-       if (out < 2 || in == 0) {
-               panners.set_available_panners(_route, std::map<std::string,std::string>());
-               return;
-       }
-
-       std::map<std::string,std::string> panner_list;
-       std::list<PannerInfo*> panner_info = PannerManager::instance().panner_info;
-       /* get available panners for current configuration. */
-       for (list<PannerInfo*>::iterator p = panner_info.begin(); p != panner_info.end(); ++p) {
-                PanPluginDescriptor* d = &(*p)->descriptor;
-                if (d->in != -1 && d->in != in) continue;
-                if (d->out != -1 && d->out != out) continue;
-                if (d->in == -1 && d->out == -1 && out <= 2) continue;
-                panner_list.insert(std::pair<std::string,std::string>(d->panner_uri,d->name));
-       }
-       panners.set_available_panners(_route, panner_list);
+       panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
 }
 
 /*
@@ -1891,10 +1875,13 @@ MixerStrip::show_send (boost::shared_ptr<Send> send)
        gain_meter().set_controls (_route, send->meter(), send->amp());
        gain_meter().setup_meters ();
 
+       uint32_t const in = _current_delivery->pans_required();
+       uint32_t const out = _current_delivery->pan_outs();
+
        panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
-       panner_ui().set_available_panners(boost::shared_ptr<ARDOUR::Route>(), std::map<std::string,std::string>());
+       panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
        panner_ui().setup_pan ();
-       panners.show_all ();
+       panner_ui().show_all ();
 
        input_button.set_sensitive (false);
        group_button.set_sensitive (false);
index c3b87ba5e498c5265910791c84e32ac97f3623c4..51c01123974827dee8caa9e2becc7dc70c54ad2e 100644 (file)
@@ -401,7 +401,7 @@ Panner2d::on_expose_event (GdkEventExpose *event)
 {
         CartesianVector c;
        cairo_t* cr;
-        bool small_size = (height <= large_size_threshold);
+        bool small = (height <= large_size_threshold);
         const double diameter = radius*2.0;
 
        cr = gdk_cairo_create (get_window()->gobj());
@@ -426,14 +426,14 @@ Panner2d::on_expose_event (GdkEventExpose *event)
        /* horizontal line of "crosshairs" */
 
         cairo_set_source_rgba (cr, 0.282, 0.517, 0.662, 1.0);
-       cairo_move_to (cr, 0.0, rint(radius) - .5);
-       cairo_line_to (cr, diameter, rint(radius) - .5);
+       cairo_move_to (cr, 0.0, rint(radius) + .5);
+       cairo_line_to (cr, diameter, rint(radius) + .5);
        cairo_stroke (cr);
 
        /* vertical line of "crosshairs" */
 
-       cairo_move_to (cr, rint(radius) - .5, 0);
-       cairo_line_to (cr, rint(radius) - .5, diameter);
+       cairo_move_to (cr, rint(radius) + .5, 0);
+       cairo_line_to (cr, rint(radius) + .5, diameter);
        cairo_stroke (cr);
 
        /* the circle on which signals live */
@@ -484,7 +484,7 @@ Panner2d::on_expose_event (GdkEventExpose *event)
 
                cairo_select_font_face (cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
 
-               if (small_size) {
+               if (small) {
                        arc_radius = 4.0;
                } else {
                        cairo_set_font_size (cr, 10);
@@ -526,12 +526,12 @@ Panner2d::on_expose_event (GdkEventExpose *event)
                                         cairo_set_source_rgba (cr, 0.517, 0.772, 0.882, 0.8);
                                         cairo_stroke (cr);
 
-                                        if (!small_size && !signal->text.empty()) {
+                                        if (!small && !signal->text.empty()) {
                                                 cairo_set_source_rgba (cr, 0.517, 0.772, 0.882, .9);
                                                 /* the +/- adjustments are a hack to try to center the text in the circle
                                                  * TODO use pango get_pixel_size() -- see mono_panner.cc
                                                  */
-                                                if (small_size) {
+                                                if (small) {
                                                         cairo_move_to (cr, c.x - 1, c.y + 1);
                                                 } else {
                                                         cairo_move_to (cr, c.x - 4, c.y + 4);
@@ -565,7 +565,7 @@ Panner2d::on_expose_event (GdkEventExpose *event)
                                 cairo_move_to (cr, c.x, c.y);
                                 cairo_save (cr);
                                 cairo_rotate (cr, -(speaker->position.azi/360.0) * (2.0 * M_PI));
-                                if (small_size) {
+                                if (small) {
                                         cairo_scale (cr, 0.8, 0.8);
                                 } else {
                                         cairo_scale (cr, 1.2, 1.2);
@@ -583,7 +583,7 @@ Panner2d::on_expose_event (GdkEventExpose *event)
                                cairo_fill (cr);
                                 cairo_restore (cr);
 
-                                if (!small_size) {
+                                if (!small) {
                                         cairo_set_font_size (cr, 16);
 
                                         /* move the text in just a bit */
index af297a85075843149c9f8cbdce727e201df3b666..0c57fab244caafc5ccbf23e00cf83515ec326d07 100644 (file)
@@ -388,7 +388,7 @@ PannerUI::build_pan_menu ()
                items.push_back (MenuElem (_("Edit..."), sigc::mem_fun (*this, &PannerUI::pan_edit)));
        }
 
-       if (_route && _panner_list.size() > 1 && !_panshell->bypassed()) {
+       if (_panner_list.size() > 1 && !_panshell->bypassed()) {
                RadioMenuItem::Group group;
                items.push_back (SeparatorElem());
 
@@ -444,9 +444,7 @@ PannerUI::pan_reset ()
 void
 PannerUI::pan_set_custom_type (std::string uri) {
        if (_suspend_menu_callbacks) return;
-       if (_route) {
-               _route->set_custom_panner_uri(uri);
-       }
+       _panshell->select_panner_by_uri(uri);
 }
 
 void
@@ -644,8 +642,7 @@ PannerUI::position_adjusted ()
 }
 
 void
-PannerUI::set_available_panners(boost::shared_ptr<ARDOUR::Route> r, std::map<std::string,std::string> p)
+PannerUI::set_available_panners(std::map<std::string,std::string> p)
 {
-       _route = r;
        _panner_list = p;
 }
index dca24451d198aec34cd34668883eb5de3a652e2f..9b349d664f0f292b68e83a650f1e0b1905db0231 100644 (file)
@@ -73,7 +73,7 @@ class PannerUI : public Gtk::HBox, public ARDOUR::SessionHandlePtr
 
        void set_width (Width);
        void setup_pan ();
-       void set_available_panners(boost::shared_ptr<ARDOUR::Route>, std::map<std::string,std::string>);
+       void set_available_panners(std::map<std::string,std::string>);
 
        void effective_pan_display ();
 
@@ -85,6 +85,7 @@ class PannerUI : public Gtk::HBox, public ARDOUR::SessionHandlePtr
 
   private:
        friend class MixerStrip;
+       friend class SendUI;
 
        boost::shared_ptr<ARDOUR::PannerShell> _panshell;
        boost::shared_ptr<ARDOUR::Panner> _panner;
@@ -161,7 +162,6 @@ class PannerUI : public Gtk::HBox, public ARDOUR::SessionHandlePtr
         void start_touch (boost::weak_ptr<ARDOUR::AutomationControl>);
         void stop_touch (boost::weak_ptr<ARDOUR::AutomationControl>);
 
-       boost::shared_ptr<ARDOUR::Route> _route;
        std::map<std::string,std::string> _panner_list;
        bool _suspend_menu_callbacks;
 };
index 1e2289d790ecc17446f6677a0fed20a134528889..05a373e9d8a01a6df91f73b96c7ed057e0a56f91 100644 (file)
@@ -45,6 +45,7 @@
 #include "ardour/audioengine.h"
 #include "ardour/internal_return.h"
 #include "ardour/internal_send.h"
+#include "ardour/panner_shell.h"
 #include "ardour/plugin_insert.h"
 #include "ardour/pannable.h"
 #include "ardour/port_insert.h"
@@ -456,6 +457,34 @@ ProcessorEntry::toggle_control_visibility (Control* c)
        _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)
        : _control (c)
        , _adjustment (gain_to_slider_position_with_max (1.0, Config->get_max_gain()), 0, 1, 0.01, 0.1)
@@ -1092,6 +1121,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 */
 
         cut_action->set_sensitive (can_cut());
@@ -2071,7 +2114,8 @@ ProcessorBox::paste_processor_state (const XMLNodeList& nlist, boost::shared_ptr
 
                                boost::shared_ptr<Pannable> sendpan(new Pannable (*_session));
                                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());
                                
@@ -2404,6 +2448,7 @@ ProcessorBox::register_actions ()
        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_("send_options"), _("Send Options"));
 
        ActionManager::register_action (popup_act_grp, X_("clear"), _("Clear (all)"),
                        sigc::ptr_fun (ProcessorBox::rb_clear));
index a66a6c4a5609db770f30494e06fb327fde556afe..021e557d364f90f6fb4c1b3d25c7993994327787 100644 (file)
@@ -138,6 +138,7 @@ public:
        void set_control_state (XMLNode const *);
        std::string state_id () const;
        Gtk::Menu* build_controls_menu ();
+       Gtk::Menu* build_send_options_menu ();
 
 protected:
        ArdourButton _button;
@@ -205,6 +206,7 @@ private:
        std::list<Control*> _controls;
 
        void toggle_control_visibility (Control *);
+       void toggle_panner_link ();
 
        class PortIcon : public Gtk::DrawingArea {
        public:
index 7c5d9a776370c6c74bda3c95c18836ca37611968..1286fd8cc9a63f6fdd5de54422b2d17ccb09511b 100644 (file)
@@ -1637,6 +1637,8 @@ RCOptionEditor::RCOptionEditor ()
 
        /* SOLO AND MUTE */
 
+       add_option (_("Solo / mute"), new OptionEditorHeading (_("Solo")));
+
        add_option (_("Solo / mute"),
             new FaderOption (
                     "solo-mute-gain",
@@ -1750,6 +1752,16 @@ RCOptionEditor::RCOptionEditor ()
                     sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_main_outs)
                     ));
 
+       add_option (_("Solo / mute"), new OptionEditorHeading (_("Send Routing")));
+
+       add_option (_("Solo / mute"),
+            new BoolOption (
+                    "link-send-and-route-panner",
+                    _("Link panners of Aux and External Sends with main panner by default"),
+                    sigc::mem_fun (*_rc_config, &RCConfiguration::get_link_send_and_route_panner),
+                    sigc::mem_fun (*_rc_config, &RCConfiguration::set_link_send_and_route_panner)
+                    ));
+
        add_option (_("MIDI"),
                    new BoolOption (
                            "send-midi-clock",
index 019307fd16b021b2ca4361edf09223b551a765cf..7e3b0e775a932471c2b33087da5021165c546477 100644 (file)
@@ -20,6 +20,7 @@
 #include <gtkmm2ext/doi.h>
 
 #include "ardour/io.h"
+#include "ardour/panner_manager.h"
 #include "ardour/send.h"
 #include "ardour/rc_configuration.h"
 
@@ -70,7 +71,11 @@ SendUI::SendUI (Gtk::Window* parent, boost::shared_ptr<Send> s, Session* session
 
        _send->output()->changed.connect (connections, invalidator (*this), boost::bind (&SendUI::outs_changed, this, _1, _2), gui_context());
 
+       uint32_t const in = _send->pans_required();
+       uint32_t const out = _send->pan_outs();
+
        _panners.set_width (Wide);
+       _panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
        _panners.setup_pan ();
 
        _gpm.setup_meters ();
@@ -97,7 +102,14 @@ SendUI::outs_changed (IOChange change, void* /*ignored*/)
 {
        ENSURE_GUI_THREAD (*this, &SendUI::outs_changed, change, ignored)
        if (change.type & IOChange::ConfigurationChanged) {
+               uint32_t const in = _send->pans_required();
+               uint32_t const out = _send->pan_outs();
+               if (_panners._panner == 0) {
+                       _panners.set_panner (_send->panner_shell(), _send->panner());
+               }
+               _panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
                _panners.setup_pan ();
+               _panners.show_all ();
                _gpm.setup_meters ();
        }
 }
index 80f8e8010a391b085aa93c367e759383be2363e7..73d667424f3a24f34292dcfd8a962dc35dc61d30 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef __ardour_panner_manager_h__
 #define __ardour_panner_manager_h__
 
+#include <map>
+#include <string>
 #include <glibmm/module.h>
 
 #include "ardour/panner.h"
 
 namespace ARDOUR {
 
+typedef std::map<std::string,std::string> PannerUriMap;
+
 struct LIBARDOUR_API PannerInfo {
+
        PanPluginDescriptor descriptor;
        Glib::Module* module;
 
@@ -51,7 +56,8 @@ public:
        std::list<PannerInfo*> panner_info;
 
        PannerInfo* select_panner (ChanCount in, ChanCount out, std::string const uri = "");
-       PannerInfo* get_by_uri (std::string uri);
+       PannerInfo* get_by_uri (std::string uri) const;
+       PannerUriMap get_available_panners(uint32_t const a_in, uint32_t const a_out) const;
 
 private:
        PannerManager();
index 76df20489f45483e506d418a45d9cb4e7943b657..02f80c7b28bc0db237c6d298593055270f407897 100644 (file)
@@ -50,7 +50,7 @@ class Pannable;
 class LIBARDOUR_API PannerShell : public SessionObject
 {
 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 ();
 
        std::string describe_parameter (Evoral::Parameter param);
@@ -64,25 +64,38 @@ public:
        XMLNode& get_state ();
        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 */
 
        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;
        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 user_selected_panner_uri() const { return _user_selected_panner_uri; }
        std::string panner_gui_uri() const { return _panner_gui_uri; }
 
+       /* this function takes the process lock: */
+       bool select_panner_by_uri (std::string const uri);
+
   private:
        friend class Route;
        void distribute_no_automation (BufferSet& src, BufferSet& dest, pframes_t nframes, gain_t gain_coeff);
        bool set_user_selected_panner_uri (std::string const uri);
 
        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;
 
        std::string _current_panner_uri;
index 23973f6a1a1c3aaf5853f9db64486fdffbfcdeb0..adae854ca723d6c9677308189618636b55c382a8 100644 (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 (bool, quieten_at_speed, "quieten-at-speed", true)
 
+CONFIG_VARIABLE (bool, link_send_and_route_panner, "link-send-and-route-panner", true)
+
 /* click */
 
 CONFIG_VARIABLE (bool, clicking, "clicking", false)
index 11500b4b10f593320a1634a70274e8f614de29b0..b4b9831d97c82d6b35cf4b3487444a305e3edb10 100644 (file)
@@ -58,7 +58,9 @@ Delivery::Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<Pann
        , _no_panner_reset (false)
 {
        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;
@@ -80,7 +82,9 @@ Delivery::Delivery (Session& s, boost::shared_ptr<Pannable> pannable, boost::sha
        , _no_panner_reset (false)
 {
        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;
@@ -364,6 +368,7 @@ Delivery::set_state (const XMLNode& node, int version)
        XMLNode* pannnode = node.child (X_("Pannable"));
        if (_panshell && _panshell->panner() && pannnode) {
                _panshell->pannable()->set_state (*pannnode, version);
+               _panshell->pannable()->set_panner(_panshell->panner());
        }
 
        return 0;
index 3c9623f3e6fa674a798c4c731258b3650a303536..0084a62285a8ddc981b6e08cd33d290bc81abd4e 100644 (file)
@@ -222,13 +222,35 @@ PannerManager::select_panner (ChanCount in, ChanCount out, std::string const uri
 }
 
 PannerInfo*
-PannerManager::get_by_uri (std::string uri)
+PannerManager::get_by_uri (std::string uri) const
 {
        PannerInfo* pi = NULL;
-       for (list<PannerInfo*>::iterator p = panner_info.begin(); p != panner_info.end(); ++p) {
+       for (list<PannerInfo*>::const_iterator p = panner_info.begin(); p != panner_info.end(); ++p) {
                if ((*p)->descriptor.panner_uri != uri) continue;
                pi = (*p);
                break;
        }
        return pi;
 }
+
+PannerUriMap
+PannerManager::get_available_panners(uint32_t const a_in, uint32_t const a_out) const
+{
+       int const in = a_in;
+       int const out = a_out;
+       PannerUriMap panner_list;
+
+       if (out < 2 || in == 0) {
+               return panner_list;
+       }
+
+       /* get available panners for current configuration. */
+       for (list<PannerInfo*>::const_iterator p = panner_info.begin(); p != panner_info.end(); ++p) {
+                PanPluginDescriptor* d = &(*p)->descriptor;
+                if (d->in != -1 && d->in != in) continue;
+                if (d->out != -1 && d->out != out) continue;
+                if (d->in == -1 && d->out == -1 && out <= 2) continue;
+                panner_list.insert(std::pair<std::string,std::string>(d->panner_uri,d->name));
+       }
+       return panner_list;
+}
index a25cb49ab5051ff68050aa2509613b92f60348cf..b489354e21142479decd3bbccdfc4913d7a908b1 100644 (file)
 #include "evoral/Curve.hpp"
 
 #include "ardour/audio_buffer.h"
+#include "ardour/audioengine.h"
 #include "ardour/buffer_set.h"
 #include "ardour/debug.h"
+#include "ardour/pannable.h"
 #include "ardour/panner.h"
 #include "ardour/panner_manager.h"
 #include "ardour/panner_shell.h"
@@ -59,21 +61,31 @@ using namespace std;
 using namespace ARDOUR;
 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)
-       , _pannable (p)
+       , _pannable_route (p)
+       , _is_send (is_send)
+       , _panlinked (true)
        , _bypassed (false)
        , _current_panner_uri("")
        , _user_selected_panner_uri("")
        , _panner_gui_uri("")
        , _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);
 }
 
 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
@@ -120,7 +132,8 @@ PannerShell::configure_io (ChanCount in, ChanCount out)
                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");
        _panner.reset (p);
        _panner->configure_io (in, out);
@@ -137,8 +150,9 @@ PannerShell::get_state ()
 
        node->add_property (X_("bypassed"), _bypassed ? X_("yes") : X_("no"));
        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 ());
        }
 
@@ -157,6 +171,10 @@ PannerShell::set_state (const XMLNode& node, int version)
                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) {
                _user_selected_panner_uri = prop->value ();
        }
@@ -170,7 +188,8 @@ PannerShell::set_state (const XMLNode& node, int version)
                        if ((prop = (*niter)->property (X_("uri")))) {
                                PannerInfo* p = PannerManager::instance().get_by_uri(prop->value());
                                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;
                                        _panner_gui_uri = p->descriptor.gui_uri;
                                        if (_panner->set_state (**niter, version) == 0) {
@@ -193,7 +212,8 @@ PannerShell::set_state (const XMLNode& node, int version)
                                                   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;
                                                _panner_gui_uri = (*p)->descriptor.gui_uri;
 
@@ -393,3 +413,41 @@ PannerShell::set_user_selected_panner_uri (std::string const uri)
        _force_reselect = true;
        return true;
 }
+
+bool
+PannerShell::select_panner_by_uri (std::string const uri)
+{
+       if (uri == _user_selected_panner_uri) return false;
+       _user_selected_panner_uri = uri;
+       if (uri == _current_panner_uri) return false;
+       _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 ();
+       }
+       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();
+}
index 1b40df24dd830dfe8a6aa87b500265232a59274f..6279dbacf6dcfa9b90f99773db81a50774dba4f4 100644 (file)
@@ -1568,6 +1568,10 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
        return 0;
 }
 
+#if 0
+/* currently unused (again) -- but will come in handy soon (again)
+ * once there is an option to link route + delivery panner settings
+ */
 void
 Route::set_custom_panner_uri (std::string const panner_uri)
 {
@@ -1619,6 +1623,7 @@ Route::set_custom_panner_uri (std::string const panner_uri)
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
        _session.set_dirty ();
 }
+#endif
 
 void
 Route::reset_instrument_info ()
@@ -2553,8 +2558,7 @@ Route::set_processor_state (const XMLNode& node)
 
                                if (prop->value() == "intsend") {
 
-                                       boost::shared_ptr<Pannable> sendpan (new Pannable (_session));
-                                       processor.reset (new InternalSend (_session, sendpan, _mute_master, boost::shared_ptr<Route>(), Delivery::Role (0)));
+                                       processor.reset (new InternalSend (_session, _pannable, _mute_master, boost::shared_ptr<Route>(), Delivery::Aux));
 
                                } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
                                           prop->value() == "lv2" ||
@@ -2570,8 +2574,7 @@ Route::set_processor_state (const XMLNode& node)
 
                                } else if (prop->value() == "send") {
 
-                                       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 {
                                        error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
index 23683fde08e1680a870594a23402e4fd3d833ddf..0de8d3a29af5c95c8ba7c11f4950ac4519ba9da9 100644 (file)
@@ -477,7 +477,11 @@ void
 VBAPanner::reset ()
 {
        set_position (0);
-       set_width (1);
+        if (_signals.size() > 1) {
+                set_width (1.0 - (1.0 / (double)_signals.size()));
+        } else {
+                set_width (0);
+        }
        set_elevation (0);
 
        update ();