merge 3.0-panexp (pan experiments) branch, revisions 8534-8585 into 3.0, thus ending...
[ardour.git] / libs / ardour / route.cc
index 6f9780d4b955c7781798e2bd56d579e6d22efa6c..b732fd09e8b6c08cff0b59fbfd6b0fff85d62782 100644 (file)
@@ -46,7 +46,9 @@
 #include "ardour/meter.h"
 #include "ardour/mix.h"
 #include "ardour/monitor_processor.h"
+#include "ardour/pannable.h"
 #include "ardour/panner.h"
+#include "ardour/panner_shell.h"
 #include "ardour/plugin_insert.h"
 #include "ardour/port.h"
 #include "ardour/port_insert.h"
@@ -60,6 +62,7 @@
 #include "ardour/utils.h"
 #include "ardour/graph.h"
 #include "ardour/unknown_processor.h"
+#include "ardour/capturing_processor.h"
 
 #include "i18n.h"
 
@@ -105,7 +108,7 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
 int
 Route::init ()
 {
-       /* add standard controls */
+        /* add standard controls */
 
        _solo_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle));
        _mute_control->set_flags (Controllable::Flag (_mute_control->flags() | Controllable::Toggle));
@@ -113,6 +116,10 @@ Route::init ()
        add_control (_solo_control);
        add_control (_mute_control);
 
+        /* panning */
+        
+        _pannable.reset (new Pannable (_session));
+
        /* input and output objects */
 
        _input.reset (new IO (_session, _name, IO::Input, _default_type));
@@ -135,7 +142,7 @@ Route::init ()
 
        add_processor (_meter, PostFader);
 
-       _main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main));
+       _main_outs.reset (new Delivery (_session, _output, _pannable, _mute_master, _name, Delivery::Main));
 
         add_processor (_main_outs, PostFader);
 
@@ -162,7 +169,9 @@ Route::init ()
 
                 /* no panning on the monitor main outs */
 
+#ifdef PANNER_HACKS
                 _main_outs->panner()->set_bypassed (true);
+#endif
        }
 
         if (is_master() || is_monitor() || is_hidden()) {
@@ -353,11 +362,11 @@ Route::set_gain (gain_t val, void *src)
                                }
                        }
 
-                       _route_group->apply (&Route::inc_gain, factor, _route_group);
+                       _route_group->foreach_route (boost::bind (&Route::inc_gain, _1, factor, _route_group));
 
                } else {
 
-                       _route_group->apply (&Route::set_gain, val, _route_group);
+                       _route_group->foreach_route (boost::bind (&Route::set_gain, _1, val, _route_group));
                }
 
                return;
@@ -614,7 +623,7 @@ Route::set_solo (bool yn, void *src)
        }
 
        if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_solo()) {
-               _route_group->apply (&Route::set_solo, yn, _route_group);
+               _route_group->foreach_route (boost::bind (&Route::set_solo, _1, yn, _route_group));
                return;
        }
 
@@ -724,7 +733,7 @@ Route::set_solo_isolated (bool yn, void *src)
        }
 
        if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_solo()) {
-               _route_group->apply (&Route::set_solo_isolated, yn, _route_group);
+               _route_group->foreach_route (boost::bind (&Route::set_solo_isolated, _1, yn, _route_group));
                return;
        }
        
@@ -792,7 +801,7 @@ void
 Route::set_mute (bool yn, void *src)
 {
        if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_mute()) {
-               _route_group->apply (&Route::set_mute, yn, _route_group);
+               _route_group->foreach_route (boost::bind (&Route::set_mute, _1, yn, _route_group));
                return;
        }
 
@@ -974,14 +983,14 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version)
 
                                } else {
 
-                                       processor.reset (new PortInsert (_session, _mute_master));
+                                       processor.reset (new PortInsert (_session, _pannable, _mute_master));
                                }
 
                        }
 
                } else if (node.name() == "Send") {
 
-                       processor.reset (new Send (_session, _mute_master));
+                       processor.reset (new Send (_session, _pannable, _mute_master));
 
                } else {
 
@@ -1851,6 +1860,8 @@ Route::state(bool full_state)
                cmt->add_content (_comment);
        }
 
+        node->add_child_nocopy (_pannable->state (full_state));
+
        for (i = _processors.begin(); i != _processors.end(); ++i) {
                node->add_child_nocopy((*i)->state (full_state));
        }
@@ -1927,6 +1938,11 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
                if (child->name() == X_("Processor")) {
                        processor_state.add_child_copy (*child);
                }
+
+
+                if (child->name() == X_("Pannable")) {
+                        _pannable->set_state (*child, version);
+                }
        }
 
        set_processor_state (processor_state);
@@ -1964,12 +1980,12 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
        if ((prop = node.property (X_("active"))) != 0) {
                bool yn = string_is_affirmative (prop->value());
                _active = !yn; // force switch
-               set_active (yn);
+               set_active (yn, this);
        }
 
        if ((prop = node.property (X_("meter-point"))) != 0) {
                MeterPoint mp = MeterPoint (string_2_enum (prop->value (), _meter_point));
-                set_meter_point (mp);
+                set_meter_point (mp, true);
                if (_meter) {
                        _meter->set_display_to_user (_meter_point == MeterCustom);
                }
@@ -2210,7 +2226,7 @@ Route::_set_state_2X (const XMLNode& node, int version)
                        if ((prop = child->property (X_("active"))) != 0) {
                                bool yn = string_is_affirmative (prop->value());
                                _active = !yn; // force switch
-                               set_active (yn);
+                               set_active (yn, this);
                        }
                        
                        if ((prop = child->property (X_("gain"))) != 0) {
@@ -2232,7 +2248,7 @@ Route::_set_state_2X (const XMLNode& node, int version)
                                io_child = *io_niter;
                                
                                if (io_child->name() == X_("Panner")) {
-                                       _main_outs->panner()->set_state(*io_child, version);
+                                       _main_outs->panner_shell()->set_state(*io_child, version);
                                } else if (io_child->name() == X_("Automation")) {
                                        /* IO's automation is for the fader */
                                        _amp->set_automation_xml_state (*io_child, Evoral::Parameter (GainAutomation));
@@ -2369,7 +2385,7 @@ Route::set_processor_state (const XMLNode& node)
 
                                 if (prop->value() == "intsend") {
                                         
-                                        processor.reset (new InternalSend (_session, _mute_master, boost::shared_ptr<Route>(), Delivery::Role (0)));
+                                        processor.reset (new InternalSend (_session, _pannable, _mute_master, boost::shared_ptr<Route>(), Delivery::Role (0)));
                                         
                                 } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
                                            prop->value() == "lv2" ||
@@ -2380,11 +2396,11 @@ Route::set_processor_state (const XMLNode& node)
                                         
                                 } else if (prop->value() == "port") {
                                         
-                                        processor.reset (new PortInsert (_session, _mute_master));
+                                        processor.reset (new PortInsert (_session, _pannable, _mute_master));
                                         
                                 } else if (prop->value() == "send") {
                                         
-                                        processor.reset (new Send (_session, _mute_master));
+                                        processor.reset (new Send (_session, _pannable, _mute_master));
                                         
                                 } else {
                                         error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
@@ -2539,11 +2555,11 @@ Route::listen_via (boost::shared_ptr<Route> route, Placement placement, bool /*a
                                 /* master never sends to control outs */
                                 return 0;
                         } else {
-                                listener.reset (new InternalSend (_session, _mute_master, route, (aux ? Delivery::Aux : Delivery::Listen)));
+                                listener.reset (new InternalSend (_session, _pannable, _mute_master, route, (aux ? Delivery::Aux : Delivery::Listen)));
                         }
 
                 } else {
-                        listener.reset (new InternalSend (_session, _mute_master, route, (aux ? Delivery::Aux : Delivery::Listen)));
+                        listener.reset (new InternalSend (_session, _pannable, _mute_master, route, (aux ? Delivery::Aux : Delivery::Listen)));
                 }
 
        } catch (failed_constructor& err) {
@@ -2554,13 +2570,22 @@ Route::listen_via (boost::shared_ptr<Route> route, Placement placement, bool /*a
                _monitor_send = listener;
        }
 
-        if (placement == PostFader) {
-                /* put it *really* at the end, not just after the panner (main outs)
-                 */
-                add_processor (listener, _processors.end());
-        } else {
-                add_processor (listener, PreFader);
-        }
+
+       if (aux) {
+
+               add_processor (listener, placement);
+
+       } else {
+               
+               if (placement == PostFader) {
+                       /* put it *really* at the end, not just after the panner (main outs)
+                        */
+                       add_processor (listener, _processors.end());
+               } else {
+                       add_processor (listener, PreFader);
+               }
+               
+       }
 
        return 0;
 }
@@ -2937,11 +2962,11 @@ Route::flush_processors ()
 }
 
 void
-Route::set_meter_point (MeterPoint p)
+Route::set_meter_point (MeterPoint p, bool force)
 {
        /* CAN BE CALLED FROM PROCESS CONTEXT */
 
-       if (_meter_point == p) {
+       if (_meter_point == p && !force) {
                return;
        }
 
@@ -2981,7 +3006,7 @@ Route::set_meter_point (MeterPoint p)
                        _meter->reflect_inputs (m_in);
                        
                        _processors.insert (loc, _meter);
-                       
+
                        /* we do not need to reconfigure the processors, because the meter
                           (a) is always ready to handle processor_max_streams
                           (b) is always an N-in/N-out processor, and thus moving
@@ -3048,6 +3073,21 @@ Route::put_monitor_send_at (Placement p)
        _session.set_dirty ();
 }
 
+boost::shared_ptr<CapturingProcessor>
+Route::add_export_point()
+{
+       // Check if it exists already
+       boost::shared_ptr<CapturingProcessor> processor;
+       if ((processor = boost::dynamic_pointer_cast<CapturingProcessor> (*_processors.begin()))) {
+               return processor;
+       }
+
+       // ...else add it
+       processor.reset (new CapturingProcessor (_session));
+       add_processor (processor, _processors.begin());
+       return processor;
+}
+
 framecnt_t
 Route::update_total_latency ()
 {
@@ -3116,8 +3156,7 @@ Route::set_latency_delay (framecnt_t longest_session_latency)
 void
 Route::automation_snapshot (framepos_t now, bool force)
 {
-       panner()->automation_snapshot (now, force);
-       
+        _pannable->automation_snapshot (now, force);
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                (*i)->automation_snapshot (now, force);
        }
@@ -3246,11 +3285,10 @@ Route::shift (framepos_t pos, framecnt_t frames)
 
        /* pan automation */
         {
-                boost::shared_ptr<AutomationControl> pc;
-                uint32_t npans = _main_outs->panner()->npanners();
-
-                for (uint32_t p = 0; p < npans; ++p) {
-                        pc = _main_outs->panner()->pan_control (0, p);
+                ControlSet::Controls& c (_pannable->controls());
+                
+                for (ControlSet::Controls::const_iterator ci = c.begin(); ci != c.end(); ++ci) {
+                        boost::shared_ptr<AutomationControl> pc = boost::dynamic_pointer_cast<AutomationControl> (ci->second);
                         if (pc) {
                                 boost::shared_ptr<AutomationList> al = pc->alist();
                                 XMLNode& before = al->get_state ();
@@ -3399,8 +3437,13 @@ Route::denormal_protection () const
 }
 
 void
-Route::set_active (bool yn)
+Route::set_active (bool yn, void* src)
 {
+       if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_route_active()) {
+               _route_group->foreach_route (boost::bind (&Route::set_active, _1, yn, _route_group));
+               return;
+       }
+       
        if (_active != yn) {
                _active = yn;
                _input->set_active (yn);
@@ -3431,10 +3474,23 @@ Route::meter ()
        }
 }
 
+boost::shared_ptr<Pannable>
+Route::pannable() const
+{
+       return _pannable;
+}
+
 boost::shared_ptr<Panner>
 Route::panner() const
 {
-       return _main_outs->panner();
+        /* may be null ! */
+       return _main_outs->panner_shell()->panner();
+}
+
+boost::shared_ptr<PannerShell>
+Route::panner_shell() const
+{
+       return _main_outs->panner_shell();
 }
 
 boost::shared_ptr<AutomationControl>