06060061e0599f76629f5bf3b12a65e318842329
[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     $Id$
19 */
20
21 #include <algorithm>
22
23 #include <cstdlib>
24
25 #include <sigc++/bind.h>
26
27 #include <ardour/types.h>
28 #include <ardour/configuration.h>
29 #include <ardour/audioplaylist.h>
30 #include <ardour/audioregion.h>
31 #include <ardour/crossfade.h>
32 #include <ardour/crossfade_compare.h>
33 #include <ardour/session.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                                 if ((*x)->refresh ()) {
278                                         /* not invalidated by the refresh */
279                                         updated.insert (*x);
280                                 }
281                         }
282                 }
283
284                 x = tmp;
285         }
286 }
287
288 void
289 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
290 {
291         boost::shared_ptr<AudioRegion> orig  = boost::dynamic_pointer_cast<AudioRegion>(o);
292         boost::shared_ptr<AudioRegion> left  = boost::dynamic_pointer_cast<AudioRegion>(l);
293         boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
294
295         for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
296                 Crossfades::iterator tmp;
297                 tmp = x;
298                 ++tmp;
299
300                 boost::shared_ptr<Crossfade> fade;
301                 
302                 if ((*x)->_in == orig) {
303                         if (! (*x)->covers(right->position())) {
304                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, left, (*x)->_out));
305                         } else {
306                                 // Overlap, the crossfade is copied on the left side of the right region instead
307                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, right, (*x)->_out));
308                         }
309                 }
310                 
311                 if ((*x)->_out == orig) {
312                         if (! (*x)->covers(right->position())) {
313                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, (*x)->_in, right));
314                         } else {
315                                 // Overlap, the crossfade is copied on the right side of the left region instead
316                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, (*x)->_in, left));
317                         }
318                 }
319                 
320                 if (fade) {
321                         _crossfades.remove (*x);
322                         add_crossfade (fade);
323                 }
324                 x = tmp;
325         }
326 }
327
328 void
329 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
330 {
331         boost::shared_ptr<AudioRegion> other;
332         boost::shared_ptr<AudioRegion> region;
333         boost::shared_ptr<AudioRegion> top;
334         boost::shared_ptr<AudioRegion> bottom;
335         boost::shared_ptr<Crossfade>   xfade;
336
337         if (in_set_state || in_partition) {
338                 return;
339         }
340
341         if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
342                 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
343                       << endmsg;
344                 return;
345         }
346
347         if (!norefresh) {
348                 refresh_dependents (r);
349         }
350
351         if (!Config->get_auto_xfade()) {
352                 return;
353         }
354
355         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
356
357                 nframes_t xfade_length;
358
359                 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
360
361                 if (other == region) {
362                         continue;
363                 }
364
365                 if (other->muted() || region->muted()) {
366                         continue;
367                 }
368                 
369
370                 if (other->layer() < region->layer()) {
371                         top = region;
372                         bottom = other;
373                 } else {
374                         top = other;
375                         bottom = region;
376                 }
377
378
379                 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
380                 
381                 try {
382                         switch (c) {
383                         case OverlapNone:
384                                 break;
385
386                         case OverlapInternal:
387                                  /* {=============== top  =============}
388                                   *     [ ----- bottom  ------- ]
389                                   */
390                                 break;
391
392                         case OverlapExternal:
393
394                                 /*     [ -------- top ------- ]
395                                  * {=========== bottom =============}
396                                  */
397                                 
398                                 /* to avoid discontinuities at the region boundaries of an internal
399                                    overlap (this region is completely within another), we create
400                                    two hidden crossfades at each boundary. this is not dependent
401                                    on the auto-xfade option, because we require it as basic
402                                    audio engineering.
403                                 */
404                                 
405                                 xfade_length = min ((nframes_t) 720, top->length());
406                                 
407                                 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
408                                 add_crossfade (xfade);
409                                 
410                                 if (top_region_at (top->last_frame() - 1) == top) {
411                                         /* 
412                                            only add a fade out if there is no region on top of the end of 'top' (which 
413                                            would cover it).
414                                         */
415                                         
416                                         xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
417                                         add_crossfade (xfade);
418                                 }
419                                 break;
420                                 
421                         default:
422                                 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active()));
423                                 add_crossfade (xfade);
424                         }
425                 }
426
427                 catch (failed_constructor& err) {
428                         continue;
429                 }
430                 
431                 catch (Crossfade::NoCrossfadeHere& err) {
432                         continue;
433                 }
434                 
435         }
436 }
437
438 void
439 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
440 {
441         Crossfades::iterator ci;
442
443         for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
444                 if (*(*ci) == *xfade) { // Crossfade::operator==()
445                         break;
446                 }
447         }
448         
449         if (ci != _crossfades.end()) {
450                 // it will just go away
451         } else {
452                 _crossfades.push_back (xfade);
453
454                 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
455                 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
456
457                 notify_crossfade_added (xfade);
458         }
459 }
460         
461 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
462 {
463         if (g_atomic_int_get(&block_notifications)) {
464                 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
465         } else {
466                 NewCrossfade (x); /* EMIT SIGNAL */
467         }
468 }
469
470 void
471 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Crossfade> xfade)
472 {
473         Crossfades::iterator i;
474
475         xfade->in()->resume_fade_in ();
476         xfade->out()->resume_fade_out ();
477
478         if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
479                 _crossfades.erase (i);
480         }
481 }
482
483 int
484 AudioPlaylist::set_state (const XMLNode& node)
485 {
486         XMLNode *child;
487         XMLNodeList nlist;
488         XMLNodeConstIterator niter;
489
490         in_set_state++;
491         freeze ();
492
493         Playlist::set_state (node);
494
495         nlist = node.children();
496
497         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
498
499                 child = *niter;
500
501                 if (child->name() != "Crossfade") {
502                         continue;
503                 }
504
505                 try {
506                         boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
507                         _crossfades.push_back (xfade);
508                         xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
509                         xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
510                         NewCrossfade(xfade);
511                 }
512                 
513                 catch (failed_constructor& err) {
514                         //      cout << string_compose (_("could not create crossfade object in playlist %1"),
515                         //        _name) 
516                         //    << endl;
517                         continue;
518                 }
519         }
520
521         thaw ();
522         in_set_state--;
523
524         return 0;
525 }
526
527 void
528 AudioPlaylist::clear (bool with_signals)
529 {
530         _crossfades.clear ();
531         Playlist::clear (with_signals);
532 }
533
534 XMLNode&
535 AudioPlaylist::state (bool full_state)
536 {
537         XMLNode& node = Playlist::state (full_state);
538
539         if (full_state) {
540                 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
541                         node.add_child_nocopy ((*i)->get_state());
542                 }
543         }
544         
545         return node;
546 }
547
548 void
549 AudioPlaylist::dump () const
550 {
551         boost::shared_ptr<Region>r;
552         boost::shared_ptr<Crossfade> x;
553
554         cerr << "Playlist \"" << _name << "\" " << endl
555              << regions.size() << " regions "
556              << _crossfades.size() << " crossfades"
557              << endl;
558
559         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
560                 r = *i;
561                 cerr << "  " << r->name() << " @ " << r << " [" 
562                      << r->start() << "+" << r->length() 
563                      << "] at " 
564                      << r->position()
565                      << " on layer "
566                      << r->layer ()
567                      << endl;
568         }
569
570         for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
571                 x = *i;
572                 cerr << "  xfade [" 
573                      << x->out()->name()
574                      << ','
575                      << x->in()->name()
576                      << " @ "
577                      << x->position()
578                      << " length = " 
579                      << x->length ()
580                      << " active ? "
581                      << (x->active() ? "yes" : "no")
582                      << endl;
583         }
584 }
585
586 bool
587 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
588 {
589         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
590         bool changed = false;
591         Crossfades::iterator c, ctmp;
592         set<boost::shared_ptr<Crossfade> > unique_xfades;
593
594         if (r == 0) {
595                 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
596                       << endmsg;
597                 /*NOTREACHED*/
598                 return false;
599         }
600
601         { 
602                 RegionLock rlock (this);
603
604                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
605                         
606                         RegionList::iterator tmp = i;
607                         ++tmp;
608                         
609                         if ((*i) == region) {
610                                 regions.erase (i);
611                                 changed = true;
612                         }
613                         
614                         i = tmp;
615                 }
616
617                 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
618
619                         set<boost::shared_ptr<Region> >::iterator xtmp = x;
620                         ++xtmp;
621                         
622                         if ((*x) == region) {
623                                 all_regions.erase (x);
624                                 changed = true;
625                         }
626                         
627                         x = xtmp;
628                 }
629
630                 region->set_playlist (boost::shared_ptr<Playlist>());
631         }
632
633         for (c = _crossfades.begin(); c != _crossfades.end(); ) {
634                 ctmp = c;
635                 ++ctmp;
636
637                 if ((*c)->involves (r)) {
638                         unique_xfades.insert (*c);
639                         _crossfades.erase (c);
640                 }
641                 
642                 c = ctmp;
643         }
644
645         if (changed) {
646                 /* overload this, it normally means "removed", not destroyed */
647                 notify_region_removed (region);
648         }
649
650         return changed;
651 }
652
653 void
654 AudioPlaylist::crossfade_changed (Change ignored)
655 {
656         if (in_flush || in_set_state) {
657                 return;
658         }
659
660         /* XXX is there a loop here? can an xfade change not happen
661            due to a playlist change? well, sure activation would
662            be an example. maybe we should check the type of change
663            that occured.
664         */
665
666         notify_modified ();
667 }
668
669 bool
670 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
671 {
672         if (in_flush || in_set_state) {
673                 return false;
674         }
675
676         Change our_interests = Change (AudioRegion::FadeInChanged|
677                                        AudioRegion::FadeOutChanged|
678                                        AudioRegion::FadeInActiveChanged|
679                                        AudioRegion::FadeOutActiveChanged|
680                                        AudioRegion::EnvelopeActiveChanged|
681                                        AudioRegion::ScaleAmplitudeChanged|
682                                        AudioRegion::EnvelopeChanged);
683         bool parent_wants_notify;
684
685         parent_wants_notify = Playlist::region_changed (what_changed, region);
686
687         if ((parent_wants_notify || (what_changed & our_interests))) {
688                 notify_modified ();
689         }
690
691         return true; 
692 }
693
694 void
695 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
696 {
697         RegionLock rlock (this);
698
699         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
700                 nframes_t start, end;
701
702                 start = (*i)->position();
703                 end = start + (*i)->overlap_length(); // not length(), important difference
704
705                 if (frame >= start && frame <= end) {
706                         clist.push_back (*i);
707                 } 
708         }
709 }
710