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