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