2 Copyright (C) 2003-2006 Paul Davis
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.
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.
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.
21 #include "pbd/stacktrace.h"
23 #include "ardour/debug.h"
24 #include "ardour/types.h"
25 #include "ardour/crossfade.h"
26 #include "ardour/audioregion.h"
27 #include "ardour/playlist.h"
28 #include "ardour/utils.h"
29 #include "ardour/session.h"
30 #include "ardour/source.h"
31 #include "ardour/region_factory.h"
37 using namespace ARDOUR
;
40 framecnt_t
Crossfade::_short_xfade_length
= 0;
42 /* XXX if and when we ever implement parallel processing of the process()
43 callback, these will need to be handled on a per-thread basis.
46 Sample
* Crossfade::crossfade_buffer_out
= 0;
47 Sample
* Crossfade::crossfade_buffer_in
= 0;
50 #define CROSSFADE_DEFAULT_PROPERTIES \
51 _active (Properties::active, _session.config.get_xfades_active ()) \
52 , _follow_overlap (Properties::follow_overlap, false)
56 namespace Properties
{
57 PropertyDescriptor
<bool> follow_overlap
;
62 Crossfade::make_property_quarks ()
64 Properties::follow_overlap
.property_id
= g_quark_from_static_string (X_("follow-overlap"));
65 DEBUG_TRACE (DEBUG::Properties
, string_compose ("quark for follow-overlap = %1\n", Properties::follow_overlap
.property_id
));
69 Crossfade::set_buffer_size (framecnt_t sz
)
71 delete [] crossfade_buffer_out
;
72 crossfade_buffer_out
= 0;
74 delete [] crossfade_buffer_in
;
75 crossfade_buffer_in
= 0;
78 crossfade_buffer_out
= new Sample
[sz
];
79 crossfade_buffer_in
= new Sample
[sz
];
84 Crossfade::operator== (const Crossfade
& other
)
86 return (_in
== other
._in
) && (_out
== other
._out
);
89 Crossfade::Crossfade (boost::shared_ptr
<AudioRegion
> in
, boost::shared_ptr
<AudioRegion
> out
,
93 : AudioRegion (in
->session(), position
, length
, in
->name() + string ("<>") + out
->name())
94 , CROSSFADE_DEFAULT_PROPERTIES
95 , _fade_in (Evoral::Parameter(FadeInAutomation
)) // linear (gain coefficient) => -inf..+6dB
96 , _fade_out (Evoral::Parameter(FadeOutAutomation
)) // linear (gain coefficient) => -inf..+6dB
103 _follow_overlap
= false;
108 Crossfade::Crossfade (boost::shared_ptr
<AudioRegion
> a
, boost::shared_ptr
<AudioRegion
> b
, CrossfadeModel model
, bool act
)
109 : AudioRegion (a
->session(), 0, 0, a
->name() + string ("<>") + b
->name())
110 , CROSSFADE_DEFAULT_PROPERTIES
111 , _fade_in (Evoral::Parameter(FadeInAutomation
)) // linear (gain coefficient) => -inf..+6dB
112 , _fade_out (Evoral::Parameter(FadeOutAutomation
)) // linear (gain coefficient) => -inf..+6dB
116 _follow_overlap
= false;
118 if (compute (a
, b
, model
)) {
119 throw failed_constructor();
127 Crossfade::Crossfade (const Playlist
& playlist
, XMLNode
const & node
)
128 : AudioRegion (playlist
.session(), 0, 0, "unnamed crossfade")
129 , CROSSFADE_DEFAULT_PROPERTIES
130 , _fade_in (Evoral::Parameter(FadeInAutomation
)) // linear (gain coefficient) => -inf..+6dB
131 , _fade_out (Evoral::Parameter(FadeOutAutomation
)) // linear (gain coefficient) => -inf..+6dB
134 boost::shared_ptr
<Region
> r
;
135 XMLProperty
const * prop
;
136 LocaleGuard
lg (X_("POSIX"));
138 /* we have to find the in/out regions before we can do anything else */
140 if ((prop
= node
.property ("in")) == 0) {
141 error
<< _("Crossfade: no \"in\" region in state") << endmsg
;
142 throw failed_constructor();
145 PBD::ID
id (prop
->value());
147 r
= playlist
.find_region (id
);
150 /* the `in' region is not in a playlist, which probably means that this crossfade
151 is in the undo record, so we have to find the region in the global region map.
153 r
= RegionFactory::region_by_id (id
);
157 error
<< string_compose (_("Crossfade: no \"in\" region %1 found in playlist %2 nor in region map"), id
, playlist
.name())
159 throw failed_constructor();
162 if ((_in
= boost::dynamic_pointer_cast
<AudioRegion
> (r
)) == 0) {
163 throw failed_constructor();
166 if ((prop
= node
.property ("out")) == 0) {
167 error
<< _("Crossfade: no \"out\" region in state") << endmsg
;
168 throw failed_constructor();
171 PBD::ID
id2 (prop
->value());
173 r
= playlist
.find_region (id2
);
176 r
= RegionFactory::region_by_id (id2
);
180 error
<< string_compose (_("Crossfade: no \"out\" region %1 found in playlist %2 nor in region map"), id2
, playlist
.name())
182 throw failed_constructor();
185 if ((_out
= boost::dynamic_pointer_cast
<AudioRegion
> (r
)) == 0) {
186 throw failed_constructor();
193 if (set_state (node
, Stateful::loading_state_version
)) {
194 throw failed_constructor();
198 Crossfade::Crossfade (boost::shared_ptr
<Crossfade
> orig
, boost::shared_ptr
<AudioRegion
> newin
, boost::shared_ptr
<AudioRegion
> newout
)
199 : AudioRegion (boost::dynamic_pointer_cast
<const AudioRegion
> (orig
), 0)
200 , CROSSFADE_DEFAULT_PROPERTIES
201 , _fade_in (orig
->_fade_in
)
202 , _fade_out (orig
->_fade_out
)
204 _active
= orig
->_active
;
205 _in_update
= orig
->_in_update
;
206 _anchor_point
= orig
->_anchor_point
;
207 _follow_overlap
= orig
->_follow_overlap
;
208 _fixed
= orig
->_fixed
;
213 // copied from Crossfade::initialize()
216 _out
->suspend_fade_out ();
217 _in
->suspend_fade_in ();
219 overlap_type
= _in
->coverage (_out
->position(), _out
->last_frame());
220 layer_relation
= (int32_t) (_in
->layer() - _out
->layer());
222 // Let's make sure the fade isn't too long
223 set_xfade_length(_length
);
227 Crossfade::~Crossfade ()
232 Crossfade::initialize ()
234 /* merge source lists from regions */
236 _sources
= _in
->sources();
237 _sources
.insert (_sources
.end(), _out
->sources().begin(), _out
->sources().end());
239 for (SourceList::iterator i
= _sources
.begin(); i
!= _sources
.end(); ++i
) {
240 (*i
)->inc_use_count ();
243 _master_sources
= _in
->master_sources();
244 _master_sources
.insert(_master_sources
.end(), _out
->master_sources().begin(), _out
->master_sources().end());
246 for (SourceList::iterator i
= _master_sources
.begin(); i
!= _master_sources
.end(); ++i
) {
247 (*i
)->inc_use_count ();
252 _out
->suspend_fade_out ();
253 _in
->suspend_fade_in ();
258 #define EQUAL_POWER_MINUS_3DB
259 #ifdef EQUAL_POWER_MINUS_3DB
261 _fade_out
.add ((_length
* 0.000000), 1.000000);
262 _fade_out
.add ((_length
* 0.166667), 0.948859);
263 _fade_out
.add ((_length
* 0.333333), 0.851507);
264 _fade_out
.add ((_length
* 0.500000), 0.707946);
265 _fade_out
.add ((_length
* 0.666667), 0.518174);
266 _fade_out
.add ((_length
* 0.833333), 0.282192);
267 _fade_out
.add ((_length
* 1.000000), 0.000000);
269 #else // EQUAL_POWER_MINUS_6DB
271 _fade_out
.add ((_length
* 0.000000), 1.000000);
272 _fade_out
.add ((_length
* 0.166667), 0.833033);
273 _fade_out
.add ((_length
* 0.333333), 0.666186);
274 _fade_out
.add ((_length
* 0.500000), 0.499459);
275 _fade_out
.add ((_length
* 0.666667), 0.332853);
276 _fade_out
.add ((_length
* 0.833333), 0.166366);
277 _fade_out
.add ((_length
* 1.000000), 0.000000);
285 #define EQUAL_POWER_MINUS_3DB
286 #ifdef EQUAL_POWER_MINUS_3DB
288 _fade_in
.add ((_length
* 0.000000), 0.000000);
289 _fade_in
.add ((_length
* 0.166667), 0.282192);
290 _fade_in
.add ((_length
* 0.333333), 0.518174);
291 _fade_in
.add ((_length
* 0.500000), 0.707946);
292 _fade_in
.add ((_length
* 0.666667), 0.851507);
293 _fade_in
.add ((_length
* 0.833333), 0.948859);
294 _fade_in
.add ((_length
* 1.000000), 1.000000);
296 #else // EQUAL_POWER_MINUS_SIX_DB
298 _fade_in
.add ((_length
* 0.000000), 0.000000);
299 _fade_in
.add ((_length
* 0.166667), 0.166366);
300 _fade_in
.add ((_length
* 0.333333), 0.332853);
301 _fade_in
.add ((_length
* 0.500000), 0.499459);
302 _fade_in
.add ((_length
* 0.666667), 0.666186);
303 _fade_in
.add ((_length
* 0.833333), 0.833033);
304 _fade_in
.add ((_length
* 1.000000), 1.000000);
310 overlap_type
= _in
->coverage (_out
->position(), _out
->last_frame());
311 layer_relation
= (int32_t) (_in
->layer() - _out
->layer());
315 Crossfade::read_raw_internal (Sample
* buf
, framecnt_t start
, framecnt_t cnt
, int channel
) const
317 Sample
* mixdown
= new Sample
[cnt
];
318 float* gain
= new float[cnt
];
321 ret
= read_at (buf
, mixdown
, gain
, start
, cnt
, channel
, cnt
);
330 Crossfade::read_at (Sample
*buf
, Sample
*mixdown_buffer
,
331 float *gain_buffer
, framepos_t start
, framecnt_t cnt
, uint32_t chan_n
,
332 framecnt_t read_frames
, framecnt_t skip_frames
) const
334 frameoffset_t offset
;
341 if (start
< _position
) {
343 /* handle an initial section of the read area that we do not
347 offset
= _position
- start
;
357 to_write
= min (_length
.val(), cnt
);
361 to_write
= min ((_length
- (start
- _position
)), cnt
);
365 offset
= start
- _position
;
367 /* Prevent data from piling up inthe crossfade buffers when reading a transparent region */
368 if (!(_out
->opaque())) {
369 memset (crossfade_buffer_out
, 0, sizeof (Sample
) * to_write
);
370 } else if (!(_in
->opaque())) {
371 memset (crossfade_buffer_in
, 0, sizeof (Sample
) * to_write
);
374 _out
->read_at (crossfade_buffer_out
, mixdown_buffer
, gain_buffer
, start
, to_write
, chan_n
, read_frames
, skip_frames
);
375 _in
->read_at (crossfade_buffer_in
, mixdown_buffer
, gain_buffer
, start
, to_write
, chan_n
, read_frames
, skip_frames
);
377 float* fiv
= new float[to_write
];
378 float* fov
= new float[to_write
];
380 _fade_in
.curve().get_vector (offset
, offset
+to_write
, fiv
, to_write
);
381 _fade_out
.curve().get_vector (offset
, offset
+to_write
, fov
, to_write
);
383 /* note: although we have not explicitly taken into account the return values
384 from _out->read_at() or _in->read_at(), the length() function does this
385 implicitly. why? because it computes a value based on the in+out regions'
386 position and length, and so we know precisely how much data they could return.
389 for (framecnt_t n
= 0; n
< to_write
; ++n
) {
390 buf
[n
] = (crossfade_buffer_out
[n
] * fov
[n
]) + (crossfade_buffer_in
[n
] * fiv
[n
]);
400 Crossfade::coverage (framepos_t start
, framepos_t end
) const
402 framepos_t my_end
= _position
+ _length
;
404 if ((start
>= _position
) && (end
<= my_end
)) {
405 return OverlapInternal
;
407 if ((end
>= _position
) && (end
<= my_end
)) {
410 if ((start
>= _position
) && (start
<= my_end
)) {
413 if ((_position
>= start
) && (_position
<= end
) && (my_end
<= end
)) {
414 return OverlapExternal
;
420 Crossfade::set_active (bool yn
)
424 PropertyChanged (PropertyChange (Properties::active
));
429 Crossfade::refresh ()
431 /* crossfades must be between non-muted regions */
433 if (_out
->muted() || _in
->muted()) {
434 Invalidated (shared_from_this ());
438 /* Top layer shouldn't be transparent */
440 if (!((layer_relation
> 0 ? _in
: _out
)->opaque())) {
441 Invalidated (shared_from_this());
445 /* regions must cannot be identically sized and placed */
447 if (_in
->position() == _out
->position() && _in
->length() == _out
->length()) {
448 Invalidated (shared_from_this());
452 /* layer ordering cannot change */
454 int32_t new_layer_relation
= (int32_t) (_in
->layer() - _out
->layer());
456 if (new_layer_relation
* layer_relation
< 0) { // different sign, layers rotated
457 Invalidated (shared_from_this ());
461 OverlapType ot
= _in
->coverage (_out
->first_frame(), _out
->last_frame());
463 if (ot
== OverlapNone
) {
464 Invalidated (shared_from_this ());
470 if (ot
!= overlap_type
) {
472 if (_follow_overlap
) {
475 compute (_in
, _out
, _session
.config
.get_xfade_model());
478 catch (NoCrossfadeHere
& err
) {
479 Invalidated (shared_from_this ());
486 Invalidated (shared_from_this ());
492 send_signal
= update ();
496 PropertyChange bounds
;
497 bounds
.add (Properties::start
);
498 bounds
.add (Properties::position
);
499 bounds
.add (Properties::length
);
500 PropertyChanged (bounds
); /* EMIT SIGNAL */
513 if (_follow_overlap
) {
514 newlen
= _out
->first_frame() + _out
->length() - _in
->first_frame();
520 Invalidated (shared_from_this ());
526 if ((_follow_overlap
&& newlen
!= _length
) || (_length
> newlen
)) {
528 double factor
= newlen
/ (double) _length
;
530 _fade_out
.x_scale (factor
);
531 _fade_in
.x_scale (factor
);
536 switch (_anchor_point
) {
538 _position
= _in
->first_frame();
542 _position
= _in
->last_frame() - _length
;
546 _position
= _out
->last_frame() - _length
;
553 Crossfade::compute (boost::shared_ptr
<AudioRegion
> a
, boost::shared_ptr
<AudioRegion
> b
, CrossfadeModel model
)
555 boost::shared_ptr
<AudioRegion
> top
;
556 boost::shared_ptr
<AudioRegion
> bottom
;
557 framecnt_t short_xfade_length
;
559 short_xfade_length
= _short_xfade_length
;
561 if (a
->layer() < b
->layer()) {
569 /* first check for matching ends */
571 if (top
->first_frame() == bottom
->first_frame()) {
573 /* Both regions start at the same point */
575 if (top
->last_frame() < bottom
->last_frame()) {
577 /* top ends before bottom, so put an xfade
578 in at the end of top.
581 /* [-------- top ---------- ]
582 * {====== bottom =====================}
588 if (top
->last_frame() < short_xfade_length
) {
591 _position
= top
->last_frame() - short_xfade_length
;
594 _length
= min (short_xfade_length
, top
->length());
595 _follow_overlap
= false;
596 _anchor_point
= EndOfIn
;
601 /* top ends after (or same time) as bottom - no xfade
604 /* [-------- top ------------------------ ]
605 * {====== bottom =====================}
608 throw NoCrossfadeHere();
611 } else if (top
->last_frame() == bottom
->last_frame()) {
613 /* Both regions end at the same point */
615 if (top
->first_frame() > bottom
->first_frame()) {
617 /* top starts after bottom, put an xfade in at the
621 /* [-------- top ---------- ]
622 * {====== bottom =====================}
627 _position
= top
->first_frame();
628 _length
= min (short_xfade_length
, top
->length());
629 _follow_overlap
= false;
630 _anchor_point
= StartOfIn
;
635 /* top starts before bottom - no xfade
638 /* [-------- top ------------------------ ]
639 * {====== bottom =====================}
642 throw NoCrossfadeHere();
647 /* OK, time to do more regular overlapping */
649 OverlapType ot
= top
->coverage (bottom
->first_frame(), bottom
->last_frame());
653 /* should be NOTREACHED as a precondition of creating
654 a new crossfade, but we need to handle it here.
656 throw NoCrossfadeHere();
659 case OverlapInternal
:
660 case OverlapExternal
:
661 /* should be NOTREACHED because of tests above */
662 throw NoCrossfadeHere();
665 case OverlapEnd
: /* top covers start of bottom but ends within it */
667 /* [---- top ------------------------]
668 * { ==== bottom ============ }
673 _anchor_point
= EndOfOut
;
675 if (model
== FullCrossfade
) {
676 _position
= bottom
->first_frame(); // "{"
677 _length
= _out
->first_frame() + _out
->length() - _in
->first_frame();
678 /* leave active alone */
679 _follow_overlap
= true;
681 _length
= min (short_xfade_length
, top
->length());
682 _position
= top
->last_frame() - _length
; // "]" - length
684 _follow_overlap
= false;
689 case OverlapStart
: /* top starts within bottom but covers bottom's end */
691 /* { ==== top ============ }
692 * [---- bottom -------------------]
697 _position
= top
->first_frame();
698 _anchor_point
= StartOfIn
;
700 if (model
== FullCrossfade
) {
701 _length
= _out
->first_frame() + _out
->length() - _in
->first_frame();
702 /* leave active alone */
703 _follow_overlap
= true;
705 _length
= min (short_xfade_length
, top
->length());
707 _follow_overlap
= false;
719 Crossfade::get_state ()
721 XMLNode
* node
= new XMLNode (X_("Crossfade"));
724 LocaleGuard
lg (X_("POSIX"));
726 id().print (buf
, sizeof (buf
));
727 node
->add_property ("id", buf
);
728 _out
->id().print (buf
, sizeof (buf
));
729 node
->add_property ("out", buf
);
730 _in
->id().print (buf
, sizeof (buf
));
731 node
->add_property ("in", buf
);
732 node
->add_property ("active", (_active
? "yes" : "no"));
733 node
->add_property ("follow-overlap", (_follow_overlap
? "yes" : "no"));
734 node
->add_property ("fixed", (_fixed
? "yes" : "no"));
735 snprintf (buf
, sizeof(buf
), "%" PRId64
, _length
.val());
736 node
->add_property ("length", buf
);
737 snprintf (buf
, sizeof(buf
), "%" PRIu32
, (uint32_t) _anchor_point
);
738 node
->add_property ("anchor-point", buf
);
739 snprintf (buf
, sizeof(buf
), "%" PRId64
, _position
.val());
740 node
->add_property ("position", buf
);
742 child
= node
->add_child ("FadeIn");
744 for (AutomationList::iterator ii
= _fade_in
.begin(); ii
!= _fade_in
.end(); ++ii
) {
747 pnode
= new XMLNode ("point");
749 snprintf (buf
, sizeof (buf
), "%" PRId64
, (framepos_t
) floor ((*ii
)->when
));
750 pnode
->add_property ("x", buf
);
751 snprintf (buf
, sizeof (buf
), "%.12g", (*ii
)->value
);
752 pnode
->add_property ("y", buf
);
753 child
->add_child_nocopy (*pnode
);
756 child
= node
->add_child ("FadeOut");
758 for (AutomationList::iterator ii
= _fade_out
.begin(); ii
!= _fade_out
.end(); ++ii
) {
761 pnode
= new XMLNode ("point");
763 snprintf (buf
, sizeof (buf
), "%" PRId64
, (framepos_t
) floor ((*ii
)->when
));
764 pnode
->add_property ("x", buf
);
765 snprintf (buf
, sizeof (buf
), "%.12g", (*ii
)->value
);
766 pnode
->add_property ("y", buf
);
767 child
->add_child_nocopy (*pnode
);
774 Crossfade::set_state (const XMLNode
& node
, int /*version*/)
776 XMLNodeConstIterator i
;
777 XMLNodeList children
;
780 const XMLProperty
* prop
;
781 LocaleGuard
lg (X_("POSIX"));
782 PropertyChange what_changed
;
785 if ((prop
= node
.property (X_("id")))) {
789 if ((prop
= node
.property ("position")) != 0) {
790 sscanf (prop
->value().c_str(), "%" PRId64
, &val
);
791 if (val
!= _position
) {
793 what_changed
.add (Properties::position
);
796 warning
<< _("old-style crossfade information - no position information") << endmsg
;
797 _position
= _in
->first_frame();
800 if ((prop
= node
.property ("active")) != 0) {
801 bool x
= string_is_affirmative (prop
->value());
804 what_changed
.add (Properties::active
);
810 if ((prop
= node
.property ("follow-overlap")) != 0) {
811 _follow_overlap
= string_is_affirmative (prop
->value());
813 _follow_overlap
= false;
816 if ((prop
= node
.property ("fixed")) != 0) {
817 _fixed
= string_is_affirmative (prop
->value());
822 if ((prop
= node
.property ("anchor-point")) != 0) {
823 _anchor_point
= AnchorPoint (atoi ((prop
->value().c_str())));
825 _anchor_point
= StartOfIn
;
828 if ((prop
= node
.property ("length")) != 0) {
830 sscanf (prop
->value().c_str(), "%" PRId64
, &val
);
831 if (val
!= _length
) {
833 what_changed
.add (Properties::length
);
838 /* XXX this branch is legacy code from before
839 the point where we stored xfade lengths.
842 if ((_length
= overlap_length()) == 0) {
843 throw failed_constructor();
847 if ((fi
= find_named_node (node
, "FadeIn")) == 0) {
851 if ((fo
= find_named_node (node
, "FadeOut")) == 0) {
860 children
= fi
->children();
862 for (i
= children
.begin(); i
!= children
.end(); ++i
) {
863 if ((*i
)->name() == "point") {
867 prop
= (*i
)->property ("x");
868 sscanf (prop
->value().c_str(), "%" PRId64
, &x
);
870 prop
= (*i
)->property ("y");
871 sscanf (prop
->value().c_str(), "%f", &y
);
877 if (_fade_in
.size() < 2) {
878 /* fade state somehow saved with no points */
882 _fade_in
.front()->value
= 0.0;
883 _fade_in
.back()->value
= 1.0;
892 children
= fo
->children();
894 for (i
= children
.begin(); i
!= children
.end(); ++i
) {
895 if ((*i
)->name() == "point") {
900 prop
= (*i
)->property ("x");
901 sscanf (prop
->value().c_str(), "%" PRId64
, &x
);
903 prop
= (*i
)->property ("y");
904 sscanf (prop
->value().c_str(), "%f", &y
);
906 _fade_out
.add (x
, y
);
910 if (_fade_out
.size() < 2) {
911 /* fade state somehow saved with no points */
915 _fade_out
.front()->value
= 1.0;
916 _fade_out
.back()->value
= 0.0;
920 PropertyChanged (what_changed
); /* EMIT SIGNAL */
921 FadesChanged (); /* EMIT SIGNAL */
927 Crossfade::can_follow_overlap () const
933 Crossfade::set_follow_overlap (bool yn
)
935 if (yn
== _follow_overlap
|| _fixed
) {
939 _follow_overlap
= yn
;
942 set_xfade_length (_short_xfade_length
);
944 set_xfade_length (_out
->first_frame() + _out
->length() - _in
->first_frame());
947 PropertyChanged (PropertyChange (Properties::follow_overlap
));
951 Crossfade::set_xfade_length (framecnt_t len
)
953 framecnt_t limit
= 0;
955 switch (_anchor_point
) {
957 limit
= _in
->length();
961 limit
= _in
->length();
965 limit
= _out
->length();
970 len
= min (limit
, len
);
972 double factor
= len
/ (double) _length
;
975 _fade_out
.x_scale (factor
);
976 _fade_in
.x_scale (factor
);
981 PropertyChanged (PropertyChange (Properties::length
));
987 Crossfade::overlap_length () const
992 return _out
->first_frame() + _out
->length() - _in
->first_frame();
996 Crossfade::set_short_xfade_length (framecnt_t n
)
998 _short_xfade_length
= n
;