From d8ec9bbea79bc9cefa3e042aae8fd585f35df92b Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 19 Nov 2010 00:58:57 +0000 Subject: [PATCH] non-crashing (but also non-functional) integration of VBAP with panner "architecture" git-svn-id: svn://localhost/ardour2/branches/3.0@8056 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/panner.h | 17 ++--- libs/ardour/ardour/session.h | 7 +++ libs/ardour/ardour/vbap.h | 10 +++ libs/ardour/ardour/vbap_speakers.h | 28 ++++++--- libs/ardour/panner.cc | 99 ++++++++++++++++-------------- libs/ardour/session.cc | 11 ++++ libs/ardour/session_state.cc | 1 + libs/ardour/vbap.cc | 47 +++++++++++++- libs/ardour/vbap_speakers.cc | 62 ++++++++++++++----- libs/pbd/cartesian.cc | 7 ++- 10 files changed, 211 insertions(+), 78 deletions(-) diff --git a/libs/ardour/ardour/panner.h b/libs/ardour/ardour/panner.h index 087471032d..da68ed8578 100644 --- a/libs/ardour/ardour/panner.h +++ b/libs/ardour/ardour/panner.h @@ -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; diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 91034cd034..d6dab480a7 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -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 @@ -723,6 +724,10 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi static PBD::Signal0 SendFeedback; + /* Speakers */ + + VBAPSpeakers& get_speakers (); + /* Controllables */ boost::shared_ptr 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 diff --git a/libs/ardour/ardour/vbap.h b/libs/ardour/ardour/vbap.h index 922a2a4631..b6c2b7a710 100644 --- a/libs/ardour/ardour/vbap.h +++ b/libs/ardour/ardour/vbap.h @@ -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 */ diff --git a/libs/ardour/ardour/vbap_speakers.h b/libs/ardour/ardour/vbap_speakers.h index cf1bbab691..054079f739 100644 --- a/libs/ardour/ardour/vbap_speakers.h +++ b/libs/ardour/ardour/vbap_speakers.h @@ -43,6 +43,7 @@ class VBAPSpeakers { }; static const int MAX_TRIPLET_AMOUNT = 60; + typedef std::vector 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 _speakers; - std::vector _matrices; /* holds matrices for a given speaker combinations */ - std::vector _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 _speakers; + std::vector _matrices; /* holds matrices for a given speaker combinations */ + std::vector _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); }; diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc index 8ce12caf69..55d1e5f751 100644 --- a/libs/ardour/panner.cc +++ b/libs/ardour/panner.cc @@ -32,6 +32,7 @@ #include +#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::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); + } +} diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index bbdfefccb7..dbb899a4d4 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -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; +} diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 9c17367704..cdb1af9596 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -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(); diff --git a/libs/ardour/vbap.cc b/libs/ardour/vbap.cc index 247df7995a..57957b086d 100644 --- a/libs/ardour/vbap.cc +++ b/libs/ardour/vbap.cc @@ -36,6 +36,7 @@ #include #include +#include #include #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; +} diff --git a/libs/ardour/vbap_speakers.cc b/libs/ardour/vbap_speakers.cc index a9a54e9d03..8d03fb3a9a 100644 --- a/libs/ardour/vbap_speakers.cc +++ b/libs/ardour/vbap_speakers.cc @@ -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;knext; } - 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 diff --git a/libs/pbd/cartesian.cc b/libs/pbd/cartesian.cc index c5a1587b4c..0a84fa6bbc 100644 --- a/libs/pbd/cartesian.cc +++ b/libs/pbd/cartesian.cc @@ -16,6 +16,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #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); }