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 "ardour/types.h"
26 #include "ardour/debug.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;
41 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
42 : Playlist (session, node, DataType::AUDIO, hidden)
45 const XMLProperty* prop = node.property("type");
46 assert(!prop || DataType(prop->value()) == DataType::AUDIO);
50 set_state (node, Stateful::loading_state_version);
54 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
55 : Playlist (session, name, DataType::AUDIO, hidden)
59 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
60 : Playlist (other, name, hidden)
62 RegionList::const_iterator in_o = other->regions.begin();
63 RegionList::iterator in_n = regions.begin();
65 while (in_o != other->regions.end()) {
66 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
68 // We look only for crossfades which begin with the current region, so we don't get doubles
69 for (Crossfades::const_iterator xfades = other->_crossfades.begin(); xfades != other->_crossfades.end(); ++xfades) {
70 if ((*xfades)->in() == ar) {
71 // We found one! Now copy it!
73 RegionList::const_iterator out_o = other->regions.begin();
74 RegionList::const_iterator out_n = regions.begin();
76 while (out_o != other->regions.end()) {
78 boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
80 if ((*xfades)->out() == ar2) {
81 boost::shared_ptr<AudioRegion>in = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
82 boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
83 boost::shared_ptr<Crossfade> new_fade = boost::shared_ptr<Crossfade> (new Crossfade (*xfades, in, out));
84 add_crossfade(new_fade);
91 // cerr << "HUH!? second region in the crossfade not found!" << endl;
100 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
101 : Playlist (other, start, cnt, name, hidden)
103 /* this constructor does NOT notify others (session) */
106 AudioPlaylist::~AudioPlaylist ()
108 _crossfades.clear ();
111 struct RegionSortByLayer {
112 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
113 return a->layer() < b->layer();
118 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
119 nframes_t cnt, unsigned chan_n)
123 nframes_t read_frames;
124 nframes_t skip_frames;
126 /* optimizing this memset() away involves a lot of conditionals
127 that may well cause more of a hit due to cache misses
128 and related stuff than just doing this here.
130 it would be great if someone could measure this
133 one way or another, parts of the requested area
134 that are not written to by Region::region_at()
135 for all Regions that cover the area need to be
139 memset (buf, 0, sizeof (Sample) * cnt);
141 /* this function is never called from a realtime thread, so
142 its OK to block (for short intervals).
145 Glib::RecMutex::Lock rm (region_lock);
147 end = start + cnt - 1;
150 _read_data_count = 0;
152 _read_data_count = 0;
154 RegionList* rlist = regions_to_read (start, start+cnt);
156 if (rlist->empty()) {
161 map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
162 map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
163 vector<uint32_t> relevant_layers;
165 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ++i) {
166 if ((*i)->coverage (start, end) != OverlapNone) {
167 relevant_regions[(*i)->layer()].push_back (*i);
168 relevant_layers.push_back ((*i)->layer());
172 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
173 if ((*i)->coverage (start, end) != OverlapNone) {
174 relevant_xfades[(*i)->upper_layer()].push_back (*i);
178 // RegionSortByLayer layer_cmp;
179 // relevant_regions.sort (layer_cmp);
181 /* XXX this whole per-layer approach is a hack that
182 should be removed once Crossfades become
183 CrossfadeRegions and we just grab a list of relevant
184 regions and call read_at() on all of them.
187 sort (relevant_layers.begin(), relevant_layers.end());
189 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
191 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
192 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
195 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
196 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
197 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("read from region %1\n", ar->name()));
199 ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
200 _read_data_count += ar->read_data_count();
203 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
204 (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
206 /* don't JACK up _read_data_count, since its the same data as we just
207 read from the regions, and the OS should handle that for us.
218 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
220 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
227 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
232 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
234 if ((*i)->involves (r)) {
235 i = _crossfades.erase (i);
244 AudioPlaylist::flush_notifications (bool from_undo)
246 Playlist::flush_notifications (from_undo);
254 Crossfades::iterator a;
255 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
256 NewCrossfade (*a); /* EMIT SIGNAL */
259 _pending_xfade_adds.clear ();
265 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
267 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
268 set<boost::shared_ptr<Crossfade> > updated;
274 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
276 Crossfades::iterator tmp;
281 /* only update them once */
283 if ((*x)->involves (ar)) {
285 pair<set<boost::shared_ptr<Crossfade> >::iterator, bool> const u = updated.insert (*x);
288 /* x was successfully inserted into the set, so it has not already been updated */
293 catch (Crossfade::NoCrossfadeHere& err) {
294 // relax, Invalidated during refresh
304 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
306 boost::shared_ptr<AudioRegion> orig = boost::dynamic_pointer_cast<AudioRegion>(o);
307 boost::shared_ptr<AudioRegion> left = boost::dynamic_pointer_cast<AudioRegion>(l);
308 boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
310 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
311 Crossfades::iterator tmp;
315 boost::shared_ptr<Crossfade> fade;
317 if ((*x)->_in == orig) {
318 if (! (*x)->covers(right->position())) {
319 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, left, (*x)->_out));
321 // Overlap, the crossfade is copied on the left side of the right region instead
322 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, right, (*x)->_out));
326 if ((*x)->_out == orig) {
327 if (! (*x)->covers(right->position())) {
328 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, right));
330 // Overlap, the crossfade is copied on the right side of the left region instead
331 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, left));
336 _crossfades.remove (*x);
337 add_crossfade (fade);
344 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
346 boost::shared_ptr<AudioRegion> other;
347 boost::shared_ptr<AudioRegion> region;
348 boost::shared_ptr<AudioRegion> top;
349 boost::shared_ptr<AudioRegion> bottom;
350 boost::shared_ptr<Crossfade> xfade;
351 RegionList* touched_regions = 0;
353 if (in_set_state || in_partition) {
357 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
358 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
364 refresh_dependents (r);
368 if (!_session.config.get_auto_xfade()) {
372 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
373 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
375 if (other == region) {
379 if (other->muted() || region->muted()) {
384 if (other->layer() < region->layer()) {
392 if (!top->opaque()) {
396 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
398 delete touched_regions;
402 nframes_t xfade_length;
407 case OverlapInternal:
408 /* {=============== top =============}
409 * [ ----- bottom ------- ]
413 case OverlapExternal:
415 /* [ -------- top ------- ]
416 * {=========== bottom =============}
419 /* to avoid discontinuities at the region boundaries of an internal
420 overlap (this region is completely within another), we create
421 two hidden crossfades at each boundary. this is not dependent
422 on the auto-xfade option, because we require it as basic
426 xfade_length = min ((framecnt_t) 720, top->length());
428 if (top_region_at (top->first_frame()) == top) {
430 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
431 add_crossfade (xfade);
434 if (top_region_at (top->last_frame() - 1) == top) {
437 only add a fade out if there is no region on top of the end of 'top' (which
441 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
442 add_crossfade (xfade);
447 /* { ==== top ============ }
448 * [---- bottom -------------------]
451 if (_session.config.get_xfade_model() == FullCrossfade) {
452 touched_regions = regions_touched (top->first_frame(), bottom->last_frame());
453 if (touched_regions->size() <= 2) {
454 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
455 add_crossfade (xfade);
459 touched_regions = regions_touched (top->first_frame(),
460 top->first_frame() + min ((framecnt_t) _session.config.get_short_xfade_seconds() * _session.frame_rate(),
462 if (touched_regions->size() <= 2) {
463 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
464 add_crossfade (xfade);
471 /* [---- top ------------------------]
472 * { ==== bottom ============ }
475 if (_session.config.get_xfade_model() == FullCrossfade) {
477 touched_regions = regions_touched (bottom->first_frame(), top->last_frame());
478 if (touched_regions->size() <= 2) {
479 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
480 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
481 add_crossfade (xfade);
485 touched_regions = regions_touched (bottom->first_frame(),
486 bottom->first_frame() + min ((framecnt_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
488 if (touched_regions->size() <= 2) {
489 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
490 add_crossfade (xfade);
495 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
496 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
497 add_crossfade (xfade);
501 catch (failed_constructor& err) {
505 catch (Crossfade::NoCrossfadeHere& err) {
511 delete touched_regions;
515 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
517 Crossfades::iterator ci;
519 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
520 if (*(*ci) == *xfade) { // Crossfade::operator==()
525 if (ci != _crossfades.end()) {
526 // it will just go away
528 _crossfades.push_back (xfade);
530 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
531 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
533 notify_crossfade_added (xfade);
537 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
539 if (g_atomic_int_get(&block_notifications)) {
540 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
542 NewCrossfade (x); /* EMIT SIGNAL */
547 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
549 Crossfades::iterator i;
550 boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
552 xfade->in()->resume_fade_in ();
553 xfade->out()->resume_fade_out ();
555 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
556 _crossfades.erase (i);
561 AudioPlaylist::set_state (const XMLNode& node, int version)
565 XMLNodeConstIterator niter;
569 Playlist::set_state (node, version);
573 nlist = node.children();
575 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
579 if (child->name() != "Crossfade") {
584 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
585 _crossfades.push_back (xfade);
586 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
587 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
591 catch (failed_constructor& err) {
592 // cout << string_compose (_("could not create crossfade object in playlist %1"),
606 AudioPlaylist::clear (bool with_signals)
608 _crossfades.clear ();
609 Playlist::clear (with_signals);
613 AudioPlaylist::state (bool full_state)
615 XMLNode& node = Playlist::state (full_state);
618 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
619 node.add_child_nocopy ((*i)->get_state());
627 AudioPlaylist::dump () const
629 boost::shared_ptr<Region>r;
630 boost::shared_ptr<Crossfade> x;
632 cerr << "Playlist \"" << _name << "\" " << endl
633 << regions.size() << " regions "
634 << _crossfades.size() << " crossfades"
637 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
639 cerr << " " << r->name() << " @ " << r << " ["
640 << r->start() << "+" << r->length()
648 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
659 << (x->active() ? "yes" : "no")
665 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
667 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
673 bool changed = false;
674 Crossfades::iterator c, ctmp;
675 set<boost::shared_ptr<Crossfade> > unique_xfades;
678 RegionLock rlock (this);
680 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
682 RegionList::iterator tmp = i;
685 if ((*i) == region) {
693 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
695 set<boost::shared_ptr<Region> >::iterator xtmp = x;
698 if ((*x) == region) {
699 all_regions.erase (x);
706 region->set_playlist (boost::shared_ptr<Playlist>());
709 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
713 if ((*c)->involves (r)) {
714 unique_xfades.insert (*c);
715 _crossfades.erase (c);
722 /* overload this, it normally means "removed", not destroyed */
723 notify_region_removed (region);
730 AudioPlaylist::crossfade_changed (const PropertyChange&)
732 if (in_flush || in_set_state) {
736 /* XXX is there a loop here? can an xfade change not happen
737 due to a playlist change? well, sure activation would
738 be an example. maybe we should check the type of change
742 notify_contents_changed ();
746 AudioPlaylist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
748 if (in_flush || in_set_state) {
752 PropertyChange our_interests;
754 our_interests.add (Properties::fade_in_active);
755 our_interests.add (Properties::fade_out_active);
756 our_interests.add (Properties::scale_amplitude);
757 our_interests.add (Properties::envelope_active);
758 our_interests.add (Properties::envelope);
759 our_interests.add (Properties::fade_in);
760 our_interests.add (Properties::fade_out);
762 bool parent_wants_notify;
764 parent_wants_notify = Playlist::region_changed (what_changed, region);
766 if (parent_wants_notify || (what_changed.contains (our_interests))) {
767 notify_contents_changed ();
774 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
776 RegionLock rlock (this);
778 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
779 nframes_t start, end;
781 start = (*i)->position();
782 end = start + (*i)->overlap_length(); // not length(), important difference
784 if (frame >= start && frame <= end) {
785 clist.push_back (*i);
791 AudioPlaylist::foreach_crossfade (boost::function<void (boost::shared_ptr<Crossfade>)> s)
793 RegionLock rl (this, false);
794 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {