X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fpanners%2Fvbap%2Fvbap.cc;h=f890b5032404ed199b1e6fbb541cacb2af579c4d;hb=4dc63966f0872efe768dad61eb9b8785d06b92d1;hp=a56a5a720d06536907356e2265d6c58355542fe7;hpb=0669bb455b72bb5333534941787a889d828ea443;p=ardour.git diff --git a/libs/panners/vbap/vbap.cc b/libs/panners/vbap/vbap.cc index a56a5a720d..f890b50324 100644 --- a/libs/panners/vbap/vbap.cc +++ b/libs/panners/vbap/vbap.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012 Paul Davis + 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 @@ -25,6 +25,10 @@ #include #include +#ifdef COMPILER_MSVC +#include +#endif + #include "pbd/cartesian.h" #include "pbd/compose.h" @@ -53,7 +57,7 @@ static PanPluginDescriptor _descriptor = { VBAPanner::factory }; -extern "C" { PanPluginDescriptor* panner_descriptor () { return &_descriptor; } } +extern "C" ARDOURPANNER_API PanPluginDescriptor* panner_descriptor () { return &_descriptor; } VBAPanner::Signal::Signal (Session&, VBAPanner&, uint32_t, uint32_t n_speakers) { @@ -65,10 +69,10 @@ VBAPanner::Signal::Signal (Session&, VBAPanner&, uint32_t, uint32_t n_speakers) } void -VBAPanner::Signal::Signal::resize_gains (uint32_t n) +VBAPanner::Signal::resize_gains (uint32_t n) { gains.assign (n, 0.0); -} +} VBAPanner::VBAPanner (boost::shared_ptr p, boost::shared_ptr s) : Panner (p) @@ -77,6 +81,9 @@ VBAPanner::VBAPanner (boost::shared_ptr p, boost::shared_ptr _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 (); } @@ -105,7 +112,7 @@ VBAPanner::configure_io (ChanCount in, ChanCount /* ignored - we use Speakers */ for (uint32_t i = 0; i < n; ++i) { Signal* s = new Signal (_pannable->session(), *this, i, _speakers->n_speakers()); _signals.push_back (s); - + } update (); @@ -114,70 +121,27 @@ 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) { + 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) { - /* 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); - - 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, elevation); - 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, elevation); - 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 */ @@ -189,8 +153,8 @@ VBAPanner::update () SignalPositionChanged(); /* emit */ } -void -VBAPanner::compute_gains (double gains[3], int speaker_ids[3], int azi, int ele) +void +VBAPanner::compute_gains (double gains[3], int speaker_ids[3], int azi, int ele) { /* calculates gain factors using loudspeaker setup and given direction */ double cartdir[3]; @@ -198,8 +162,10 @@ VBAPanner::compute_gains (double gains[3], int speaker_ids[3], int azi, int ele) int i,j,k; double small_g; double big_sm_g, gtmp[3]; + const int dimension = _speakers->dimension(); + assert(dimension == 2 || dimension == 3); - spherical_to_cartesian (azi, ele, 1.0, cartdir[0], cartdir[1], cartdir[2]); + spherical_to_cartesian (azi, ele, 1.0, cartdir[0], cartdir[1], cartdir[2]); big_sm_g = -100000.0; gains[0] = gains[1] = gains[2] = 0; @@ -209,12 +175,12 @@ VBAPanner::compute_gains (double gains[3], int speaker_ids[3], int azi, int ele) small_g = 10000000.0; - for (j = 0; j < _speakers->dimension(); j++) { + for (j = 0; j < dimension; j++) { gtmp[j] = 0.0; - for (k = 0; k < _speakers->dimension(); k++) { - gtmp[j] += cartdir[k] * _speakers->matrix(i)[j*_speakers->dimension()+k]; + for (k = 0; k < dimension; k++) { + gtmp[j] += cartdir[k] * _speakers->matrix(i)[j * dimension + k]; } if (gtmp[j] < small_g) { @@ -226,8 +192,8 @@ VBAPanner::compute_gains (double gains[3], int speaker_ids[3], int azi, int ele) 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); @@ -241,11 +207,11 @@ VBAPanner::compute_gains (double gains[3], int speaker_ids[3], int azi, int ele) } } } - + power = sqrt (gains[0]*gains[0] + gains[1]*gains[1] + gains[2]*gains[2]); if (power > 0) { - gains[0] /= power; + gains[0] /= power; gains[1] /= power; gains[2] /= power; } @@ -297,8 +263,8 @@ VBAPanner::distribute_one (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_co assert (sz == obufs.count().n_audio()); - int8_t outputs[sz]; // on the stack, no malloc - + int8_t *outputs = (int8_t*)alloca(sz); // on the stack, no malloc + /* set initial state of each output "record" */ @@ -316,21 +282,21 @@ VBAPanner::distribute_one (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_co if (signal->outputs[o] != -1) { /* used last time */ outputs[signal->outputs[o]] |= 1; - } + } if (signal->desired_outputs[o] != -1) { /* used this time */ outputs[signal->desired_outputs[o]] |= 1<<1; - } + } } /* at this point, we can test a speaker's status: - (outputs[o] & 1) <= in use before - (outputs[o] & 2) <= in use this time - (outputs[o] & 3) == 3 <= in use both times - outputs[o] == 0 <= not in use either time - + (*outputs[o] & 1) <= in use before + (*outputs[o] & 2) <= in use this time + (*outputs[o] & 3) == 3 <= in use both times + *outputs[o] == 0 <= not in use either time + */ for (int o = 0; o < 3; ++o) { @@ -344,14 +310,14 @@ VBAPanner::distribute_one (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_co pan = gain_coefficient * signal->desired_gains[o]; if (pan == 0.0 && signal->gains[output] == 0.0) { - + /* nothing deing delivered to this output */ signal->gains[output] = 0.0; - + } else if (fabs (pan - signal->gains[output]) > 0.00001) { - - /* signal to this output but the gain coefficient has changed, so + + /* signal to this output but the gain coefficient has changed, so interpolate between them. */ @@ -360,10 +326,10 @@ VBAPanner::distribute_one (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_co signal->gains[output] = pan; } else { - + /* signal to this output, same gain as before so just copy with gain */ - + mix_buffers_with_gain (obufs.get_audio (output).data(),src,nframes,pan); signal->gains[output] = pan; } @@ -388,9 +354,9 @@ VBAPanner::distribute_one (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_co */ } -void +void VBAPanner::distribute_one_automated (AudioBuffer& /*src*/, BufferSet& /*obufs*/, - framepos_t /*start*/, framepos_t /*end*/, + framepos_t /*start*/, framepos_t /*end*/, pframes_t /*nframes*/, pan_t** /*buffers*/, uint32_t /*which*/) { /* XXX to be implemented */ @@ -424,7 +390,7 @@ VBAPanner::out() const return ChanCount (DataType::AUDIO, _speakers->n_speakers()); } -std::set +std::set VBAPanner::what_can_be_automated() const { set s; @@ -437,15 +403,15 @@ VBAPanner::what_can_be_automated() const } return s; } - + string 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: @@ -453,7 +419,7 @@ VBAPanner::describe_parameter (Evoral::Parameter p) } } -string +string VBAPanner::value_as_string (boost::shared_ptr ac) const { /* DO NOT USE LocaleGuard HERE */ @@ -461,16 +427,16 @@ VBAPanner::value_as_string (boost::shared_ptr ac) const switch (ac->parameter().type()) { case PanAzimuthAutomation: /* direction */ - return string_compose (_("%1\u00B0"), 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"); } } @@ -485,7 +451,7 @@ VBAPanner::signal_position (uint32_t n) const } boost::shared_ptr -VBAPanner::get_speakers () const +VBAPanner::get_speakers () const { return _speakers->parent(); } @@ -515,8 +481,12 @@ VBAPanner::set_elevation (double e) void VBAPanner::reset () { - set_position (0); - set_width (1); + 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 ();