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