e438742266100a9c6f5591f518c5b3cb26cc4ab2
[ardour.git] / libs / ardour / panner.cc
1 /*
2     Copyright (C) 2004 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/error.h"
37 #include "pbd/failed_constructor.h"
38 #include "pbd/xml++.h"
39 #include "pbd/enumwriter.h"
40
41 #include "evoral/Curve.hpp"
42
43 #include "ardour/session.h"
44 #include "ardour/panner.h"
45 #include "ardour/utils.h"
46 #include "ardour/audio_buffer.h"
47
48 #include "ardour/runtime_functions.h"
49 #include "ardour/buffer_set.h"
50 #include "ardour/audio_buffer.h"
51 #include "ardour/vbap.h"
52
53 #include "i18n.h"
54
55 #include "pbd/mathfix.h"
56
57 using namespace std;
58 using namespace ARDOUR;
59 using namespace PBD;
60
61 float Panner::current_automation_version_number = 1.0;
62
63 string EqualPowerStereoPanner::name = "Equal Power Stereo";
64
65 /* this is a default mapper of control values to a pan position
66    others can be imagined.
67 */
68
69 static double direct_control_to_stereo_pan (double fract)
70 {
71         return BaseStereoPanner::lr_fract_to_azimuth (fract);
72 }
73
74 StreamPanner::StreamPanner (Panner& p, Evoral::Parameter param)
75         : parent (p)
76 {
77         assert (param.type() != NullAutomation);
78
79         _muted = false;
80         _mono = false;
81
82         /* get our AutomationControl from our parent Panner, creating it if required */
83         _control = boost::dynamic_pointer_cast<AutomationControl> (parent.control (param, true));
84 }
85
86 StreamPanner::~StreamPanner ()
87 {
88 }
89
90 void
91 StreamPanner::set_mono (bool yn)
92 {
93         if (yn != _mono) {
94                 _mono = yn;
95                 StateChanged ();
96         }
97 }
98
99 void
100 Panner::PanControllable::set_value (double val)
101 {
102         panner.streampanner (parameter().id()).set_position (AngularVector (direct_control_to_stereo_pan (val), 0.0));
103         AutomationControl::set_value(val);
104 }
105
106 double
107 Panner::PanControllable::get_value (void) const
108 {
109         return AutomationControl::get_value();
110 }
111
112 void
113 StreamPanner::set_muted (bool yn)
114 {
115         if (yn != _muted) {
116                 _muted = yn;
117                 StateChanged ();
118         }
119 }
120
121 void
122 StreamPanner::set_position (const AngularVector& av, bool link_call)
123 {
124         if (!link_call && parent.linked()) {
125                 parent.set_position (av, *this);
126         }
127
128         if (_angles != av) {
129                 _angles = av;
130                 update ();
131                 Changed ();
132                 _control->Changed ();
133         }
134 }
135
136 int
137 StreamPanner::set_state (const XMLNode& node, int /*version*/)
138 {
139         const XMLProperty* prop;
140         XMLNodeConstIterator iter;
141
142         if ((prop = node.property (X_("muted")))) {
143                 set_muted (string_is_affirmative (prop->value()));
144         }
145
146         if ((prop = node.property (X_("mono")))) {
147                 set_mono (string_is_affirmative (prop->value()));
148         }
149
150         return 0;
151 }
152
153 void
154 StreamPanner::add_state (XMLNode& node)
155 {
156         node.add_property (X_("muted"), (muted() ? "yes" : "no"));
157         node.add_property (X_("mono"), (_mono ? "yes" : "no"));
158 }
159
160 void
161 StreamPanner::distribute (AudioBuffer& src, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes)
162 {
163         if (_mono) {
164                 /* we're in mono mode, so just pan the input to all outputs equally */
165                 int const N = parent.nouts ();
166                 for (int i = 0; i < N; ++i) {
167                         mix_buffers_with_gain (obufs.get_audio(i).data(), src.data(), nframes, gain_coeff);
168                 }
169         } else {
170                 /* normal mode, call the `real' distribute method */
171                 do_distribute (src, obufs, gain_coeff, nframes);
172         }
173 }
174
175 void
176 StreamPanner::distribute_automated (AudioBuffer& src, BufferSet& obufs,
177                                     nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers)
178 {
179         if (_mono) {
180                 /* we're in mono mode, so just pan the input to all outputs equally */
181                 int const N = parent.nouts ();
182                 for (int i = 0; i < N; ++i) {
183                         mix_buffers_with_gain (obufs.get_audio(i).data(), src.data(), nframes, 1.0);
184                 }
185         } else {
186                 /* normal mode, call the `real' distribute method */
187                 do_distribute_automated (src, obufs, start, end, nframes, buffers);
188         }
189         
190 }
191
192
193 /*---------------------------------------------------------------------- */
194
195 BaseStereoPanner::BaseStereoPanner (Panner& p, Evoral::Parameter param)
196         : StreamPanner (p, param)
197         , left (0.5)
198         , right (0.5)
199         , left_interp (left)
200         , right_interp (right)
201 {
202 }
203
204 BaseStereoPanner::~BaseStereoPanner ()
205 {
206 }
207
208 int
209 BaseStereoPanner::load (istream& in, string path, uint32_t& linecnt)
210 {
211         char line[128];
212         LocaleGuard lg (X_("POSIX"));
213
214         _control->list()->clear ();
215
216         while (in.getline (line, sizeof (line), '\n')) {
217                 nframes_t when;
218                 double value;
219
220                 ++linecnt;
221
222                 if (strcmp (line, "end") == 0) {
223                         break;
224                 }
225
226                 if (sscanf (line, "%" PRIu32 " %lf", &when, &value) != 2) {
227                         warning << string_compose(_("badly formatted pan automation event record at line %1 of %2 (ignored) [%3]"), linecnt, path, line) << endmsg;
228                         continue;
229                 }
230
231                 _control->list()->fast_simple_add (when, value);
232         }
233
234         /* now that we are done loading */
235
236         ((AutomationList*)_control->list().get())->StateChanged ();
237
238         return 0;
239 }
240
241 void
242 BaseStereoPanner::do_distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes)
243 {
244         assert(obufs.count().n_audio() == 2);
245
246         pan_t delta;
247         Sample* dst;
248         pan_t pan;
249
250         if (_muted) {
251                 return;
252         }
253
254         Sample* const src = srcbuf.data();
255
256         /* LEFT */
257
258         dst = obufs.get_audio(0).data();
259
260         if (fabsf ((delta = (left - desired_left))) > 0.002) { // about 1 degree of arc
261
262                 /* we've moving the pan by an appreciable amount, so we must
263                    interpolate over 64 frames or nframes, whichever is smaller */
264
265                 nframes_t const limit = min ((nframes_t)64, nframes);
266                 nframes_t n;
267
268                 delta = -(delta / (float) (limit));
269
270                 for (n = 0; n < limit; n++) {
271                         left_interp = left_interp + delta;
272                         left = left_interp + 0.9 * (left - left_interp);
273                         dst[n] += src[n] * left * gain_coeff;
274                 }
275
276                 /* then pan the rest of the buffer; no need for interpolation for this bit */
277
278                 pan = left * gain_coeff;
279
280                 mix_buffers_with_gain (dst+n,src+n,nframes-n,pan);
281
282         } else {
283
284                 left = desired_left;
285                 left_interp = left;
286
287                 if ((pan = (left * gain_coeff)) != 1.0f) {
288
289                         if (pan != 0.0f) {
290
291                                 /* pan is 1 but also not 0, so we must do it "properly" */
292
293                                 mix_buffers_with_gain(dst,src,nframes,pan);
294
295                                 /* mark that we wrote into the buffer */
296
297                                 // obufs[0] = 0;
298
299                         }
300
301                 } else {
302
303                         /* pan is 1 so we can just copy the input samples straight in */
304
305                         mix_buffers_no_gain(dst,src,nframes);
306
307                         /* mark that we wrote into the buffer */
308
309                         // obufs[0] = 0;
310                 }
311         }
312
313         /* RIGHT */
314
315         dst = obufs.get_audio(1).data();
316
317         if (fabsf ((delta = (right - desired_right))) > 0.002) { // about 1 degree of arc
318
319                 /* we're moving the pan by an appreciable amount, so we must
320                    interpolate over 64 frames or nframes, whichever is smaller */
321
322                 nframes_t const limit = min ((nframes_t)64, nframes);
323                 nframes_t n;
324
325                 delta = -(delta / (float) (limit));
326
327                 for (n = 0; n < limit; n++) {
328                         right_interp = right_interp + delta;
329                         right = right_interp + 0.9 * (right - right_interp);
330                         dst[n] += src[n] * right * gain_coeff;
331                 }
332
333                 /* then pan the rest of the buffer, no need for interpolation for this bit */
334
335                 pan = right * gain_coeff;
336
337                 mix_buffers_with_gain(dst+n,src+n,nframes-n,pan);
338
339                 /* XXX it would be nice to mark the buffer as written to */
340
341         } else {
342
343                 right = desired_right;
344                 right_interp = right;
345
346                 if ((pan = (right * gain_coeff)) != 1.0f) {
347
348                         if (pan != 0.0f) {
349
350                                 /* pan is not 1 but also not 0, so we must do it "properly" */
351                                 
352                                 mix_buffers_with_gain(dst,src,nframes,pan);
353
354                                 /* XXX it would be nice to mark the buffer as written to */
355                         }
356
357                 } else {
358
359                         /* pan is 1 so we can just copy the input samples straight in */
360                         
361                         mix_buffers_no_gain(dst,src,nframes);
362
363                         /* XXX it would be nice to mark the buffer as written to */
364                 }
365         }
366 }
367
368 /*---------------------------------------------------------------------- */
369
370 EqualPowerStereoPanner::EqualPowerStereoPanner (Panner& p, Evoral::Parameter param)
371         : BaseStereoPanner (p, param)
372 {
373         update ();
374
375         left = desired_left;
376         right = desired_right;
377         left_interp = left;
378         right_interp = right;
379 }
380
381 EqualPowerStereoPanner::~EqualPowerStereoPanner ()
382 {
383 }
384
385 void
386 EqualPowerStereoPanner::update ()
387 {
388         /* it would be very nice to split this out into a virtual function
389            that can be accessed from BaseStereoPanner and used in do_distribute_automated().
390
391            but the place where its used in do_distribute_automated() is a tight inner loop,
392            and making "nframes" virtual function calls to compute values is an absurd
393            overhead.
394         */
395
396         /* x == 0 => hard left = 180.0 degrees
397            x == 1 => hard right = 0.0 degrees
398         */
399
400         double _x = BaseStereoPanner::azimuth_to_lr_fract (_angles.azi);
401
402         float const panR = _x;
403         float const panL = 1 - panR;
404
405         float const pan_law_attenuation = -3.0f;
406         float const scale = 2.0f - 4.0f * powf (10.0f,pan_law_attenuation/20.0f);
407
408         desired_left = panL * (scale * panL + 1.0f - scale);
409         desired_right = panR * (scale * panR + 1.0f - scale);
410
411         _effective_angles = _angles;
412         //_control->set_value(x);
413 }
414
415 void
416 EqualPowerStereoPanner::do_distribute_automated (AudioBuffer& srcbuf, BufferSet& obufs,
417                                                  nframes_t start, nframes_t end, nframes_t nframes,
418                                                  pan_t** buffers)
419 {
420         assert (obufs.count().n_audio() == 2);
421
422         Sample* dst;
423         pan_t* pbuf;
424         Sample* const src = srcbuf.data();
425
426         /* fetch positional data */
427
428         if (!_control->list()->curve().rt_safe_get_vector (start, end, buffers[0], nframes)) {
429                 /* fallback */
430                 if (!_muted) {
431                         do_distribute (srcbuf, obufs, 1.0, nframes);
432                 }
433                 return;
434         }
435
436         /* store effective pan position. do this even if we are muted */
437
438         if (nframes > 0) {
439                 _effective_angles.azi = BaseStereoPanner::lr_fract_to_azimuth (buffers[0][nframes-1]);
440         }
441
442         if (_muted) {
443                 return;
444         }
445
446         /* apply pan law to convert positional data into pan coefficients for
447            each buffer (output)
448         */
449
450         const float pan_law_attenuation = -3.0f;
451         const float scale = 2.0f - 4.0f * powf (10.0f,pan_law_attenuation/20.0f);
452
453         for (nframes_t n = 0; n < nframes; ++n) {
454
455                 float const panR = buffers[0][n];
456                 float const panL = 1 - panR;
457
458                 buffers[0][n] = panL * (scale * panL + 1.0f - scale);
459                 buffers[1][n] = panR * (scale * panR + 1.0f - scale);
460         }
461
462         /* LEFT */
463
464         dst = obufs.get_audio(0).data();
465         pbuf = buffers[0];
466
467         for (nframes_t n = 0; n < nframes; ++n) {
468                 dst[n] += src[n] * pbuf[n];
469         }
470
471         /* XXX it would be nice to mark the buffer as written to */
472
473         /* RIGHT */
474
475         dst = obufs.get_audio(1).data();
476         pbuf = buffers[1];
477
478         for (nframes_t n = 0; n < nframes; ++n) {
479                 dst[n] += src[n] * pbuf[n];
480         }
481
482         /* XXX it would be nice to mark the buffer as written to */
483 }
484
485 StreamPanner*
486 EqualPowerStereoPanner::factory (Panner& parent, Evoral::Parameter param, Speakers& /* ignored */)
487 {
488         return new EqualPowerStereoPanner (parent, param);
489 }
490
491 XMLNode&
492 EqualPowerStereoPanner::get_state (void)
493 {
494         return state (true);
495 }
496
497 XMLNode&
498 EqualPowerStereoPanner::state (bool /*full_state*/)
499 {
500         XMLNode* root = new XMLNode ("StreamPanner");
501         char buf[64];
502         LocaleGuard lg (X_("POSIX"));
503
504         snprintf (buf, sizeof (buf), "%.12g", _angles.azi);
505         root->add_property (X_("azimuth"), buf);
506         root->add_property (X_("type"), EqualPowerStereoPanner::name);
507
508         // XXX: dont save automation here... its part of the automatable panner now.
509
510         StreamPanner::add_state (*root);
511
512         root->add_child_nocopy (_control->get_state ());
513
514         return *root;
515 }
516
517 int
518 EqualPowerStereoPanner::set_state (const XMLNode& node, int version)
519 {
520         const XMLProperty* prop;
521         LocaleGuard lg (X_("POSIX"));
522
523         if ((prop = node.property (X_("azimuth")))) {
524                 AngularVector a (atof (prop->value().c_str()), 0.0);
525                 set_position (a, true);
526         } else if ((prop = node.property (X_("x")))) {
527                 /* old school cartesian positioning */
528                 AngularVector a;
529                 a.azi = BaseStereoPanner::lr_fract_to_azimuth (atof (prop->value().c_str()));
530                 set_position (a, true);
531         }
532
533         StreamPanner::set_state (node, version);
534
535         for (XMLNodeConstIterator iter = node.children().begin(); iter != node.children().end(); ++iter) {
536
537                 if ((*iter)->name() == X_("Controllable")) {
538                         if ((prop = (*iter)->property("name")) != 0 && prop->value() == "panner") {
539                                 _control->set_state (**iter, version);
540                         }
541
542                 } else if ((*iter)->name() == X_("Automation")) {
543
544                         _control->alist()->set_state (*((*iter)->children().front()), version);
545
546                         if (_control->alist()->automation_state() != Off) {
547                                 double degrees = BaseStereoPanner::lr_fract_to_azimuth (_control->list()->eval (parent.session().transport_frame()));
548                                 set_position (AngularVector (degrees, 0.0));
549                         }
550                 }
551         }
552
553         return 0;
554 }
555
556 Panner::Panner (string name, Session& s)
557         : SessionObject (s, name)
558         , Automatable (s)
559 {
560         //set_name_old_auto (name);
561         set_name (name);
562
563         _linked = false;
564         _link_direction = SameDirection;
565         _bypassed = false;
566         _mono = false;
567 }
568
569 Panner::~Panner ()
570 {
571 }
572
573 void
574 Panner::set_linked (bool yn)
575 {
576         if (yn != _linked) {
577                 _linked = yn;
578                 _session.set_dirty ();
579                 LinkStateChanged (); /* EMIT SIGNAL */
580         }
581 }
582
583 void
584 Panner::set_link_direction (LinkDirection ld)
585 {
586         if (ld != _link_direction) {
587                 _link_direction = ld;
588                 _session.set_dirty ();
589                 LinkStateChanged (); /* EMIT SIGNAL */
590         }
591 }
592
593
594 void
595 Panner::set_bypassed (bool yn)
596 {
597         if (yn != _bypassed) {
598                 _bypassed = yn;
599                 StateChanged ();
600         }
601 }
602
603
604 void
605 Panner::reset_to_default ()
606 {
607         vector<float> positions;
608
609         switch (outputs.size()) {
610         case 0:
611         case 1:
612                 return;
613         }
614
615         if (outputs.size() == 2) {
616                 AngularVector a;
617                 switch (_streampanners.size()) {
618                 case 1:
619                         a.azi = 90.0; /* "front" or "top", in degrees */
620                         _streampanners.front()->set_position (a);
621                         _streampanners.front()->pan_control()->list()->reset_default (0.5);
622                         return;
623                         break;
624                 case 2:
625                         a.azi = 180.0; /* "left", in degrees */
626                         _streampanners.front()->set_position (a);
627                         _streampanners.front()->pan_control()->list()->reset_default (0.0);
628                         a.azi = 0.0; /* "right", in degrees */
629                         _streampanners.back()->set_position (a);
630                         _streampanners.back()->pan_control()->list()->reset_default (1.0);
631                         return;
632                 default:
633                         break;
634                 }
635         }
636
637         vector<Output>::iterator o;
638         vector<StreamPanner*>::iterator p;
639
640         for (o = outputs.begin(), p = _streampanners.begin(); o != outputs.end() && p != _streampanners.end(); ++o, ++p) {
641                 (*p)->set_position ((*o).position);
642         }
643 }
644
645 void
646 Panner::reset_streampanner (uint32_t which)
647 {
648         AngularVector a;
649
650         if (which >= _streampanners.size() || which >= outputs.size()) {
651                 return;
652         }
653
654         switch (outputs.size()) {
655         case 0:
656         case 1:
657                 return;
658
659         case 2:
660                 switch (_streampanners.size()) {
661                 case 1:
662                         /* stereo out, 1 stream, default = middle */
663                         a.azi = 90.0; /* "front" or "top", in degrees */
664                         _streampanners.front()->set_position (a);
665                         _streampanners.front()->pan_control()->list()->reset_default (0.5);
666                         break;
667                 case 2:
668                         /* stereo out, 2 streams, default = hard left/right */
669                         if (which == 0) {
670                                 a.azi = 180.0; /* "left", in degrees */
671                                 _streampanners.front()->set_position (a);
672                                 _streampanners.front()->pan_control()->list()->reset_default (0.0);
673                         } else {
674                                 a.azi = 0.0; /* "right", in degrees */
675                                 _streampanners.back()->set_position (a);
676                                 _streampanners.back()->pan_control()->list()->reset_default (1.0);
677                         }
678                         break;
679                 }
680                 return;
681
682         default:
683                 _streampanners[which]->set_position (outputs[which].position);
684         }
685 }
686
687 /**
688  *    Reset the panner with a given number of outs and panners (and hence inputs)
689  *
690  *    \param nouts Number of outputs.
691  *    \param npans Number of panners.
692  */
693 void
694 Panner::reset (uint32_t nouts, uint32_t npans)
695 {
696         uint32_t n;
697         bool changed = false;
698         bool do_not_and_did_not_need_panning = ((nouts < 2) && (outputs.size() < 2));
699
700         /* if new and old config don't need panning, or if
701            the config hasn't changed, we're done.
702         */
703
704         if (do_not_and_did_not_need_panning ||
705             ((nouts == outputs.size()) && (npans == _streampanners.size()))) {
706                 return;
707         }
708
709         n = _streampanners.size();
710         clear_panners ();
711
712         if (n != npans) {
713                 changed = true;
714         }
715
716         n = outputs.size();
717         outputs.clear ();
718
719         if (n != nouts) {
720                 changed = true;
721         }
722
723         if (nouts < 2) {
724                 /* no need for panning with less than 2 outputs */
725                 if (changed) {
726                         Changed (); /* EMIT SIGNAL */
727                 }
728                 return;
729         }
730
731         switch (nouts) {
732         case 0:
733                 /* XXX: this can never happen */
734                 break;
735
736         case 1:
737                 /* XXX: this can never happen */
738                 fatal << _("programming error:")
739                       << X_("Panner::reset() called with a single output")
740                       << endmsg;
741                 /*NOTREACHED*/
742                 break;
743
744         case 2: // line
745                 outputs.push_back (Output (AngularVector (180.0, 0.0)));
746                 outputs.push_back (Output (AngularVector (0.0, 0,0)));
747                 for (n = 0; n < npans; ++n) {
748                         _streampanners.push_back (new EqualPowerStereoPanner (*this, Evoral::Parameter(PanAutomation, 0, n)));
749                 }
750                 break;
751
752         default:
753                 setup_speakers (nouts);
754                 for (n = 0; n < npans; ++n) {
755                         _streampanners.push_back (new VBAPanner (*this, Evoral::Parameter(PanAutomation, 0, n), _session.get_speakers()));
756                 }
757                 break;
758         }
759
760         for (std::vector<StreamPanner*>::iterator x = _streampanners.begin(); x != _streampanners.end(); ++x) {
761                 (*x)->update ();
762         }
763
764         /* must emit Changed here, otherwise the changes to the pan_control below raise further
765            signals which the GUI is not prepared for until it has seen the Changed here.
766         */
767         
768         if (changed) {
769                 Changed (); /* EMIT SIGNAL */
770         }
771
772         /* force hard left/right panning in a common case: 2in/2out
773         */
774
775         if (npans == 2 && outputs.size() == 2) {
776
777                 /* Do this only if we changed configuration, or our configuration
778                    appears to be the default set up (zero degrees)
779                 */
780
781                 AngularVector left;
782                 AngularVector right;
783
784                 left = _streampanners.front()->get_position ();
785                 right = _streampanners.back()->get_position ();
786
787                 if (changed || ((left.azi == 0.0) && (right.azi == 0.0))) {
788
789                         _streampanners.front()->set_position (AngularVector (180.0, 0.0));
790                         _streampanners.front()->pan_control()->list()->reset_default (0.0);
791
792                         _streampanners.back()->set_position (AngularVector (0.0, 0.0));
793                         _streampanners.back()->pan_control()->list()->reset_default (1.0);
794                 }
795
796         } else if (npans > 1 && outputs.size() > 2) {
797
798                 /* 2d panning: spread signals equally around a circle */
799
800                 double degree_step = 360.0 / nouts;
801                 double deg;
802
803                 /* even number of signals? make sure the top two are either side of "top".
804                    otherwise, just start at the "top" (90.0 degrees) and rotate around
805                  */
806
807                 if (npans % 2) {
808                         deg = 90.0 - degree_step;
809                 } else {
810                         deg = 90.0;
811                 }
812
813                 for (std::vector<StreamPanner*>::iterator x = _streampanners.begin(); x != _streampanners.end(); ++x) {
814                         (*x)->set_position (AngularVector (deg, 0.0));
815                         deg += degree_step;
816                 }
817         }
818 }
819
820 void
821 Panner::remove (uint32_t which)
822 {
823         vector<StreamPanner*>::iterator i;
824         for (i = _streampanners.begin(); i != _streampanners.end() && which; ++i, --which) {}
825
826         if (i != _streampanners.end()) {
827                 delete *i;
828                 _streampanners.erase (i);
829         }
830 }
831
832
833 /** Remove all our StreamPanners */
834 void
835 Panner::clear_panners ()
836 {
837         for (vector<StreamPanner*>::iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) {
838                 delete *i;
839         }
840
841         _streampanners.clear ();
842 }
843
844 void
845 Panner::set_automation_style (AutoStyle style)
846 {
847         for (vector<StreamPanner*>::iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) {
848                 ((AutomationList*)(*i)->pan_control()->list().get())->set_automation_style (style);
849         }
850         _session.set_dirty ();
851 }
852
853 void
854 Panner::set_automation_state (AutoState state)
855 {
856         for (vector<StreamPanner*>::iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) {
857                 ((AutomationList*)(*i)->pan_control()->list().get())->set_automation_state (state);
858         }
859         _session.set_dirty ();
860 }
861
862 AutoState
863 Panner::automation_state () const
864 {
865         boost::shared_ptr<AutomationList> l;
866         if (!empty()) {
867                 boost::shared_ptr<AutomationControl> control = _streampanners.front()->pan_control();
868                 if (control) {
869                         l = boost::dynamic_pointer_cast<AutomationList>(control->list());
870                 }
871         }
872
873         return l ? l->automation_state() : Off;
874 }
875
876 AutoStyle
877 Panner::automation_style () const
878 {
879         boost::shared_ptr<AutomationList> l;
880         if (!empty()) {
881                 boost::shared_ptr<AutomationControl> control = _streampanners.front()->pan_control();
882                 if (control) {
883                         l = boost::dynamic_pointer_cast<AutomationList>(control->list());
884                 }
885         }
886
887         return l ? l->automation_style() : Absolute;
888 }
889
890 struct PanPlugins {
891     string name;
892     uint32_t nouts;
893     StreamPanner* (*factory)(Panner&, Evoral::Parameter, Speakers&);
894 };
895
896 PanPlugins pan_plugins[] = {
897         { EqualPowerStereoPanner::name, 2, EqualPowerStereoPanner::factory },
898         { VBAPanner::name, 3, VBAPanner::factory },
899         { string (""), 0, 0 }
900 };
901
902 XMLNode&
903 Panner::get_state (void)
904 {
905         return state (true);
906 }
907
908 XMLNode&
909 Panner::state (bool full)
910 {
911         XMLNode* node = new XMLNode ("Panner");
912
913         char buf[32];
914
915         node->add_property (X_("linked"), (_linked ? "yes" : "no"));
916         node->add_property (X_("link_direction"), enum_2_string (_link_direction));
917         node->add_property (X_("bypassed"), (bypassed() ? "yes" : "no"));
918
919         for (vector<Panner::Output>::iterator o = outputs.begin(); o != outputs.end(); ++o) {
920                 XMLNode* onode = new XMLNode (X_("Output"));
921                 snprintf (buf, sizeof (buf), "%.12g", (*o).position.azi);
922                 onode->add_property (X_("azimuth"), buf);
923                 snprintf (buf, sizeof (buf), "%.12g", (*o).position.ele);
924                 onode->add_property (X_("elevation"), buf);
925                 node->add_child_nocopy (*onode);
926         }
927
928         for (vector<StreamPanner*>::const_iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) {
929                 node->add_child_nocopy ((*i)->state (full));
930         }
931
932         node->add_child_nocopy (get_automation_xml_state ());
933
934         return *node;
935 }
936
937 int
938 Panner::set_state (const XMLNode& node, int version)
939 {
940         XMLNodeList nlist;
941         XMLNodeConstIterator niter;
942         const XMLProperty *prop;
943         uint32_t i;
944         uint32_t num_panners = 0;
945         StreamPanner* sp;
946         LocaleGuard lg (X_("POSIX"));
947
948         clear_panners ();
949
950         ChanCount ins = ChanCount::ZERO;
951         ChanCount outs = ChanCount::ZERO;
952
953         // XXX: this might not be necessary anymore
954         outputs.clear ();
955
956         if ((prop = node.property (X_("linked"))) != 0) {
957                 set_linked (string_is_affirmative (prop->value()));
958         }
959
960         if ((prop = node.property (X_("bypassed"))) != 0) {
961                 set_bypassed (string_is_affirmative (prop->value()));
962         }
963
964         if ((prop = node.property (X_("link_direction"))) != 0) {
965                 LinkDirection ld; /* here to provide type information */
966                 set_link_direction (LinkDirection (string_2_enum (prop->value(), ld)));
967         }
968
969         nlist = node.children();
970
971         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
972                 if ((*niter)->name() == X_("Output")) {
973
974                         AngularVector a;
975
976                         if ((prop = (*niter)->property (X_("azimuth")))) {
977                                 sscanf (prop->value().c_str(), "%lg", &a.azi);
978                         } else if ((prop = (*niter)->property (X_("x")))) {
979                                 /* old school cartesian */
980                                 a.azi = BaseStereoPanner::lr_fract_to_azimuth (atof (prop->value().c_str()));
981                         }
982
983                         if ((prop = (*niter)->property (X_("elevation")))) {
984                                 sscanf (prop->value().c_str(), "%lg", &a.ele);
985                         }
986
987                         outputs.push_back (Output (a));
988                 }
989         }
990
991         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
992
993                 if ((*niter)->name() == X_("StreamPanner")) {
994
995                         if ((prop = (*niter)->property (X_("type")))) {
996
997                                 for (i = 0; pan_plugins[i].factory; ++i) {
998                                         if (prop->value() == pan_plugins[i].name) {
999
1000
1001                                                 /* note that we assume that all the stream panners
1002                                                    are of the same type. pretty good
1003                                                    assumption, but it's still an assumption.
1004                                                 */
1005
1006                                                 sp = pan_plugins[i].factory (*this, Evoral::Parameter(PanAutomation, 0, num_panners), _session.get_speakers ());
1007                                                 num_panners++;
1008
1009                                                 if (sp->set_state (**niter, version) == 0) {
1010                                                         _streampanners.push_back (sp);
1011                                                 }
1012
1013                                                 break;
1014                                         }
1015                                 }
1016
1017
1018                                 if (!pan_plugins[i].factory) {
1019                                         error << string_compose (_("Unknown panner plugin \"%1\" found in pan state - ignored"),
1020                                                           prop->value())
1021                                               << endmsg;
1022                                 }
1023
1024                         } else {
1025                                 error << _("panner plugin node has no type information!")
1026                                       << endmsg;
1027                                 return -1;
1028                         }
1029
1030                 }
1031         }
1032
1033         reset (outputs.size (), num_panners);
1034         /* don't try to do old-school automation loading if it wasn't marked as existing */
1035
1036         if ((prop = node.property (X_("automation")))) {
1037
1038                 /* automation path is relative */
1039
1040                 automation_path = Glib::build_filename(_session.automation_dir(), prop->value ());
1041         }
1042
1043         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1044                 if ((*niter)->name() == X_("Automation")) {
1045                         set_automation_xml_state (**niter, Evoral::Parameter (PanAutomation));
1046                 }
1047         }
1048         
1049         return 0;
1050 }
1051
1052 bool
1053 Panner::touching () const
1054 {
1055         for (vector<StreamPanner*>::const_iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) {
1056                 if (((AutomationList*)(*i)->pan_control()->list().get())->touching ()) {
1057                         return true;
1058                 }
1059         }
1060
1061         return false;
1062 }
1063
1064 void
1065 Panner::set_position (const AngularVector& a, StreamPanner& orig)
1066 {
1067         AngularVector delta;
1068         AngularVector new_position;
1069
1070         delta = orig.get_position() - a;
1071
1072         if (_link_direction == SameDirection) {
1073
1074                 for (vector<StreamPanner*>::iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) {
1075                         if (*i == &orig) {
1076                                 (*i)->set_position (a, true);
1077                         } else {
1078                                 new_position = (*i)->get_position() + delta;
1079                                 (*i)->set_position (new_position, true);
1080                         }
1081                 }
1082
1083         } else {
1084
1085                 for (vector<StreamPanner*>::iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) {
1086                         if (*i == &orig) {
1087                                 (*i)->set_position (a, true);
1088                         } else {
1089                                 new_position = (*i)->get_position() - delta;
1090                                 (*i)->set_position (new_position, true);
1091                         }
1092                 }
1093         }
1094 }
1095
1096 void
1097 Panner::distribute_no_automation (BufferSet& inbufs, BufferSet& outbufs, nframes_t nframes, gain_t gain_coeff)
1098 {
1099         if (outbufs.count().n_audio() == 0) {
1100                 // Don't want to lose audio...
1101                 assert(inbufs.count().n_audio() == 0);
1102                 return;
1103         }
1104
1105         // We shouldn't be called in the first place...
1106         assert(!bypassed());
1107         assert(!empty());
1108
1109
1110         if (outbufs.count().n_audio() == 1) {
1111
1112                 AudioBuffer& dst = outbufs.get_audio(0);
1113
1114                 if (gain_coeff == 0.0f) {
1115
1116                         /* only one output, and gain was zero, so make it silent */
1117
1118                         dst.silence (nframes);
1119
1120                 } else if (gain_coeff == 1.0f){
1121
1122                         /* mix all buffers into the output */
1123
1124                         // copy the first
1125                         dst.read_from(inbufs.get_audio(0), nframes);
1126
1127                         // accumulate starting with the second
1128                         if (inbufs.count().n_audio() > 0) {
1129                                 BufferSet::audio_iterator i = inbufs.audio_begin();
1130                                 for (++i; i != inbufs.audio_end(); ++i) {
1131                                         dst.merge_from(*i, nframes);
1132                                 }
1133                         }
1134
1135                 } else {
1136
1137                         /* mix all buffers into the output, scaling them all by the gain */
1138
1139                         // copy the first
1140                         dst.read_from(inbufs.get_audio(0), nframes);
1141
1142                         // accumulate (with gain) starting with the second
1143                         if (inbufs.count().n_audio() > 0) {
1144                                 BufferSet::audio_iterator i = inbufs.audio_begin();
1145                                 for (++i; i != inbufs.audio_end(); ++i) {
1146                                         dst.accumulate_with_gain_from(*i, nframes, gain_coeff);
1147                                 }
1148                         }
1149
1150                 }
1151
1152                 return;
1153         }
1154
1155         /* the terrible silence ... */
1156         for (BufferSet::audio_iterator i = outbufs.audio_begin(); i != outbufs.audio_end(); ++i) {
1157                 i->silence(nframes);
1158         }
1159
1160         BufferSet::audio_iterator i = inbufs.audio_begin();
1161
1162         for (vector<StreamPanner*>::iterator pan = _streampanners.begin(); pan != _streampanners.end() && i != inbufs.audio_end(); ++pan, ++i) {
1163                 (*pan)->distribute (*i, outbufs, gain_coeff, nframes);
1164         }
1165 }
1166
1167 void
1168 Panner::run (BufferSet& inbufs, BufferSet& outbufs, framepos_t start_frame, framepos_t end_frame, nframes_t nframes)
1169 {
1170         if (outbufs.count().n_audio() == 0) {
1171                 // Failing to deliver audio we were asked to deliver is a bug
1172                 assert(inbufs.count().n_audio() == 0);
1173                 return;
1174         }
1175
1176         // We shouldn't be called in the first place...
1177         assert(!bypassed());
1178         assert(!empty());
1179
1180         // If we shouldn't play automation defer to distribute_no_automation
1181         if (!(automation_state() & Play || ((automation_state() & Touch) && !touching()))) {
1182
1183                 // Speed quietning
1184                 gain_t gain_coeff = 1.0;
1185
1186                 if (fabsf(_session.transport_speed()) > 1.5f && Config->get_quieten_at_speed ()) {
1187                         gain_coeff = speed_quietning;
1188                 }
1189
1190                 distribute_no_automation (inbufs, outbufs, nframes, gain_coeff);
1191                 return;
1192         }
1193
1194         // Otherwise.. let the automation flow, baby
1195
1196         if (outbufs.count().n_audio() == 1) {
1197
1198                 AudioBuffer& dst = outbufs.get_audio(0);
1199
1200                 // FIXME: apply gain automation?
1201
1202                 // copy the first
1203                 dst.read_from(inbufs.get_audio(0), nframes);
1204
1205                 // accumulate starting with the second
1206                 BufferSet::audio_iterator i = inbufs.audio_begin();
1207                 for (++i; i != inbufs.audio_end(); ++i) {
1208                         dst.merge_from(*i, nframes);
1209                 }
1210
1211                 return;
1212         }
1213
1214         // More than 1 output, we should have 1 panner for each input
1215         //assert(_streampanners.size() == inbufs.count().n_audio());
1216
1217         /* the terrible silence ... */
1218         for (BufferSet::audio_iterator i = outbufs.audio_begin(); i != outbufs.audio_end(); ++i) {
1219                 i->silence(nframes);
1220         }
1221
1222         BufferSet::audio_iterator i = inbufs.audio_begin();
1223         for (vector<StreamPanner*>::iterator pan = _streampanners.begin(); pan != _streampanners.end(); ++pan, ++i) {
1224                 (*pan)->distribute_automated (*i, outbufs, start_frame, end_frame, nframes, _session.pan_automation_buffer());
1225         }
1226 }
1227
1228 /* old school automation handling */
1229
1230 /*
1231 void
1232 Panner::set_name (string str)
1233 {
1234         automation_path = Glib::build_filename(_session.automation_dir(),
1235                 _session.snap_name() + "-pan-" + legalize_for_path (str) + ".automation");
1236 }
1237 */
1238
1239 int
1240 Panner::load ()
1241 {
1242         char line[128];
1243         uint32_t linecnt = 0;
1244         float version;
1245         vector<StreamPanner*>::iterator sp;
1246         LocaleGuard lg (X_("POSIX"));
1247
1248         if (automation_path.length() == 0) {
1249                 return 0;
1250         }
1251
1252         if (access (automation_path.c_str(), F_OK)) {
1253                 return 0;
1254         }
1255
1256         ifstream in (automation_path.c_str());
1257
1258         if (!in) {
1259                 error << string_compose (_("cannot open pan automation file %1 (%2)"),
1260                                   automation_path, strerror (errno))
1261                       << endmsg;
1262                 return -1;
1263         }
1264
1265         sp = _streampanners.begin();
1266
1267         while (in.getline (line, sizeof(line), '\n')) {
1268
1269                 if (++linecnt == 1) {
1270                         if (memcmp (line, X_("version"), 7) == 0) {
1271                                 if (sscanf (line, "version %f", &version) != 1) {
1272                                         error << string_compose(_("badly formed version number in pan automation event file \"%1\""), automation_path) << endmsg;
1273                                         return -1;
1274                                 }
1275                         } else {
1276                                 error << string_compose(_("no version information in pan automation event file \"%1\" (first line = %2)"),
1277                                                  automation_path, line) << endmsg;
1278                                 return -1;
1279                         }
1280
1281                         continue;
1282                 }
1283
1284                 if (strlen (line) == 0 || line[0] == '#') {
1285                         continue;
1286                 }
1287
1288                 if (strcmp (line, "begin") == 0) {
1289
1290                         if (sp == _streampanners.end()) {
1291                                 error << string_compose (_("too many panner states found in pan automation file %1"),
1292                                                   automation_path)
1293                                       << endmsg;
1294                                 return -1;
1295                         }
1296
1297                         if ((*sp)->load (in, automation_path, linecnt)) {
1298                                 return -1;
1299                         }
1300
1301                         ++sp;
1302                 }
1303         }
1304
1305         return 0;
1306 }
1307
1308 void
1309 Panner::set_mono (bool yn)
1310 {
1311         if (yn != _mono) {
1312                 _mono = yn;
1313                 StateChanged ();
1314         }
1315
1316         for (vector<StreamPanner*>::iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) {
1317                 (*i)->set_mono (yn);
1318         }
1319 }
1320
1321 string
1322 Panner::value_as_string (double v)
1323 {
1324         if (Panner::equivalent (v, 0.5)) {
1325                 return _("C");
1326         } else if (equivalent (v, 0)) {
1327                 return _("L");
1328         } else if (equivalent (v, 1)) {
1329                 return _("R");
1330         } else if (v < 0.5) {
1331                 stringstream s;
1332                 s << fixed << setprecision (0) << _("L") << ((0.5 - v) * 200) << "%";
1333                 return s.str();
1334         } else {
1335                 stringstream s;
1336                 s << fixed << setprecision (0) << _("R") << ((v -0.5) * 200) << "%";
1337                 return s.str ();
1338         }
1339
1340         return "";
1341 }
1342
1343 void
1344 Panner::setup_speakers (uint32_t nouts)
1345 {
1346         switch (nouts) {
1347         case 3:
1348                 /* top, bottom kind-of-left & bottom kind-of-right */
1349                 outputs.push_back (AngularVector (90.0, 0.0));
1350                 outputs.push_back (AngularVector (215.0, 0,0));
1351                 outputs.push_back (AngularVector (335.0, 0,0));
1352                 break;
1353         case 4:
1354                 /* clockwise from top left */
1355                 outputs.push_back (AngularVector (135.0, 0.0));
1356                 outputs.push_back (AngularVector (45.0, 0.0));
1357                 outputs.push_back (AngularVector (335.0, 0.0));
1358                 outputs.push_back (AngularVector (215.0, 0.0));
1359                 break;
1360
1361         default: 
1362         {
1363                 double degree_step = 360.0 / nouts;
1364                 double deg;
1365                 uint32_t n;
1366
1367                 /* even number of speakers? make sure the top two are either side of "top".
1368                    otherwise, just start at the "top" (90.0 degrees) and rotate around
1369                  */
1370
1371                 if (nouts % 2) {
1372                         deg = 90.0 - degree_step;
1373                 } else {
1374                         deg = 90.0;
1375                 }
1376                 for (n = 0; n < nouts; ++n, deg += degree_step) {
1377                         outputs.push_back (Output (AngularVector (deg, 0.0)));
1378                 }
1379         }
1380         }
1381
1382         Speakers& speakers (_session.get_speakers());
1383                         
1384         speakers.clear_speakers ();
1385
1386         for (vector<Output>::iterator o = outputs.begin(); o != outputs.end(); ++o) {
1387                 speakers.add_speaker ((*o).position);
1388         }
1389 }