summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/ardour/ardour/vbap.h144
-rw-r--r--libs/ardour/ardour/vbap_speakers.h109
-rw-r--r--libs/ardour/vbap.cc106
-rw-r--r--libs/ardour/vbap_speakers.cc87
-rw-r--r--libs/pbd/cartesian.cc71
-rw-r--r--libs/pbd/pbd/cartesian.h27
-rw-r--r--libs/pbd/wscript1
7 files changed, 376 insertions, 169 deletions
diff --git a/libs/ardour/ardour/vbap.h b/libs/ardour/ardour/vbap.h
index 45e5a84653..922a2a4631 100644
--- a/libs/ardour/ardour/vbap.h
+++ b/libs/ardour/ardour/vbap.h
@@ -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__
@@ -37,83 +22,13 @@
#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
index 0000000000..cf1bbab691
--- /dev/null
+++ b/libs/ardour/ardour/vbap_speakers.h
@@ -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__ */
diff --git a/libs/ardour/vbap.cc b/libs/ardour/vbap.cc
index d0114986ce..247df7995a 100644
--- a/libs/ardour/vbap.cc
+++ b/libs/ardour/vbap.cc
@@ -38,14 +38,24 @@
#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));
+ }
}
diff --git a/libs/ardour/vbap_speakers.cc b/libs/ardour/vbap_speakers.cc
index 5b29aeb380..a9a54e9d03 100644
--- a/libs/ardour/vbap_speakers.cc
+++ b/libs/ardour/vbap_speakers.cc
@@ -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
index 0000000000..c5a1587b4c
--- /dev/null
+++ b/libs/pbd/cartesian.cc
@@ -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
index 0000000000..67f8f0629c
--- /dev/null
+++ b/libs/pbd/pbd/cartesian.h
@@ -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__ */
diff --git a/libs/pbd/wscript b/libs/pbd/wscript
index 854aaa2642..a2c8802750 100644
--- a/libs/pbd/wscript
+++ b/libs/pbd/wscript
@@ -58,6 +58,7 @@ def build(bld):
basename.cc
base_ui.cc
boost_debug.cc
+ cartesian.cc
command.cc
convert.cc
controllable.cc