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()) {
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()) {
385 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
392 case OverlapInternal:
393 /* {=============== top =============}
394 * [ ----- bottom ------- ]
398 case OverlapExternal:
400 /* [ -------- top ------- ]
401 * {=========== bottom =============}
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
411 xfade_length = min ((nframes_t) 720, top->length());
413 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
414 add_crossfade (xfade);
416 if (top_region_at (top->last_frame() - 1) == top) {
418 only add a fade out if there is no region on top of the end of 'top' (which
422 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
423 add_crossfade (xfade);
428 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active()));
429 add_crossfade (xfade);
433 catch (failed_constructor& err) {
437 catch (Crossfade::NoCrossfadeHere& err) {
445 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
447 Crossfades::iterator ci;
449 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
450 if (*(*ci) == *xfade) { // Crossfade::operator==()
455 if (ci != _crossfades.end()) {
456 // it will just go away
458 _crossfades.push_back (xfade);
460 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
461 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
463 notify_crossfade_added (xfade);
467 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
469 if (g_atomic_int_get(&block_notifications)) {
470 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
472 NewCrossfade (x); /* EMIT SIGNAL */
477 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Crossfade> xfade)
479 Crossfades::iterator i;
481 xfade->in()->resume_fade_in ();
482 xfade->out()->resume_fade_out ();
484 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
485 _crossfades.erase (i);
490 AudioPlaylist::set_state (const XMLNode& node)
494 XMLNodeConstIterator niter;
499 Playlist::set_state (node);
501 nlist = node.children();
503 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
507 if (child->name() != "Crossfade") {
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));
519 catch (failed_constructor& err) {
520 // cout << string_compose (_("could not create crossfade object in playlist %1"),
534 AudioPlaylist::clear (bool with_signals)
536 _crossfades.clear ();
537 Playlist::clear (with_signals);
541 AudioPlaylist::state (bool full_state)
543 XMLNode& node = Playlist::state (full_state);
546 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
547 node.add_child_nocopy ((*i)->get_state());
555 AudioPlaylist::dump () const
557 boost::shared_ptr<Region>r;
558 boost::shared_ptr<Crossfade> x;
560 cerr << "Playlist \"" << _name << "\" " << endl
561 << regions.size() << " regions "
562 << _crossfades.size() << " crossfades"
565 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
567 cerr << " " << r->name() << " @ " << r << " ["
568 << r->start() << "+" << r->length()
576 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
587 << (x->active() ? "yes" : "no")
593 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
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;
601 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
608 RegionLock rlock (this);
610 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
612 RegionList::iterator tmp = i;
615 if ((*i) == region) {
623 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
625 set<boost::shared_ptr<Region> >::iterator xtmp = x;
628 if ((*x) == region) {
629 all_regions.erase (x);
636 region->set_playlist (boost::shared_ptr<Playlist>());
639 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
643 if ((*c)->involves (r)) {
644 unique_xfades.insert (*c);
645 _crossfades.erase (c);
652 /* overload this, it normally means "removed", not destroyed */
653 notify_region_removed (region);
660 AudioPlaylist::crossfade_changed (Change ignored)
662 if (in_flush || in_set_state) {
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
676 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
678 if (in_flush || in_set_state) {
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;
691 parent_wants_notify = Playlist::region_changed (what_changed, region);
693 if ((parent_wants_notify || (what_changed & our_interests))) {
701 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
703 RegionLock rlock (this);
705 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
706 nframes_t start, end;
708 start = (*i)->position();
709 end = start + (*i)->overlap_length(); // not length(), important difference
711 if (frame >= start && frame <= end) {
712 clist.push_back (*i);