2 Copyright (C) 2003 Paul Davis
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.
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.
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.
24 #include <sigc++/bind.h>
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>
37 using namespace ARDOUR;
42 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
43 : Playlist (session, node, hidden)
50 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
51 : Playlist (session, name, hidden)
55 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
56 : Playlist (other, name, hidden)
58 RegionList::const_iterator in_o = other->regions.begin();
59 RegionList::iterator in_n = regions.begin();
61 while (in_o != other->regions.end()) {
62 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
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!
69 RegionList::const_iterator out_o = other->regions.begin();
70 RegionList::const_iterator out_n = regions.begin();
72 while (out_o != other->regions.end()) {
74 boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
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);
87 // cerr << "HUH!? second region in the crossfade not found!" << endl;
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)
99 /* this constructor does NOT notify others (session) */
102 AudioPlaylist::~AudioPlaylist ()
104 GoingAway (); /* EMIT SIGNAL */
106 /* drop connections to signals */
110 _crossfades.clear ();
113 struct RegionSortByLayer {
114 bool operator() (boost::shared_ptr<Region>a, boost::shared_ptr<Region>b) {
115 return a->layer() < b->layer();
120 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
121 nframes_t cnt, unsigned chan_n)
125 nframes_t read_frames;
126 nframes_t skip_frames;
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.
132 it would be great if someone could measure this
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
141 memset (buf, 0, sizeof (Sample) * cnt);
143 /* this function is never called from a realtime thread, so
144 its OK to block (for short intervals).
147 Glib::Mutex::Lock rm (region_lock);
149 end = start + cnt - 1;
153 _read_data_count = 0;
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;
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());
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);
172 // RegionSortByLayer layer_cmp;
173 // relevant_regions.sort (layer_cmp);
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.
181 sort (relevant_layers.begin(), relevant_layers.end());
183 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
185 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
186 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
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);
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();
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);
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.
209 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
211 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
218 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
223 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
225 if ((*i)->involves (r)) {
226 i = _crossfades.erase (i);
235 AudioPlaylist::flush_notifications ()
237 Playlist::flush_notifications();
245 Crossfades::iterator a;
246 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
247 NewCrossfade (*a); /* EMIT SIGNAL */
250 _pending_xfade_adds.clear ();
256 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
258 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
259 set<boost::shared_ptr<Crossfade> > updated;
265 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
267 Crossfades::iterator tmp;
272 /* only update them once */
274 if ((*x)->involves (ar)) {
276 if (find (updated.begin(), updated.end(), *x) == updated.end()) {
278 if ((*x)->refresh ()) {
283 catch (Crossfade::NoCrossfadeHere& err) {
284 // relax, Invalidated during refresh
294 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
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);
300 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
301 Crossfades::iterator tmp;
305 boost::shared_ptr<Crossfade> fade;
307 if ((*x)->_in == orig) {
308 if (! (*x)->covers(right->position())) {
309 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, left, (*x)->_out));
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));
316 if ((*x)->_out == orig) {
317 if (! (*x)->covers(right->position())) {
318 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, (*x)->_in, right));
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));
326 _crossfades.remove (*x);
327 add_crossfade (fade);
334 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
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;
342 if (in_set_state || in_partition) {
346 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
347 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
353 refresh_dependents (r);
357 if (!Config->get_auto_xfade()) {
361 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
363 nframes_t xfade_length;
365 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
367 if (other == region) {
371 if (other->muted() || region->muted()) {
376 if (other->layer() < region->layer()) {
386 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
393 case OverlapInternal:
394 /* {=============== top =============}
395 * [ ----- bottom ------- ]
399 case OverlapExternal:
401 /* [ -------- top ------- ]
402 * {=========== bottom =============}
405 /* to avoid discontinuities at the region boundaries of an internal
406 overlap (this region is completely within another), we create
407 two hidden crossfades at each boundary. this is not dependent
408 on the auto-xfade option, because we require it as basic
412 xfade_length = min ((nframes_t) 720, top->length());
414 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
415 add_crossfade (xfade);
417 if (top_region_at (top->last_frame() - 1) == top) {
419 only add a fade out if there is no region on top of the end of 'top' (which
423 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
424 add_crossfade (xfade);
429 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active()));
430 add_crossfade (xfade);
434 catch (failed_constructor& err) {
438 catch (Crossfade::NoCrossfadeHere& err) {
446 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
448 Crossfades::iterator ci;
450 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
451 if (*(*ci) == *xfade) { // Crossfade::operator==()
456 if (ci != _crossfades.end()) {
457 // it will just go away
459 _crossfades.push_back (xfade);
461 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
462 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
464 notify_crossfade_added (xfade);
468 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
470 if (g_atomic_int_get(&block_notifications)) {
471 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
473 NewCrossfade (x); /* EMIT SIGNAL */
478 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Crossfade> xfade)
480 Crossfades::iterator i;
482 xfade->in()->resume_fade_in ();
483 xfade->out()->resume_fade_out ();
485 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
486 _crossfades.erase (i);
491 AudioPlaylist::set_state (const XMLNode& node)
495 XMLNodeConstIterator niter;
500 Playlist::set_state (node);
502 nlist = node.children();
504 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
508 if (child->name() != "Crossfade") {
513 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
514 _crossfades.push_back (xfade);
515 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
516 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
520 catch (failed_constructor& err) {
521 // cout << string_compose (_("could not create crossfade object in playlist %1"),
535 AudioPlaylist::clear (bool with_signals)
537 _crossfades.clear ();
538 Playlist::clear (with_signals);
542 AudioPlaylist::state (bool full_state)
544 XMLNode& node = Playlist::state (full_state);
547 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
548 node.add_child_nocopy ((*i)->get_state());
556 AudioPlaylist::dump () const
558 boost::shared_ptr<Region>r;
559 boost::shared_ptr<Crossfade> x;
561 cerr << "Playlist \"" << _name << "\" " << endl
562 << regions.size() << " regions "
563 << _crossfades.size() << " crossfades"
566 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
568 cerr << " " << r->name() << " @ " << r << " ["
569 << r->start() << "+" << r->length()
577 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
588 << (x->active() ? "yes" : "no")
594 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
596 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
597 bool changed = false;
598 Crossfades::iterator c, ctmp;
599 set<boost::shared_ptr<Crossfade> > unique_xfades;
602 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
609 RegionLock rlock (this);
611 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
613 RegionList::iterator tmp = i;
616 if ((*i) == region) {
624 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
626 set<boost::shared_ptr<Region> >::iterator xtmp = x;
629 if ((*x) == region) {
630 all_regions.erase (x);
637 region->set_playlist (boost::shared_ptr<Playlist>());
640 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
644 if ((*c)->involves (r)) {
645 unique_xfades.insert (*c);
646 _crossfades.erase (c);
653 /* overload this, it normally means "removed", not destroyed */
654 notify_region_removed (region);
661 AudioPlaylist::crossfade_changed (Change ignored)
663 if (in_flush || in_set_state) {
667 /* XXX is there a loop here? can an xfade change not happen
668 due to a playlist change? well, sure activation would
669 be an example. maybe we should check the type of change
677 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
679 if (in_flush || in_set_state) {
683 Change our_interests = Change (AudioRegion::FadeInChanged|
684 AudioRegion::FadeOutChanged|
685 AudioRegion::FadeInActiveChanged|
686 AudioRegion::FadeOutActiveChanged|
687 AudioRegion::EnvelopeActiveChanged|
688 AudioRegion::ScaleAmplitudeChanged|
689 AudioRegion::EnvelopeChanged);
690 bool parent_wants_notify;
692 parent_wants_notify = Playlist::region_changed (what_changed, region);
694 if ((parent_wants_notify || (what_changed & our_interests))) {
702 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
704 RegionLock rlock (this);
706 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
707 nframes_t start, end;
709 start = (*i)->position();
710 end = start + (*i)->overlap_length(); // not length(), important difference
712 if (frame >= start && frame <= end) {
713 clist.push_back (*i);