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