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.
34 #include "pbd/cartesian.h"
35 #include "pbd/convert.h"
36 #include "pbd/error.h"
37 #include "pbd/failed_constructor.h"
38 #include "pbd/xml++.h"
39 #include "pbd/enumwriter.h"
41 #include "evoral/Curve.hpp"
43 #include "ardour/audio_buffer.h"
44 #include "ardour/audio_buffer.h"
45 #include "ardour/buffer_set.h"
46 #include "ardour/pan_controllable.h"
47 #include "ardour/pannable.h"
48 #include "ardour/runtime_functions.h"
49 #include "ardour/session.h"
50 #include "ardour/utils.h"
51 #include "ardour/mix.h"
53 #include "panner_balance.h"
57 #include "pbd/mathfix.h"
60 using namespace ARDOUR;
63 static PanPluginDescriptor _descriptor = {
65 "http://ardour.org/plugin/panner_balance",
66 "http://ardour.org/plugin/panner_balance#ui",
69 Pannerbalance::factory
72 extern "C" ARDOURPANNER_API PanPluginDescriptor* panner_descriptor () { return &_descriptor; }
74 Pannerbalance::Pannerbalance (boost::shared_ptr<Pannable> p)
77 if (!_pannable->has_state()) {
78 _pannable->pan_azimuth_control->set_value (0.5, Controllable::NoGroup);
84 pos_interp[0] = pos[0] = desired_pos[0];
86 pos_interp[1] = pos[1] = desired_pos[1];
88 _pannable->pan_azimuth_control->Changed.connect_same_thread (*this, boost::bind (&Pannerbalance::update, this));
91 Pannerbalance::~Pannerbalance ()
96 Pannerbalance::position () const
98 return _pannable->pan_azimuth_control->get_value();
102 Pannerbalance::set_position (double p)
104 if (clamp_position (p)) {
105 _pannable->pan_azimuth_control->set_value (p, Controllable::NoGroup);
110 Pannerbalance::thaw ()
119 Pannerbalance::update ()
125 float const pos = _pannable->pan_azimuth_control->get_value();
128 desired_pos[0] = 1.0;
129 desired_pos[1] = 1.0;
130 } else if (pos > .5) {
131 desired_pos[0] = 2 - 2. * pos;
132 desired_pos[1] = 1.0;
134 desired_pos[0] = 1.0;
135 desired_pos[1] = 2. * pos;
140 Pannerbalance::clamp_position (double& p)
142 p = max (min (p, 1.0), 0.0);
147 Pannerbalance::position_range () const
149 return make_pair (0, 1);
153 Pannerbalance::distribute_one (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_coeff, pframes_t nframes, uint32_t which)
155 assert (obufs.count().n_audio() == 2);
161 Sample* const src = srcbuf.data();
163 dst = obufs.get_audio(which).data();
165 if (fabsf ((delta = (pos[which] - desired_pos[which]))) > 0.002) { // about 1 degree of arc
167 /* we've moving the pan by an appreciable amount, so we must
168 interpolate over 64 frames or nframes, whichever is smaller */
170 pframes_t const limit = min ((pframes_t) 64, nframes);
173 delta = -(delta / (float) (limit));
175 for (n = 0; n < limit; n++) {
176 pos_interp[which] = pos_interp[which] + delta;
177 pos[which] = pos_interp[which] + 0.9 * (pos[which] - pos_interp[which]);
178 dst[n] += src[n] * pos[which] * gain_coeff;
181 /* then pan the rest of the buffer; no need for interpolation for this bit */
183 pan = pos[which] * gain_coeff;
185 mix_buffers_with_gain (dst+n,src+n,nframes-n,pan);
189 pos[which] = desired_pos[which];
190 pos_interp[which] = pos[which];
192 if ((pan = (pos[which] * gain_coeff)) != 1.0f) {
196 /* pan is 1 but also not 0, so we must do it "properly" */
198 //obufs.get_audio(1).read_from (srcbuf, nframes);
199 mix_buffers_with_gain(dst,src,nframes,pan);
201 /* mark that we wrote into the buffer */
208 /* pan is 1 so we can just copy the input samples straight in */
209 mix_buffers_no_gain(dst,src,nframes);
215 Pannerbalance::distribute_one_automated (AudioBuffer& srcbuf, BufferSet& obufs,
216 framepos_t start, framepos_t end, pframes_t nframes,
217 pan_t** buffers, uint32_t which)
219 assert (obufs.count().n_audio() == 2);
223 Sample* const src = srcbuf.data();
224 pan_t* const position = buffers[0];
226 /* fetch positional data */
228 if (!_pannable->pan_azimuth_control->list()->curve().rt_safe_get_vector (start, end, position, nframes)) {
230 distribute_one (srcbuf, obufs, 1.0, nframes, which);
234 for (pframes_t n = 0; n < nframes; ++n) {
236 float const pos = position[n];
238 if (which == 0) { // Left
240 buffers[which][n] = 2 - 2. * pos;
242 buffers[which][n] = 1.0;
246 buffers[which][n] = 2. * pos;
248 buffers[which][n] = 1.0;
253 dst = obufs.get_audio(which).data();
254 pbuf = buffers[which];
256 for (pframes_t n = 0; n < nframes; ++n) {
257 dst[n] += src[n] * pbuf[n];
260 /* XXX it would be nice to mark the buffer as written to */
264 Pannerbalance::factory (boost::shared_ptr<Pannable> p, boost::shared_ptr<Speakers> /* ignored */)
266 return new Pannerbalance (p);
270 Pannerbalance::get_state ()
272 XMLNode& root (Panner::get_state ());
273 root.add_property (X_("uri"), _descriptor.panner_uri);
274 /* this is needed to allow new sessions to load with old Ardour: */
275 root.add_property (X_("type"), _descriptor.name);
279 std::set<Evoral::Parameter>
280 Pannerbalance::what_can_be_automated() const
282 set<Evoral::Parameter> s;
283 s.insert (Evoral::Parameter (PanAzimuthAutomation));
288 Pannerbalance::describe_parameter (Evoral::Parameter p)
291 case PanAzimuthAutomation:
294 return _pannable->describe_parameter (p);
299 Pannerbalance::value_as_string (boost::shared_ptr<const AutomationControl> ac) const
301 /* DO NOT USE LocaleGuard HERE */
302 double val = ac->get_value();
304 switch (ac->parameter().type()) {
305 case PanAzimuthAutomation:
306 /* We show the position of the center of the image relative to the left & right.
307 This is expressed as a pair of percentage values that ranges from (100,0)
308 (hard left) through (50,50) (hard center) to (0,100) (hard right).
310 This is pretty wierd, but its the way audio engineers expect it. Just remember that
311 the center of the USA isn't Kansas, its (50LA, 50NY) and it will all make sense.
313 This is designed to be as narrow as possible. Dedicated
314 panner GUIs can do their own version of this if they need
315 something less compact.
318 return string_compose (_("L%1R%2"), (int) rint (100.0 * (1.0 - val)),
319 (int) rint (100.0 * val));
327 Pannerbalance::reset ()