mo' better fixins fer xfades, plus reinstate hiding xfades during drags
[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                                 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                 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
386                 
387                 try {
388                         switch (c) {
389                         case OverlapNone:
390                                 break;
391
392                         case OverlapInternal:
393                                  /* {=============== top  =============}
394                                   *     [ ----- bottom  ------- ]
395                                   */
396                                 break;
397
398                         case OverlapExternal:
399
400                                 /*     [ -------- top ------- ]
401                                  * {=========== bottom =============}
402                                  */
403                                 
404                                 /* to avoid discontinuities at the region boundaries of an internal
405                                    overlap (this region is completely within another), we create
406                                    two hidden crossfades at each boundary. this is not dependent
407                                    on the auto-xfade option, because we require it as basic
408                                    audio engineering.
409                                 */
410                                 
411                                 xfade_length = min ((nframes_t) 720, top->length());
412                                 
413                                 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
414                                 add_crossfade (xfade);
415                                 
416                                 if (top_region_at (top->last_frame() - 1) == top) {
417                                         /* 
418                                            only add a fade out if there is no region on top of the end of 'top' (which 
419                                            would cover it).
420                                         */
421                                         
422                                         xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
423                                         add_crossfade (xfade);
424                                 }
425                                 break;
426                                 
427                         default:
428                                 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active()));
429                                 add_crossfade (xfade);
430                         }
431                 }
432
433                 catch (failed_constructor& err) {
434                         continue;
435                 }
436                 
437                 catch (Crossfade::NoCrossfadeHere& err) {
438                         continue;
439                 }
440                 
441         }
442 }
443
444 void
445 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
446 {
447         Crossfades::iterator ci;
448
449         for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
450                 if (*(*ci) == *xfade) { // Crossfade::operator==()
451                         break;
452                 }
453         }
454         
455         if (ci != _crossfades.end()) {
456                 // it will just go away
457         } else {
458                 _crossfades.push_back (xfade);
459
460                 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
461                 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
462
463                 notify_crossfade_added (xfade);
464         }
465 }
466         
467 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
468 {
469         if (g_atomic_int_get(&block_notifications)) {
470                 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
471         } else {
472                 NewCrossfade (x); /* EMIT SIGNAL */
473         }
474 }
475
476 void
477 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Crossfade> xfade)
478 {
479         Crossfades::iterator i;
480
481         xfade->in()->resume_fade_in ();
482         xfade->out()->resume_fade_out ();
483
484         if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
485                 _crossfades.erase (i);
486         }
487 }
488
489 int
490 AudioPlaylist::set_state (const XMLNode& node)
491 {
492         XMLNode *child;
493         XMLNodeList nlist;
494         XMLNodeConstIterator niter;
495
496         in_set_state++;
497         freeze ();
498
499         Playlist::set_state (node);
500
501         nlist = node.children();
502
503         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
504
505                 child = *niter;
506
507                 if (child->name() != "Crossfade") {
508                         continue;
509                 }
510
511                 try {
512                         boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
513                         _crossfades.push_back (xfade);
514                         xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
515                         xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
516                         NewCrossfade(xfade);
517                 }
518                 
519                 catch (failed_constructor& err) {
520                         //      cout << string_compose (_("could not create crossfade object in playlist %1"),
521                         //        _name) 
522                         //    << endl;
523                         continue;
524                 }
525         }
526
527         thaw ();
528         in_set_state--;
529
530         return 0;
531 }
532
533 void
534 AudioPlaylist::clear (bool with_signals)
535 {
536         _crossfades.clear ();
537         Playlist::clear (with_signals);
538 }
539
540 XMLNode&
541 AudioPlaylist::state (bool full_state)
542 {
543         XMLNode& node = Playlist::state (full_state);
544
545         if (full_state) {
546                 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
547                         node.add_child_nocopy ((*i)->get_state());
548                 }
549         }
550         
551         return node;
552 }
553
554 void
555 AudioPlaylist::dump () const
556 {
557         boost::shared_ptr<Region>r;
558         boost::shared_ptr<Crossfade> x;
559
560         cerr << "Playlist \"" << _name << "\" " << endl
561              << regions.size() << " regions "
562              << _crossfades.size() << " crossfades"
563              << endl;
564
565         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
566                 r = *i;
567                 cerr << "  " << r->name() << " @ " << r << " [" 
568                      << r->start() << "+" << r->length() 
569                      << "] at " 
570                      << r->position()
571                      << " on layer "
572                      << r->layer ()
573                      << endl;
574         }
575
576         for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
577                 x = *i;
578                 cerr << "  xfade [" 
579                      << x->out()->name()
580                      << ','
581                      << x->in()->name()
582                      << " @ "
583                      << x->position()
584                      << " length = " 
585                      << x->length ()
586                      << " active ? "
587                      << (x->active() ? "yes" : "no")
588                      << endl;
589         }
590 }
591
592 bool
593 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
594 {
595         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
596         bool changed = false;
597         Crossfades::iterator c, ctmp;
598         set<boost::shared_ptr<Crossfade> > unique_xfades;
599
600         if (r == 0) {
601                 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
602                       << endmsg;
603                 /*NOTREACHED*/
604                 return false;
605         }
606
607         { 
608                 RegionLock rlock (this);
609
610                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
611                         
612                         RegionList::iterator tmp = i;
613                         ++tmp;
614                         
615                         if ((*i) == region) {
616                                 regions.erase (i);
617                                 changed = true;
618                         }
619                         
620                         i = tmp;
621                 }
622
623                 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
624
625                         set<boost::shared_ptr<Region> >::iterator xtmp = x;
626                         ++xtmp;
627                         
628                         if ((*x) == region) {
629                                 all_regions.erase (x);
630                                 changed = true;
631                         }
632                         
633                         x = xtmp;
634                 }
635
636                 region->set_playlist (boost::shared_ptr<Playlist>());
637         }
638
639         for (c = _crossfades.begin(); c != _crossfades.end(); ) {
640                 ctmp = c;
641                 ++ctmp;
642
643                 if ((*c)->involves (r)) {
644                         unique_xfades.insert (*c);
645                         _crossfades.erase (c);
646                 }
647                 
648                 c = ctmp;
649         }
650
651         if (changed) {
652                 /* overload this, it normally means "removed", not destroyed */
653                 notify_region_removed (region);
654         }
655
656         return changed;
657 }
658
659 void
660 AudioPlaylist::crossfade_changed (Change ignored)
661 {
662         if (in_flush || in_set_state) {
663                 return;
664         }
665
666         /* XXX is there a loop here? can an xfade change not happen
667            due to a playlist change? well, sure activation would
668            be an example. maybe we should check the type of change
669            that occured.
670         */
671
672         notify_modified ();
673 }
674
675 bool
676 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
677 {
678         if (in_flush || in_set_state) {
679                 return false;
680         }
681
682         Change our_interests = Change (AudioRegion::FadeInChanged|
683                                        AudioRegion::FadeOutChanged|
684                                        AudioRegion::FadeInActiveChanged|
685                                        AudioRegion::FadeOutActiveChanged|
686                                        AudioRegion::EnvelopeActiveChanged|
687                                        AudioRegion::ScaleAmplitudeChanged|
688                                        AudioRegion::EnvelopeChanged);
689         bool parent_wants_notify;
690
691         parent_wants_notify = Playlist::region_changed (what_changed, region);
692
693         if ((parent_wants_notify || (what_changed & our_interests))) {
694                 notify_modified ();
695         }
696
697         return true; 
698 }
699
700 void
701 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
702 {
703         RegionLock rlock (this);
704
705         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
706                 nframes_t start, end;
707
708                 start = (*i)->position();
709                 end = start + (*i)->overlap_length(); // not length(), important difference
710
711                 if (frame >= start && frame <= end) {
712                         clist.push_back (*i);
713                 } 
714         }
715 }
716