some new source
[ardour.git] / libs / ardour / panner_shell.cc
1 /*
2     Copyright (C) 2004-2011 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #include <inttypes.h>
21
22 #include <cmath>
23 #include <cerrno>
24 #include <fstream>
25 #include <cstdlib>
26 #include <string>
27 #include <cstdio>
28 #include <locale.h>
29 #include <unistd.h>
30 #include <float.h>
31 #include <iomanip>
32
33 #include <glibmm.h>
34
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"
41
42 #include "evoral/Curve.hpp"
43
44 #include "ardour/audio_buffer.h"
45 #include "ardour/audio_buffer.h"
46 #include "ardour/automatable.h"
47 #include "ardour/buffer_set.h"
48 #include "ardour/pannable.h"
49 #include "ardour/panner.h"
50 #include "ardour/panner_manager.h"
51 #include "ardour/panner_shell.h"
52 #include "ardour/runtime_functions.h"
53 #include "ardour/session.h"
54 #include "ardour/utils.h"
55
56 #include "i18n.h"
57
58 #include "pbd/mathfix.h"
59
60 using namespace std;
61 using namespace ARDOUR;
62 using namespace PBD;
63
64 PannerShell::PannerShell (string name, Session& s, boost::shared_ptr<Pannable> p)
65         : SessionObject (s, name)
66         , _pannable (p)
67 {
68         set_name (name);
69 }
70
71 PannerShell::~PannerShell ()
72 {
73 }
74
75 void
76 PannerShell::configure_io (ChanCount in, ChanCount out)
77 {
78         uint32_t nouts = out.n_audio();
79         uint32_t nins = in.n_audio();
80
81         /* if new and old config don't need panning, or if
82            the config hasn't changed, we're done.
83         */
84
85         if (_panner && _panner->in().n_audio() == nins && _panner->out().n_audio() == nouts) {
86                 return;
87         }
88
89         if (nouts < 2 || nins == 0) {
90                 /* no need for panning with less than 2 outputs or no inputs */
91                 if (_panner) {
92                         _panner.reset ();
93                         Changed (); /* EMIT SIGNAL */
94                 }
95                 return;
96         }
97
98         PannerInfo* pi = PannerManager::instance().select_panner (in, out);
99
100         if (pi == 0) {
101                 abort ();
102         }
103
104         _panner.reset (pi->descriptor.factory (_pannable, _session.get_speakers()));
105
106         Changed (); /* EMIT SIGNAL */
107 }
108
109 XMLNode&
110 PannerShell::get_state (void)
111 {
112         return state (true);
113 }
114
115 XMLNode&
116 PannerShell::state (bool full)
117 {
118         XMLNode* node = new XMLNode ("PannerShell");
119
120         if (_panner) {
121                 node->add_child_nocopy (_panner->state (full));
122         }
123
124         return *node;
125 }
126
127 int
128 PannerShell::set_state (const XMLNode& node, int version)
129 {
130         XMLNodeList nlist = node.children ();
131         XMLNodeConstIterator niter;
132         const XMLProperty *prop;
133         LocaleGuard lg (X_("POSIX"));
134
135         _panner.reset ();
136
137         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
138
139                 if ((*niter)->name() == X_("Panner")) {
140
141                         if ((prop = (*niter)->property (X_("type")))) {
142
143                                 list<PannerInfo*>::iterator p;
144                                 PannerManager& pm (PannerManager::instance());
145
146                                 for (p = pm.panner_info.begin(); p != pm.panner_info.end(); ++p) {
147                                         if (prop->value() == (*p)->descriptor.name) {
148
149                                                 /* note that we assume that all the stream panners
150                                                    are of the same type. pretty good
151                                                    assumption, but it's still an assumption.
152                                                 */
153                                                         
154                                                 _panner.reset ((*p)->descriptor.factory (_pannable, _session.get_speakers ()));
155                                                 
156                                                 if (_panner->set_state (**niter, version) == 0) {
157                                                         return -1;
158                                                 }
159
160                                                 break;
161                                         }
162                                 }
163
164                                 if (p == pm.panner_info.end()) {
165                                         error << string_compose (_("Unknown panner plugin \"%1\" found in pan state - ignored"),
166                                                           prop->value())
167                                               << endmsg;
168                                 }
169
170                         } else {
171                                 error << _("panner plugin node has no type information!")
172                                       << endmsg;
173                                 return -1;
174                         }
175                 }
176         }
177
178         return 0;
179 }
180
181
182 void
183 PannerShell::distribute_no_automation (BufferSet& inbufs, BufferSet& outbufs, pframes_t nframes, gain_t gain_coeff)
184 {
185         if (outbufs.count().n_audio() == 0) {
186                 // Don't want to lose audio...
187                 assert(inbufs.count().n_audio() == 0);
188                 return;
189         }
190
191         if (outbufs.count().n_audio() == 1) {
192
193                 /* just one output: no real panning going on */
194
195                 AudioBuffer& dst = outbufs.get_audio(0);
196
197                 if (gain_coeff == 0.0f) {
198
199                         /* gain was zero, so make it silent */
200
201                         dst.silence (nframes);
202
203                 } else if (gain_coeff == 1.0f){
204
205                         /* mix all input buffers into the output */
206
207                         // copy the first
208                         dst.read_from(inbufs.get_audio(0), nframes);
209
210                         // accumulate starting with the second
211                         if (inbufs.count().n_audio() > 0) {
212                                 BufferSet::audio_iterator i = inbufs.audio_begin();
213                                 for (++i; i != inbufs.audio_end(); ++i) {
214                                         dst.merge_from(*i, nframes);
215                                 }
216                         }
217
218                 } else {
219
220                         /* mix all buffers into the output, scaling them all by the gain */
221
222                         // copy the first
223                         dst.read_from(inbufs.get_audio(0), nframes);
224
225                         // accumulate (with gain) starting with the second
226                         if (inbufs.count().n_audio() > 0) {
227                                 BufferSet::audio_iterator i = inbufs.audio_begin();
228                                 for (++i; i != inbufs.audio_end(); ++i) {
229                                         dst.accumulate_with_gain_from(*i, nframes, gain_coeff);
230                                 }
231                         }
232
233                 }
234
235                 return;
236         }
237
238         /* multiple outputs ... we must have a panner */
239
240         assert (_panner);
241
242         /* setup silent buffers so that we can mix into the outbuffers (slightly suboptimal -
243            better to copy the first set of data then mix after that, but hey, its 2011)
244          */
245
246         for (BufferSet::audio_iterator b = outbufs.audio_begin(); b != outbufs.audio_end(); ++b) {
247                 (*b).silence (nframes);
248         }
249
250         _panner->distribute (inbufs, outbufs, gain_coeff, nframes);
251 }
252
253 void
254 PannerShell::run (BufferSet& inbufs, BufferSet& outbufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes)
255 {
256         if (outbufs.count().n_audio() == 0) {
257                 // Failing to deliver audio we were asked to deliver is a bug
258                 assert(inbufs.count().n_audio() == 0);
259                 return;
260         }
261
262         if (outbufs.count().n_audio() == 1) {
263
264                 /* one output only: no panner */
265
266                 AudioBuffer& dst = outbufs.get_audio(0);
267
268                 // FIXME: apply gain automation?
269
270                 // copy the first
271                 dst.read_from (inbufs.get_audio(0), nframes);
272
273                 // accumulate starting with the second
274                 BufferSet::audio_iterator i = inbufs.audio_begin();
275                 for (++i; i != inbufs.audio_end(); ++i) {
276                         dst.merge_from (*i, nframes);
277                 }
278
279                 return;
280         }
281
282         // More than 1 output
283
284         AutoState as = _panner->automation_state ();
285
286         // If we shouldn't play automation defer to distribute_no_automation
287
288         if (!(as & Play || ((as & Touch) && !_panner->touching()))) {
289
290                 // Speed quietning
291                 gain_t gain_coeff = 1.0;
292                 
293                 if (fabsf(_session.transport_speed()) > 1.5f && Config->get_quieten_at_speed ()) {
294                         gain_coeff = speed_quietning;
295                 }
296
297                 distribute_no_automation (inbufs, outbufs, nframes, gain_coeff);
298
299         } else {
300
301                 /* setup the terrible silence so that we can mix into the outbuffers (slightly suboptimal -
302                    better to copy the first set of data then mix after that, but hey, its 2011)
303                 */
304                 for (BufferSet::audio_iterator i = outbufs.audio_begin(); i != outbufs.audio_end(); ++i) {
305                         i->silence(nframes);
306                 }
307                 
308                 _panner->distribute_automated (inbufs, outbufs, start_frame, end_frame, nframes, _session.pan_automation_buffer());
309         }
310 }
311