fix crash with a new session
[ardour.git] / libs / panners / vbap / vbap.cc
index 99a83d4106da01839316eda49ed7aefe39d0fa57..2f047b23427c321f85e7eeaa11e4407d32d0712d 100644 (file)
@@ -7,6 +7,7 @@
 #include <string>
 
 #include "pbd/cartesian.h"
+#include "pbd/compose.h"
 
 #include "ardour/amp.h"
 #include "ardour/audio_buffer.h"
@@ -18,6 +19,8 @@
 #include "vbap.h"
 #include "vbap_speakers.h"
 
+#include "i18n.h"
+
 using namespace PBD;
 using namespace ARDOUR;
 using namespace std;
@@ -99,27 +102,55 @@ VBAPanner::update ()
 
                 /* panner width control is [-1.0 .. 1.0]; we ignore sign, and map to [0 .. 360] degrees
                    so that a width of 1 corresponds to a signal equally present from all directions, 
-                   and a width of zero corresponds to a point source from the "center" (above)
+                   and a width of zero corresponds to a point source from the "center" (above) point
+                   on the perimeter of the speaker array.
                 */
 
                 double w = fabs (_pannable->pan_width_control->get_value()) * 360.0;
                 
-                double min_dir = center - w;
+                double min_dir = center - (w/2.0);
+                if (min_dir < 0) {
+                        min_dir = 360.0 + min_dir; // its already negative
+                }
                 min_dir = max (min (min_dir, 360.0), 0.0);
                 
-                double max_dir = center + w;
+                double max_dir = center + (w/2.0);
+                if (max_dir > 360.0) {
+                        max_dir = max_dir - 360.0;
+                }
                 max_dir = max (min (max_dir, 360.0), 0.0);
                 
-                double degree_step_per_signal = (max_dir - min_dir) / _signals.size();
+                if (max_dir < min_dir) {
+                        swap (max_dir, min_dir);
+                }
+
+                double degree_step_per_signal = (max_dir - min_dir) / (_signals.size() - 1);
                 double signal_direction = min_dir;
-                
-                for (vector<Signal*>::iterator s = _signals.begin(); s != _signals.end(); ++s) {
+
+                if (w >= 0.0) {
+
+                        /* positive width - normal order of signal spread */
+
+                        for (vector<Signal*>::iterator s = _signals.begin(); s != _signals.end(); ++s) {
                         
-                        Signal* signal = *s;
+                                Signal* signal = *s;
+                                
+                                signal->direction = AngularVector (signal_direction, 0.0);
+                                compute_gains (signal->desired_gains, signal->desired_outputs, signal->direction.azi, signal->direction.ele);
+                                signal_direction += degree_step_per_signal;
+                        }
+                } else {
+
+                        /* inverted width - reverse order of signal spread */
+
+                        for (vector<Signal*>::reverse_iterator s = _signals.rbegin(); s != _signals.rend(); ++s) {
                         
-                        signal->direction = AngularVector (signal_direction, 0.0);
-                        compute_gains (signal->desired_gains, signal->desired_outputs, signal->direction.azi, signal->direction.ele);
-                        signal_direction += degree_step_per_signal;
+                                Signal* signal = *s;
+                                
+                                signal->direction = AngularVector (signal_direction, 0.0);
+                                compute_gains (signal->desired_gains, signal->desired_outputs, signal->direction.azi, signal->direction.ele);
+                                signal_direction += degree_step_per_signal;
+                        }
                 }
 
         } else if (_signals.size() == 1) {
@@ -142,7 +173,7 @@ VBAPanner::compute_gains (double gains[3], int speaker_ids[3], int azi, int ele)
        double small_g;
        double big_sm_g, gtmp[3];
 
-       azi_ele_to_cart (azi,ele, cartdir[0], cartdir[1], cartdir[2]);  
+       spherical_to_cartesian (azi, ele, 1.0, cartdir[0], cartdir[1], cartdir[2]);  
        big_sm_g = -100000.0;
 
        gains[0] = gains[1] = gains[2] = 0;