fix midi buffer erase()
[ardour.git] / libs / panners / 2in2out / panner_2in2out.cc
index 2c2856361c8014708609144880ac416ff45fd820..f18dd94f45a6ef706602f301ff27443fac39cb54 100644 (file)
@@ -49,6 +49,7 @@
 #include "ardour/runtime_functions.h"
 #include "ardour/session.h"
 #include "ardour/utils.h"
+#include "ardour/mix.h"
 
 #include "panner_2in2out.h"
 
@@ -62,11 +63,14 @@ using namespace PBD;
 
 static PanPluginDescriptor _descriptor = {
         "Equal Power Stereo",
+        "http://ardour.org/plugin/panner_2in2out",
+        "http://ardour.org/plugin/panner_2in2out#ui",
         2, 2,
+        10000,
         Panner2in2out::factory
 };
 
-extern "C" { PanPluginDescriptor* panner_descriptor () { return &_descriptor; } }
+extern "C" ARDOURPANNER_API PanPluginDescriptor* panner_descriptor () { return &_descriptor; }
 
 Panner2in2out::Panner2in2out (boost::shared_ptr<Pannable> p)
        : Panner (p)
@@ -74,7 +78,14 @@ Panner2in2out::Panner2in2out (boost::shared_ptr<Pannable> p)
         if (!_pannable->has_state()) {
                 _pannable->pan_azimuth_control->set_value (0.5);
                 _pannable->pan_width_control->set_value (1.0);
-        } 
+        }
+
+        double const w = width();
+        double const wrange = min (position(), (1 - position())) * 2;
+        if (fabs(w) > wrange) {
+                set_width(w > 0 ? wrange : -wrange);
+        }
+
         
         update ();
         
@@ -122,9 +133,22 @@ Panner2in2out::set_width (double p)
         }
 }
 
+void
+Panner2in2out::thaw ()
+{
+       Panner::thaw ();
+       if (_frozen == 0) {
+               update ();
+       }
+}
+
 void
 Panner2in2out::update ()
 {
+       if (_frozen) {
+               return;
+       }
+
         /* it would be very nice to split this out into a virtual function
            that can be accessed from BaseStereoPanner and used in do_distribute_automated().
            
@@ -138,10 +162,16 @@ Panner2in2out::update ()
         */
         
         float pos[2];
-        const double width = _pannable->pan_width_control->get_value();
-        const double direction_as_lr_fract = _pannable->pan_azimuth_control->get_value();
+        double width = this->width ();
+        const double direction_as_lr_fract = position ();
+
+        double const wrange = min (position(), (1 - position())) * 2;
+        if (fabs(width) > wrange) {
+                width = (width  > 0 ? wrange : -wrange);
+        }
 
         if (width < 0.0) {
+                width = -width;
                 pos[0] = direction_as_lr_fract + (width/2.0); // left signal lr_fract
                 pos[1] = direction_as_lr_fract - (width/2.0); // right signal lr_fract
         } else {
@@ -174,17 +204,30 @@ Panner2in2out::update ()
 bool
 Panner2in2out::clamp_position (double& p)
 {
-        double w = _pannable->pan_width_control->get_value();
+        double w = width ();
         return clamp_stereo_pan (p, w);
 }
 
 bool
 Panner2in2out::clamp_width (double& w)
 {
-        double p = _pannable->pan_azimuth_control->get_value();
+        double p = position ();
         return clamp_stereo_pan (p, w);
 }
 
+pair<double, double>
+Panner2in2out::position_range () const
+{
+       return make_pair (0.5 - (1 - width()) / 2, 0.5 + (1 - width()) / 2);
+}
+
+pair<double, double>
+Panner2in2out::width_range () const
+{
+       double const w = min (position(), (1 - position())) * 2;
+       return make_pair (-w, w);
+}
+
 bool
 Panner2in2out::clamp_stereo_pan (double& direction_as_lr_fract, double& width)
 {
@@ -268,7 +311,8 @@ Panner2in2out::distribute_one (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gai
                        if (pan != 0.0f) {
 
                                /* pan is 1 but also not 0, so we must do it "properly" */
-
+                               
+                               //obufs.get_audio(1).read_from (srcbuf, nframes);
                                mix_buffers_with_gain(dst,src,nframes,pan);
 
                                /* mark that we wrote into the buffer */
@@ -327,7 +371,8 @@ Panner2in2out::distribute_one (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gai
                                /* pan is not 1 but also not 0, so we must do it "properly" */
                                
                                mix_buffers_with_gain(dst,src,nframes,pan);
-
+                               // obufs.get_audio(1).read_from (srcbuf, nframes);
+                               
                                /* XXX it would be nice to mark the buffer as written to */
                        }
 
@@ -388,6 +433,8 @@ Panner2in2out::distribute_one_automated (AudioBuffer& srcbuf, BufferSet& obufs,
                         panR = position[n] + (width[n]/2.0f); // center - width/2
                 }
 
+                panR = max(0.f, min(1.f, panR));
+
                 const float panL = 1 - panR;
 
                 /* note that are overwriting buffers, but its OK
@@ -425,33 +472,21 @@ Panner2in2out::distribute_one_automated (AudioBuffer& srcbuf, BufferSet& obufs,
 }
 
 Panner*
-Panner2in2out::factory (boost::shared_ptr<Pannable> p, Speakers& /* ignored */)
+Panner2in2out::factory (boost::shared_ptr<Pannable> p, boost::shared_ptr<Speakers> /* ignored */)
 {
        return new Panner2in2out (p);
 }
 
 XMLNode&
-Panner2in2out::get_state (void)
-{
-       return state (true);
-}
-
-XMLNode&
-Panner2in2out::state (bool /*full_state*/)
+Panner2in2out::get_state ()
 {
        XMLNode& root (Panner::get_state ());
+       root.add_property (X_("uri"), _descriptor.panner_uri);
+       /* this is needed to allow new sessions to load with old Ardour: */
        root.add_property (X_("type"), _descriptor.name);
        return root;
 }
 
-int
-Panner2in2out::set_state (const XMLNode& node, int version)
-{
-       LocaleGuard lg (X_("POSIX"));
-       Panner::set_state (node, version);
-       return 0;
-}
-
 std::set<Evoral::Parameter> 
 Panner2in2out::what_can_be_automated() const
 {
@@ -473,3 +508,42 @@ Panner2in2out::describe_parameter (Evoral::Parameter p)
                 return _pannable->describe_parameter (p);
         }
 }
+
+string 
+Panner2in2out::value_as_string (boost::shared_ptr<AutomationControl> ac) const
+{
+        /* DO NOT USE LocaleGuard HERE */
+        double val = ac->get_value();
+
+        switch (ac->parameter().type()) {
+        case PanAzimuthAutomation:
+                /* We show the position of the center of the image relative to the left & right.
+                   This is expressed as a pair of percentage values that ranges from (100,0) 
+                   (hard left) through (50,50) (hard center) to (0,100) (hard right).
+                   
+                   This is pretty wierd, but its the way audio engineers expect it. Just remember that
+                   the center of the USA isn't Kansas, its (50LA, 50NY) and it will all make sense.
+                
+                  This is designed to be as narrow as possible. Dedicated
+                  panner GUIs can do their own version of this if they need
+                  something less compact.
+                */
+                
+                return string_compose (_("L%1R%2"), (int) rint (100.0 * (1.0 - val)),
+                                       (int) rint (100.0 * val));
+
+        case PanWidthAutomation:
+                return string_compose (_("Width: %1%%"), (int) floor (100.0 * val));
+                
+        default:
+                return _("unused");
+        }
+}
+
+void
+Panner2in2out::reset ()
+{
+       set_position (0.5);
+       set_width (1);
+       update ();
+}