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