virtualize audioregion, make crossfade IS-A audioregion
[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 <sigc++/bind.h>
25
26 #include <ardour/types.h>
27 #include <ardour/configuration.h>
28 #include <ardour/audioplaylist.h>
29 #include <ardour/audioregion.h>
30 #include <ardour/crossfade.h>
31 #include <ardour/crossfade_compare.h>
32 #include <ardour/session.h>
33 #include <pbd/enumwriter.h>
34
35 #include "i18n.h"
36
37 using namespace ARDOUR;
38 using namespace sigc;
39 using namespace std;
40 using namespace PBD;
41
42 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
43         : Playlist (session, node, DataType::AUDIO, hidden)
44 {
45         const XMLProperty* prop = node.property("type");
46         assert(!prop || DataType(prop->value()) == DataType::AUDIO);
47
48         in_set_state++;
49         set_state (node);
50         in_set_state--;
51 }
52
53 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
54         : Playlist (session, name, DataType::AUDIO, hidden)
55 {
56 }
57
58 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
59         : Playlist (other, name, hidden)
60 {
61         RegionList::const_iterator in_o  = other->regions.begin();
62         RegionList::iterator in_n = regions.begin();
63
64         while (in_o != other->regions.end()) {
65                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
66
67                 // We look only for crossfades which begin with the current region, so we don't get doubles
68                 for (Crossfades::const_iterator xfades = other->_crossfades.begin(); xfades != other->_crossfades.end(); ++xfades) {
69                         if ((*xfades)->in() == ar) {
70                                 // We found one! Now copy it!
71
72                                 RegionList::const_iterator out_o = other->regions.begin();
73                                 RegionList::const_iterator out_n = regions.begin();
74
75                                 while (out_o != other->regions.end()) {
76                                         
77                                         boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
78                                         
79                                         if ((*xfades)->out() == ar2) {
80                                                 boost::shared_ptr<AudioRegion>in  = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
81                                                 boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
82                                                 boost::shared_ptr<Crossfade> new_fade = boost::shared_ptr<Crossfade> (new Crossfade (*xfades, in, out));
83                                                 add_crossfade(new_fade);
84                                                 break;
85                                         }
86                                         
87                                         out_o++;
88                                         out_n++;
89                                 }
90 //                              cerr << "HUH!? second region in the crossfade not found!" << endl;
91                         }
92                 }
93
94                 in_o++;
95                 in_n++;
96         }
97 }
98
99 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
100         : Playlist (other, start, cnt, name, hidden)
101 {
102         /* this constructor does NOT notify others (session) */
103 }
104
105 AudioPlaylist::~AudioPlaylist ()
106 {
107         GoingAway (); /* EMIT SIGNAL */
108
109         /* drop connections to signals */
110
111         notify_callbacks ();
112         
113         _crossfades.clear ();
114 }
115
116 struct RegionSortByLayer {
117     bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
118             return a->layer() < b->layer();
119     }
120 };
121
122 ARDOUR::nframes_t
123 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
124                      nframes_t cnt, unsigned chan_n)
125 {
126         nframes_t ret = cnt;
127         nframes_t end;
128
129         /* optimizing this memset() away involves a lot of conditionals
130            that may well cause more of a hit due to cache misses 
131            and related stuff than just doing this here.
132            
133            it would be great if someone could measure this
134            at some point.
135
136            one way or another, parts of the requested area
137            that are not written to by Region::region_at()
138            for all Regions that cover the area need to be
139            zeroed.
140         */
141
142         memset (buf, 0, sizeof (Sample) * cnt);
143
144         /* this function is never called from a realtime thread, so 
145            its OK to block (for short intervals).
146         */
147
148         Glib::Mutex::Lock rm (region_lock);
149
150         end =  start + cnt - 1;
151
152         _read_data_count = 0;
153
154         map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
155         map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
156         vector<uint32_t> relevant_layers;
157
158         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
159                 if ((*i)->coverage (start, end) != OverlapNone) {
160                         relevant_regions[(*i)->layer()].push_back (*i);
161                         relevant_layers.push_back ((*i)->layer());
162                 }
163         }
164
165         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
166                 if ((*i)->coverage (start, end) != OverlapNone) {
167                         relevant_xfades[(*i)->upper_layer()].push_back (*i);
168                 }
169         }
170
171 //      RegionSortByLayer layer_cmp;
172 //      relevant_regions.sort (layer_cmp);
173
174         /* XXX this whole per-layer approach is a hack that
175            should be removed once Crossfades become
176            CrossfadeRegions and we just grab a list of relevant
177            regions and call read_at() on all of them.
178         */
179
180         sort (relevant_layers.begin(), relevant_layers.end());
181
182         for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
183
184                 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
185                 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
186
187                 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
188                         boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
189                         assert(ar);
190                         ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
191                         _read_data_count += ar->read_data_count();
192                 }
193                 
194                 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
195                         (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
196
197                         /* don't JACK up _read_data_count, since its the same data as we just
198                            read from the regions, and the OS should handle that for us.
199                         */
200                 }
201         }
202
203         return ret;
204 }
205
206
207 void
208 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
209 {
210         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
211
212         if (in_set_state) {
213                 return;
214         }
215         
216         if (r == 0) {
217                 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
218                       << endmsg;
219                 return;
220         }
221
222         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
223                 
224                 if ((*i)->involves (r)) {
225                         i = _crossfades.erase (i);
226                 } else {
227                         ++i;
228                 }
229         }
230 }
231
232
233 void
234 AudioPlaylist::flush_notifications ()
235 {
236         Playlist::flush_notifications();
237
238         if (in_flush) {
239                 return;
240         }
241
242         in_flush = true;
243
244         Crossfades::iterator a;
245         for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
246                 NewCrossfade (*a); /* EMIT SIGNAL */
247         }
248
249         _pending_xfade_adds.clear ();
250         
251         in_flush = false;
252 }
253
254 void
255 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
256 {
257         boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
258         set<boost::shared_ptr<Crossfade> > updated;
259
260         if (ar == 0) {
261                 return;
262         }
263
264         for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
265
266                 Crossfades::iterator tmp;
267                 
268                 tmp = x;
269                 ++tmp;
270
271                 /* only update them once */
272
273                 if ((*x)->involves (ar)) {
274
275                         if (find (updated.begin(), updated.end(), *x) == updated.end()) {
276                                 try { 
277                                         if ((*x)->refresh ()) {
278                                                 updated.insert (*x);
279                                         }
280                                 }
281
282                                 catch (Crossfade::NoCrossfadeHere& err) {
283                                         // relax, Invalidated during refresh
284                                 }
285                         }
286                 }
287
288                 x = tmp;
289         }
290 }
291
292 void
293 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
294 {
295         boost::shared_ptr<AudioRegion> orig  = boost::dynamic_pointer_cast<AudioRegion>(o);
296         boost::shared_ptr<AudioRegion> left  = boost::dynamic_pointer_cast<AudioRegion>(l);
297         boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
298
299         for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
300                 Crossfades::iterator tmp;
301                 tmp = x;
302                 ++tmp;
303
304                 boost::shared_ptr<Crossfade> fade;
305                 
306                 if ((*x)->_in == orig) {
307                         if (! (*x)->covers(right->position())) {
308                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, left, (*x)->_out));
309                         } else {
310                                 // Overlap, the crossfade is copied on the left side of the right region instead
311                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, right, (*x)->_out));
312                         }
313                 }
314                 
315                 if ((*x)->_out == orig) {
316                         if (! (*x)->covers(right->position())) {
317                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, right));
318                         } else {
319                                 // Overlap, the crossfade is copied on the right side of the left region instead
320                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, left));
321                         }
322                 }
323                 
324                 if (fade) {
325                         _crossfades.remove (*x);
326                         add_crossfade (fade);
327                 }
328                 x = tmp;
329         }
330 }
331
332 void
333 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
334 {
335         boost::shared_ptr<AudioRegion> other;
336         boost::shared_ptr<AudioRegion> region;
337         boost::shared_ptr<AudioRegion> top;
338         boost::shared_ptr<AudioRegion> bottom;
339         boost::shared_ptr<Crossfade>   xfade;
340
341         if (in_set_state || in_partition) {
342                 return;
343         }
344
345         if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
346                 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
347                       << endmsg;
348                 return;
349         }
350
351         if (!norefresh) {
352                 refresh_dependents (r);
353         }
354
355
356         if (!Config->get_auto_xfade()) {
357                 return;
358         }
359
360         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
361
362                 nframes_t xfade_length;
363
364                 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
365
366                 if (other == region) {
367                         continue;
368                 }
369
370                 if (other->muted() || region->muted()) {
371                         continue;
372                 }
373                 
374
375                 if (other->layer() < region->layer()) {
376                         top = region;
377                         bottom = other;
378                 } else {
379                         top = other;
380                         bottom = region;
381                 }
382
383
384
385                 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
386
387                 try {
388                         switch (c) {
389                         case OverlapNone:
390                                 break;
391
392                         case OverlapInternal:
393                                  /* {=============== top  =============}
394                                   *     [ ----- bottom  ------- ]
395                                   */
396                                 break;
397
398                         case OverlapExternal:
399
400                                 /*     [ -------- top ------- ]
401                                  * {=========== bottom =============}
402                                  */
403                                 
404                                 /* to avoid discontinuities at the region boundaries of an internal
405                                    overlap (this region is completely within another), we create
406                                    two hidden crossfades at each boundary. this is not dependent
407                                    on the auto-xfade option, because we require it as basic
408                                    audio engineering.
409                                 */
410                                 
411                                 xfade_length = min ((nframes_t) 720, top->length());
412                                 
413                                 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
414                                 add_crossfade (xfade);
415
416                                 if (top_region_at (top->last_frame() - 1) == top) {
417                                         /* 
418                                            only add a fade out if there is no region on top of the end of 'top' (which 
419                                            would cover it).
420                                         */
421                                         
422                                         xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
423                                         add_crossfade (xfade);
424                                 }
425                                 break;
426                                 
427                         default:
428                                 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active()));
429                                 add_crossfade (xfade);
430                         }
431                 }
432
433                 catch (failed_constructor& err) {
434                         continue;
435                 }
436                 
437                 catch (Crossfade::NoCrossfadeHere& err) {
438                         continue;
439                 }
440                 
441         }
442 }
443
444 void
445 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
446 {
447         Crossfades::iterator ci;
448
449         for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
450                 if (*(*ci) == *xfade) { // Crossfade::operator==()
451                         break;
452                 }
453         }
454         
455         if (ci != _crossfades.end()) {
456                 // it will just go away
457         } else {
458                 _crossfades.push_back (xfade);
459
460                 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
461                 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
462
463                 notify_crossfade_added (xfade);
464         }
465 }
466         
467 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
468 {
469         if (g_atomic_int_get(&block_notifications)) {
470                 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
471         } else {
472                 NewCrossfade (x); /* EMIT SIGNAL */
473         }
474 }
475
476 void
477 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
478 {
479         Crossfades::iterator i;
480         boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
481
482         xfade->in()->resume_fade_in ();
483         xfade->out()->resume_fade_out ();
484
485         if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
486                 _crossfades.erase (i);
487         }
488 }
489
490 int
491 AudioPlaylist::set_state (const XMLNode& node)
492 {
493         XMLNode *child;
494         XMLNodeList nlist;
495         XMLNodeConstIterator niter;
496
497         in_set_state++;
498         freeze ();
499
500         Playlist::set_state (node);
501
502         nlist = node.children();
503
504         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
505
506                 child = *niter;
507
508                 if (child->name() != "Crossfade") {
509                         continue;
510                 }
511
512                 try {
513                         boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
514                         _crossfades.push_back (xfade);
515                         xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
516                         xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
517                         NewCrossfade(xfade);
518                 }
519                 
520                 catch (failed_constructor& err) {
521                         //      cout << string_compose (_("could not create crossfade object in playlist %1"),
522                         //        _name) 
523                         //    << endl;
524                         continue;
525                 }
526         }
527
528         thaw ();
529         in_set_state--;
530
531         return 0;
532 }
533
534 void
535 AudioPlaylist::clear (bool with_signals)
536 {
537         _crossfades.clear ();
538         Playlist::clear (with_signals);
539 }
540
541 XMLNode&
542 AudioPlaylist::state (bool full_state)
543 {
544         XMLNode& node = Playlist::state (full_state);
545
546         if (full_state) {
547                 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
548                         node.add_child_nocopy ((*i)->get_state());
549                 }
550         }
551         
552         return node;
553 }
554
555 void
556 AudioPlaylist::dump () const
557 {
558         boost::shared_ptr<Region>r;
559         boost::shared_ptr<Crossfade> x;
560
561         cerr << "Playlist \"" << _name << "\" " << endl
562              << regions.size() << " regions "
563              << _crossfades.size() << " crossfades"
564              << endl;
565
566         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
567                 r = *i;
568                 cerr << "  " << r->name() << " @ " << r << " [" 
569                      << r->start() << "+" << r->length() 
570                      << "] at " 
571                      << r->position()
572                      << " on layer "
573                      << r->layer ()
574                      << endl;
575         }
576
577         for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
578                 x = *i;
579                 cerr << "  xfade [" 
580                      << x->out()->name()
581                      << ','
582                      << x->in()->name()
583                      << " @ "
584                      << x->position()
585                      << " length = " 
586                      << x->length ()
587                      << " active ? "
588                      << (x->active() ? "yes" : "no")
589                      << endl;
590         }
591 }
592
593 bool
594 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
595 {
596         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
597         bool changed = false;
598         Crossfades::iterator c, ctmp;
599         set<boost::shared_ptr<Crossfade> > unique_xfades;
600
601         if (r == 0) {
602                 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
603                       << endmsg;
604                 /*NOTREACHED*/
605                 return false;
606         }
607
608         { 
609                 RegionLock rlock (this);
610
611                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
612                         
613                         RegionList::iterator tmp = i;
614                         ++tmp;
615                         
616                         if ((*i) == region) {
617                                 regions.erase (i);
618                                 changed = true;
619                         }
620                         
621                         i = tmp;
622                 }
623
624                 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
625
626                         set<boost::shared_ptr<Region> >::iterator xtmp = x;
627                         ++xtmp;
628                         
629                         if ((*x) == region) {
630                                 all_regions.erase (x);
631                                 changed = true;
632                         }
633                         
634                         x = xtmp;
635                 }
636
637                 region->set_playlist (boost::shared_ptr<Playlist>());
638         }
639
640         for (c = _crossfades.begin(); c != _crossfades.end(); ) {
641                 ctmp = c;
642                 ++ctmp;
643
644                 if ((*c)->involves (r)) {
645                         unique_xfades.insert (*c);
646                         _crossfades.erase (c);
647                 }
648                 
649                 c = ctmp;
650         }
651
652         if (changed) {
653                 /* overload this, it normally means "removed", not destroyed */
654                 notify_region_removed (region);
655         }
656
657         return changed;
658 }
659
660 void
661 AudioPlaylist::crossfade_changed (Change ignored)
662 {
663         if (in_flush || in_set_state) {
664                 return;
665         }
666
667         /* XXX is there a loop here? can an xfade change not happen
668            due to a playlist change? well, sure activation would
669            be an example. maybe we should check the type of change
670            that occured.
671         */
672
673         notify_modified ();
674 }
675
676 bool
677 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
678 {
679         if (in_flush || in_set_state) {
680                 return false;
681         }
682
683         Change our_interests = Change (AudioRegion::FadeInChanged|
684                                        AudioRegion::FadeOutChanged|
685                                        AudioRegion::FadeInActiveChanged|
686                                        AudioRegion::FadeOutActiveChanged|
687                                        AudioRegion::EnvelopeActiveChanged|
688                                        AudioRegion::ScaleAmplitudeChanged|
689                                        AudioRegion::EnvelopeChanged);
690         bool parent_wants_notify;
691
692         parent_wants_notify = Playlist::region_changed (what_changed, region);
693
694         if ((parent_wants_notify || (what_changed & our_interests))) {
695                 notify_modified ();
696         }
697
698         return true; 
699 }
700
701 void
702 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
703 {
704         RegionLock rlock (this);
705
706         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
707                 nframes_t start, end;
708
709                 start = (*i)->position();
710                 end = start + (*i)->overlap_length(); // not length(), important difference
711
712                 if (frame >= start && frame <= end) {
713                         clist.push_back (*i);
714                 } 
715         }
716 }
717