merged with 1697 revision of trunk (which is post-rc1 but pre-rc2
[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
34 #include "i18n.h"
35
36 using namespace ARDOUR;
37 using namespace sigc;
38 using namespace std;
39 using namespace PBD;
40
41 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
42         : Playlist (session, node, hidden)
43 {
44         in_set_state++;
45         set_state (node);
46         in_set_state--;
47 }
48
49 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
50         : Playlist (session, name, hidden)
51 {
52 }
53
54 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
55         : Playlist (other, name, hidden)
56 {
57         RegionList::const_iterator in_o  = other->regions.begin();
58         RegionList::iterator in_n = regions.begin();
59
60         while (in_o != other->regions.end()) {
61                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
62
63                 // We look only for crossfades which begin with the current region, so we don't get doubles
64                 for (Crossfades::const_iterator xfades = other->_crossfades.begin(); xfades != other->_crossfades.end(); ++xfades) {
65                         if ((*xfades)->in() == ar) {
66                                 // We found one! Now copy it!
67
68                                 RegionList::const_iterator out_o = other->regions.begin();
69                                 RegionList::const_iterator out_n = regions.begin();
70
71                                 while (out_o != other->regions.end()) {
72                                         
73                                         boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
74                                         
75                                         if ((*xfades)->out() == ar2) {
76                                                 boost::shared_ptr<AudioRegion>in  = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
77                                                 boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
78                                                 boost::shared_ptr<Crossfade> new_fade = boost::shared_ptr<Crossfade> (new Crossfade (*(*xfades), in, out));
79                                                 add_crossfade(new_fade);
80                                                 break;
81                                         }
82                                         
83                                         out_o++;
84                                         out_n++;
85                                 }
86 //                              cerr << "HUH!? second region in the crossfade not found!" << endl;
87                         }
88                 }
89
90                 in_o++;
91                 in_n++;
92         }
93 }
94
95 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
96         : Playlist (other, start, cnt, name, hidden)
97 {
98         /* this constructor does NOT notify others (session) */
99 }
100
101 AudioPlaylist::~AudioPlaylist ()
102 {
103         GoingAway (); /* EMIT SIGNAL */
104
105         /* drop connections to signals */
106
107         notify_callbacks ();
108
109         _crossfades.clear ();
110 }
111
112 struct RegionSortByLayer {
113     bool operator() (boost::shared_ptr<Region>a, boost::shared_ptr<Region>b) {
114             return a->layer() < b->layer();
115     }
116 };
117
118 nframes_t
119 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
120                      nframes_t cnt, unsigned chan_n)
121 {
122         nframes_t ret = cnt;
123         nframes_t end;
124         nframes_t read_frames;
125         nframes_t skip_frames;
126
127         /* optimizing this memset() away involves a lot of conditionals
128            that may well cause more of a hit due to cache misses 
129            and related stuff than just doing this here.
130            
131            it would be great if someone could measure this
132            at some point.
133
134            one way or another, parts of the requested area
135            that are not written to by Region::region_at()
136            for all Regions that cover the area need to be
137            zeroed.
138         */
139
140         memset (buf, 0, sizeof (Sample) * cnt);
141
142         /* this function is never called from a realtime thread, so 
143            its OK to block (for short intervals).
144         */
145
146         Glib::Mutex::Lock rm (region_lock);
147
148         end =  start + cnt - 1;
149
150         read_frames = 0;
151         skip_frames = 0;
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, read_frames, skip_frames);
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                 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
385
386                 try {
387                         switch (c) {
388                         case OverlapNone:
389                                 break;
390
391                         case OverlapInternal:
392                                  /* {=============== top  =============}
393                                   *     [ ----- bottom  ------- ]
394                                   */
395                                 break;
396
397                         case OverlapExternal:
398
399                                 /*     [ -------- top ------- ]
400                                  * {=========== bottom =============}
401                                  */
402                                 
403                                 /* to avoid discontinuities at the region boundaries of an internal
404                                    overlap (this region is completely within another), we create
405                                    two hidden crossfades at each boundary. this is not dependent
406                                    on the auto-xfade option, because we require it as basic
407                                    audio engineering.
408                                 */
409                                 
410                                 xfade_length = min ((nframes_t) 720, top->length());
411                                 
412                                 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
413                                 add_crossfade (xfade);
414                                 
415                                 if (top_region_at (top->last_frame() - 1) == top) {
416                                         /* 
417                                            only add a fade out if there is no region on top of the end of 'top' (which 
418                                            would cover it).
419                                         */
420                                         
421                                         xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
422                                         add_crossfade (xfade);
423                                 }
424                                 break;
425                                 
426                         default:
427                                 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active()));
428                                 add_crossfade (xfade);
429                         }
430                 }
431
432                 catch (failed_constructor& err) {
433                         continue;
434                 }
435                 
436                 catch (Crossfade::NoCrossfadeHere& err) {
437                         continue;
438                 }
439                 
440         }
441 }
442
443 void
444 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
445 {
446         Crossfades::iterator ci;
447
448         for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
449                 if (*(*ci) == *xfade) { // Crossfade::operator==()
450                         break;
451                 }
452         }
453         
454         if (ci != _crossfades.end()) {
455                 // it will just go away
456         } else {
457                 _crossfades.push_back (xfade);
458
459                 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
460                 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
461
462                 notify_crossfade_added (xfade);
463         }
464 }
465         
466 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
467 {
468         if (g_atomic_int_get(&block_notifications)) {
469                 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
470         } else {
471                 NewCrossfade (x); /* EMIT SIGNAL */
472         }
473 }
474
475 void
476 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Crossfade> xfade)
477 {
478         Crossfades::iterator i;
479
480         xfade->in()->resume_fade_in ();
481         xfade->out()->resume_fade_out ();
482
483         if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
484                 _crossfades.erase (i);
485         }
486 }
487
488 int
489 AudioPlaylist::set_state (const XMLNode& node)
490 {
491         XMLNode *child;
492         XMLNodeList nlist;
493         XMLNodeConstIterator niter;
494
495         in_set_state++;
496         freeze ();
497
498         Playlist::set_state (node);
499
500         nlist = node.children();
501
502         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
503
504                 child = *niter;
505
506                 if (child->name() != "Crossfade") {
507                         continue;
508                 }
509
510                 try {
511                         boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
512                         _crossfades.push_back (xfade);
513                         xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
514                         xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
515                         NewCrossfade(xfade);
516                 }
517                 
518                 catch (failed_constructor& err) {
519                         //      cout << string_compose (_("could not create crossfade object in playlist %1"),
520                         //        _name) 
521                         //    << endl;
522                         continue;
523                 }
524         }
525
526         thaw ();
527         in_set_state--;
528
529         return 0;
530 }
531
532 void
533 AudioPlaylist::clear (bool with_signals)
534 {
535         _crossfades.clear ();
536         Playlist::clear (with_signals);
537 }
538
539 XMLNode&
540 AudioPlaylist::state (bool full_state)
541 {
542         XMLNode& node = Playlist::state (full_state);
543
544         if (full_state) {
545                 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
546                         node.add_child_nocopy ((*i)->get_state());
547                 }
548         }
549         
550         return node;
551 }
552
553 void
554 AudioPlaylist::dump () const
555 {
556         boost::shared_ptr<Region>r;
557         boost::shared_ptr<Crossfade> x;
558
559         cerr << "Playlist \"" << _name << "\" " << endl
560              << regions.size() << " regions "
561              << _crossfades.size() << " crossfades"
562              << endl;
563
564         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
565                 r = *i;
566                 cerr << "  " << r->name() << " @ " << r << " [" 
567                      << r->start() << "+" << r->length() 
568                      << "] at " 
569                      << r->position()
570                      << " on layer "
571                      << r->layer ()
572                      << endl;
573         }
574
575         for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
576                 x = *i;
577                 cerr << "  xfade [" 
578                      << x->out()->name()
579                      << ','
580                      << x->in()->name()
581                      << " @ "
582                      << x->position()
583                      << " length = " 
584                      << x->length ()
585                      << " active ? "
586                      << (x->active() ? "yes" : "no")
587                      << endl;
588         }
589 }
590
591 bool
592 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
593 {
594         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
595         bool changed = false;
596         Crossfades::iterator c, ctmp;
597         set<boost::shared_ptr<Crossfade> > unique_xfades;
598
599         if (r == 0) {
600                 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
601                       << endmsg;
602                 /*NOTREACHED*/
603                 return false;
604         }
605
606         { 
607                 RegionLock rlock (this);
608
609                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
610                         
611                         RegionList::iterator tmp = i;
612                         ++tmp;
613                         
614                         if ((*i) == region) {
615                                 regions.erase (i);
616                                 changed = true;
617                         }
618                         
619                         i = tmp;
620                 }
621
622                 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
623
624                         set<boost::shared_ptr<Region> >::iterator xtmp = x;
625                         ++xtmp;
626                         
627                         if ((*x) == region) {
628                                 all_regions.erase (x);
629                                 changed = true;
630                         }
631                         
632                         x = xtmp;
633                 }
634
635                 region->set_playlist (boost::shared_ptr<Playlist>());
636         }
637
638         for (c = _crossfades.begin(); c != _crossfades.end(); ) {
639                 ctmp = c;
640                 ++ctmp;
641
642                 if ((*c)->involves (r)) {
643                         unique_xfades.insert (*c);
644                         _crossfades.erase (c);
645                 }
646                 
647                 c = ctmp;
648         }
649
650         if (changed) {
651                 /* overload this, it normally means "removed", not destroyed */
652                 notify_region_removed (region);
653         }
654
655         return changed;
656 }
657
658 void
659 AudioPlaylist::crossfade_changed (Change ignored)
660 {
661         if (in_flush || in_set_state) {
662                 return;
663         }
664
665         /* XXX is there a loop here? can an xfade change not happen
666            due to a playlist change? well, sure activation would
667            be an example. maybe we should check the type of change
668            that occured.
669         */
670
671         notify_modified ();
672 }
673
674 bool
675 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
676 {
677         if (in_flush || in_set_state) {
678                 return false;
679         }
680
681         Change our_interests = Change (AudioRegion::FadeInChanged|
682                                        AudioRegion::FadeOutChanged|
683                                        AudioRegion::FadeInActiveChanged|
684                                        AudioRegion::FadeOutActiveChanged|
685                                        AudioRegion::EnvelopeActiveChanged|
686                                        AudioRegion::ScaleAmplitudeChanged|
687                                        AudioRegion::EnvelopeChanged);
688         bool parent_wants_notify;
689
690         parent_wants_notify = Playlist::region_changed (what_changed, region);
691
692         if ((parent_wants_notify || (what_changed & our_interests))) {
693                 notify_modified ();
694         }
695
696         return true; 
697 }
698
699 void
700 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
701 {
702         RegionLock rlock (this);
703
704         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
705                 nframes_t start, end;
706
707                 start = (*i)->position();
708                 end = start + (*i)->overlap_length(); // not length(), important difference
709
710                 if (frame >= start && frame <= end) {
711                         clist.push_back (*i);
712                 } 
713         }
714 }
715