X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fpanners%2Fvbap%2Fvbap.cc;h=ea2d26fb313e043e1768cd43b41b58119f168599;hb=371e8bdb55a85bed86748b46caf3d6edfdd9e3f5;hp=2f047b23427c321f85e7eeaa11e4407d32d0712d;hpb=110311e1860d6fb18b1985ca47f33126ae69f678;p=ardour.git diff --git a/libs/panners/vbap/vbap.cc b/libs/panners/vbap/vbap.cc index 2f047b2342..ea2d26fb31 100644 --- a/libs/panners/vbap/vbap.cc +++ b/libs/panners/vbap/vbap.cc @@ -1,3 +1,22 @@ +/* + Copyright (C) 2012 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 #include #include @@ -27,13 +46,16 @@ using namespace std; static PanPluginDescriptor _descriptor = { "VBAP 2D panner", + "http://ardour.org/plugin/panner_vbap", + "http://ardour.org/plugin/panner_vbap#ui", -1, -1, + 1000, VBAPanner::factory }; extern "C" { PanPluginDescriptor* panner_descriptor () { return &_descriptor; } } -VBAPanner::Signal::Signal (Session& session, VBAPanner& p, uint32_t n, uint32_t n_speakers) +VBAPanner::Signal::Signal (Session&, VBAPanner&, uint32_t, uint32_t n_speakers) { resize_gains (n_speakers); @@ -53,7 +75,11 @@ VBAPanner::VBAPanner (boost::shared_ptr p, boost::shared_ptr , _speakers (new VBAPSpeakers (s)) { _pannable->pan_azimuth_control->Changed.connect_same_thread (*this, boost::bind (&VBAPanner::update, this)); + _pannable->pan_elevation_control->Changed.connect_same_thread (*this, boost::bind (&VBAPanner::update, this)); _pannable->pan_width_control->Changed.connect_same_thread (*this, boost::bind (&VBAPanner::update, this)); + if (!_pannable->has_state()) { + reset(); + } update (); } @@ -91,76 +117,36 @@ VBAPanner::configure_io (ChanCount in, ChanCount /* ignored - we use Speakers */ void VBAPanner::update () { - /* recompute signal directions based on panner azimuth and, if relevant, width (diffusion) parameters) - */ - - /* panner azimuth control is [0 .. 1.0] which we interpret as [0 .. 360] degrees - */ - double center = _pannable->pan_azimuth_control->get_value() * 360.0; + /* recompute signal directions based on panner azimuth and, if relevant, width (diffusion) and elevation parameters */ + double elevation = _pannable->pan_elevation_control->get_value() * 90.0; if (_signals.size() > 1) { - - /* panner width control is [-1.0 .. 1.0]; we ignore sign, and map to [0 .. 360] degrees - so that a width of 1 corresponds to a signal equally present from all directions, - and a width of zero corresponds to a point source from the "center" (above) point - on the perimeter of the speaker array. - */ - - double w = fabs (_pannable->pan_width_control->get_value()) * 360.0; - - double min_dir = center - (w/2.0); - if (min_dir < 0) { - min_dir = 360.0 + min_dir; // its already negative - } - min_dir = max (min (min_dir, 360.0), 0.0); - - double max_dir = center + (w/2.0); - if (max_dir > 360.0) { - max_dir = max_dir - 360.0; - } - max_dir = max (min (max_dir, 360.0), 0.0); + double w = - (_pannable->pan_width_control->get_value()); + double signal_direction = 1.0 - (_pannable->pan_azimuth_control->get_value() + (w/2)); + double grd_step_per_signal = w / (_signals.size() - 1); + for (vector::iterator s = _signals.begin(); s != _signals.end(); ++s) { - if (max_dir < min_dir) { - swap (max_dir, min_dir); - } - - double degree_step_per_signal = (max_dir - min_dir) / (_signals.size() - 1); - double signal_direction = min_dir; - - if (w >= 0.0) { + Signal* signal = *s; - /* positive width - normal order of signal spread */ + int over = signal_direction; + over -= (signal_direction >= 0) ? 0 : 1; + signal_direction -= (double)over; - for (vector::iterator s = _signals.begin(); s != _signals.end(); ++s) { - - Signal* signal = *s; - - signal->direction = AngularVector (signal_direction, 0.0); - compute_gains (signal->desired_gains, signal->desired_outputs, signal->direction.azi, signal->direction.ele); - signal_direction += degree_step_per_signal; - } - } else { - - /* inverted width - reverse order of signal spread */ - - for (vector::reverse_iterator s = _signals.rbegin(); s != _signals.rend(); ++s) { - - Signal* signal = *s; - - signal->direction = AngularVector (signal_direction, 0.0); - compute_gains (signal->desired_gains, signal->desired_outputs, signal->direction.azi, signal->direction.ele); - signal_direction += degree_step_per_signal; - } + signal->direction = AngularVector (signal_direction * 360.0, elevation); + compute_gains (signal->desired_gains, signal->desired_outputs, signal->direction.azi, signal->direction.ele); + signal_direction += grd_step_per_signal; } - } else if (_signals.size() == 1) { + double center = (1.0 - _pannable->pan_azimuth_control->get_value()) * 360.0; /* width has no role to play if there is only 1 signal: VBAP does not do "diffusion" of a single channel */ Signal* s = _signals.front(); - s->direction = AngularVector (center, 0); + s->direction = AngularVector (center, elevation); compute_gains (s->desired_gains, s->desired_outputs, s->direction.azi, s->direction.ele); } + + SignalPositionChanged(); /* emit */ } void @@ -363,31 +349,23 @@ VBAPanner::distribute_one (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_co } void -VBAPanner::distribute_one_automated (AudioBuffer& src, BufferSet& obufs, - framepos_t start, framepos_t end, pframes_t nframes, pan_t** buffers, uint32_t which) +VBAPanner::distribute_one_automated (AudioBuffer& /*src*/, BufferSet& /*obufs*/, + framepos_t /*start*/, framepos_t /*end*/, + pframes_t /*nframes*/, pan_t** /*buffers*/, uint32_t /*which*/) { + /* XXX to be implemented */ } XMLNode& VBAPanner::get_state () { - return state (true); -} - -XMLNode& -VBAPanner::state (bool full_state) -{ - XMLNode& node (Panner::get_state()); + XMLNode& node (Panner::get_state()); + node.add_property (X_("uri"), _descriptor.panner_uri); + /* this is needed to allow new sessions to load with old Ardour: */ node.add_property (X_("type"), _descriptor.name); return node; } -int -VBAPanner::set_state (const XMLNode& node, int /*version*/) -{ - return 0; -} - Panner* VBAPanner::factory (boost::shared_ptr p, boost::shared_ptr s) { @@ -414,6 +392,9 @@ VBAPanner::what_can_be_automated() const if (_signals.size() > 1) { s.insert (Evoral::Parameter (PanWidthAutomation)); } + if (_speakers->dimension() == 3) { + s.insert (Evoral::Parameter (PanElevationAutomation)); + } return s; } @@ -422,9 +403,11 @@ VBAPanner::describe_parameter (Evoral::Parameter p) { switch (p.type()) { case PanAzimuthAutomation: - return _("Direction"); + return _("Azimuth"); case PanWidthAutomation: - return _("Diffusion"); + return _("Width"); + case PanElevationAutomation: + return _("Elevation"); default: return _pannable->describe_parameter (p); } @@ -438,13 +421,16 @@ VBAPanner::value_as_string (boost::shared_ptr ac) const switch (ac->parameter().type()) { case PanAzimuthAutomation: /* direction */ - return string_compose (_("%1"), int (rint (val * 360.0))); + return string_compose (_("%1\u00B0"), (int (rint (val * 360.0))+180)%360); case PanWidthAutomation: /* diffusion */ return string_compose (_("%1%%"), (int) floor (100.0 * fabs(val))); + + case PanElevationAutomation: /* elevation */ + return string_compose (_("%1\u00B0"), (int) floor (90.0 * fabs(val))); default: - return _pannable->value_as_string (ac); + return _("unused"); } } @@ -467,15 +453,11 @@ VBAPanner::get_speakers () const void VBAPanner::set_position (double p) { - if (p < 0.0) { - p = 1.0 + p; - } - - if (p > 1.0) { - p = fmod (p, 1.0); - } - - _pannable->pan_azimuth_control->set_value (p); + /* map into 0..1 range */ + int over = p; + over -= (p >= 0) ? 0 : 1; + p -= (double)over; + _pannable->pan_azimuth_control->set_value (p); } void @@ -483,3 +465,23 @@ VBAPanner::set_width (double w) { _pannable->pan_width_control->set_value (min (1.0, max (-1.0, w))); } + +void +VBAPanner::set_elevation (double e) +{ + _pannable->pan_elevation_control->set_value (min (1.0, max (0.0, e))); +} + +void +VBAPanner::reset () +{ + set_position (.5); + if (_signals.size() > 1) { + set_width (1.0 - (1.0 / (double)_signals.size())); + } else { + set_width (1.0); + } + set_elevation (0); + + update (); +}