always create short xfades when adding a region based on capture
[ardour.git] / libs / ardour / audio_playlist.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 */
19
20 #include <algorithm>
21
22 #include <cstdlib>
23
24 #include "ardour/types.h"
25 #include "ardour/debug.h"
26 #include "ardour/audioplaylist.h"
27 #include "ardour/audioregion.h"
28 #include "ardour/region_sorters.h"
29 #include "ardour/session.h"
30
31 #include "i18n.h"
32
33 using namespace ARDOUR;
34 using namespace std;
35 using namespace PBD;
36
37 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
38         : Playlist (session, node, DataType::AUDIO, hidden)
39 {
40 #ifndef NDEBUG
41         const XMLProperty* prop = node.property("type");
42         assert(!prop || DataType(prop->value()) == DataType::AUDIO);
43 #endif
44
45         in_set_state++;
46         if (set_state (node, Stateful::loading_state_version)) {
47                 throw failed_constructor();
48         }
49         in_set_state--;
50
51         relayer ();
52 }
53
54 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
55         : Playlist (session, name, DataType::AUDIO, hidden)
56 {
57 }
58
59 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
60         : Playlist (other, name, hidden)
61 {
62 }
63
64 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, framepos_t start, framecnt_t cnt, string name, bool hidden)
65         : Playlist (other, start, cnt, name, hidden)
66 {
67         RegionReadLock rlock2 (const_cast<AudioPlaylist*> (other.get()));
68         in_set_state++;
69
70         framepos_t const end = start + cnt - 1;
71
72         /* Audio regions that have been created by the Playlist constructor
73            will currently have the same fade in/out as the regions that they
74            were created from.  This is wrong, so reset the fades here.
75         */
76
77         RegionList::iterator ours = regions.begin ();
78
79         for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
80                 boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (*i);
81                 assert (region);
82
83                 framecnt_t fade_in = 64;
84                 framecnt_t fade_out = 64;
85
86                 switch (region->coverage (start, end)) {
87                 case Evoral::OverlapNone:
88                         continue;
89
90                 case Evoral::OverlapInternal:
91                 {
92                         framecnt_t const offset = start - region->position ();
93                         framecnt_t const trim = region->last_frame() - end;
94                         if (region->fade_in()->back()->when > offset) {
95                                 fade_in = region->fade_in()->back()->when - offset;
96                         }
97                         if (region->fade_out()->back()->when > trim) {
98                                 fade_out = region->fade_out()->back()->when - trim;
99                         }
100                         break;
101                 }
102
103                 case Evoral::OverlapStart: {
104                         if (end > region->position() + region->fade_in()->back()->when)
105                                 fade_in = region->fade_in()->back()->when;  //end is after fade-in, preserve the fade-in
106                         if (end > region->last_frame() - region->fade_out()->back()->when)
107                                 fade_out = region->fade_out()->back()->when - ( region->last_frame() - end );  //end is inside the fadeout, preserve the fades endpoint
108                         break;
109                 }
110
111                 case Evoral::OverlapEnd: {
112                         if (start < region->last_frame() - region->fade_out()->back()->when)  //start is before fade-out, preserve the fadeout
113                                 fade_out = region->fade_out()->back()->when;
114
115                         if (start < region->position() + region->fade_in()->back()->when)
116                                 fade_in = region->fade_in()->back()->when - (start - region->position());  //end is inside the fade-in, preserve the fade-in endpoint
117                         break;
118                 }
119
120                 case Evoral::OverlapExternal:
121                         fade_in = region->fade_in()->back()->when;
122                         fade_out = region->fade_out()->back()->when;
123                         break;
124                 }
125
126                 boost::shared_ptr<AudioRegion> our_region = boost::dynamic_pointer_cast<AudioRegion> (*ours);
127                 assert (our_region);
128
129                 our_region->set_fade_in_length (fade_in);
130                 our_region->set_fade_out_length (fade_out);
131                 ++ours;
132         }
133
134         in_set_state--;
135
136         /* this constructor does NOT notify others (session) */
137 }
138
139 /** Sort by descending layer and then by ascending position */
140 struct ReadSorter {
141     bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
142             if (a->layer() != b->layer()) {
143                     return a->layer() > b->layer();
144             }
145
146             return a->position() < b->position();
147     }
148 };
149
150 /** A segment of region that needs to be read */
151 struct Segment {
152         Segment (boost::shared_ptr<AudioRegion> r, Evoral::Range<framepos_t> a) : region (r), range (a) {}
153         
154         boost::shared_ptr<AudioRegion> region; ///< the region
155         Evoral::Range<framepos_t> range;       ///< range of the region to read, in session frames
156 };
157
158 /** @param start Start position in session frames.
159  *  @param cnt Number of frames to read.
160  */
161 ARDOUR::framecnt_t
162 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, framepos_t start,
163                      framecnt_t cnt, unsigned chan_n)
164 {
165         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Playlist %1 read @ %2 for %3, channel %4, regions %5\n",
166                                                            name(), start, cnt, chan_n, regions.size()));
167
168         /* optimizing this memset() away involves a lot of conditionals
169            that may well cause more of a hit due to cache misses
170            and related stuff than just doing this here.
171
172            it would be great if someone could measure this
173            at some point.
174
175            one way or another, parts of the requested area
176            that are not written to by Region::region_at()
177            for all Regions that cover the area need to be
178            zeroed.
179         */
180
181         memset (buf, 0, sizeof (Sample) * cnt);
182
183         /* this function is never called from a realtime thread, so
184            its OK to block (for short intervals).
185         */
186
187         Playlist::RegionReadLock rl (this);
188
189         /* Find all the regions that are involved in the bit we are reading,
190            and sort them by descending layer and ascending position.
191         */
192         boost::shared_ptr<RegionList> all = regions_touched_locked (start, start + cnt - 1);
193         all->sort (ReadSorter ());
194
195         /* This will be a list of the bits of our read range that we have
196            handled completely (ie for which no more regions need to be read).
197            It is a list of ranges in session frames.
198         */
199         Evoral::RangeList<framepos_t> done;
200
201         /* This will be a list of the bits of regions that we need to read */
202         list<Segment> to_do;
203         
204         /* Now go through the `all' list filling in `to_do' and `done' */
205         for (RegionList::iterator i = all->begin(); i != all->end(); ++i) {
206                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (*i);
207
208                 /* Work out which bits of this region need to be read;
209                    first, trim to the range we are reading...
210                 */
211                 Evoral::Range<framepos_t> region_range = ar->range ();
212                 region_range.from = max (region_range.from, start);
213                 region_range.to = min (region_range.to, start + cnt - 1);
214
215                 /* ... and then remove the bits that are already done */
216                 Evoral::RangeList<framepos_t> region_to_do = Evoral::subtract (region_range, done);
217
218                 /* Read those bits, adding their bodies (the parts between end-of-fade-in
219                    and start-of-fade-out) to the `done' list.
220                 */
221
222                 Evoral::RangeList<framepos_t>::List t = region_to_do.get ();
223
224                 for (Evoral::RangeList<framepos_t>::List::iterator j = t.begin(); j != t.end(); ++j) {
225                         Evoral::Range<framepos_t> d = *j;
226                         to_do.push_back (Segment (ar, d));
227
228                         if (ar->opaque ()) {
229                                 /* Cut this range down to just the body and mark it done */
230                                 Evoral::Range<framepos_t> body = ar->body_range ();
231                                 if (body.from < d.to && body.to > d.from) {
232                                         d.from = max (d.from, body.from);
233                                         d.to = min (d.to, body.to);
234                                         done.add (d);
235                                 }
236                         }
237                 }
238         }
239
240         /* Now go backwards through the to_do list doing the actual reads */
241         for (list<Segment>::reverse_iterator i = to_do.rbegin(); i != to_do.rend(); ++i) {
242                 i->region->read_at (buf + i->range.from - start, mixdown_buffer, gain_buffer, i->range.from, i->range.to - i->range.from + 1, chan_n);
243         }
244
245         return cnt;
246 }
247
248 void
249 AudioPlaylist::check_crossfades (Evoral::Range<framepos_t> range)
250 {
251         if (in_set_state || in_partition || !_session.config.get_auto_xfade ()) {
252                 return;
253         }
254         
255         boost::shared_ptr<RegionList> starts = regions_with_start_within (range);
256         boost::shared_ptr<RegionList> ends = regions_with_end_within (range);
257
258         RegionList all = *starts;
259         std::copy (ends->begin(), ends->end(), back_inserter (all));
260
261         all.sort (RegionSortByLayer ());
262
263         set<boost::shared_ptr<Region> > done_start;
264         set<boost::shared_ptr<Region> > done_end;
265
266         for (RegionList::reverse_iterator i = all.rbegin(); i != all.rend(); ++i) {
267                 for (RegionList::reverse_iterator j = all.rbegin(); j != all.rend(); ++j) {
268
269                         if (i == j) {
270                                 continue;
271                         }
272
273                         if ((*i)->muted() || (*j)->muted()) {
274                                 continue;
275                         }
276
277                         if ((*i)->position() == (*j)->position() && ((*i)->length() == (*j)->length())) {
278                                 /* precise overlay: no xfade */
279                                 continue;
280                         }
281
282                         if ((*i)->position() == (*j)->position() || ((*i)->last_frame() == (*j)->last_frame())) {
283                                 /* starts or ends match: no xfade */
284                                 continue;
285                         }
286                         
287                         boost::shared_ptr<AudioRegion> top;
288                         boost::shared_ptr<AudioRegion> bottom;
289                 
290                         if ((*i)->layer() < (*j)->layer()) {
291                                 top = boost::dynamic_pointer_cast<AudioRegion> (*j);
292                                 bottom = boost::dynamic_pointer_cast<AudioRegion> (*i);
293                         } else {
294                                 top = boost::dynamic_pointer_cast<AudioRegion> (*i);
295                                 bottom = boost::dynamic_pointer_cast<AudioRegion> (*j);
296                         }
297                         
298                         if (!top->opaque ()) {
299                                 continue;
300                         }
301
302                         Evoral::OverlapType const c = top->coverage (bottom->position(), bottom->last_frame());
303                         
304                         if (c == Evoral::OverlapStart) {
305                                 
306                                 /* top starts within bottom but covers bottom's end */
307                                 
308                                 /*                   { ==== top ============ } 
309                                  *   [---- bottom -------------------] 
310                                  */
311
312                                 if (done_start.find (top) == done_start.end() && done_end.find (bottom) == done_end.end ()) {
313
314                                         /* Top's fade-in will cause an implicit fade-out of bottom */
315                                         
316                                         framecnt_t len = 0;
317
318                                         if (_capture_insertion_underway) {
319                                                 len = _session.config.get_short_xfade_seconds() * _session.frame_rate();
320                                         } else {
321                                                 switch (_session.config.get_xfade_model()) {
322                                                 case FullCrossfade:
323                                                         len = bottom->last_frame () - top->first_frame ();
324                                                         break;
325                                                 case ShortCrossfade:
326                                                         len = _session.config.get_short_xfade_seconds() * _session.frame_rate();
327                                                         break;
328                                                 }
329                                         }
330                                         
331                                         top->set_fade_in_active (true);
332                                         top->set_fade_in_is_xfade (true);
333
334                                         /* XXX may 2012: -3dB and -6dB curves
335                                          * are the same right now 
336                                          */
337
338                                         switch (_session.config.get_xfade_choice ()) {
339                                         case ConstantPowerMinus3dB:
340                                                 top->set_fade_in (FadeConstantPower, len);
341                                                 break;
342                                         case ConstantPowerMinus6dB:
343                                                 top->set_fade_in (FadeConstantPower, len);
344                                                 break;
345                                         case RegionFades:
346                                                 top->set_fade_in_length (len);
347                                                 break;
348                                         }
349                                         
350                                         done_start.insert (top);
351                                 }
352
353                         } else if (c == Evoral::OverlapEnd) {
354                                 
355                                 /* top covers start of bottom but ends within it */
356                                 
357                                 /* [---- top ------------------------] 
358                                  *                { ==== bottom ============ } 
359                                  */
360
361                                 if (done_end.find (top) == done_end.end() && done_start.find (bottom) == done_start.end ()) {
362                                         /* Top's fade-out will cause an implicit fade-in of bottom */
363                                         
364                                         framecnt_t len = 0;
365
366                                         if (_capture_insertion_underway) {
367                                                 len = _session.config.get_short_xfade_seconds() * _session.frame_rate();
368                                         } else {
369                                                 switch (_session.config.get_xfade_model()) {
370                                                 case FullCrossfade:
371                                                         len = top->last_frame () - bottom->first_frame ();
372                                                         break;
373                                                 case ShortCrossfade:
374                                                         len = _session.config.get_short_xfade_seconds() * _session.frame_rate();
375                                                         break;
376                                                 }
377                                         }
378                                         
379                                         top->set_fade_out_active (true);
380                                         top->set_fade_out_is_xfade (true);
381
382                                         switch (_session.config.get_xfade_choice ()) {
383                                         case ConstantPowerMinus3dB:
384                                                 top->set_fade_out (FadeConstantPower, len);
385                                                 break;
386                                         case ConstantPowerMinus6dB:
387                                                 top->set_fade_out (FadeConstantPower, len);
388                                                 break;
389                                         case RegionFades:
390                                                 top->set_fade_out_length (len);
391                                                 break;
392                                         }
393
394                                         done_end.insert (top);
395                                 }
396                         }
397                 }
398         }
399
400         for (RegionList::iterator i = starts->begin(); i != starts->end(); ++i) {
401                 if (done_start.find (*i) == done_start.end()) {
402                         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (*i);
403                         r->set_default_fade_in ();
404                 }
405         }
406
407         for (RegionList::iterator i = ends->begin(); i != ends->end(); ++i) {
408                 if (done_end.find (*i) == done_end.end()) {
409                         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (*i);
410                         r->set_default_fade_out ();
411                 }
412         }
413 }
414
415 void
416 AudioPlaylist::dump () const
417 {
418         boost::shared_ptr<Region>r;
419
420         cerr << "Playlist \"" << _name << "\" " << endl
421              << regions.size() << " regions "
422              << endl;
423
424         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
425                 r = *i;
426                 cerr << "  " << r->name() << " @ " << r << " ["
427                      << r->start() << "+" << r->length()
428                      << "] at "
429                      << r->position()
430                      << " on layer "
431                      << r->layer ()
432                      << endl;
433         }
434 }
435
436 bool
437 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
438 {
439         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
440
441         if (!r) {
442                 return false;
443         }
444
445         bool changed = false;
446
447         {
448                 RegionWriteLock rlock (this);
449
450                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
451
452                         RegionList::iterator tmp = i;
453                         ++tmp;
454
455                         if ((*i) == region) {
456                                 regions.erase (i);
457                                 changed = true;
458                         }
459
460                         i = tmp;
461                 }
462
463                 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
464
465                         set<boost::shared_ptr<Region> >::iterator xtmp = x;
466                         ++xtmp;
467
468                         if ((*x) == region) {
469                                 all_regions.erase (x);
470                                 changed = true;
471                         }
472
473                         x = xtmp;
474                 }
475
476                 region->set_playlist (boost::shared_ptr<Playlist>());
477         }
478
479         if (changed) {
480                 /* overload this, it normally means "removed", not destroyed */
481                 notify_region_removed (region);
482         }
483
484         return changed;
485 }
486
487 bool
488 AudioPlaylist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
489 {
490         if (in_flush || in_set_state) {
491                 return false;
492         }
493
494         PropertyChange our_interests;
495
496         our_interests.add (Properties::fade_in_active);
497         our_interests.add (Properties::fade_out_active);
498         our_interests.add (Properties::scale_amplitude);
499         our_interests.add (Properties::envelope_active);
500         our_interests.add (Properties::envelope);
501         our_interests.add (Properties::fade_in);
502         our_interests.add (Properties::fade_out);
503
504         bool parent_wants_notify;
505
506         parent_wants_notify = Playlist::region_changed (what_changed, region);
507
508         if (parent_wants_notify || (what_changed.contains (our_interests))) {
509                 notify_contents_changed ();
510         }
511
512         return true;
513 }
514
515 void
516 AudioPlaylist::pre_combine (vector<boost::shared_ptr<Region> >& copies)
517 {
518         RegionSortByPosition cmp;
519         boost::shared_ptr<AudioRegion> ar;
520
521         sort (copies.begin(), copies.end(), cmp);
522
523         ar = boost::dynamic_pointer_cast<AudioRegion> (copies.front());
524
525         /* disable fade in of the first region */
526
527         if (ar) {
528                 ar->set_fade_in_active (false);
529         }
530
531         ar = boost::dynamic_pointer_cast<AudioRegion> (copies.back());
532
533         /* disable fade out of the last region */
534
535         if (ar) {
536                 ar->set_fade_out_active (false);
537         }
538 }
539
540 void
541 AudioPlaylist::post_combine (vector<boost::shared_ptr<Region> >& originals, boost::shared_ptr<Region> compound_region)
542 {
543         RegionSortByPosition cmp;
544         boost::shared_ptr<AudioRegion> ar;
545         boost::shared_ptr<AudioRegion> cr;
546
547         if ((cr = boost::dynamic_pointer_cast<AudioRegion> (compound_region)) == 0) {
548                 return;
549         }
550
551         sort (originals.begin(), originals.end(), cmp);
552
553         ar = boost::dynamic_pointer_cast<AudioRegion> (originals.front());
554
555         /* copy the fade in of the first into the compound region */
556
557         if (ar) {
558                 cr->set_fade_in (ar->fade_in());
559         }
560
561         ar = boost::dynamic_pointer_cast<AudioRegion> (originals.back());
562
563         if (ar) {
564                 /* copy the fade out of the last into the compound region */
565                 cr->set_fade_out (ar->fade_out());
566         }
567 }
568
569 void
570 AudioPlaylist::pre_uncombine (vector<boost::shared_ptr<Region> >& originals, boost::shared_ptr<Region> compound_region)
571 {
572         RegionSortByPosition cmp;
573         boost::shared_ptr<AudioRegion> ar;
574         boost::shared_ptr<AudioRegion> cr = boost::dynamic_pointer_cast<AudioRegion>(compound_region);
575
576         if (!cr) {
577                 return;
578         }
579
580         sort (originals.begin(), originals.end(), cmp);
581
582         /* no need to call clear_changes() on the originals because that is
583          * done within Playlist::uncombine ()
584          */
585
586         for (vector<boost::shared_ptr<Region> >::iterator i = originals.begin(); i != originals.end(); ++i) {
587
588                 if ((ar = boost::dynamic_pointer_cast<AudioRegion> (*i)) == 0) {
589                         continue;
590                 }
591
592                 /* scale the uncombined regions by any gain setting for the
593                  * compound one.
594                  */
595
596                 ar->set_scale_amplitude (ar->scale_amplitude() * cr->scale_amplitude());
597
598                 if (i == originals.begin()) {
599
600                         /* copy the compound region's fade in back into the first
601                            original region.
602                         */
603
604                         if (cr->fade_in()->back()->when <= ar->length()) {
605                                 /* don't do this if the fade is longer than the
606                                  * region
607                                  */
608                                 ar->set_fade_in (cr->fade_in());
609                         }
610
611
612                 } else if (*i == originals.back()) {
613
614                         /* copy the compound region's fade out back into the last
615                            original region.
616                         */
617
618                         if (cr->fade_out()->back()->when <= ar->length()) {
619                                 /* don't do this if the fade is longer than the
620                                  * region
621                                  */
622                                 ar->set_fade_out (cr->fade_out());
623                         }
624
625                 }
626
627                 _session.add_command (new StatefulDiffCommand (*i));
628         }
629 }
630
631 int
632 AudioPlaylist::set_state (const XMLNode& node, int version)
633 {
634         int const r = Playlist::set_state (node, version);
635         if (r) {
636                 return r;
637         }
638
639         /* Read legacy Crossfade nodes and set up region fades accordingly */
640
641         XMLNodeList children = node.children ();
642         for (XMLNodeConstIterator i = children.begin(); i != children.end(); ++i) {
643                 if ((*i)->name() == X_("Crossfade")) {
644
645                         XMLProperty* p = (*i)->property (X_("active"));
646                         assert (p);
647                         if (!string_is_affirmative (p->value())) {
648                                 continue;
649                         }
650
651                         p = (*i)->property (X_("in"));
652                         assert (p);
653                         boost::shared_ptr<Region> in = region_by_id (PBD::ID (p->value ()));
654                         assert (in);
655                         boost::shared_ptr<AudioRegion> in_a = boost::dynamic_pointer_cast<AudioRegion> (in);
656                         assert (in_a);
657
658                         p = (*i)->property (X_("out"));
659                         assert (p);
660                         boost::shared_ptr<Region> out = region_by_id (PBD::ID (p->value ()));
661                         assert (out);
662                         boost::shared_ptr<AudioRegion> out_a = boost::dynamic_pointer_cast<AudioRegion> (out);
663                         assert (out_a);
664
665                         XMLNodeList c = (*i)->children ();
666                         for (XMLNodeConstIterator j = c.begin(); j != c.end(); ++j) {
667                                 if ((*j)->name() == X_("FadeIn")) {
668                                         in_a->fade_in()->set_state (**j, version);
669                                         in_a->set_fade_in_active (true);
670                                 } else if ((*j)->name() == X_("FadeOut")) {
671                                         out_a->fade_out()->set_state (**j, version);
672                                         out_a->set_fade_out_active (true);
673                                 }
674                         }
675                 }
676         }
677
678         return 0;
679 }