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