non-crashing (but also non-functional) integration of VBAP with panner "architecture"
authorPaul Davis <paul@linuxaudiosystems.com>
Fri, 19 Nov 2010 00:58:57 +0000 (00:58 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Fri, 19 Nov 2010 00:58:57 +0000 (00:58 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@8056 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/ardour/ardour/panner.h
libs/ardour/ardour/session.h
libs/ardour/ardour/vbap.h
libs/ardour/ardour/vbap_speakers.h
libs/ardour/panner.cc
libs/ardour/session.cc
libs/ardour/session_state.cc
libs/ardour/vbap.cc
libs/ardour/vbap_speakers.cc
libs/pbd/cartesian.cc

index 087471032d12acb2722ad3fe6a82718253c6950f..da68ed8578a8836b371a3e4eabfc85f20c44354e 100644 (file)
@@ -203,13 +203,14 @@ class Panner : public SessionObject, public Automatable
 {
 public:
        struct Output {
-               float x;
-               float y;
-               pan_t current_pan;
-               pan_t desired_pan;
-
-               Output (float xp, float yp)
-                       : x (xp), y (yp), current_pan (0), desired_pan (0) {}
+            float x;
+            float y;
+            float z;
+            pan_t current_pan;
+            pan_t desired_pan;
+            
+            Output (float xp, float yp, float zp = 0.0)
+            : x (xp), y (yp), z (zp), current_pan (0), desired_pan (0) {}
 
        };
 
@@ -320,6 +321,8 @@ public:
 
        static float current_automation_version_number;
 
+        void setup_speakers (uint32_t nouts);
+        
        /* old school automation handling */
 
        std::string automation_path;
index 91034cd034587c1acd62403252fe4575ce3a94f9..d6dab480a7b12fc3e0d2f35c4b1b5384b1432c27 100644 (file)
@@ -52,6 +52,7 @@
 #include "ardour/location.h"
 #include "ardour/timecode.h"
 #include "ardour/interpolation.h"
+#include "ardour/vbap_speakers.h"
 
 #ifdef HAVE_JACK_SESSION
 #include <jack/session.h>
@@ -723,6 +724,10 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
 
        static PBD::Signal0<void> SendFeedback;
 
+        /* Speakers */
+
+        VBAPSpeakers& get_speakers ();
+
        /* Controllables */
 
        boost::shared_ptr<PBD::Controllable> controllable_by_id (const PBD::ID&);
@@ -1462,6 +1467,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
 
        void start_time_changed (framepos_t);
        void end_time_changed (framepos_t);
+
+        VBAPSpeakers* _speakers; 
 };
 
 } // namespace ARDOUR
index 922a2a463197445d872428efcb0c5cf4d3a73e67..b6c2b7a710f86d428740006a7d0cec2f07c580dd 100644 (file)
@@ -36,9 +36,19 @@ class VBAPanner : public StreamPanner {
         ~VBAPanner ();
 
         void do_distribute (AudioBuffer&, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes);
+       void do_distribute_automated (AudioBuffer& src, BufferSet& obufs,
+                                      nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers);
 
         void set_azimuth_elevation (double azimuth, double elevation);
 
+       XMLNode& state (bool full_state);
+       XMLNode& get_state ();
+       int set_state (const XMLNode&, int version);
+
+        /* there never was any old-school automation */
+
+       int load (std::istream&, std::string path, uint32_t&) { return 0; }
+
   private:
         double _azimuth;   /* direction for the signal source */
         double _elevation; /* elevation of the signal source */
index cf1bbab691fe3addc97cb676ee6a700e93812128..054079f739fc0c5aa166d5e89ccbe75b8971f2f6 100644 (file)
@@ -43,6 +43,7 @@ class VBAPSpeakers {
         };
 
         static const int MAX_TRIPLET_AMOUNT = 60;
+        typedef std::vector<double> dvector;
 
         VBAPSpeakers ();
         ~VBAPSpeakers ();
@@ -50,8 +51,9 @@ class VBAPSpeakers {
         int  add_speaker (double direction, double elevation = 0.0);
         void remove_speaker (int id);
         void move_speaker (int id, double direction, double elevation = 0.0);
-        
-        const double* matrix (int tuple) const  { return _matrices[tuple]; }
+        void clear_speakers ();
+
+        const dvector matrix (int tuple) const  { return _matrices[tuple]; }
         int speaker_for_tuple (int tuple, int which) const { return _speaker_tuples[tuple][which]; }
 
         int           n_tuples () const  { return _matrices.size(); }
@@ -76,9 +78,21 @@ class VBAPSpeakers {
             void move (double azimuth, double elevation);
         };
 
-        std::vector<Speaker> _speakers;
-        std::vector<double[9]> _matrices;       /* holds matrices for a given speaker combinations */
-        std::vector<int[3]>    _speaker_tuples; /* holds speakers IDs for a given combination */
+        struct twoDmatrix : public dvector {
+          twoDmatrix() : dvector (4, 0.0) {}
+        };
+
+        struct threeDmatrix : public dvector {
+          threeDmatrix() : dvector (9, 0.0) {}
+        };
+        
+        struct tmatrix : public dvector {
+          tmatrix() : dvector (3, 0.0) {}
+        };
+
+        std::vector<Speaker>  _speakers;
+        std::vector<dvector>  _matrices;       /* holds matrices for a given speaker combinations */
+        std::vector<tmatrix>  _speaker_tuples; /* holds speakers IDs for a given combination */
 
         /* A struct for all loudspeakers */
         struct ls_triplet_chain {
@@ -98,8 +112,8 @@ class VBAPSpeakers {
         void add_ldsp_triplet (int i, int j, int k, struct ls_triplet_chain **ls_triplets);
         int  lines_intersect (int i,int j,int k,int l);
         void calculate_3x3_matrixes (struct ls_triplet_chain *ls_triplets);
-        void choose_ls_triplets (struct ls_triplet_chain **ls_triplets);
-        void choose_ls_pairs ();
+        void choose_speaker_triplets (struct ls_triplet_chain **ls_triplets);
+        void choose_speaker_pairs ();
         void sort_2D_lss (int* sorted_lss);
         int  calc_2D_inv_tmatrix (double azi1,double azi2, double* inv_mat);
 };
index 8ce12caf6994d909ec679bdd230c679763e6e375..55d1e5f751ecb622f7eb9bb82bc0380693774235 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <glibmm.h>
 
+#include "pbd/cartesian.h"
 #include "pbd/error.h"
 #include "pbd/failed_constructor.h"
 #include "pbd/xml++.h"
@@ -47,6 +48,7 @@
 #include "ardour/runtime_functions.h"
 #include "ardour/buffer_set.h"
 #include "ardour/audio_buffer.h"
+#include "ardour/vbap.h"
 
 #include "i18n.h"
 
@@ -947,58 +949,19 @@ Panner::reset (uint32_t nouts, uint32_t npans)
        case 2: // line
                outputs.push_back (Output (0, 0));
                outputs.push_back (Output (1.0, 0));
-
                for (n = 0; n < npans; ++n) {
                        _streampanners.push_back (new EqualPowerStereoPanner (*this, Evoral::Parameter(PanAutomation, 0, n)));
                }
-               break;
-
-       case 3: // triangle
-               outputs.push_back (Output  (0.5, 0));
-               outputs.push_back (Output  (0, 1.0));
-               outputs.push_back (Output  (1.0, 1.0));
+                break;
 
+        case 3:
+        case 4:
+        case 5:
+        default:
+                setup_speakers (nouts);
                for (n = 0; n < npans; ++n) {
-                       _streampanners.push_back (new Multi2dPanner (*this, Evoral::Parameter(PanAutomation, 0, n)));
+                       _streampanners.push_back (new VBAPanner (*this, Evoral::Parameter(PanAutomation, 0, n), _session.get_speakers()));
                }
-
-               break;
-
-       case 4: // square
-               outputs.push_back (Output  (0, 0));
-               outputs.push_back (Output  (1.0, 0));
-               outputs.push_back (Output  (1.0, 1.0));
-               outputs.push_back (Output  (0, 1.0));
-
-               for (n = 0; n < npans; ++n) {
-                       _streampanners.push_back (new Multi2dPanner (*this, Evoral::Parameter(PanAutomation, 0, n)));
-               }
-
-               break;
-
-       case 5: //square+offcenter center
-               outputs.push_back (Output  (0, 0));
-               outputs.push_back (Output  (1.0, 0));
-               outputs.push_back (Output  (1.0, 1.0));
-               outputs.push_back (Output  (0, 1.0));
-               outputs.push_back (Output  (0.5, 0.75));
-
-               for (n = 0; n < npans; ++n) {
-                       _streampanners.push_back (new Multi2dPanner (*this, Evoral::Parameter(PanAutomation, 0, n)));
-               }
-
-               break;
-
-       default:
-               /* XXX horrible placement. FIXME */
-               for (n = 0; n < nouts; ++n) {
-                       outputs.push_back (Output (0.1 * n, 0.1 * n));
-               }
-
-               for (n = 0; n < npans; ++n) {
-                       _streampanners.push_back (new Multi2dPanner (*this, Evoral::Parameter(PanAutomation, 0, n)));
-               }
-
                break;
        }
 
@@ -1669,3 +1632,47 @@ Panner::value_as_string (double v)
 
        return "";
 }
+
+void
+Panner::setup_speakers (uint32_t nouts)
+{
+        switch (nouts) {
+        case 3:
+               outputs.push_back (Output  (0.5, 0));
+               outputs.push_back (Output  (0, 1.0));
+               outputs.push_back (Output  (1.0, 1.0));
+                break;
+        case 4:
+               outputs.push_back (Output  (0, 0));
+               outputs.push_back (Output  (1.0, 0));
+               outputs.push_back (Output  (1.0, 1.0));
+               outputs.push_back (Output  (0, 1.0));
+                break;
+
+       case 5: //square+offcenter center
+               outputs.push_back (Output  (0, 0));
+               outputs.push_back (Output  (1.0, 0));
+               outputs.push_back (Output  (1.0, 1.0));
+               outputs.push_back (Output  (0, 1.0));
+               outputs.push_back (Output  (0.5, 0.75));
+                break;
+
+       default:
+               /* XXX horrible placement. FIXME */
+               for (uint32_t n = 0; n < nouts; ++n) {
+                       outputs.push_back (Output (0.1 * n, 0.1 * n));
+               }
+        }
+
+        VBAPSpeakers& speakers (_session.get_speakers());
+
+        speakers.clear_speakers ();
+
+        for (vector<Output>::iterator o = outputs.begin(); o != outputs.end(); ++o) {
+                double azimuth;
+                double elevation;
+                
+                cart_to_azi_ele ((*o).x + 1.0, (*o).y + 1.0, (*o).z, azimuth, elevation);
+                speakers.add_speaker (azimuth, elevation);
+        }
+}
index bbdfefccb72564ab53d879b7c9f4dccba03aa060..dbb899a4d4912c2f9b5091ff566ad379f421c712 100644 (file)
@@ -99,6 +99,7 @@
 #include "ardour/tempo.h"
 #include "ardour/utils.h"
 #include "ardour/graph.h"
+#include "ardour/vbap_speakers.h"
 
 #include "midi++/port.h"
 #include "midi++/mmc.h"
@@ -326,6 +327,7 @@ Session::destroy ()
        boost_debug_list_ptrs ();
 
        delete _locations;
+        delete _speakers;
 
        DEBUG_TRACE (DEBUG::Destruction, "Session::destroy() done\n");
 }
@@ -4177,3 +4179,12 @@ Session::ensure_search_path_includes (const string& path, DataType type)
                 break;
         }
 }
+
+VBAPSpeakers&
+Session::get_speakers() 
+{
+        if (!_speakers) {
+                _speakers = new VBAPSpeakers;
+        }
+        return *_speakers;
+}
index 9c1736770437e814e12450be5c55fc95073ca283..cdb1af959604553b8217b9b9a87c6372aedfc24f 100644 (file)
@@ -217,6 +217,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
        midi_control_ui = 0;
         _step_editors = 0;
         no_questions_about_missing_files = false;
+        _speakers = 0;
 
        AudioDiskstream::allocate_working_buffers();
 
index 247df7995a1d259d13ef8216d9b6a1198005e384..57957b086d2297a00d91daef81f235d55e8684ce 100644 (file)
@@ -36,6 +36,7 @@
 #include <cstdio>
 #include <cstring>
 
+#include <iostream>
 #include <string>
 
 #include "pbd/cartesian.h"
@@ -85,6 +86,8 @@ VBAPanner::compute_gains (double gains[3], int speaker_ids[3], int azi, int ele)
         double small_g;
         double big_sm_g, gtmp[3];
 
+        cerr << "COMPUTE GAINS with " << _speakers.n_tuples() << endl;
+
         azi_ele_to_cart (azi,ele, cartdir[0], cartdir[1], cartdir[2]);  
         big_sm_g = -100000.0;
 
@@ -102,6 +105,7 @@ VBAPanner::compute_gains (double gains[3], int speaker_ids[3], int azi, int ele)
 
                         if (gtmp[j] < small_g) {
                                 small_g = gtmp[j];
+                                cerr << "For triplet " << i << " g = " << small_g << endl;
                         }
                 }
 
@@ -112,6 +116,8 @@ VBAPanner::compute_gains (double gains[3], int speaker_ids[3], int azi, int ele)
                         gains[0] = gtmp[0]; 
                         gains[1] = gtmp[1]; 
 
+                        cerr << "Best triplet = " << i << endl;
+
                         speaker_ids[0]= _speakers.speaker_for_tuple (i, 0);
                         speaker_ids[1]= _speakers.speaker_for_tuple (i, 1);
 
@@ -149,6 +155,17 @@ VBAPanner::do_distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_coe
 
         if ((was_dirty = _dirty)) {
                 compute_gains (desired_gains, desired_outputs, _azimuth, _elevation);
+
+                cerr << " @ " << _azimuth << " /= " << _elevation
+                     << " Outputs: "
+                     << desired_outputs[0] << ' '
+                     << desired_outputs[1] << ' '
+                     << desired_outputs[2] 
+                     << " Gains "
+                     << desired_gains[0] << ' '
+                     << desired_gains[1] << ' '
+                     << desired_gains[2] 
+                     << endl;
         }
 
         bool todo[n_audio];
@@ -157,19 +174,20 @@ VBAPanner::do_distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_coe
                 todo[o] = true;
         }
 
+        
         /* VBAP may distribute the signal across up to 3 speakers depending on
            the configuration of the speakers.
         */
 
         for (int o = 0; o < 3; ++o) {
-                if (outputs[o] != -1) {
+                if (desired_outputs[o] != -1) {
 
                         nframes_t n = 0;
 
                         /* XXX TODO: interpolate across changes in gain and/or outputs
                          */
 
-                        dst = obufs.get_audio(outputs[o]).data();
+                        dst = obufs.get_audio(desired_outputs[o]).data();
 
                         pan = gain_coefficient * desired_gains[o];
                         mix_buffers_with_gain (dst+n,src+n,nframes-n,pan);
@@ -191,3 +209,28 @@ VBAPanner::do_distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_coe
                 memcpy (outputs, desired_outputs, sizeof (outputs));
         }
 }
+
+void 
+VBAPanner::do_distribute_automated (AudioBuffer& src, BufferSet& obufs,
+                                    nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers)
+{
+}
+
+XMLNode&
+VBAPanner::get_state ()
+{
+        return state (true);
+}
+
+XMLNode&
+VBAPanner::state (bool full_state)
+{
+        XMLNode* node = new XMLNode (X_("VBAPanner"));
+        return *node;
+}
+
+int
+VBAPanner::set_state (const XMLNode& node, int /*version*/)
+{
+        return 0;
+}
index a9a54e9d0331b6a74b648380c9fd3798c76582d1..8d03fb3a9a0bb3b3d9e3fe9a0f9b6b580ea18806 100644 (file)
@@ -63,11 +63,20 @@ VBAPSpeakers::~VBAPSpeakers ()
 {
 }
 
+void
+VBAPSpeakers::clear_speakers ()
+{
+        _speakers.clear ();
+        update ();
+}
+
 int 
 VBAPSpeakers::add_speaker (double azimuth, double elevation)
 {
         int id = _speakers.size();
 
+        cerr << "Added speaker " << id << " at " << azimuth << " /= " << elevation << endl;
+
         _speakers.push_back (Speaker (id, azimuth, elevation));
         update ();
 
@@ -112,12 +121,22 @@ VBAPSpeakers::update ()
 
         _dimension = dim;
 
+        cerr << "update with dimension = " << dim << " speakers = " << _speakers.size() << endl;
+
+        if (_speakers.size() < 2) {
+                /* nothing to be done with less than two speakers */
+                return;
+        }
+
         if (_dimension == 3)  {
                 ls_triplet_chain *ls_triplets = 0;
-                choose_ls_triplets (&ls_triplets);
-                calculate_3x3_matrixes (ls_triplets);
+                choose_speaker_triplets (&ls_triplets);
+                if (ls_triplets) {
+                        calculate_3x3_matrixes (ls_triplets);
+                        free (ls_triplets);
+                }
         } else {
-                choose_ls_pairs ();
+                choose_speaker_pairs ();
         }
 
         Changed (); /* EMIT SIGNAL */
@@ -138,7 +157,7 @@ VBAPSpeakers::angle_to_cart(ang_vec *from, cart_vec *to)
 }  
 
 void 
-VBAPSpeakers::choose_ls_triplets(struct ls_triplet_chain **ls_triplets) 
+VBAPSpeakers::choose_speaker_triplets(struct ls_triplet_chain **ls_triplets) 
 {
         /* Selects the loudspeaker triplets, and
            calculates the inversion matrices for each selected triplet.
@@ -159,9 +178,9 @@ VBAPSpeakers::choose_ls_triplets(struct ls_triplet_chain **ls_triplets)
         struct ls_triplet_chain *trip_ptr, *prev, *tmp_ptr;
 
         if (n_speakers == 0) {
-                fprintf(stderr,"Number of loudspeakers is zero\nExiting\n");
-                exit(-1);
+                return;
         }
+
         for (i = 0; i < n_speakers; i++) {
                 for (j = i+1; j < n_speakers; j++) {
                         for(k=j+1;k<n_speakers;k++) {
@@ -323,13 +342,15 @@ VBAPSpeakers::add_ldsp_triplet(int i, int j, int k, struct ls_triplet_chain **ls
                 prev = trip_ptr;
                 trip_ptr = trip_ptr->next;
         }
-        trip_ptr = (struct ls_triplet_chain*) 
-                malloc (sizeof (struct ls_triplet_chain));
+
+        trip_ptr = (struct ls_triplet_chain*) malloc (sizeof (struct ls_triplet_chain));
+
         if (prev == 0) {
                 *ls_triplets = trip_ptr;
         } else {
                 prev->next = trip_ptr;
         }
+
         trip_ptr->next = 0;
         trip_ptr->ls_nos[0] = i;
         trip_ptr->ls_nos[1] = j;
@@ -484,8 +505,10 @@ VBAPSpeakers::calculate_3x3_matrixes(struct ls_triplet_chain *ls_triplets)
         _matrices.clear ();
         _speaker_tuples.clear ();
 
-        _matrices.reserve (triplet_count);
-        _speaker_tuples.reserve (triplet_count);
+        for (int n = 0; n < triplet_count; ++n) {
+                _matrices.push_back (threeDmatrix());
+                _speaker_tuples.push_back (tmatrix());
+        }
 
         while (tr_ptr != 0) {
                 lp1 =  &(_speakers[tr_ptr->ls_nos[0]].coords);
@@ -531,7 +554,7 @@ VBAPSpeakers::calculate_3x3_matrixes(struct ls_triplet_chain *ls_triplets)
 }
 
 void 
-VBAPSpeakers::choose_ls_pairs (){
+VBAPSpeakers::choose_speaker_pairs (){
 
         /* selects the loudspeaker pairs, calculates the inversion
            matrices and stores the data to a global array
@@ -539,11 +562,17 @@ VBAPSpeakers::choose_ls_pairs (){
         const int n_speakers = _speakers.size();
         int sorted_speakers[n_speakers];
         bool exists[n_speakers];
-        double inverse_matrix[n_speakers][4];
+        double inverse_matrix[n_speakers][4]; 
         int expected_pairs = 0;
         int pair;
         int speaker;
 
+        cerr << "CHOOSE PAIRS\n";
+
+        if (n_speakers == 0) {
+                return;
+        }
+
         for (speaker = 0; speaker < n_speakers; ++speaker) {
                 exists[speaker] = false;
         }
@@ -579,10 +608,13 @@ VBAPSpeakers::choose_ls_pairs (){
         _matrices.clear ();
         _speaker_tuples.clear ();
 
-        _matrices.reserve (expected_pairs);
-        _speaker_tuples.reserve (expected_pairs);
+        for (int n = 0; n < expected_pairs; ++n) {
+                _matrices.push_back (twoDmatrix());
+                _speaker_tuples.push_back (tmatrix());
+        }
 
         for (speaker = 0; speaker < n_speakers - 1; speaker++) {
+                cerr << "exists[" << speaker << "] = " << exists[speaker] << endl;
                 if (exists[speaker]) {
                         _matrices[pair][0] = inverse_matrix[speaker][0];
                         _matrices[pair][1] = inverse_matrix[speaker][1];
@@ -605,6 +637,8 @@ VBAPSpeakers::choose_ls_pairs (){
                 _speaker_tuples[pair][0] = sorted_speakers[n_speakers-1];
                 _speaker_tuples[pair][1] = sorted_speakers[0];
         }
+
+        cerr << "PAIRS done, tuples == " << n_tuples() << " pair = " << pair << endl;
 }
 
 void 
index c5a1587b4c2618cda38d716f7fd17637536f6676..0a84fa6bbc5263774815b3a74be95db644a6618f 100644 (file)
@@ -16,6 +16,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include <iostream>
 #include <cmath>
 #include "pbd/cartesian.h"
 
@@ -39,13 +40,13 @@ PBD::cart_to_azi_ele (double x, double y, double z, double& azimuth, double& ele
         if(x == 0.0) {
                 atan_y_per_x = M_PI / 2;
         } else {
-                atan_y_per_x = atan(y / x);
+                atan_y_per_x = atan (y/x);
         }
 
         azimuth = atan_y_per_x / atorad;
 
         if (x < 0.0) {
-                azimuth +=180.0;
+                azimuth += 180.0;
         }
 
         distance = sqrt (x*x + y*y);
@@ -66,6 +67,8 @@ PBD::cart_to_azi_ele (double x, double y, double z, double& azimuth, double& ele
 
         elevation = atan_x_pl_y_per_z / atorad;
 
+        std::cerr << x << ", " << y << ", " << z << " = " << azimuth << " /= " << elevation << std::endl;
+
         // distance = sqrtf (x*x + y*y + z*z);
 }