2 Copyright (C) 2004-2011 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 #include "pbd/cartesian.h"
36 #include "pbd/convert.h"
37 #include "pbd/error.h"
38 #include "pbd/failed_constructor.h"
39 #include "pbd/xml++.h"
40 #include "pbd/enumwriter.h"
42 #include "evoral/Curve.hpp"
44 #include "ardour/session.h"
45 #include "ardour/panner.h"
46 #include "ardour/panner_1in2out.h"
47 #include "ardour/utils.h"
48 #include "ardour/audio_buffer.h"
50 #include "ardour/runtime_functions.h"
51 #include "ardour/buffer_set.h"
52 #include "ardour/audio_buffer.h"
53 #include "ardour/vbap.h"
57 #include "pbd/mathfix.h"
60 using namespace ARDOUR;
63 static PanPluginDescriptor _descriptor = {
64 "Mono to Stereo Panner",
66 Panner1in2out::factory
69 extern "C" { PanPluginDescriptor* panner_descriptor () { return &_descriptor; }
71 Panner1in2out::Panner1in2out (PannerShell& p)
73 , _position (new PanControllable (parent.session(), _("position"), this, Evoral::Parameter(PanAzimuthAutomation, 0, 0)))
77 , right_interp (right)
80 desired_right = right;
83 Panner1in2out::~Panner1in2out ()
88 Panner1in2out::set_position (double p)
91 _desired_left = 1 - p;
95 Panner1in2out::do_distribute_one (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_coeff, pframes_t nframes, uint32_t /* not used */)
97 assert (obufs.count().n_audio() == 2);
107 Sample* const src = srcbuf.data();
111 dst = obufs.get_audio(0).data();
113 if (fabsf ((delta = (left[which] - desired_left[which]))) > 0.002) { // about 1 degree of arc
115 /* we've moving the pan by an appreciable amount, so we must
116 interpolate over 64 frames or nframes, whichever is smaller */
118 pframes_t const limit = min ((pframes_t) 64, nframes);
121 delta = -(delta / (float) (limit));
123 for (n = 0; n < limit; n++) {
124 left_interp[which] = left_interp[which] + delta;
125 left = left_interp[which] + 0.9 * (left[which] - left_interp[which]);
126 dst[n] += src[n] * left[which] * gain_coeff;
129 /* then pan the rest of the buffer; no need for interpolation for this bit */
131 pan = left[which] * gain_coeff;
133 mix_buffers_with_gain (dst+n,src+n,nframes-n,pan);
137 left[which] = desired_left[which];
138 left_interp[which] = left[which];
140 if ((pan = (left[which] * gain_coeff)) != 1.0f) {
144 /* pan is 1 but also not 0, so we must do it "properly" */
146 mix_buffers_with_gain(dst,src,nframes,pan);
148 /* mark that we wrote into the buffer */
156 /* pan is 1 so we can just copy the input samples straight in */
158 mix_buffers_no_gain(dst,src,nframes);
160 /* XXX it would be nice to mark that we wrote into the buffer */
166 dst = obufs.get_audio(1).data();
168 if (fabsf ((delta = (right[which] - desired_right[which]))) > 0.002) { // about 1 degree of arc
170 /* we're moving the pan by an appreciable amount, so we must
171 interpolate over 64 frames or nframes, whichever is smaller */
173 pframes_t const limit = min ((pframes_t) 64, nframes);
176 delta = -(delta / (float) (limit));
178 for (n = 0; n < limit; n++) {
179 right_interp[which] = right_interp[which] + delta;
180 right[which] = right_interp[which] + 0.9 * (right[which] - right_interp[which]);
181 dst[n] += src[n] * right[which] * gain_coeff;
184 /* then pan the rest of the buffer, no need for interpolation for this bit */
186 pan = right[which] * gain_coeff;
188 mix_buffers_with_gain(dst+n,src+n,nframes-n,pan);
190 /* XXX it would be nice to mark the buffer as written to */
194 right[which] = desired_right[which];
195 right_interp[which] = right[which];
197 if ((pan = (right[which] * gain_coeff)) != 1.0f) {
201 /* pan is not 1 but also not 0, so we must do it "properly" */
203 mix_buffers_with_gain(dst,src,nframes,pan);
205 /* XXX it would be nice to mark the buffer as written to */
210 /* pan is 1 so we can just copy the input samples straight in */
212 mix_buffers_no_gain(dst,src,nframes);
214 /* XXX it would be nice to mark the buffer as written to */
221 Panner1in2out::describe_parameter (Evoral::Parameter param)
223 switch (param.type()) {
224 case PanWidthAutomation:
226 case PanAzimuthAutomation:
227 return "Pan:position";
228 case PanElevationAutomation:
229 error << X_("stereo panner should not have elevation control") << endmsg;
230 return "Pan:elevation";
233 return Automatable::describe_parameter (param);