moved 2.1-staging to trunk @ rev 1765
[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, hidden)
44 {
45         in_set_state++;
46         set_state (node);
47         in_set_state--;
48 }
49
50 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
51         : Playlist (session, name, hidden)
52 {
53 }
54
55 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
56         : Playlist (other, name, hidden)
57 {
58         RegionList::const_iterator in_o  = other->regions.begin();
59         RegionList::iterator in_n = regions.begin();
60
61         while (in_o != other->regions.end()) {
62                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
63
64                 // We look only for crossfades which begin with the current region, so we don't get doubles
65                 for (Crossfades::const_iterator xfades = other->_crossfades.begin(); xfades != other->_crossfades.end(); ++xfades) {
66                         if ((*xfades)->in() == ar) {
67                                 // We found one! Now copy it!
68
69                                 RegionList::const_iterator out_o = other->regions.begin();
70                                 RegionList::const_iterator out_n = regions.begin();
71
72                                 while (out_o != other->regions.end()) {
73                                         
74                                         boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
75                                         
76                                         if ((*xfades)->out() == ar2) {
77                                                 boost::shared_ptr<AudioRegion>in  = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
78                                                 boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
79                                                 boost::shared_ptr<Crossfade> new_fade = boost::shared_ptr<Crossfade> (new Crossfade (*(*xfades), in, out));
80                                                 add_crossfade(new_fade);
81                                                 break;
82                                         }
83                                         
84                                         out_o++;
85                                         out_n++;
86                                 }
87 //                              cerr << "HUH!? second region in the crossfade not found!" << endl;
88                         }
89                 }
90
91                 in_o++;
92                 in_n++;
93         }
94 }
95
96 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
97         : Playlist (other, start, cnt, name, hidden)
98 {
99         /* this constructor does NOT notify others (session) */
100 }
101
102 AudioPlaylist::~AudioPlaylist ()
103 {
104         GoingAway (); /* EMIT SIGNAL */
105
106         /* drop connections to signals */
107
108         notify_callbacks ();
109
110         _crossfades.clear ();
111 }
112
113 struct RegionSortByLayer {
114     bool operator() (boost::shared_ptr<Region>a, boost::shared_ptr<Region>b) {
115             return a->layer() < b->layer();
116     }
117 };
118
119 nframes_t
120 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
121                      nframes_t cnt, unsigned chan_n)
122 {
123         nframes_t ret = cnt;
124         nframes_t end;
125         nframes_t read_frames;
126         nframes_t skip_frames;
127
128         /* optimizing this memset() away involves a lot of conditionals
129            that may well cause more of a hit due to cache misses 
130            and related stuff than just doing this here.
131            
132            it would be great if someone could measure this
133            at some point.
134
135            one way or another, parts of the requested area
136            that are not written to by Region::region_at()
137            for all Regions that cover the area need to be
138            zeroed.
139         */
140
141         memset (buf, 0, sizeof (Sample) * cnt);
142
143         /* this function is never called from a realtime thread, so 
144            its OK to block (for short intervals).
145         */
146
147         Glib::Mutex::Lock rm (region_lock);
148
149         end =  start + cnt - 1;
150
151         read_frames = 0;
152         skip_frames = 0;
153         _read_data_count = 0;
154
155         map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
156         map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
157         vector<uint32_t> relevant_layers;
158
159         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
160                 if ((*i)->coverage (start, end) != OverlapNone) {
161                         relevant_regions[(*i)->layer()].push_back (*i);
162                         relevant_layers.push_back ((*i)->layer());
163                 }
164         }
165
166         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
167                 if ((*i)->coverage (start, end) != OverlapNone) {
168                         relevant_xfades[(*i)->upper_layer()].push_back (*i);
169                 }
170         }
171
172 //      RegionSortByLayer layer_cmp;
173 //      relevant_regions.sort (layer_cmp);
174
175         /* XXX this whole per-layer approach is a hack that
176            should be removed once Crossfades become
177            CrossfadeRegions and we just grab a list of relevant
178            regions and call read_at() on all of them.
179         */
180
181         sort (relevant_layers.begin(), relevant_layers.end());
182
183         for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
184
185                 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
186                 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
187
188                 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
189                         boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
190                         assert(ar);
191                         ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
192                         _read_data_count += ar->read_data_count();
193                 }
194                 
195                 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
196                         (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
197
198                         /* don't JACK up _read_data_count, since its the same data as we just
199                            read from the regions, and the OS should handle that for us.
200                         */
201                 }
202         }
203
204         return ret;
205 }
206
207
208 void
209 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
210 {
211         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
212
213         if (in_set_state) {
214                 return;
215         }
216         
217         if (r == 0) {
218                 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
219                       << endmsg;
220                 return;
221         }
222
223         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
224                 
225                 if ((*i)->involves (r)) {
226                         i = _crossfades.erase (i);
227                 } else {
228                         ++i;
229                 }
230         }
231 }
232
233
234 void
235 AudioPlaylist::flush_notifications ()
236 {
237         Playlist::flush_notifications();
238
239         if (in_flush) {
240                 return;
241         }
242
243         in_flush = true;
244
245         Crossfades::iterator a;
246         for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
247                 NewCrossfade (*a); /* EMIT SIGNAL */
248         }
249
250         _pending_xfade_adds.clear ();
251         
252         in_flush = false;
253 }
254
255 void
256 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
257 {
258         boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
259         set<boost::shared_ptr<Crossfade> > updated;
260
261         if (ar == 0) {
262                 return;
263         }
264
265         for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
266
267                 Crossfades::iterator tmp;
268                 
269                 tmp = x;
270                 ++tmp;
271
272                 /* only update them once */
273
274                 if ((*x)->involves (ar)) {
275
276                         if (find (updated.begin(), updated.end(), *x) == updated.end()) {
277                                 try { 
278                                         if ((*x)->refresh ()) {
279                                                 updated.insert (*x);
280                                         }
281                                 }
282
283                                 catch (Crossfade::NoCrossfadeHere& err) {
284                                         // relax, Invalidated during refresh
285                                 }
286                         }
287                 }
288
289                 x = tmp;
290         }
291 }
292
293 void
294 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
295 {
296         boost::shared_ptr<AudioRegion> orig  = boost::dynamic_pointer_cast<AudioRegion>(o);
297         boost::shared_ptr<AudioRegion> left  = boost::dynamic_pointer_cast<AudioRegion>(l);
298         boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
299
300         for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
301                 Crossfades::iterator tmp;
302                 tmp = x;
303                 ++tmp;
304
305                 boost::shared_ptr<Crossfade> fade;
306                 
307                 if ((*x)->_in == orig) {
308                         if (! (*x)->covers(right->position())) {
309                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, left, (*x)->_out));
310                         } else {
311                                 // Overlap, the crossfade is copied on the left side of the right region instead
312                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, right, (*x)->_out));
313                         }
314                 }
315                 
316                 if ((*x)->_out == orig) {
317                         if (! (*x)->covers(right->position())) {
318                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, (*x)->_in, right));
319                         } else {
320                                 // Overlap, the crossfade is copied on the right side of the left region instead
321                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, (*x)->_in, left));
322                         }
323                 }
324                 
325                 if (fade) {
326                         _crossfades.remove (*x);
327                         add_crossfade (fade);
328                 }
329                 x = tmp;
330         }
331 }
332
333 void
334 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
335 {
336         boost::shared_ptr<AudioRegion> other;
337         boost::shared_ptr<AudioRegion> region;
338         boost::shared_ptr<AudioRegion> top;
339         boost::shared_ptr<AudioRegion> bottom;
340         boost::shared_ptr<Crossfade>   xfade;
341
342         if (in_set_state || in_partition) {
343                 return;
344         }
345
346         if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
347                 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
348                       << endmsg;
349                 return;
350         }
351
352         if (!norefresh) {
353                 refresh_dependents (r);
354         }
355
356
357         if (!Config->get_auto_xfade()) {
358                 return;
359         }
360
361         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
362
363                 nframes_t xfade_length;
364
365                 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
366
367                 if (other == region) {
368                         continue;
369                 }
370
371                 if (other->muted() || region->muted()) {
372                         continue;
373                 }
374                 
375
376                 if (other->layer() < region->layer()) {
377                         top = region;
378                         bottom = other;
379                 } else {
380                         top = other;
381                         bottom = region;
382                 }
383
384
385
386                 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
387
388                 try {
389                         switch (c) {
390                         case OverlapNone:
391                                 break;
392
393                         case OverlapInternal:
394                                  /* {=============== top  =============}
395                                   *     [ ----- bottom  ------- ]
396                                   */
397                                 break;
398
399                         case OverlapExternal:
400
401                                 /*     [ -------- top ------- ]
402                                  * {=========== bottom =============}
403                                  */
404                                 
405                                 /* to avoid discontinuities at the region boundaries of an internal
406                                    overlap (this region is completely within another), we create
407                                    two hidden crossfades at each boundary. this is not dependent
408                                    on the auto-xfade option, because we require it as basic
409                                    audio engineering.
410                                 */
411                                 
412                                 xfade_length = min ((nframes_t) 720, top->length());
413                                 
414                                 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
415                                 add_crossfade (xfade);
416
417                                 if (top_region_at (top->last_frame() - 1) == top) {
418                                         /* 
419                                            only add a fade out if there is no region on top of the end of 'top' (which 
420                                            would cover it).
421                                         */
422                                         
423                                         xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
424                                         add_crossfade (xfade);
425                                 }
426                                 break;
427                                 
428                         default:
429                                 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active()));
430                                 add_crossfade (xfade);
431                         }
432                 }
433
434                 catch (failed_constructor& err) {
435                         continue;
436                 }
437                 
438                 catch (Crossfade::NoCrossfadeHere& err) {
439                         continue;
440                 }
441                 
442         }
443 }
444
445 void
446 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
447 {
448         Crossfades::iterator ci;
449
450         for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
451                 if (*(*ci) == *xfade) { // Crossfade::operator==()
452                         break;
453                 }
454         }
455         
456         if (ci != _crossfades.end()) {
457                 // it will just go away
458         } else {
459                 _crossfades.push_back (xfade);
460
461                 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
462                 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
463
464                 notify_crossfade_added (xfade);
465         }
466 }
467         
468 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
469 {
470         if (g_atomic_int_get(&block_notifications)) {
471                 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
472         } else {
473                 NewCrossfade (x); /* EMIT SIGNAL */
474         }
475 }
476
477 void
478 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Crossfade> xfade)
479 {
480         Crossfades::iterator i;
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