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