Fix crash due to invalidated shared_ptr, as suggested by Paul
[ardour.git] / libs / ardour / audio_playlist.cc
1 /*
2     Copyright (C) 2003 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <algorithm>
21
22 #include <cstdlib>
23
24 #include <sigc++/bind.h>
25
26 #include <ardour/types.h>
27 #include <ardour/configuration.h>
28 #include <ardour/audioplaylist.h>
29 #include <ardour/audioregion.h>
30 #include <ardour/crossfade.h>
31 #include <ardour/crossfade_compare.h>
32 #include <ardour/session.h>
33 #include <pbd/enumwriter.h>
34
35 #include "i18n.h"
36
37 using namespace ARDOUR;
38 using namespace sigc;
39 using namespace std;
40 using namespace PBD;
41
42 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
43         : Playlist (session, node, DataType::AUDIO, hidden)
44 {
45         const XMLProperty* prop = node.property("type");
46         assert(!prop || DataType(prop->value()) == DataType::AUDIO);
47
48         in_set_state++;
49         set_state (node);
50         in_set_state--;
51 }
52
53 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
54         : Playlist (session, name, DataType::AUDIO, hidden)
55 {
56 }
57
58 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
59         : Playlist (other, name, hidden)
60 {
61         RegionList::const_iterator in_o  = other->regions.begin();
62         RegionList::iterator in_n = regions.begin();
63
64         while (in_o != other->regions.end()) {
65                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
66
67                 // We look only for crossfades which begin with the current region, so we don't get doubles
68                 for (Crossfades::const_iterator xfades = other->_crossfades.begin(); xfades != other->_crossfades.end(); ++xfades) {
69                         if ((*xfades)->in() == ar) {
70                                 // We found one! Now copy it!
71
72                                 RegionList::const_iterator out_o = other->regions.begin();
73                                 RegionList::const_iterator out_n = regions.begin();
74
75                                 while (out_o != other->regions.end()) {
76                                         
77                                         boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
78                                         
79                                         if ((*xfades)->out() == ar2) {
80                                                 boost::shared_ptr<AudioRegion>in  = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
81                                                 boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
82                                                 boost::shared_ptr<Crossfade> new_fade = boost::shared_ptr<Crossfade> (new Crossfade (*xfades, in, out));
83                                                 add_crossfade(new_fade);
84                                                 break;
85                                         }
86                                         
87                                         out_o++;
88                                         out_n++;
89                                 }
90 //                              cerr << "HUH!? second region in the crossfade not found!" << endl;
91                         }
92                 }
93
94                 in_o++;
95                 in_n++;
96         }
97 }
98
99 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
100         : Playlist (other, start, cnt, name, hidden)
101 {
102         /* this constructor does NOT notify others (session) */
103 }
104
105 AudioPlaylist::~AudioPlaylist ()
106 {
107         GoingAway (); /* EMIT SIGNAL */
108
109         /* drop connections to signals */
110
111         notify_callbacks ();
112         
113         _crossfades.clear ();
114 }
115
116 struct RegionSortByLayer {
117     bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
118             return a->layer() < b->layer();
119     }
120 };
121
122 ARDOUR::nframes_t
123 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
124                      nframes_t cnt, unsigned chan_n)
125 {
126         nframes_t end;
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_data_count = 0;
152
153         map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
154         map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
155         vector<uint32_t> relevant_layers;
156
157         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
158                 if ((*i)->coverage (start, end) != OverlapNone) {
159                         relevant_regions[(*i)->layer()].push_back (*i);
160                         relevant_layers.push_back ((*i)->layer());
161                 }
162         }
163
164         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
165                 if ((*i)->coverage (start, end) != OverlapNone) {
166                         relevant_xfades[(*i)->upper_layer()].push_back (*i);
167                 }
168         }
169
170 //      RegionSortByLayer layer_cmp;
171 //      relevant_regions.sort (layer_cmp);
172
173         /* XXX this whole per-layer approach is a hack that
174            should be removed once Crossfades become
175            CrossfadeRegions and we just grab a list of relevant
176            regions and call read_at() on all of them.
177         */
178
179         sort (relevant_layers.begin(), relevant_layers.end());
180
181         for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
182
183                 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
184                 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
185
186                 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
187                         boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
188                         assert(ar);
189                         ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
190                         _read_data_count += ar->read_data_count();
191                 }
192                 
193                 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
194                         (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
195
196                         /* don't JACK up _read_data_count, since its the same data as we just
197                            read from the regions, and the OS should handle that for us.
198                         */
199                 }
200         }
201
202         return cnt;
203 }
204
205
206 void
207 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
208 {
209         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
210
211         if (in_set_state) {
212                 return;
213         }
214         
215         if (r == 0) {
216                 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
217                       << endmsg;
218                 return;
219         }
220
221         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
222                 
223                 if ((*i)->involves (r)) {
224                         i = _crossfades.erase (i);
225                 } else {
226                         ++i;
227                 }
228         }
229 }
230
231
232 void
233 AudioPlaylist::flush_notifications ()
234 {
235         Playlist::flush_notifications();
236
237         if (in_flush) {
238                 return;
239         }
240
241         in_flush = true;
242
243         Crossfades::iterator a;
244         for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
245                 NewCrossfade (*a); /* EMIT SIGNAL */
246         }
247
248         _pending_xfade_adds.clear ();
249         
250         in_flush = false;
251 }
252
253 void
254 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
255 {
256         boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
257         set<boost::shared_ptr<Crossfade> > updated;
258
259         if (ar == 0) {
260                 return;
261         }
262
263         for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
264
265                 Crossfades::iterator tmp;
266                 
267                 tmp = x;
268                 ++tmp;
269
270                 /* only update them once */
271
272                 if ((*x)->involves (ar)) {
273
274                         pair<set<boost::shared_ptr<Crossfade> >::iterator, bool> const u = updated.insert (*x);
275                         
276                         if (u.second) {
277                                 /* x was successfully inserted into the set, so it has not already been updated */
278                                 try {
279                                         (*x)->refresh ();
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                 if (!top->opaque()) {
384                         continue;
385                 }
386
387                 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
388
389                 try {
390                         switch (c) {
391                         case OverlapNone:
392                                 break;
393
394                         case OverlapInternal:
395                                  /* {=============== top  =============}
396                                   *     [ ----- bottom  ------- ]
397                                   */
398                                 break;
399
400                         case OverlapExternal:
401
402                                 /*     [ -------- top ------- ]
403                                  * {=========== bottom =============}
404                                  */
405                                 
406                                 /* to avoid discontinuities at the region boundaries of an internal
407                                    overlap (this region is completely within another), we create
408                                    two hidden crossfades at each boundary. this is not dependent
409                                    on the auto-xfade option, because we require it as basic
410                                    audio engineering.
411                                 */
412                                 
413                                 xfade_length = min ((nframes_t) 720, top->length());
414                                 
415                                 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
416                                 add_crossfade (xfade);
417
418                                 if (top_region_at (top->last_frame() - 1) == top) {
419                                         /* 
420                                            only add a fade out if there is no region on top of the end of 'top' (which 
421                                            would cover it).
422                                         */
423                                         
424                                         xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
425                                         add_crossfade (xfade);
426                                 }
427                                 break;
428                                 
429                         default:
430                                 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active()));
431                                 add_crossfade (xfade);
432                         }
433                 }
434
435                 catch (failed_constructor& err) {
436                         continue;
437                 }
438                 
439                 catch (Crossfade::NoCrossfadeHere& err) {
440                         continue;
441                 }
442                 
443         }
444 }
445
446 void
447 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
448 {
449         Crossfades::iterator ci;
450
451         for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
452                 if (*(*ci) == *xfade) { // Crossfade::operator==()
453                         break;
454                 }
455         }
456         
457         if (ci != _crossfades.end()) {
458                 // it will just go away
459         } else {
460                 _crossfades.push_back (xfade);
461
462                 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
463                 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
464
465                 notify_crossfade_added (xfade);
466         }
467 }
468         
469 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
470 {
471         if (g_atomic_int_get(&block_notifications)) {
472                 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
473         } else {
474                 NewCrossfade (x); /* EMIT SIGNAL */
475         }
476 }
477
478 void
479 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
480 {
481         Crossfades::iterator i;
482         boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
483
484         xfade->in()->resume_fade_in ();
485         xfade->out()->resume_fade_out ();
486
487         if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
488                 _crossfades.erase (i);
489         }
490 }
491
492 int
493 AudioPlaylist::set_state (const XMLNode& node)
494 {
495         XMLNode *child;
496         XMLNodeList nlist;
497         XMLNodeConstIterator niter;
498
499         in_set_state++;
500         freeze ();
501
502         Playlist::set_state (node);
503
504         nlist = node.children();
505
506         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
507
508                 child = *niter;
509
510                 if (child->name() != "Crossfade") {
511                         continue;
512                 }
513
514                 try {
515                         boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
516                         _crossfades.push_back (xfade);
517                         xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
518                         xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
519                         NewCrossfade(xfade);
520                 }
521                 
522                 catch (failed_constructor& err) {
523                         //      cout << string_compose (_("could not create crossfade object in playlist %1"),
524                         //        _name) 
525                         //    << endl;
526                         continue;
527                 }
528         }
529
530         thaw ();
531         in_set_state--;
532
533         return 0;
534 }
535
536 void
537 AudioPlaylist::clear (bool with_signals)
538 {
539         _crossfades.clear ();
540         Playlist::clear (with_signals);
541 }
542
543 XMLNode&
544 AudioPlaylist::state (bool full_state)
545 {
546         XMLNode& node = Playlist::state (full_state);
547
548         if (full_state) {
549                 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
550                         node.add_child_nocopy ((*i)->get_state());
551                 }
552         }
553         
554         return node;
555 }
556
557 void
558 AudioPlaylist::dump () const
559 {
560         boost::shared_ptr<Region>r;
561         boost::shared_ptr<Crossfade> x;
562
563         cerr << "Playlist \"" << _name << "\" " << endl
564              << regions.size() << " regions "
565              << _crossfades.size() << " crossfades"
566              << endl;
567
568         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
569                 r = *i;
570                 cerr << "  " << r->name() << " @ " << r << " [" 
571                      << r->start() << "+" << r->length() 
572                      << "] at " 
573                      << r->position()
574                      << " on layer "
575                      << r->layer ()
576                      << endl;
577         }
578
579         for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
580                 x = *i;
581                 cerr << "  xfade [" 
582                      << x->out()->name()
583                      << ','
584                      << x->in()->name()
585                      << " @ "
586                      << x->position()
587                      << " length = " 
588                      << x->length ()
589                      << " active ? "
590                      << (x->active() ? "yes" : "no")
591                      << endl;
592         }
593 }
594
595 bool
596 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
597 {
598         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
599         bool changed = false;
600         Crossfades::iterator c, ctmp;
601         set<boost::shared_ptr<Crossfade> > unique_xfades;
602
603         if (r == 0) {
604                 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
605                       << endmsg;
606                 /*NOTREACHED*/
607                 return false;
608         }
609
610         { 
611                 RegionLock rlock (this);
612
613                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
614                         
615                         RegionList::iterator tmp = i;
616                         ++tmp;
617                         
618                         if ((*i) == region) {
619                                 regions.erase (i);
620                                 changed = true;
621                         }
622                         
623                         i = tmp;
624                 }
625
626                 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
627
628                         set<boost::shared_ptr<Region> >::iterator xtmp = x;
629                         ++xtmp;
630                         
631                         if ((*x) == region) {
632                                 all_regions.erase (x);
633                                 changed = true;
634                         }
635                         
636                         x = xtmp;
637                 }
638
639                 region->set_playlist (boost::shared_ptr<Playlist>());
640         }
641
642         for (c = _crossfades.begin(); c != _crossfades.end(); ) {
643                 ctmp = c;
644                 ++ctmp;
645
646                 if ((*c)->involves (r)) {
647                         unique_xfades.insert (*c);
648                         _crossfades.erase (c);
649                 }
650                 
651                 c = ctmp;
652         }
653
654         if (changed) {
655                 /* overload this, it normally means "removed", not destroyed */
656                 notify_region_removed (region);
657         }
658
659         return changed;
660 }
661
662 void
663 AudioPlaylist::crossfade_changed (Change ignored)
664 {
665         if (in_flush || in_set_state) {
666                 return;
667         }
668
669         /* XXX is there a loop here? can an xfade change not happen
670            due to a playlist change? well, sure activation would
671            be an example. maybe we should check the type of change
672            that occured.
673         */
674
675         notify_modified ();
676 }
677
678 bool
679 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
680 {
681         if (in_flush || in_set_state) {
682                 return false;
683         }
684
685         Change our_interests = Change (AudioRegion::FadeInChanged|
686                                        AudioRegion::FadeOutChanged|
687                                        AudioRegion::FadeInActiveChanged|
688                                        AudioRegion::FadeOutActiveChanged|
689                                        AudioRegion::EnvelopeActiveChanged|
690                                        AudioRegion::ScaleAmplitudeChanged|
691                                        AudioRegion::EnvelopeChanged);
692         bool parent_wants_notify;
693
694         parent_wants_notify = Playlist::region_changed (what_changed, region);
695
696         if ((parent_wants_notify || (what_changed & our_interests))) {
697                 notify_modified ();
698         }
699
700         return true; 
701 }
702
703 void
704 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
705 {
706         RegionLock rlock (this);
707
708         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
709                 nframes_t start, end;
710
711                 start = (*i)->position();
712                 end = start + (*i)->overlap_length(); // not length(), important difference
713
714                 if (frame >= start && frame <= end) {
715                         clist.push_back (*i);
716                 } 
717         }
718 }
719