steps toward a working VBAP panner
authorPaul Davis <paul@linuxaudiosystems.com>
Thu, 18 Nov 2010 18:01:30 +0000 (18:01 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Thu, 18 Nov 2010 18:01:30 +0000 (18:01 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@8055 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/ardour/ardour/vbap.h
libs/ardour/ardour/vbap_speakers.h [new file with mode: 0644]
libs/ardour/vbap.cc
libs/ardour/vbap_speakers.cc
libs/pbd/cartesian.cc [new file with mode: 0644]
libs/pbd/pbd/cartesian.h [new file with mode: 0644]
libs/pbd/wscript

index 45e5a84653b7176637447e98a72236d1aca29bb8..922a2a463197445d872428efcb0c5cf4d3a73e67 100644 (file)
@@ -1,34 +1,19 @@
-/* 
-   This software is being provided to you, the licensee, by Ville Pulkki,
-   under the following license. By obtaining, using and/or copying this
-   software, you agree that you have read, understood, and will comply
-   with these terms and conditions: Permission to use, copy, modify and
-   distribute, including the right to grant others rights to distribute
-   at any tier, this software and its documentation for any purpose and
-   without fee or royalty is hereby granted, provided that you agree to
-   comply with the following copyright notice and statements, including
-   the disclaimer, and that the same appear on ALL copies of the software
-   and documentation, including modifications that you make for internal
-   use or for distribution:
-   
-   Copyright 1998 by Ville Pulkki, Helsinki University of Technology.  All
-   rights reserved.  
-   
-   The software may be used, distributed, and included to commercial
-   products without any charges. When included to a commercial product,
-   the method "Vector Base Amplitude Panning" and its developer Ville
-   Pulkki must be referred to in documentation.
-   
-   This software is provided "as is", and Ville Pulkki or Helsinki
-   University of Technology make no representations or warranties,
-   expressed or implied. By way of example, but not limitation, Helsinki
-   University of Technology or Ville Pulkki make no representations or
-   warranties of merchantability or fitness for any particular purpose or
-   that the use of the licensed software or documentation will not
-   infringe any third party patents, copyrights, trademarks or other
-   rights. The name of Ville Pulkki or Helsinki University of Technology
-   may not be used in advertising or publicity pertaining to distribution
-   of the software.
+/*
+    Copyright (C) 2010 Paul Davis
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
 #ifndef __libardour_vbap_h__
 #include <string>
 #include <map>
 
+#include <pbd/signals.h>
+
 #include "ardour/panner.h"
 
 namespace ARDOUR {
 
-class VBAPSpeakers {
-  public:
-        struct cart_vec {
-            float x;
-            float y;
-            float z;
-        };
-        
-        struct ang_vec {
-            float azi;
-            float ele;
-            float length;
-        };
-
-        static const int MAX_TRIPLET_AMOUNT = 60;
-
-        VBAPSpeakers ();
-        ~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]; }
-        int speaker_for_tuple (int tuple, int which) const { return _speaker_tuples[tuple][which]; }
-
-        int           n_tuples () const  { return _matrices.size(); }
-        int           dimension() const { return _dimension; }
-
-        static void angle_to_cart(ang_vec *from, cart_vec *to);
-
-  private:
-        static const double MIN_VOL_P_SIDE_LGTH = 0.01;
-        int   _dimension;  
-
-        /* A struct for a loudspeaker instance */
-        struct Speaker { 
-            int id;
-            cart_vec coords;
-            ang_vec angles;
-            
-            Speaker (int, double azimuth, double elevation);
-
-            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 */
-
-        /* A struct for all loudspeakers */
-        struct ls_triplet_chain {
-            int ls_nos[3];
-            float inv_mx[9];
-            struct ls_triplet_chain *next;
-        };
-
-        static float vec_angle(cart_vec v1, cart_vec v2);
-        static float vec_length(cart_vec v1);
-        static float vec_prod(cart_vec v1, cart_vec v2);
-        static float vol_p_side_lgth(int i, int j,int k, const std::vector<Speaker>&);
-        static void  cross_prod(cart_vec v1,cart_vec v2, cart_vec *res);
-
-        void update ();
-        int  any_ls_inside_triplet (int a, int b, int c);
-        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 sort_2D_lss (int* sorted_lss);
-        int  calc_2D_inv_tmatrix (double azi1,double azi2, double* inv_mat);
-};
+class VBAPSpeakers;
 
 class VBAPanner : public StreamPanner { 
   public:
@@ -124,20 +39,23 @@ class VBAPanner : public StreamPanner {
 
         void set_azimuth_elevation (double azimuth, double elevation);
 
-        /* a utility function to convert azimuth+elevation into cartesian coordinates 
-           as used by the StreamPanner API
-        */
-        
-        void azi_ele_to_cart (int azi, int ele, double* c);
-
   private:
-        double        _azimuth;   /* direction for the signal source */
-        double        _elevation; /* elevation of the signal source */
-        VBAPSpeakers& _speakers;
+        double _azimuth;   /* direction for the signal source */
+        double _elevation; /* elevation of the signal source */
+        bool   _dirty;
+        double gains[3];
+        double desired_gains[3];
+        int    outputs[3];
+        int    desired_outputs[3];
+
+        PBD::ScopedConnection speaker_connection;
 
+        VBAPSpeakers& _speakers;
+        
         void compute_gains (double g[3], int ls[3], int azi, int ele);
 
         void update ();
+        void mark_dirty ();
 };
 
 } /* namespace */
diff --git a/libs/ardour/ardour/vbap_speakers.h b/libs/ardour/ardour/vbap_speakers.h
new file mode 100644 (file)
index 0000000..cf1bbab
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+    Copyright (C) 2010 Paul Davis
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __libardour_vbap_speakers_h__
+#define __libardour_vbap_speakers_h__
+
+#include <string>
+#include <map>
+
+#include <pbd/signals.h>
+
+#include "ardour/panner.h"
+
+namespace ARDOUR {
+
+class VBAPSpeakers {
+  public:
+        struct cart_vec {
+            float x;
+            float y;
+            float z;
+        };
+        
+        struct ang_vec {
+            float azi;
+            float ele;
+            float length;
+        };
+
+        static const int MAX_TRIPLET_AMOUNT = 60;
+
+        VBAPSpeakers ();
+        ~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]; }
+        int speaker_for_tuple (int tuple, int which) const { return _speaker_tuples[tuple][which]; }
+
+        int           n_tuples () const  { return _matrices.size(); }
+        int           dimension() const { return _dimension; }
+
+        static void angle_to_cart(ang_vec *from, cart_vec *to);
+
+        PBD::Signal0<void> Changed;
+
+  private:
+        static const double MIN_VOL_P_SIDE_LGTH = 0.01;
+        int   _dimension;  
+
+        /* A struct for a loudspeaker instance */
+        struct Speaker { 
+            int id;
+            cart_vec coords;
+            ang_vec angles;
+            
+            Speaker (int, double azimuth, double elevation);
+
+            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 */
+
+        /* A struct for all loudspeakers */
+        struct ls_triplet_chain {
+            int ls_nos[3];
+            float inv_mx[9];
+            struct ls_triplet_chain *next;
+        };
+
+        static float vec_angle(cart_vec v1, cart_vec v2);
+        static float vec_length(cart_vec v1);
+        static float vec_prod(cart_vec v1, cart_vec v2);
+        static float vol_p_side_lgth(int i, int j,int k, const std::vector<Speaker>&);
+        static void  cross_prod(cart_vec v1,cart_vec v2, cart_vec *res);
+
+        void update ();
+        int  any_ls_inside_triplet (int a, int b, int c);
+        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 sort_2D_lss (int* sorted_lss);
+        int  calc_2D_inv_tmatrix (double azi1,double azi2, double* inv_mat);
+};
+
+} /* namespace */
+
+#endif /* __libardour_vbap_speakers_h__ */
index d0114986ce8209767dde8b460caa97296b7f4fa1..247df7995a1d259d13ef8216d9b6a1198005e384 100644 (file)
 
 #include <string>
 
+#include "pbd/cartesian.h"
+
 #include "ardour/vbap.h"
+#include "ardour/vbap_speakers.h"
+#include "ardour/audio_buffer.h"
+#include "ardour/buffer_set.h"
 
+using namespace PBD;
 using namespace ARDOUR;
+using namespace std;
 
 VBAPanner::VBAPanner (Panner& parent, Evoral::Parameter param, VBAPSpeakers& s)
         : StreamPanner (parent, param)
+        , _dirty (false)
         , _speakers (s)
+
 {
+         _speakers.Changed.connect_same_thread (speaker_connection, boost::bind (&VBAPanner::mark_dirty, this));
 }
 
 VBAPanner::~VBAPanner ()
@@ -53,21 +63,16 @@ VBAPanner::~VBAPanner ()
 }
 
 void
-VBAPanner::azi_ele_to_cart (int azi, int ele, double* c)
+VBAPanner::mark_dirty ()
 {
-        static const double atorad = (2.0 * M_PI / 360.0) ;
-        c[0] = cos (azi * atorad) * cos (ele * atorad);
-        c[1] = sin (azi * atorad) * cos (ele * atorad);
-        c[2] = sin (ele * atorad);
+        _dirty = true;
 }
 
 void
 VBAPanner::update ()
 {
-        double g[3];
-        int    ls[3];
-
-        compute_gains (g, ls, _azimuth, _elevation);
+        cart_to_azi_ele (_x, _y, _z, _azimuth, _elevation);
+        _dirty = true;
 }
 
 void 
@@ -80,23 +85,33 @@ 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);  
+        azi_ele_to_cart (azi,ele, cartdir[0], cartdir[1], cartdir[2]);  
         big_sm_g = -100000.0;
 
-        for (i = 0; i < _speakers.n_tuples(); i++){
+        for (i = 0; i < _speakers.n_tuples(); i++) {
+
                 small_g = 10000000.0;
+
                 for (j = 0; j < _speakers.dimension(); j++) {
+
                         gtmp[j]=0.0;
-                        for (k = 0; k < _speakers.dimension(); k++)
-                                gtmp[j]+=cartdir[k]*_speakers.matrix(i)[j*_speakers.dimension()+k]; 
-                        if (gtmp[j] < small_g)
+
+                        for (k = 0; k < _speakers.dimension(); k++) {
+                                gtmp[j] += cartdir[k] * _speakers.matrix(i)[j*_speakers.dimension()+k]; 
+                        }
+
+                        if (gtmp[j] < small_g) {
                                 small_g = gtmp[j];
+                        }
                 }
 
                 if (small_g > big_sm_g) {
+
                         big_sm_g = small_g;
-                        gains[0]=gtmp[0]; 
-                        gains[1]=gtmp[1]; 
+
+                        gains[0] = gtmp[0]; 
+                        gains[1] = gtmp[1]; 
+
                         speaker_ids[0]= _speakers.speaker_for_tuple (i, 0);
                         speaker_ids[1]= _speakers.speaker_for_tuple (i, 1);
 
@@ -105,7 +120,7 @@ VBAPanner::compute_gains (double gains[3], int speaker_ids[3], int azi, int ele)
                                 speaker_ids[2] = _speakers.speaker_for_tuple (i, 2);
                         } else {
                                 gains[2] = 0.0;
-                                speaker_ids[2] = 0;
+                                speaker_ids[2] = -1;
                         }
                 }
         }
@@ -115,9 +130,64 @@ VBAPanner::compute_gains (double gains[3], int speaker_ids[3], int azi, int ele)
         gains[0] /= power; 
         gains[1] /= power;
         gains[2] /= power;
+
+        _dirty = false;
 }
 
 void
-VBAPanner::do_distribute (AudioBuffer& bufs, BufferSet& obufs, gain_t gain_coefficient, nframes_t nframes)
+VBAPanner::do_distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_coefficient, nframes_t nframes)
 {
+       if (_muted) {
+               return;
+       }
+
+       Sample* const src = srcbuf.data();
+       Sample* dst;
+        pan_t pan;
+        uint32_t n_audio = obufs.count().n_audio();
+        bool was_dirty;
+
+        if ((was_dirty = _dirty)) {
+                compute_gains (desired_gains, desired_outputs, _azimuth, _elevation);
+        }
+
+        bool todo[n_audio];
+        
+        for (uint32_t o = 0; o < n_audio; ++o) {
+                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) {
+
+                        nframes_t n = 0;
+
+                        /* XXX TODO: interpolate across changes in gain and/or outputs
+                         */
+
+                        dst = obufs.get_audio(outputs[o]).data();
+
+                        pan = gain_coefficient * desired_gains[o];
+                        mix_buffers_with_gain (dst+n,src+n,nframes-n,pan);
+
+                        todo[o] = false;
+               }
+        }
+        
+        for (uint32_t o = 0; o < n_audio; ++o) {
+                if (todo[o]) {
+                        /* VBAP decided not to deliver any audio to this output, so we write silence */
+                        dst = obufs.get_audio(o).data();
+                        memset (dst, 0, sizeof (Sample) * nframes);
+                }
+        }
+        
+        if (was_dirty) {
+                memcpy (gains, desired_gains, sizeof (gains));
+                memcpy (outputs, desired_outputs, sizeof (outputs));
+        }
 }
index 5b29aeb380a3cd94ddd0f337f161cd6f923958da..a9a54e9d0331b6a74b648380c9fd3798c76582d1 100644 (file)
@@ -34,7 +34,7 @@
 #include <cmath>
 #include <stdlib.h>
 
-#include "ardour/vbap.h"
+#include "ardour/vbap_speakers.h"
 
 using namespace ARDOUR;
 using namespace std;
@@ -113,12 +113,14 @@ VBAPSpeakers::update ()
         _dimension = dim;
 
         if (_dimension == 3)  {
-                ls_triplet_chain *ls_triplets = NULL;
+                ls_triplet_chain *ls_triplets = 0;
                 choose_ls_triplets (&ls_triplets);
                 calculate_3x3_matrixes (ls_triplets);
         } else {
                 choose_ls_pairs ();
         }
+
+        Changed (); /* EMIT SIGNAL */
 }
 
 void 
@@ -160,9 +162,9 @@ VBAPSpeakers::choose_ls_triplets(struct ls_triplet_chain **ls_triplets)
                 fprintf(stderr,"Number of loudspeakers is zero\nExiting\n");
                 exit(-1);
         }
-        for(i=0;i<n_speakers;i++)
-                for(j=i+1;j<n_speakers;j++)
-                        for(k=j+1;k<n_speakers;k++){
+        for (i = 0; i < n_speakers; i++) {
+                for (j = i+1; j < n_speakers; j++) {
+                        for(k=j+1;k<n_speakers;k++) {
                                 if (vol_p_side_lgth(i,j, k, _speakers) > MIN_VOL_P_SIDE_LGTH){
                                         connections[i][j]=1;
                                         connections[j][i]=1;
@@ -173,18 +175,24 @@ VBAPSpeakers::choose_ls_triplets(struct ls_triplet_chain **ls_triplets)
                                         add_ldsp_triplet(i,j,k,ls_triplets);
                                 }
                         }
+                }
+        }
+
         /*calculate distancies between all speakers and sorting them*/
         table_size =(((n_speakers - 1) * (n_speakers)) / 2); 
-        for(i=0;i<table_size; i++)
+        for (i = 0; i < table_size; i++) {
                 distance_table[i] = 100000.0;
-        for(i=0;i<n_speakers;i++){ 
-                for(j=(i+1);j<n_speakers; j++){ 
-                        if(connections[i][j] == 1) {
+        }
+
+        for (i = 0;i < n_speakers; i++) { 
+                for (j = i+1; j < n_speakers; j++) { 
+                        if (connections[i][j] == 1) {
                                 distance = fabs(vec_angle(_speakers[i].coords,_speakers[j].coords));
                                 k=0;
-                                while(distance_table[k] < distance)
+                                while(distance_table[k] < distance) {
                                         k++;
-                                for(l=(table_size - 1);l > k ;l--){
+                                }
+                                for (l = table_size - 1; l > k ; l--) {
                                         distance_table[l] = distance_table[l-1];
                                         distance_table_i[l] = distance_table_i[l-1];
                                         distance_table_j[l] = distance_table_j[l-1];
@@ -200,33 +208,36 @@ VBAPSpeakers::choose_ls_triplets(struct ls_triplet_chain **ls_triplets)
         /* disconnecting connections which are crossing shorter ones,
            starting from shortest one and removing all that cross it,
            and proceeding to next shortest */
-        for(i=0; i<(table_size); i++){
+        for (i = 0; i < table_size; i++) {
                 int fst_ls = distance_table_i[i];
                 int sec_ls = distance_table_j[i];
-                if(connections[fst_ls][sec_ls] == 1)
-                        for(j=0; j<n_speakers ; j++)
-                                for(k=j+1; k<n_speakers; k++)
-                                        if(j!=fst_ls) && (k != sec_ls) && (k!=fst_ls) && (j != sec_ls)){
-                                                if(lines_intersect(fst_ls, sec_ls, j,k) == 1){
+                if (connections[fst_ls][sec_ls] == 1) {
+                        for (j = 0; j < n_speakers; j++) {
+                                for (k = j+1; k < n_speakers; k++) {
+                                        if ((j!=fst_ls) && (k != sec_ls) && (k!=fst_ls) && (j != sec_ls)){
+                                                if (lines_intersect(fst_ls, sec_ls, j,k) == 1){
                                                         connections[j][k] = 0;
                                                         connections[k][j] = 0;
                                                 }
                                         }
+                                }
+                        }
+                }
         }
 
         /* remove triangles which had crossing sides
            with smaller triangles or include loudspeakers*/
         trip_ptr = *ls_triplets;
-        prev = NULL;
-        while (trip_ptr != NULL){
+        prev = 0;
+        while (trip_ptr != 0){
                 i = trip_ptr->ls_nos[0];
                 j = trip_ptr->ls_nos[1];
                 k = trip_ptr->ls_nos[2];
-                if(connections[i][j] == 0 || 
-                   connections[i][k] == 0 || 
-                   connections[j][k] == 0 ||
-                   any_ls_inside_triplet(i,j,k) == 1 ){
-                        if(prev != NULL) {
+                if (connections[i][j] == 0 || 
+                    connections[i][k] == 0 || 
+                    connections[j][k] == 0 ||
+                    any_ls_inside_triplet(i,j,k) == 1 ){
+                        if (prev != 0) {
                                 prev->next = trip_ptr->next;
                                 tmp_ptr = trip_ptr;
                                 trip_ptr = trip_ptr->next;
@@ -306,20 +317,20 @@ VBAPSpeakers::add_ldsp_triplet(int i, int j, int k, struct ls_triplet_chain **ls
 
         struct ls_triplet_chain *trip_ptr, *prev;
         trip_ptr = *ls_triplets;
-        prev = NULL;
+        prev = 0;
         
-        while (trip_ptr != NULL){
+        while (trip_ptr != 0){
                 prev = trip_ptr;
                 trip_ptr = trip_ptr->next;
         }
         trip_ptr = (struct ls_triplet_chain*) 
                 malloc (sizeof (struct ls_triplet_chain));
-        if (prev == NULL) {
+        if (prev == 0) {
                 *ls_triplets = trip_ptr;
         } else {
                 prev->next = trip_ptr;
         }
-        trip_ptr->next = NULL;
+        trip_ptr->next = 0;
         trip_ptr->ls_nos[0] = i;
         trip_ptr->ls_nos[1] = j;
         trip_ptr->ls_nos[2] = k;
@@ -463,7 +474,7 @@ VBAPSpeakers::calculate_3x3_matrixes(struct ls_triplet_chain *ls_triplets)
         
         /* counting triplet amount */
 
-        while (tr_ptr != NULL) {
+        while (tr_ptr != 0) {
                 triplet_count++;
                 tr_ptr = tr_ptr->next;
         }
@@ -476,7 +487,7 @@ VBAPSpeakers::calculate_3x3_matrixes(struct ls_triplet_chain *ls_triplets)
         _matrices.reserve (triplet_count);
         _speaker_tuples.reserve (triplet_count);
 
-        while (tr_ptr != NULL) {
+        while (tr_ptr != 0) {
                 lp1 =  &(_speakers[tr_ptr->ls_nos[0]].coords);
                 lp2 =  &(_speakers[tr_ptr->ls_nos[1]].coords);
                 lp3 =  &(_speakers[tr_ptr->ls_nos[2]].coords);
@@ -509,9 +520,9 @@ VBAPSpeakers::calculate_3x3_matrixes(struct ls_triplet_chain *ls_triplets)
                 _matrices[triplet][7] = invmx[7];
                 _matrices[triplet][8] = invmx[8];
 
-                _speaker_tuples[triplet][0] = tr_ptr->ls_nos[0]+1;
-                _speaker_tuples[triplet][1] = tr_ptr->ls_nos[1]+1;
-                _speaker_tuples[triplet][2] = tr_ptr->ls_nos[2]+1;
+                _speaker_tuples[triplet][0] = tr_ptr->ls_nos[0];
+                _speaker_tuples[triplet][1] = tr_ptr->ls_nos[1];
+                _speaker_tuples[triplet][2] = tr_ptr->ls_nos[2];
 
                 triplet++;
 
@@ -553,7 +564,7 @@ VBAPSpeakers::choose_ls_pairs (){
                 }
         }
         
-        if(((6.283 - _speakers[sorted_speakers[n_speakers-1]].angles.azi) 
+        if (((6.283 - _speakers[sorted_speakers[n_speakers-1]].angles.azi) 
             +_speakers[sorted_speakers[0]].angles.azi) <= (M_PI - 0.175)) {
                 if(calc_2D_inv_tmatrix(_speakers[sorted_speakers[n_speakers-1]].angles.azi, 
                                        _speakers[sorted_speakers[0]].angles.azi, 
@@ -578,8 +589,8 @@ VBAPSpeakers::choose_ls_pairs (){
                         _matrices[pair][2] = inverse_matrix[speaker][2];
                         _matrices[pair][3] = inverse_matrix[speaker][3];
 
-                        _speaker_tuples[pair][0] = sorted_speakers[speaker]+1;
-                        _speaker_tuples[pair][1] = sorted_speakers[speaker+1]+1;
+                        _speaker_tuples[pair][0] = sorted_speakers[speaker];
+                        _speaker_tuples[pair][1] = sorted_speakers[speaker+1];
 
                         pair++;
                 }
@@ -591,8 +602,8 @@ VBAPSpeakers::choose_ls_pairs (){
                 _matrices[pair][2] = inverse_matrix[speaker][2];
                 _matrices[pair][3] = inverse_matrix[speaker][3];
 
-                _speaker_tuples[pair][0] = sorted_speakers[n_speakers-1]+1;
-                _speaker_tuples[pair][1] = sorted_speakers[0]+1;
+                _speaker_tuples[pair][0] = sorted_speakers[n_speakers-1];
+                _speaker_tuples[pair][1] = sorted_speakers[0];
         }
 }
 
diff --git a/libs/pbd/cartesian.cc b/libs/pbd/cartesian.cc
new file mode 100644 (file)
index 0000000..c5a1587
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+    Copyright (C) 2010 Paul Davis
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <cmath>
+#include "pbd/cartesian.h"
+
+void
+PBD::azi_ele_to_cart (double azi, double ele, double& x, double& y, double& z)
+{
+        static const double atorad = 2.0 * M_PI / 360.0 ;
+        x = cos (azi * atorad) * cos (ele * atorad);
+        y = sin (azi * atorad) * cos (ele * atorad);
+        z = sin (ele * atorad);
+}
+
+void 
+PBD::cart_to_azi_ele (double x, double y, double z, double& azimuth, double& elevation)
+{
+        /* converts cartesian coordinates to angular */
+        const double atorad = 2.0 * M_PI / 360.0;
+        double atan_y_per_x, atan_x_pl_y_per_z;
+        double distance;
+
+        if(x == 0.0) {
+                atan_y_per_x = M_PI / 2;
+        } else {
+                atan_y_per_x = atan(y / x);
+        }
+
+        azimuth = atan_y_per_x / atorad;
+
+        if (x < 0.0) {
+                azimuth +=180.0;
+        }
+
+        distance = sqrt (x*x + y*y);
+
+        if (z == 0.0) {
+                atan_x_pl_y_per_z = 0.0;
+        } else {
+                atan_x_pl_y_per_z = atan (z/distance);
+        }
+
+        if (distance == 0.0) {
+                if (z < 0.0) {
+                        atan_x_pl_y_per_z = -M_PI/2.0;
+                } else {
+                        atan_x_pl_y_per_z = M_PI/2.0;
+                }
+        }
+
+        elevation = atan_x_pl_y_per_z / atorad;
+
+        // distance = sqrtf (x*x + y*y + z*z);
+}
+
diff --git a/libs/pbd/pbd/cartesian.h b/libs/pbd/pbd/cartesian.h
new file mode 100644 (file)
index 0000000..67f8f06
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+    Copyright (C) 2010 Paul Davis
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __libpbd_cartesian_h__
+#define __libpbd_cartesian_h__
+
+namespace PBD {
+        void azi_ele_to_cart (double azi, double ele, double& x, double& y, double& z);
+        void cart_to_azi_ele (double x, double y, double z, double& azi, double& ele);
+}
+
+#endif /* __libpbd_cartesian_h__ */
index 854aaa2642a8a09e36bdbb6830989f09ab4faca3..a2c880275034da4d23ffd2fdca1c8d98c43149b9 100644 (file)
@@ -58,6 +58,7 @@ def build(bld):
                basename.cc
                base_ui.cc
                 boost_debug.cc
+                cartesian.cc
                command.cc
                convert.cc
                controllable.cc