Merged with trunk R1304
[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, 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         nframes_t read_frames;
129         nframes_t skip_frames;
130
131         /* optimizing this memset() away involves a lot of conditionals
132            that may well cause more of a hit due to cache misses 
133            and related stuff than just doing this here.
134            
135            it would be great if someone could measure this
136            at some point.
137
138            one way or another, parts of the requested area
139            that are not written to by Region::region_at()
140            for all Regions that cover the area need to be
141            zeroed.
142         */
143
144         memset (buf, 0, sizeof (Sample) * cnt);
145
146         /* this function is never called from a realtime thread, so 
147            its OK to block (for short intervals).
148         */
149
150         Glib::Mutex::Lock rm (region_lock);
151
152         end =  start + cnt - 1;
153
154         read_frames = 0;
155         skip_frames = 0;
156         _read_data_count = 0;
157
158         map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
159         map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
160         vector<uint32_t> relevant_layers;
161
162         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
163                 if ((*i)->coverage (start, end) != OverlapNone) {
164                         relevant_regions[(*i)->layer()].push_back (*i);
165                         relevant_layers.push_back ((*i)->layer());
166                 }
167         }
168
169         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
170                 if ((*i)->coverage (start, end) != OverlapNone) {
171                         relevant_xfades[(*i)->upper_layer()].push_back (*i);
172                 }
173         }
174
175 //      RegionSortByLayer layer_cmp;
176 //      relevant_regions.sort (layer_cmp);
177
178         /* XXX this whole per-layer approach is a hack that
179            should be removed once Crossfades become
180            CrossfadeRegions and we just grab a list of relevant
181            regions and call read_at() on all of them.
182         */
183
184         sort (relevant_layers.begin(), relevant_layers.end());
185
186         for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
187
188                 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
189                 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
190
191                 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
192                         boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
193                         assert(ar);
194                         ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
195                         _read_data_count += ar->read_data_count();
196                 }
197                 
198                 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
199                         (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
200
201                         /* don't JACK up _read_data_count, since its the same data as we just
202                            read from the regions, and the OS should handle that for us.
203                         */
204                 }
205         }
206
207         return ret;
208 }
209
210
211 void
212 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
213 {
214         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
215
216         if (in_set_state) {
217                 return;
218         }
219         
220         if (r == 0) {
221                 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
222                       << endmsg;
223                 return;
224         }
225
226         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
227                 
228                 if ((*i)->involves (r)) {
229                         i = _crossfades.erase (i);
230                 } else {
231                         ++i;
232                 }
233         }
234 }
235
236
237 void
238 AudioPlaylist::flush_notifications ()
239 {
240         Playlist::flush_notifications();
241
242         if (in_flush) {
243                 return;
244         }
245
246         in_flush = true;
247
248         Crossfades::iterator a;
249         for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
250                 NewCrossfade (*a); /* EMIT SIGNAL */
251         }
252
253         _pending_xfade_adds.clear ();
254         
255         in_flush = false;
256 }
257
258 void
259 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
260 {
261         boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
262         set<boost::shared_ptr<Crossfade> > updated;
263
264         if (ar == 0) {
265                 return;
266         }
267
268         for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
269
270                 Crossfades::iterator tmp;
271                 
272                 tmp = x;
273                 ++tmp;
274
275                 /* only update them once */
276
277                 if ((*x)->involves (ar)) {
278
279                         if (find (updated.begin(), updated.end(), *x) == updated.end()) {
280                                 if ((*x)->refresh ()) {
281                                         /* not invalidated by the refresh */
282                                         updated.insert (*x);
283                                 }
284                         }
285                 }
286
287                 x = tmp;
288         }
289 }
290
291 void
292 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
293 {
294         boost::shared_ptr<AudioRegion> orig  = boost::dynamic_pointer_cast<AudioRegion>(o);
295         boost::shared_ptr<AudioRegion> left  = boost::dynamic_pointer_cast<AudioRegion>(l);
296         boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
297
298         for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
299                 Crossfades::iterator tmp;
300                 tmp = x;
301                 ++tmp;
302
303                 boost::shared_ptr<Crossfade> fade;
304                 
305                 if ((*x)->_in == orig) {
306                         if (! (*x)->covers(right->position())) {
307                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, left, (*x)->_out));
308                         } else {
309                                 // Overlap, the crossfade is copied on the left side of the right region instead
310                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, right, (*x)->_out));
311                         }
312                 }
313                 
314                 if ((*x)->_out == orig) {
315                         if (! (*x)->covers(right->position())) {
316                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, (*x)->_in, right));
317                         } else {
318                                 // Overlap, the crossfade is copied on the right side of the left region instead
319                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, (*x)->_in, left));
320                         }
321                 }
322                 
323                 if (fade) {
324                         _crossfades.remove (*x);
325                         add_crossfade (fade);
326                 }
327                 x = tmp;
328         }
329 }
330
331 void
332 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
333 {
334         boost::shared_ptr<AudioRegion> other;
335         boost::shared_ptr<AudioRegion> region;
336         boost::shared_ptr<AudioRegion> top;
337         boost::shared_ptr<AudioRegion> bottom;
338         boost::shared_ptr<Crossfade>   xfade;
339
340         if (in_set_state || in_partition) {
341                 return;
342         }
343
344         cerr << "Check dependents of " << r->name() << endl;
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         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