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.
25 #include <sigc++/bind.h>
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>
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()) {
277 if ((*x)->refresh ()) {
278 /* not invalidated by the refresh */
289 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
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);
295 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
296 Crossfades::iterator tmp;
300 boost::shared_ptr<Crossfade> fade;
302 if ((*x)->_in == orig) {
303 if (! (*x)->covers(right->position())) {
304 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, left, (*x)->_out));
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));
311 if ((*x)->_out == orig) {
312 if (! (*x)->covers(right->position())) {
313 fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, (*x)->_in, right));
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));
321 _crossfades.remove (*x);
322 add_crossfade (fade);
329 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
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;
337 if (in_set_state || in_partition) {
341 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
342 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
348 refresh_dependents (r);
351 if (!Config->get_auto_xfade()) {
355 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
357 nframes_t xfade_length;
359 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
361 if (other == region) {
365 if (other->muted() || region->muted()) {
370 if (other->layer() < region->layer()) {
379 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
386 case OverlapInternal:
387 /* {=============== top =============}
388 * [ ----- bottom ------- ]
392 case OverlapExternal:
394 /* [ -------- top ------- ]
395 * {=========== bottom =============}
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
405 xfade_length = min ((nframes_t) 720, top->length());
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);
411 if (top_region_at (top->last_frame() - 1) == top) {
413 only add a fade out if there is no region on top of the end of 'top' (which
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);
424 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active()));
425 add_crossfade (xfade);
429 catch (failed_constructor& err) {
433 catch (Crossfade::NoCrossfadeHere& err) {
441 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
443 Crossfades::iterator ci;
445 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
446 if (*(*ci) == *xfade) { // Crossfade::operator==()
451 if (ci != _crossfades.end()) {
452 // it will just go away
454 _crossfades.push_back (xfade);
456 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
457 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
459 notify_crossfade_added (xfade);
463 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
465 if (g_atomic_int_get(&block_notifications)) {
466 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
468 NewCrossfade (x); /* EMIT SIGNAL */
473 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Crossfade> xfade)
475 Crossfades::iterator i;
477 xfade->in()->resume_fade_in ();
478 xfade->out()->resume_fade_out ();
480 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
481 _crossfades.erase (i);
486 AudioPlaylist::set_state (const XMLNode& node)
490 XMLNodeConstIterator niter;
495 Playlist::set_state (node);
497 nlist = node.children();
499 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
503 if (child->name() != "Crossfade") {
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));
515 catch (failed_constructor& err) {
516 // cout << string_compose (_("could not create crossfade object in playlist %1"),
530 AudioPlaylist::clear (bool with_signals)
532 _crossfades.clear ();
533 Playlist::clear (with_signals);
537 AudioPlaylist::state (bool full_state)
539 XMLNode& node = Playlist::state (full_state);
542 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
543 node.add_child_nocopy ((*i)->get_state());
551 AudioPlaylist::dump () const
553 boost::shared_ptr<Region>r;
554 boost::shared_ptr<Crossfade> x;
556 cerr << "Playlist \"" << _name << "\" " << endl
557 << regions.size() << " regions "
558 << _crossfades.size() << " crossfades"
561 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
563 cerr << " " << r->name() << " @ " << r << " ["
564 << r->start() << "+" << r->length()
572 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
583 << (x->active() ? "yes" : "no")
589 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
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;
597 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
604 RegionLock rlock (this);
606 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
608 RegionList::iterator tmp = i;
611 if ((*i) == region) {
619 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
621 set<boost::shared_ptr<Region> >::iterator xtmp = x;
624 if ((*x) == region) {
625 all_regions.erase (x);
632 region->set_playlist (boost::shared_ptr<Playlist>());
635 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
639 if ((*c)->involves (r)) {
640 unique_xfades.insert (*c);
641 _crossfades.erase (c);
648 /* overload this, it normally means "removed", not destroyed */
649 notify_region_removed (region);
656 AudioPlaylist::crossfade_changed (Change ignored)
658 if (in_flush || in_set_state) {
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
672 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
674 if (in_flush || in_set_state) {
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;
687 parent_wants_notify = Playlist::region_changed (what_changed, region);
689 if ((parent_wants_notify || (what_changed & our_interests))) {
697 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
699 RegionLock rlock (this);
701 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
702 nframes_t start, end;
704 start = (*i)->position();
705 end = start + (*i)->overlap_length(); // not length(), important difference
707 if (frame >= start && frame <= end) {
708 clist.push_back (*i);