Large nasty commit in the form of a 5000 line patch chock-full of completely
[ardour.git] / libs / ardour / crossfade.cc
1 /*
2     Copyright (C) 2003 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id$
19 */
20
21 #include <sigc++/bind.h>
22
23 #include <ardour/types.h>
24 #include <ardour/crossfade.h>
25 #include <ardour/crossfade_compare.h>
26 #include <ardour/audioregion.h>
27 #include <ardour/playlist.h>
28 #include <ardour/utils.h>
29 #include <ardour/session.h>
30
31 #include "i18n.h"
32 #include <locale.h>
33
34 using namespace std;
35 using namespace ARDOUR;
36 using namespace PBD;
37
38 jack_nframes_t Crossfade::_short_xfade_length = 0;
39 Change Crossfade::ActiveChanged = ARDOUR::new_change();
40
41 /* XXX if and when we ever implement parallel processing of the process()
42    callback, these will need to be handled on a per-thread basis.
43 */
44
45 Sample* Crossfade::crossfade_buffer_out = 0;
46 Sample* Crossfade::crossfade_buffer_in = 0;
47
48 void
49 Crossfade::set_buffer_size (jack_nframes_t sz)
50 {
51         if (crossfade_buffer_out) {
52                 delete [] crossfade_buffer_out;
53                 crossfade_buffer_out = 0;
54         }
55
56         if (crossfade_buffer_in) {
57                 delete [] crossfade_buffer_in;
58                 crossfade_buffer_in = 0;
59         }
60
61         if (sz) {
62                 crossfade_buffer_out = new Sample[sz];
63                 crossfade_buffer_in = new Sample[sz];
64         }
65 }
66
67 bool
68 Crossfade::operator== (const Crossfade& other)
69 {
70         return (_in == other._in) && (_out == other._out);
71 }
72
73 Crossfade::Crossfade (ARDOUR::AudioRegion& in, ARDOUR::AudioRegion& out, 
74                       jack_nframes_t length,
75                       jack_nframes_t position,
76                       AnchorPoint ap)
77         : _fade_in (0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
78           _fade_out (0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
79 {
80         _in = &in;
81         _out = &out;
82         _length = length;
83         _position = position;
84         _anchor_point = ap;
85         _follow_overlap = false;
86         _active = true;
87         _fixed = true;
88                 
89         initialize ();
90 }
91
92 Crossfade::Crossfade (ARDOUR::AudioRegion& a, ARDOUR::AudioRegion& b, CrossfadeModel model, bool act)
93         : _fade_in (0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
94           _fade_out (0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
95 {
96         _in_update = false;
97         _fixed = false;
98
99         if (compute (a, b, model)) {
100                 throw failed_constructor();
101         }
102
103         _active = act;
104
105         initialize ();
106
107 }
108
109 Crossfade::Crossfade (const Playlist& playlist, XMLNode& node)
110         :  _fade_in (0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
111            _fade_out (0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
112 {
113         Region* r;
114         XMLProperty* prop;
115         id_t id;
116         LocaleGuard lg (X_("POSIX"));
117
118         /* we have to find the in/out regions before we can do anything else */
119
120         if ((prop = node.property ("in")) == 0) {
121                 error << _("Crossfade: no \"in\" region in state") << endmsg;
122                 throw failed_constructor();
123         }
124         
125         sscanf (prop->value().c_str(), "%" PRIu64, &id);
126
127         if ((r = playlist.find_region (id)) == 0) {
128                 error << string_compose (_("Crossfade: no \"in\" region %1 found in playlist %2"), id, playlist.name())
129                       << endmsg;
130                 throw failed_constructor();
131         }
132         
133         if ((_in = dynamic_cast<AudioRegion*> (r)) == 0) {
134                 throw failed_constructor();
135         }
136
137         if ((prop = node.property ("out")) == 0) {
138                 error << _("Crossfade: no \"out\" region in state") << endmsg;
139                 throw failed_constructor();
140         }
141
142         sscanf (prop->value().c_str(), "%" PRIu64, &id);
143
144         if ((r = playlist.find_region (id)) == 0) {
145                 error << string_compose (_("Crossfade: no \"out\" region %1 found in playlist %2"), id, playlist.name())
146                       << endmsg;
147                 throw failed_constructor();
148         }
149         
150         if ((_out = dynamic_cast<AudioRegion*> (r)) == 0) {
151                 throw failed_constructor();
152         }
153
154         _length = 0;
155         initialize(false);
156         
157         if (set_state (node)) {
158                 throw failed_constructor();
159         }
160
161         save_state ("initial");
162 }
163
164 Crossfade::Crossfade (const Crossfade &orig, ARDOUR::AudioRegion *newin, ARDOUR::AudioRegion *newout)
165         : _fade_in(orig._fade_in),
166           _fade_out(orig._fade_out)
167 {
168         _active                         = orig._active;
169         _in_update                      = orig._in_update;
170         _length                         = orig._length;
171         _position                       = orig._position;
172         _anchor_point           = orig._anchor_point;
173         _follow_overlap         = orig._follow_overlap;
174         _fixed                          = orig._fixed;
175         _follow_overlap         = orig._follow_overlap;
176         _short_xfade_length = orig._short_xfade_length;
177         
178         _in = newin;
179         _out = newout;
180
181         // copied from Crossfade::initialize()
182         _in_update = false;
183         
184         _out->suspend_fade_out ();
185         _in->suspend_fade_in ();
186
187         overlap_type = _in->coverage (_out->position(), _out->last_frame());
188
189         // Let's make sure the fade isn't too long
190         set_length(_length);
191 }
192
193
194 Crossfade::~Crossfade ()
195 {
196         for (StateMap::iterator i = states.begin(); i != states.end(); ++i) {
197                 delete *i;
198         }
199 }
200
201 void
202 Crossfade::initialize (bool savestate)
203 {
204         _in_update = false;
205         
206         _out->suspend_fade_out ();
207         _in->suspend_fade_in ();
208
209         _fade_out.freeze ();
210         _fade_out.clear ();
211         _fade_out.add (0.0, 1.0);
212         _fade_out.add ((_length * 0.1), 0.99);
213         _fade_out.add ((_length * 0.2), 0.97);
214         _fade_out.add ((_length * 0.8), 0.03);
215         _fade_out.add ((_length * 0.9), 0.01);
216         _fade_out.add (_length, 0.0);
217         _fade_out.thaw ();
218         
219         _fade_in.freeze ();
220         _fade_in.clear ();
221         _fade_in.add (0.0, 0.0);
222         _fade_in.add ((_length * 0.1),  0.01);
223         _fade_in.add ((_length * 0.2),  0.03);
224         _fade_in.add ((_length * 0.8),  0.97);
225         _fade_in.add ((_length * 0.9),  0.99);
226         _fade_in.add (_length, 1.0);
227         _fade_in.thaw ();
228
229 //      _in->StateChanged.connect (slot (*this, &Crossfade::member_changed));
230 //      _out->StateChanged.connect (slot (*this, &Crossfade::member_changed));
231
232         overlap_type = _in->coverage (_out->position(), _out->last_frame());
233
234         if (savestate) {
235                 save_state ("initial");
236         }
237 }       
238
239 int
240 Crossfade::compute (AudioRegion& a, AudioRegion& b, CrossfadeModel model)
241 {
242         AudioRegion* top;
243         AudioRegion* bottom;
244         jack_nframes_t short_xfade_length;
245
246         short_xfade_length = _short_xfade_length; 
247
248         if (a.layer() < b.layer()) {
249                 top = &b;
250                 bottom = &a;
251         } else {
252                 top = &a;
253                 bottom = &b;
254         }
255         
256         /* first check for matching ends */
257         
258         if (top->first_frame() == bottom->first_frame()) {
259                 
260                 /* Both regions start at the same point */
261                 
262                 if (top->last_frame() < bottom->last_frame()) {
263                         
264                         /* top ends before bottom, so put an xfade
265                            in at the end of top.
266                         */
267                         
268                         /* [-------- top ---------- ]
269                          * {====== bottom =====================}
270                          */
271
272                         _in = bottom;
273                         _out = top;
274
275                         if (top->last_frame() < short_xfade_length) {
276                                 _position = 0;
277                         } else {
278                                 _position = top->last_frame() - short_xfade_length;
279                         }
280
281                         _length = min (short_xfade_length, top->length());
282                         _follow_overlap = false;
283                         _anchor_point = EndOfIn;
284                         _active = true;
285                         _fixed = true;
286
287                 } else {
288                         /* top ends after (or same time) as bottom - no xfade
289                          */
290                         
291                         /* [-------- top ------------------------ ]
292                          * {====== bottom =====================}
293                          */
294
295                         throw NoCrossfadeHere();
296                 }
297                 
298         } else if (top->last_frame() == bottom->last_frame()) {
299                 
300                 /* Both regions end at the same point */
301                 
302                 if (top->first_frame() > bottom->first_frame()) {
303                         
304                         /* top starts after bottom, put an xfade in at the
305                            start of top
306                         */
307                         
308                         /*            [-------- top ---------- ]
309                          * {====== bottom =====================}
310                          */
311
312                         _in = top;
313                         _out = bottom;
314                         _position = top->first_frame();
315                         _length = min (short_xfade_length, top->length());
316                         _follow_overlap = false;
317                         _anchor_point = StartOfIn;
318                         _active = true;
319                         _fixed = true;
320                         
321                 } else {
322                         /* top starts before bottom - no xfade
323                          */
324
325                         /* [-------- top ------------------------ ]
326                          *    {====== bottom =====================}
327                          */
328
329                         throw NoCrossfadeHere();
330                 }
331
332         } else {
333         
334                 /* OK, time to do more regular overlapping */
335
336                 OverlapType ot = top->coverage (bottom->first_frame(), bottom->last_frame());
337
338                 switch (ot) {
339                 case OverlapNone:
340                         /* should be NOTREACHED as a precondition of creating
341                            a new crossfade, but we need to handle it here.
342                         */
343                         throw NoCrossfadeHere();
344                         break;
345                         
346                 case OverlapInternal:
347                 case OverlapExternal:
348                         /* should be NOTREACHED because of tests above */
349                         throw NoCrossfadeHere();
350                         break;
351                         
352                 case OverlapEnd: /* top covers start of bottom but ends within it */
353
354                         /* [---- top ------------------------] 
355                          *                { ==== bottom ============ } 
356                          */ 
357
358                         _in = bottom;
359                         _out = top;
360                         _position = bottom->first_frame();
361                         _anchor_point = StartOfIn;
362
363                         if (model == FullCrossfade) {
364                                 _length = _out->first_frame() + _out->length() - _in->first_frame();
365                                 /* leave active alone */
366                                 _follow_overlap = true;
367                         } else {
368                                 _length = min (short_xfade_length, top->length());
369                                 _active = true;
370                                 _follow_overlap = false;
371                                 
372                         }
373                         break;
374                         
375                 case OverlapStart:   /* top starts within bottom but covers bottom's end */
376
377                         /*                   { ==== top ============ } 
378                          *   [---- bottom -------------------] 
379                          */
380
381                         _in = top;
382                         _out = bottom;
383                         _position = top->first_frame();
384                         _anchor_point = StartOfIn;
385
386                         if (model == FullCrossfade) {
387                                 _length = _out->first_frame() + _out->length() - _in->first_frame();
388                                 /* leave active alone */
389                                 _follow_overlap = true;
390                         } else {
391                                 _length = min (short_xfade_length, top->length());
392                                 _active = true;
393                                 _follow_overlap = false;
394                                 
395                         }
396                         
397                         break;
398                 }
399         }
400         
401         return 0;
402 }
403
404 jack_nframes_t 
405 Crossfade::read_at (Sample *buf, Sample *mixdown_buffer, 
406                     float *gain_buffer, char * workbuf, jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n,
407                     jack_nframes_t read_frames, jack_nframes_t skip_frames)
408 {
409         jack_nframes_t offset;
410         jack_nframes_t to_write;
411
412         if (!_active) {
413                 return 0;
414         }
415
416         if (start < _position) {
417
418                 /* handle an initial section of the read area that we do not
419                    cover.
420                 */
421
422                 offset = _position - start;
423
424                 if (offset < cnt) {
425                         cnt -= offset;
426                 } else {
427                         return 0;
428                 }
429                 
430                 start = _position;
431                 buf += offset;
432                 to_write = min (_length, cnt);
433
434         } else {
435                 
436                 to_write = min (_length - (start - _position), cnt);
437                 
438         }
439
440         offset = start - _position;
441
442         _out->read_at (crossfade_buffer_out, mixdown_buffer, gain_buffer, workbuf, start, to_write, chan_n, read_frames, skip_frames);
443         _in->read_at (crossfade_buffer_in, mixdown_buffer, gain_buffer, workbuf, start, to_write, chan_n, read_frames, skip_frames);
444
445         float* fiv = new float[to_write];
446         float* fov = new float[to_write];
447
448         _fade_in.get_vector (offset, offset+to_write, fiv, to_write);
449         _fade_out.get_vector (offset, offset+to_write, fov, to_write);
450
451         /* note: although we have not explicitly taken into account the return values
452            from _out->read_at() or _in->read_at(), the length() function does this
453            implicitly. why? because it computes a value based on the in+out regions'
454            position and length, and so we know precisely how much data they could return. 
455         */
456
457         for (jack_nframes_t n = 0; n < to_write; ++n) {
458                 buf[n] = (crossfade_buffer_out[n] * fov[n]) + (crossfade_buffer_in[n] * fiv[n]);
459         }
460
461         delete [] fov;
462         delete [] fiv;
463
464         return to_write;
465 }       
466
467 OverlapType 
468 Crossfade::coverage (jack_nframes_t start, jack_nframes_t end) const
469 {
470         jack_nframes_t my_end = _position + _length;
471
472         if ((start >= _position) && (end <= my_end)) {
473                 return OverlapInternal;
474         }
475         if ((end >= _position) && (end <= my_end)) {
476                 return OverlapStart;
477         }
478         if ((start >= _position) && (start <= my_end)) {
479                 return OverlapEnd;
480         }
481         if ((_position >= start) && (_position <= end) && (my_end <= end)) {
482                 return OverlapExternal;
483         }
484         return OverlapNone;
485 }
486
487 void
488 Crossfade::set_active (bool yn)
489 {
490         if (_active != yn) {
491                 _active = yn;
492                 save_state (_("active changed"));
493                 send_state_changed (ActiveChanged);
494         }
495 }
496
497 bool
498 Crossfade::refresh ()
499 {
500         /* crossfades must be between non-muted regions */
501         
502         if (_out->muted() || _in->muted()) {
503                 Invalidated (this);
504                 return false;
505         }
506
507         /* overlap type must be Start, End or External */
508
509         OverlapType ot;
510         
511         ot = _in->coverage (_out->first_frame(), _out->last_frame());
512         
513         switch (ot) {
514         case OverlapNone:
515         case OverlapInternal:
516                 Invalidated (this);
517                 return false;
518                 
519         default:
520                 break;
521         }
522                 
523         /* overlap type must not have altered */
524         
525         if (ot != overlap_type) {
526                 Invalidated (this);
527                 return false;
528         } 
529
530         /* time to update */
531
532         return update (false);
533 }
534
535 bool
536 Crossfade::update (bool force)
537 {
538         jack_nframes_t newlen;
539         bool save = false;
540
541         if (_follow_overlap) {
542                 newlen = _out->first_frame() + _out->length() - _in->first_frame();
543         } else {
544                 newlen = _length;
545         }
546
547         if (newlen == 0) {
548                 Invalidated (this);
549                 return false;
550         }
551
552         _in_update = true;
553
554         if (force || (_follow_overlap && newlen != _length) || (_length > newlen)) {
555
556                 double factor =  newlen / (double) _length;
557                 
558                 _fade_out.x_scale (factor);
559                 _fade_in.x_scale (factor);
560                 
561                 _length = newlen;
562
563                 save = true;
564
565         } 
566
567         switch (_anchor_point) {
568         case StartOfIn:
569                 if (_position != _in->first_frame()) {
570                         _position = _in->first_frame();
571                         save = true;
572                 }
573                 break;
574
575         case EndOfIn:
576                 if (_position != _in->last_frame() - _length) {
577                         _position = _in->last_frame() - _length;
578                         save = true;
579                 }
580                 break;
581
582         case EndOfOut:
583                 if (_position != _out->last_frame() - _length) {
584                         _position = _out->last_frame() - _length;
585                         save = true;
586                 }
587         }
588
589         if (save) {
590                 save_state ("updated");
591         } 
592
593         /* UI's may need to know that the overlap changed even 
594            though the xfade length did not.
595         */
596         
597         send_state_changed (BoundsChanged); /* EMIT SIGNAL */
598
599         _in_update = false;
600
601         return true;
602 }
603
604 void
605 Crossfade::member_changed (Change what_changed)
606 {
607         Change what_we_care_about = Change (Region::MuteChanged|
608                                             Region::LayerChanged|
609                                             ARDOUR::BoundsChanged);
610
611         if (what_changed & what_we_care_about) {
612                 refresh ();
613         }
614 }
615
616 Change
617 Crossfade::restore_state (StateManager::State& state)
618 {
619         CrossfadeState* xfstate = dynamic_cast<CrossfadeState*> (&state);
620         Change what_changed = Change (0);
621
622         _in_update = true;
623         
624         xfstate->fade_in_memento ();
625         xfstate->fade_out_memento ();
626
627         if (_length != xfstate->length) {
628                 what_changed = Change (what_changed|LengthChanged);
629                 _length = xfstate->length;
630         }
631         if (_active != xfstate->active) {
632                 what_changed = Change (what_changed|ActiveChanged);
633                 _active = xfstate->active;
634         }
635         if (_position != xfstate->position) {
636                 what_changed = Change (what_changed|PositionChanged);
637                 _position = xfstate->position;
638         }
639
640         /* XXX what to do about notifications for these? I don't
641            think (G)UI cares about them because they are
642            implicit in the bounds.
643         */
644
645         _follow_overlap = xfstate->follow_overlap;
646         _anchor_point = xfstate->anchor_point;
647
648         _in_update = false;
649
650         return Change (what_changed);
651 }
652
653 StateManager::State*
654 Crossfade::state_factory (std::string why) const
655 {
656         CrossfadeState* state = new CrossfadeState (why);
657
658         state->fade_in_memento = _fade_in.get_memento ();
659         state->fade_out_memento = _fade_out.get_memento ();
660         state->active = _active;
661         state->length = _length;
662         state->position = _position;
663         state->follow_overlap = _follow_overlap;
664         state->anchor_point = _anchor_point;
665
666         return state;
667 }
668         
669 UndoAction
670 Crossfade::get_memento() const
671 {
672   return sigc::bind (mem_fun (*(const_cast<Crossfade *> (this)), &StateManager::use_state), _current_state_id);
673 }
674
675 XMLNode&
676 Crossfade::get_state () 
677 {
678         XMLNode* node = new XMLNode (X_("Crossfade"));
679         XMLNode* child;
680         char buf[64];
681         LocaleGuard lg (X_("POSIX"));
682
683         snprintf (buf, sizeof(buf), "%" PRIu64, _out->id());
684         node->add_property ("out", buf);
685         snprintf (buf, sizeof(buf), "%" PRIu64, _in->id());
686         node->add_property ("in", buf);
687         node->add_property ("active", (_active ? "yes" : "no"));
688         node->add_property ("follow-overlap", (_follow_overlap ? "yes" : "no"));
689         node->add_property ("fixed", (_fixed ? "yes" : "no"));
690         snprintf (buf, sizeof(buf), "%" PRIu32, _length);
691         node->add_property ("length", buf);
692         snprintf (buf, sizeof(buf), "%" PRIu32, (uint32_t) _anchor_point);
693         node->add_property ("anchor-point", buf);
694         snprintf (buf, sizeof(buf), "%" PRIu32, (uint32_t) _position);
695         node->add_property ("position", buf);
696
697         child = node->add_child ("FadeIn");
698
699         for (AutomationList::iterator ii = _fade_in.begin(); ii != _fade_in.end(); ++ii) {
700                 XMLNode* pnode;
701
702                 pnode = new XMLNode ("point");
703
704                 snprintf (buf, sizeof (buf), "%" PRIu32, (jack_nframes_t) floor ((*ii)->when));
705                 pnode->add_property ("x", buf);
706                 snprintf (buf, sizeof (buf), "%f", (*ii)->value);
707                 pnode->add_property ("y", buf);
708                 child->add_child_nocopy (*pnode);
709         }
710
711         child = node->add_child ("FadeOut");
712
713         for (AutomationList::iterator ii = _fade_out.begin(); ii != _fade_out.end(); ++ii) {
714                 XMLNode* pnode;
715
716                 pnode = new XMLNode ("point");
717
718                 snprintf (buf, sizeof (buf), "%" PRIu32, (jack_nframes_t) floor ((*ii)->when));
719                 pnode->add_property ("x", buf);
720                 snprintf (buf, sizeof (buf), "%f", (*ii)->value);
721                 pnode->add_property ("y", buf);
722                 child->add_child_nocopy (*pnode);
723         }
724
725         return *node;
726 }
727
728 int
729 Crossfade::set_state (const XMLNode& node)
730 {
731         XMLNodeConstIterator i;
732         XMLNodeList children;
733         XMLNode* fi;
734         XMLNode* fo;
735         const XMLProperty* prop;
736         LocaleGuard lg (X_("POSIX"));
737
738         if ((prop = node.property ("position")) != 0) {
739                 _position = atoi (prop->value().c_str());
740         } else {
741                 warning << _("old-style crossfade information - no position information") << endmsg;
742                 _position = _in->first_frame();
743         }
744
745         if ((prop = node.property ("active")) != 0) {
746                 _active = (prop->value() == "yes");
747         } else {
748                 _active = true;
749         }
750
751         if ((prop = node.property ("follow-overlap")) != 0) {
752                 _follow_overlap = (prop->value() == "yes");
753         } else {
754                 _follow_overlap = false;
755         }
756
757         if ((prop = node.property ("fixed")) != 0) {
758                 _fixed = (prop->value() == "yes");
759         } else {
760                 _fixed = false;
761         }
762
763         if ((prop = node.property ("anchor-point")) != 0) {
764                 _anchor_point = AnchorPoint (atoi ((prop->value().c_str())));
765         } else {
766                 _anchor_point = StartOfIn;
767         }
768
769         if ((prop = node.property ("length")) != 0) {
770
771                 _length = atol (prop->value().c_str());
772
773         } else {
774                 
775                 /* XXX this branch is legacy code from before
776                    the point where we stored xfade lengths.
777                 */
778                 
779                 if ((_length = overlap_length()) == 0) {
780                         throw failed_constructor();
781                 }
782         }
783
784         if ((fi = find_named_node (node, "FadeIn")) == 0) {
785                 return -1;
786         }
787         
788         if ((fo = find_named_node (node, "FadeOut")) == 0) {
789                 return -1;
790         }
791
792         /* fade in */
793         
794         _fade_in.clear ();
795         
796         children = fi->children();
797         
798         for (i = children.begin(); i != children.end(); ++i) {
799                 if ((*i)->name() == "point") {
800                         jack_nframes_t x;
801                         float y;
802                         
803                         prop = (*i)->property ("x");
804                         sscanf (prop->value().c_str(), "%" PRIu32, &x);
805                         
806                         prop = (*i)->property ("y");
807                         sscanf (prop->value().c_str(), "%f", &y);
808
809                         _fade_in.add (x, y);
810                 }
811         }
812         
813         /* fade out */
814         
815         _fade_out.clear ();
816
817         children = fo->children();
818         
819         for (i = children.begin(); i != children.end(); ++i) {
820                 if ((*i)->name() == "point") {
821                         jack_nframes_t x;
822                         float y;
823                         XMLProperty* prop;
824
825                         prop = (*i)->property ("x");
826                         sscanf (prop->value().c_str(), "%" PRIu32, &x);
827
828                         prop = (*i)->property ("y");
829                         sscanf (prop->value().c_str(), "%f", &y);
830                         
831                         _fade_out.add (x, y);
832                 }
833         }
834
835         return 0;
836 }
837
838 bool
839 Crossfade::can_follow_overlap () const
840 {
841         return !_fixed;
842 }
843
844 void
845 Crossfade::set_follow_overlap (bool yn)
846 {
847         if (yn == _follow_overlap || _fixed) {
848                 return;
849         }
850
851         _follow_overlap = yn;
852
853         if (!yn) {
854                 set_length (_short_xfade_length);
855         } else {
856                 set_length (_out->first_frame() + _out->length() - _in->first_frame());
857         }
858 }
859
860 jack_nframes_t
861 Crossfade::set_length (jack_nframes_t len)
862 {
863         jack_nframes_t limit;
864
865         switch (_anchor_point) {
866         case StartOfIn:
867                 limit = _in->length();
868                 break;
869
870         case EndOfIn:
871                 limit = _in->length();
872                 break;
873
874         case EndOfOut:
875                 limit = _out->length();
876                 break;
877                 
878         }
879
880         len = min (limit, len);
881
882         double factor = len / (double) _length;
883
884         _in_update = true;
885         _fade_out.x_scale (factor);
886         _fade_in.x_scale (factor);
887         _in_update = false;
888         
889         _length = len;
890
891         save_state ("length changed");
892
893         send_state_changed (LengthChanged);
894
895         return len;
896 }
897
898 jack_nframes_t
899 Crossfade::overlap_length () const
900 {
901         if (_fixed) {
902                 return _length;
903         }
904         return _out->first_frame() + _out->length() - _in->first_frame();
905 }
906
907 void
908 Crossfade::set_short_xfade_length (jack_nframes_t n)
909 {
910         _short_xfade_length = n;
911 }