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 "ardour/types.h"
25 #include "ardour/debug.h"
26 #include "ardour/configuration.h"
27 #include "ardour/audioplaylist.h"
28 #include "ardour/audioregion.h"
29 #include "ardour/crossfade.h"
30 #include "ardour/session.h"
31 #include "pbd/enumwriter.h"
35 using namespace ARDOUR;
40 namespace Properties {
41 PBD::PropertyDescriptor<bool> crossfades;
46 AudioPlaylist::make_property_quarks ()
48 Properties::crossfades.property_id = g_quark_from_static_string (X_("crossfades"));
49 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for crossfades = %1\n", Properties::crossfades.property_id));
52 CrossfadeListProperty::CrossfadeListProperty (AudioPlaylist& pl)
53 : SequenceProperty<std::list<boost::shared_ptr<Crossfade> > > (Properties::crossfades.property_id, boost::bind (&AudioPlaylist::update, &pl, _1))
59 CrossfadeListProperty::CrossfadeListProperty (CrossfadeListProperty const & p)
60 : PBD::SequenceProperty<std::list<boost::shared_ptr<Crossfade> > > (p)
61 , _playlist (p._playlist)
67 CrossfadeListProperty *
68 CrossfadeListProperty::create () const
70 return new CrossfadeListProperty (_playlist);
73 CrossfadeListProperty *
74 CrossfadeListProperty::clone () const
76 return new CrossfadeListProperty (*this);
80 CrossfadeListProperty::get_content_as_xml (boost::shared_ptr<Crossfade> xfade, XMLNode & node) const
82 /* Crossfades are not written to any state when they are no
83 longer in use, so we must write their state here.
86 XMLNode& c = xfade->get_state ();
87 node.add_child_nocopy (c);
90 boost::shared_ptr<Crossfade>
91 CrossfadeListProperty::get_content_from_xml (XMLNode const & node) const
93 XMLNodeList const c = node.children ();
94 assert (c.size() == 1);
95 return boost::shared_ptr<Crossfade> (new Crossfade (_playlist, *c.front()));
99 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
100 : Playlist (session, node, DataType::AUDIO, hidden)
101 , _crossfades (*this)
104 const XMLProperty* prop = node.property("type");
105 assert(!prop || DataType(prop->value()) == DataType::AUDIO);
108 add_property (_crossfades);
111 set_state (node, Stateful::loading_state_version);
115 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
116 : Playlist (session, name, DataType::AUDIO, hidden)
117 , _crossfades (*this)
119 add_property (_crossfades);
122 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
123 : Playlist (other, name, hidden)
124 , _crossfades (*this)
126 add_property (_crossfades);
128 RegionList::const_iterator in_o = other->regions.begin();
129 RegionList::iterator in_n = regions.begin();
131 while (in_o != other->regions.end()) {
132 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
134 // We look only for crossfades which begin with the current region, so we don't get doubles
135 for (Crossfades::const_iterator xfades = other->_crossfades.begin(); xfades != other->_crossfades.end(); ++xfades) {
136 if ((*xfades)->in() == ar) {
137 // We found one! Now copy it!
139 RegionList::const_iterator out_o = other->regions.begin();
140 RegionList::const_iterator out_n = regions.begin();
142 while (out_o != other->regions.end()) {
144 boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
146 if ((*xfades)->out() == ar2) {
147 boost::shared_ptr<AudioRegion>in = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
148 boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
149 boost::shared_ptr<Crossfade> new_fade = boost::shared_ptr<Crossfade> (new Crossfade (*xfades, in, out));
150 add_crossfade(new_fade);
157 // cerr << "HUH!? second region in the crossfade not found!" << endl;
166 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, framepos_t start, framecnt_t cnt, string name, bool hidden)
167 : Playlist (other, start, cnt, name, hidden)
168 , _crossfades (*this)
170 add_property (_crossfades);
172 /* Audio regions that have been created by the Playlist constructor
173 will currently have the same fade in/out as the regions that they
174 were created from. This is wrong, so reset the fades here.
177 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
178 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (*i);
180 ar->set_default_fades ();
183 /* this constructor does NOT notify others (session) */
186 AudioPlaylist::~AudioPlaylist ()
188 _crossfades.clear ();
191 struct RegionSortByLayer {
192 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
193 return a->layer() < b->layer();
198 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, framepos_t start,
199 framecnt_t cnt, unsigned chan_n)
201 framecnt_t ret = cnt;
203 /* optimizing this memset() away involves a lot of conditionals
204 that may well cause more of a hit due to cache misses
205 and related stuff than just doing this here.
207 it would be great if someone could measure this
210 one way or another, parts of the requested area
211 that are not written to by Region::region_at()
212 for all Regions that cover the area need to be
216 memset (buf, 0, sizeof (Sample) * cnt);
218 /* this function is never called from a realtime thread, so
219 its OK to block (for short intervals).
222 Glib::RecMutex::Lock rm (region_lock);
224 framepos_t const end = start + cnt - 1;
225 framecnt_t read_frames = 0;
226 framecnt_t skip_frames = 0;
227 _read_data_count = 0;
229 _read_data_count = 0;
231 RegionList* rlist = regions_to_read (start, start+cnt);
233 if (rlist->empty()) {
238 map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
239 map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
240 vector<uint32_t> relevant_layers;
242 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ++i) {
243 if ((*i)->coverage (start, end) != OverlapNone) {
244 relevant_regions[(*i)->layer()].push_back (*i);
245 relevant_layers.push_back ((*i)->layer());
249 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
250 if ((*i)->coverage (start, end) != OverlapNone) {
251 relevant_xfades[(*i)->upper_layer()].push_back (*i);
255 // RegionSortByLayer layer_cmp;
256 // relevant_regions.sort (layer_cmp);
258 /* XXX this whole per-layer approach is a hack that
259 should be removed once Crossfades become
260 CrossfadeRegions and we just grab a list of relevant
261 regions and call read_at() on all of them.
264 sort (relevant_layers.begin(), relevant_layers.end());
266 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
268 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
269 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
272 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
273 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
274 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("read from region %1\n", ar->name()));
276 ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
277 _read_data_count += ar->read_data_count();
280 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
281 (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
283 /* don't JACK up _read_data_count, since its the same data as we just
284 read from the regions, and the OS should handle that for us.
295 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
297 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
304 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
309 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
311 if ((*i)->involves (r)) {
312 i = _crossfades.erase (i);
321 AudioPlaylist::flush_notifications (bool from_undo)
323 Playlist::flush_notifications (from_undo);
331 Crossfades::iterator a;
332 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
333 NewCrossfade (*a); /* EMIT SIGNAL */
336 _pending_xfade_adds.clear ();
342 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
344 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
345 set<boost::shared_ptr<Crossfade> > updated;
351 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
353 Crossfades::iterator tmp;
358 /* only update them once */
360 if ((*x)->involves (ar)) {
362 pair<set<boost::shared_ptr<Crossfade> >::iterator, bool> const u = updated.insert (*x);
365 /* x was successfully inserted into the set, so it has not already been updated */
370 catch (Crossfade::NoCrossfadeHere& err) {
371 // relax, Invalidated during refresh
381 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
383 boost::shared_ptr<AudioRegion> orig = boost::dynamic_pointer_cast<AudioRegion>(o);
384 boost::shared_ptr<AudioRegion> left = boost::dynamic_pointer_cast<AudioRegion>(l);
385 boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
387 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
388 Crossfades::iterator tmp;
392 boost::shared_ptr<Crossfade> fade;
394 if ((*x)->_in == orig) {
395 if (! (*x)->covers(right->position())) {
396 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, left, (*x)->_out));
398 // Overlap, the crossfade is copied on the left side of the right region instead
399 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, right, (*x)->_out));
403 if ((*x)->_out == orig) {
404 if (! (*x)->covers(right->position())) {
405 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, right));
407 // Overlap, the crossfade is copied on the right side of the left region instead
408 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, left));
413 _crossfades.remove (*x);
414 add_crossfade (fade);
421 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
423 boost::shared_ptr<AudioRegion> other;
424 boost::shared_ptr<AudioRegion> region;
425 boost::shared_ptr<AudioRegion> top;
426 boost::shared_ptr<AudioRegion> bottom;
427 boost::shared_ptr<Crossfade> xfade;
428 RegionList* touched_regions = 0;
430 if (in_set_state || in_partition) {
434 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
435 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
441 refresh_dependents (r);
445 if (!_session.config.get_auto_xfade()) {
449 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
450 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
452 if (other == region) {
456 if (other->muted() || region->muted()) {
460 if (other->position() == r->position() && other->length() == r->length()) {
461 /* precise overlay of two regions - no xfade */
465 if (other->layer() < region->layer()) {
473 if (!top->opaque()) {
477 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
479 delete touched_regions;
483 framecnt_t xfade_length;
488 case OverlapInternal:
489 /* {=============== top =============}
490 * [ ----- bottom ------- ]
494 case OverlapExternal:
496 /* [ -------- top ------- ]
497 * {=========== bottom =============}
500 /* to avoid discontinuities at the region boundaries of an internal
501 overlap (this region is completely within another), we create
502 two hidden crossfades at each boundary. this is not dependent
503 on the auto-xfade option, because we require it as basic
507 xfade_length = min ((framecnt_t) 720, top->length());
509 if (top_region_at (top->first_frame()) == top) {
511 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
512 add_crossfade (xfade);
515 if (top_region_at (top->last_frame() - 1) == top) {
518 only add a fade out if there is no region on top of the end of 'top' (which
522 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
523 add_crossfade (xfade);
528 /* { ==== top ============ }
529 * [---- bottom -------------------]
532 if (_session.config.get_xfade_model() == FullCrossfade) {
533 touched_regions = regions_touched (top->first_frame(), bottom->last_frame());
534 if (touched_regions->size() <= 2) {
535 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
536 add_crossfade (xfade);
540 touched_regions = regions_touched (top->first_frame(),
541 top->first_frame() + min ((framecnt_t) _session.config.get_short_xfade_seconds() * _session.frame_rate(),
543 if (touched_regions->size() <= 2) {
544 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
545 add_crossfade (xfade);
552 /* [---- top ------------------------]
553 * { ==== bottom ============ }
556 if (_session.config.get_xfade_model() == FullCrossfade) {
558 touched_regions = regions_touched (bottom->first_frame(), top->last_frame());
559 if (touched_regions->size() <= 2) {
560 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
561 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
562 add_crossfade (xfade);
566 touched_regions = regions_touched (bottom->first_frame(),
567 bottom->first_frame() + min ((framecnt_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
569 if (touched_regions->size() <= 2) {
570 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
571 add_crossfade (xfade);
576 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
577 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
578 add_crossfade (xfade);
582 catch (failed_constructor& err) {
586 catch (Crossfade::NoCrossfadeHere& err) {
592 delete touched_regions;
596 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
598 Crossfades::iterator ci;
600 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
601 if (*(*ci) == *xfade) { // Crossfade::operator==()
606 if (ci != _crossfades.end()) {
607 // it will just go away
609 _crossfades.push_back (xfade);
611 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
612 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
614 notify_crossfade_added (xfade);
618 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
620 if (g_atomic_int_get(&block_notifications)) {
621 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
623 NewCrossfade (x); /* EMIT SIGNAL */
628 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
630 Crossfades::iterator i;
631 boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
633 xfade->in()->resume_fade_in ();
634 xfade->out()->resume_fade_out ();
636 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
637 _crossfades.erase (i);
642 AudioPlaylist::set_state (const XMLNode& node, int version)
646 XMLNodeConstIterator niter;
650 Playlist::set_state (node, version);
654 nlist = node.children();
656 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
660 if (child->name() != "Crossfade") {
665 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
666 _crossfades.push_back (xfade);
667 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
668 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
672 catch (failed_constructor& err) {
673 // cout << string_compose (_("could not create crossfade object in playlist %1"),
687 AudioPlaylist::clear (bool with_signals)
689 _crossfades.clear ();
690 Playlist::clear (with_signals);
694 AudioPlaylist::state (bool full_state)
696 XMLNode& node = Playlist::state (full_state);
699 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
700 node.add_child_nocopy ((*i)->get_state());
708 AudioPlaylist::dump () const
710 boost::shared_ptr<Region>r;
711 boost::shared_ptr<Crossfade> x;
713 cerr << "Playlist \"" << _name << "\" " << endl
714 << regions.size() << " regions "
715 << _crossfades.size() << " crossfades"
718 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
720 cerr << " " << r->name() << " @ " << r << " ["
721 << r->start() << "+" << r->length()
729 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
740 << (x->active() ? "yes" : "no")
746 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
748 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
754 bool changed = false;
755 Crossfades::iterator c, ctmp;
756 set<boost::shared_ptr<Crossfade> > unique_xfades;
759 RegionLock rlock (this);
761 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
763 RegionList::iterator tmp = i;
766 if ((*i) == region) {
774 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
776 set<boost::shared_ptr<Region> >::iterator xtmp = x;
779 if ((*x) == region) {
780 all_regions.erase (x);
787 region->set_playlist (boost::shared_ptr<Playlist>());
790 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
794 if ((*c)->involves (r)) {
795 unique_xfades.insert (*c);
796 _crossfades.erase (c);
803 /* overload this, it normally means "removed", not destroyed */
804 notify_region_removed (region);
811 AudioPlaylist::crossfade_changed (const PropertyChange&)
813 if (in_flush || in_set_state) {
817 /* XXX is there a loop here? can an xfade change not happen
818 due to a playlist change? well, sure activation would
819 be an example. maybe we should check the type of change
823 notify_contents_changed ();
827 AudioPlaylist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
829 if (in_flush || in_set_state) {
833 PropertyChange our_interests;
835 our_interests.add (Properties::fade_in_active);
836 our_interests.add (Properties::fade_out_active);
837 our_interests.add (Properties::scale_amplitude);
838 our_interests.add (Properties::envelope_active);
839 our_interests.add (Properties::envelope);
840 our_interests.add (Properties::fade_in);
841 our_interests.add (Properties::fade_out);
843 bool parent_wants_notify;
845 parent_wants_notify = Playlist::region_changed (what_changed, region);
847 if (parent_wants_notify || (what_changed.contains (our_interests))) {
848 notify_contents_changed ();
855 AudioPlaylist::crossfades_at (framepos_t frame, Crossfades& clist)
857 RegionLock rlock (this);
859 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
860 framepos_t const start = (*i)->position ();
861 framepos_t const end = start + (*i)->overlap_length(); // not length(), important difference
863 if (frame >= start && frame <= end) {
864 clist.push_back (*i);
870 AudioPlaylist::foreach_crossfade (boost::function<void (boost::shared_ptr<Crossfade>)> s)
872 RegionLock rl (this, false);
873 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
879 AudioPlaylist::update (const CrossfadeListProperty::ChangeRecord& change)
881 for (CrossfadeListProperty::ChangeContainer::const_iterator i = change.added.begin(); i != change.added.end(); ++i) {
885 /* don't remove crossfades here; they will be dealt with by the dependency code */
888 boost::shared_ptr<Crossfade>
889 AudioPlaylist::find_crossfade (const PBD::ID& id) const
891 Crossfades::const_iterator i = _crossfades.begin ();
892 while (i != _crossfades.end() && (*i)->id() != id) {
896 if (i == _crossfades.end()) {
897 return boost::shared_ptr<Crossfade> ();