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, DataType::AUDIO, hidden)
45 const XMLProperty* prop = node.property("type");
46 assert(!prop || DataType(prop->value()) == DataType::AUDIO);
53 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
54 : Playlist (session, name, DataType::AUDIO, hidden)
58 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
59 : Playlist (other, name, hidden)
61 RegionList::const_iterator in_o = other->regions.begin();
62 RegionList::iterator in_n = regions.begin();
64 while (in_o != other->regions.end()) {
65 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
67 // We look only for crossfades which begin with the current region, so we don't get doubles
68 for (Crossfades::const_iterator xfades = other->_crossfades.begin(); xfades != other->_crossfades.end(); ++xfades) {
69 if ((*xfades)->in() == ar) {
70 // We found one! Now copy it!
72 RegionList::const_iterator out_o = other->regions.begin();
73 RegionList::const_iterator out_n = regions.begin();
75 while (out_o != other->regions.end()) {
77 boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
79 if ((*xfades)->out() == ar2) {
80 boost::shared_ptr<AudioRegion>in = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
81 boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
82 boost::shared_ptr<Crossfade> new_fade = boost::shared_ptr<Crossfade> (new Crossfade (*xfades, in, out));
83 add_crossfade(new_fade);
90 // cerr << "HUH!? second region in the crossfade not found!" << endl;
99 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
100 : Playlist (other, start, cnt, name, hidden)
102 /* this constructor does NOT notify others (session) */
105 AudioPlaylist::~AudioPlaylist ()
107 GoingAway (); /* EMIT SIGNAL */
109 /* drop connections to signals */
113 _crossfades.clear ();
116 struct RegionSortByLayer {
117 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
118 return a->layer() < b->layer();
123 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
124 nframes_t cnt, unsigned chan_n)
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;
151 _read_data_count = 0;
153 map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
154 map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
155 vector<uint32_t> relevant_layers;
157 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
158 if ((*i)->coverage (start, end) != OverlapNone) {
159 relevant_regions[(*i)->layer()].push_back (*i);
160 relevant_layers.push_back ((*i)->layer());
164 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
165 if ((*i)->coverage (start, end) != OverlapNone) {
166 relevant_xfades[(*i)->upper_layer()].push_back (*i);
170 // RegionSortByLayer layer_cmp;
171 // relevant_regions.sort (layer_cmp);
173 /* XXX this whole per-layer approach is a hack that
174 should be removed once Crossfades become
175 CrossfadeRegions and we just grab a list of relevant
176 regions and call read_at() on all of them.
179 sort (relevant_layers.begin(), relevant_layers.end());
181 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
183 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
184 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
186 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
187 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
189 ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
190 _read_data_count += ar->read_data_count();
193 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
194 (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
196 /* don't JACK up _read_data_count, since its the same data as we just
197 read from the regions, and the OS should handle that for us.
207 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
209 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
216 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
221 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
223 if ((*i)->involves (r)) {
224 i = _crossfades.erase (i);
233 AudioPlaylist::flush_notifications ()
235 Playlist::flush_notifications();
243 Crossfades::iterator a;
244 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
245 NewCrossfade (*a); /* EMIT SIGNAL */
248 _pending_xfade_adds.clear ();
254 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
256 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
257 set<boost::shared_ptr<Crossfade> > updated;
263 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
265 Crossfades::iterator tmp;
270 /* only update them once */
272 if ((*x)->involves (ar)) {
274 pair<set<boost::shared_ptr<Crossfade> >::iterator, bool> const u = updated.insert (*x);
277 /* x was successfully inserted into the set, so it has not already been updated */
282 catch (Crossfade::NoCrossfadeHere& err) {
283 // relax, Invalidated during refresh
293 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
295 boost::shared_ptr<AudioRegion> orig = boost::dynamic_pointer_cast<AudioRegion>(o);
296 boost::shared_ptr<AudioRegion> left = boost::dynamic_pointer_cast<AudioRegion>(l);
297 boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
299 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
300 Crossfades::iterator tmp;
304 boost::shared_ptr<Crossfade> fade;
306 if ((*x)->_in == orig) {
307 if (! (*x)->covers(right->position())) {
308 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, left, (*x)->_out));
310 // Overlap, the crossfade is copied on the left side of the right region instead
311 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, right, (*x)->_out));
315 if ((*x)->_out == orig) {
316 if (! (*x)->covers(right->position())) {
317 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, right));
319 // Overlap, the crossfade is copied on the right side of the left region instead
320 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, left));
325 _crossfades.remove (*x);
326 add_crossfade (fade);
333 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
335 boost::shared_ptr<AudioRegion> other;
336 boost::shared_ptr<AudioRegion> region;
337 boost::shared_ptr<AudioRegion> top;
338 boost::shared_ptr<AudioRegion> bottom;
339 boost::shared_ptr<Crossfade> xfade;
340 RegionList* touched_regions;
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()) {
384 if (!top->opaque()) {
388 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
395 case OverlapInternal:
396 /* {=============== top =============}
397 * [ ----- bottom ------- ]
401 case OverlapExternal:
403 /* [ -------- top ------- ]
404 * {=========== bottom =============}
407 /* to avoid discontinuities at the region boundaries of an internal
408 overlap (this region is completely within another), we create
409 two hidden crossfades at each boundary. this is not dependent
410 on the auto-xfade option, because we require it as basic
414 xfade_length = min ((nframes_t) 720, top->length());
416 if (top_region_at (top->first_frame()) == top) {
418 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
419 add_crossfade (xfade);
422 if (top_region_at (top->last_frame() - 1) == top) {
425 only add a fade out if there is no region on top of the end of 'top' (which
429 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
430 add_crossfade (xfade);
435 /* { ==== top ============ }
436 * [---- bottom -------------------]
439 if (Config->get_xfade_model() == FullCrossfade) {
440 touched_regions = regions_touched (top->first_frame(), bottom->last_frame());
441 if (touched_regions->size() <= 2) {
442 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active()));
443 add_crossfade (xfade);
447 touched_regions = regions_touched (top->first_frame(),
448 top->first_frame() + min ((nframes_t)Config->get_short_xfade_seconds() * _session.frame_rate(),
450 if (touched_regions->size() <= 2) {
451 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active()));
452 add_crossfade (xfade);
459 /* [---- top ------------------------]
460 * { ==== bottom ============ }
463 if (Config->get_xfade_model() == FullCrossfade) {
465 touched_regions = regions_touched (bottom->first_frame(), top->last_frame());
466 if (touched_regions->size() <= 2) {
467 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
468 Config->get_xfade_model(), Config->get_xfades_active()));
469 add_crossfade (xfade);
473 touched_regions = regions_touched (bottom->first_frame(),
474 bottom->first_frame() + min ((nframes_t)Config->get_short_xfade_seconds() * _session.frame_rate(),
476 if (touched_regions->size() <= 2) {
477 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active()));
478 add_crossfade (xfade);
483 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
484 Config->get_xfade_model(), Config->get_xfades_active()));
485 add_crossfade (xfade);
489 catch (failed_constructor& err) {
493 catch (Crossfade::NoCrossfadeHere& err) {
501 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
503 Crossfades::iterator ci;
505 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
506 if (*(*ci) == *xfade) { // Crossfade::operator==()
511 if (ci != _crossfades.end()) {
512 // it will just go away
514 _crossfades.push_back (xfade);
516 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
517 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
519 notify_crossfade_added (xfade);
523 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
525 if (g_atomic_int_get(&block_notifications)) {
526 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
529 NewCrossfade (x); /* EMIT SIGNAL */
534 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
536 Crossfades::iterator i;
537 boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
539 xfade->in()->resume_fade_in ();
540 xfade->out()->resume_fade_out ();
542 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
543 _crossfades.erase (i);
548 AudioPlaylist::set_state (const XMLNode& node)
552 XMLNodeConstIterator niter;
557 Playlist::set_state (node);
559 nlist = node.children();
561 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
565 if (child->name() != "Crossfade") {
570 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
571 _crossfades.push_back (xfade);
572 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
573 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
577 catch (failed_constructor& err) {
578 // cout << string_compose (_("could not create crossfade object in playlist %1"),
592 AudioPlaylist::clear (bool with_signals)
594 _crossfades.clear ();
595 Playlist::clear (with_signals);
599 AudioPlaylist::state (bool full_state)
601 XMLNode& node = Playlist::state (full_state);
604 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
605 node.add_child_nocopy ((*i)->get_state());
613 AudioPlaylist::dump () const
615 boost::shared_ptr<Region>r;
616 boost::shared_ptr<Crossfade> x;
618 cerr << "Playlist \"" << _name << "\" " << endl
619 << regions.size() << " regions "
620 << _crossfades.size() << " crossfades"
623 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
625 cerr << " " << r->name() << " @ " << r << " ["
626 << r->start() << "+" << r->length()
634 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
645 << (x->active() ? "yes" : "no")
651 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
653 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
654 bool changed = false;
655 Crossfades::iterator c, ctmp;
656 set<boost::shared_ptr<Crossfade> > unique_xfades;
659 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
666 RegionLock rlock (this);
668 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
670 RegionList::iterator tmp = i;
673 if ((*i) == region) {
681 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
683 set<boost::shared_ptr<Region> >::iterator xtmp = x;
686 if ((*x) == region) {
687 all_regions.erase (x);
694 region->set_playlist (boost::shared_ptr<Playlist>());
697 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
701 if ((*c)->involves (r)) {
702 unique_xfades.insert (*c);
703 _crossfades.erase (c);
710 /* overload this, it normally means "removed", not destroyed */
711 notify_region_removed (region);
718 AudioPlaylist::crossfade_changed (Change ignored)
720 if (in_flush || in_set_state) {
724 /* XXX is there a loop here? can an xfade change not happen
725 due to a playlist change? well, sure activation would
726 be an example. maybe we should check the type of change
734 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
736 if (in_flush || in_set_state) {
740 Change our_interests = Change (AudioRegion::FadeInChanged|
741 AudioRegion::FadeOutChanged|
742 AudioRegion::FadeInActiveChanged|
743 AudioRegion::FadeOutActiveChanged|
744 AudioRegion::EnvelopeActiveChanged|
745 AudioRegion::ScaleAmplitudeChanged|
746 AudioRegion::EnvelopeChanged);
747 bool parent_wants_notify;
749 parent_wants_notify = Playlist::region_changed (what_changed, region);
751 if ((parent_wants_notify || (what_changed & our_interests))) {
759 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
761 RegionLock rlock (this);
763 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
764 nframes_t start, end;
766 start = (*i)->position();
767 end = start + (*i)->overlap_length(); // not length(), important difference
769 if (frame >= start && frame <= end) {
770 clist.push_back (*i);