2 Copyright (C) 2004-2011 Paul Davis
3 adopted from 2in2out panner by Robin Gareus <robin@gareus.org>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36 #include "pbd/cartesian.h"
37 #include "pbd/convert.h"
38 #include "pbd/error.h"
39 #include "pbd/failed_constructor.h"
40 #include "pbd/xml++.h"
41 #include "pbd/enumwriter.h"
43 #include "evoral/Curve.hpp"
45 #include "ardour/audio_buffer.h"
46 #include "ardour/audio_buffer.h"
47 #include "ardour/buffer_set.h"
48 #include "ardour/pan_controllable.h"
49 #include "ardour/pannable.h"
50 #include "ardour/runtime_functions.h"
51 #include "ardour/session.h"
52 #include "ardour/utils.h"
53 #include "ardour/mix.h"
55 #include "panner_balance.h"
59 #include "pbd/mathfix.h"
62 using namespace ARDOUR;
65 static PanPluginDescriptor _descriptor = {
67 "http://ardour.org/plugin/panner_balance",
68 "http://ardour.org/plugin/panner_balance#ui",
71 Pannerbalance::factory
74 extern "C" ARDOURPANNER_API PanPluginDescriptor* panner_descriptor () { return &_descriptor; }
76 Pannerbalance::Pannerbalance (boost::shared_ptr<Pannable> p)
79 if (!_pannable->has_state()) {
80 _pannable->pan_azimuth_control->set_value (0.5);
86 pos_interp[0] = pos[0] = desired_pos[0];
88 pos_interp[1] = pos[1] = desired_pos[1];
90 _pannable->pan_azimuth_control->Changed.connect_same_thread (*this, boost::bind (&Pannerbalance::update, this));
93 Pannerbalance::~Pannerbalance ()
98 Pannerbalance::position () const
100 return _pannable->pan_azimuth_control->get_value();
104 Pannerbalance::set_position (double p)
106 if (clamp_position (p)) {
107 _pannable->pan_azimuth_control->set_value (p);
112 Pannerbalance::thaw ()
121 Pannerbalance::update ()
127 float const pos = _pannable->pan_azimuth_control->get_value();
130 desired_pos[0] = 1.0;
131 desired_pos[1] = 1.0;
132 } else if (pos > .5) {
133 desired_pos[0] = 2 - 2. * pos;
134 desired_pos[1] = 1.0;
136 desired_pos[0] = 1.0;
137 desired_pos[1] = 2. * pos;
142 Pannerbalance::clamp_position (double& p)
144 p = max (min (p, 1.0), 0.0);
149 Pannerbalance::position_range () const
151 return make_pair (0, 1);
155 Pannerbalance::distribute_one (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_coeff, pframes_t nframes, uint32_t which)
157 assert (obufs.count().n_audio() == 2);
163 Sample* const src = srcbuf.data();
165 dst = obufs.get_audio(which).data();
167 if (fabsf ((delta = (pos[which] - desired_pos[which]))) > 0.002) { // about 1 degree of arc
169 /* we've moving the pan by an appreciable amount, so we must
170 interpolate over 64 frames or nframes, whichever is smaller */
172 pframes_t const limit = min ((pframes_t) 64, nframes);
175 delta = -(delta / (float) (limit));
177 for (n = 0; n < limit; n++) {
178 pos_interp[which] = pos_interp[which] + delta;
179 pos[which] = pos_interp[which] + 0.9 * (pos[which] - pos_interp[which]);
180 dst[n] += src[n] * pos[which] * gain_coeff;
183 /* then pan the rest of the buffer; no need for interpolation for this bit */
185 pan = pos[which] * gain_coeff;
187 mix_buffers_with_gain (dst+n,src+n,nframes-n,pan);
191 pos[which] = desired_pos[which];
192 pos_interp[which] = pos[which];
194 if ((pan = (pos[which] * gain_coeff)) != 1.0f) {
198 /* pan is 1 but also not 0, so we must do it "properly" */
200 //obufs.get_audio(1).read_from (srcbuf, nframes);
201 mix_buffers_with_gain(dst,src,nframes,pan);
203 /* mark that we wrote into the buffer */
210 /* pan is 1 so we can just copy the input samples straight in */
211 mix_buffers_no_gain(dst,src,nframes);
217 Pannerbalance::distribute_one_automated (AudioBuffer& srcbuf, BufferSet& obufs,
218 framepos_t start, framepos_t end, pframes_t nframes,
219 pan_t** buffers, uint32_t which)
221 assert (obufs.count().n_audio() == 2);
225 Sample* const src = srcbuf.data();
226 pan_t* const position = buffers[0];
228 /* fetch positional data */
230 if (!_pannable->pan_azimuth_control->list()->curve().rt_safe_get_vector (start, end, position, nframes)) {
232 distribute_one (srcbuf, obufs, 1.0, nframes, which);
236 for (pframes_t n = 0; n < nframes; ++n) {
238 float const pos = position[n];
240 if (which == 0) { // Left
242 buffers[which][n] = 2 - 2. * pos;
244 buffers[which][n] = 1.0;
248 buffers[which][n] = 2. * pos;
250 buffers[which][n] = 1.0;
255 dst = obufs.get_audio(which).data();
256 pbuf = buffers[which];
258 for (pframes_t n = 0; n < nframes; ++n) {
259 dst[n] += src[n] * pbuf[n];
262 /* XXX it would be nice to mark the buffer as written to */
266 Pannerbalance::factory (boost::shared_ptr<Pannable> p, boost::shared_ptr<Speakers> /* ignored */)
268 return new Pannerbalance (p);
272 Pannerbalance::get_state ()
274 XMLNode& root (Panner::get_state ());
275 root.add_property (X_("uri"), _descriptor.panner_uri);
276 /* this is needed to allow new sessions to load with old Ardour: */
277 root.add_property (X_("type"), _descriptor.name);
281 std::set<Evoral::Parameter>
282 Pannerbalance::what_can_be_automated() const
284 set<Evoral::Parameter> s;
285 s.insert (Evoral::Parameter (PanAzimuthAutomation));
290 Pannerbalance::describe_parameter (Evoral::Parameter p)
293 case PanAzimuthAutomation:
296 return _pannable->describe_parameter (p);
301 Pannerbalance::value_as_string (boost::shared_ptr<AutomationControl> ac) const
303 /* DO NOT USE LocaleGuard HERE */
304 double val = ac->get_value();
306 switch (ac->parameter().type()) {
307 case PanAzimuthAutomation:
308 /* We show the position of the center of the image relative to the left & right.
309 This is expressed as a pair of percentage values that ranges from (100,0)
310 (hard left) through (50,50) (hard center) to (0,100) (hard right).
312 This is pretty wierd, but its the way audio engineers expect it. Just remember that
313 the center of the USA isn't Kansas, its (50LA, 50NY) and it will all make sense.
315 This is designed to be as narrow as possible. Dedicated
316 panner GUIs can do their own version of this if they need
317 something less compact.
320 return string_compose (_("L%1R%2"), (int) rint (100.0 * (1.0 - val)),
321 (int) rint (100.0 * val));
329 Pannerbalance::reset ()