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 /* this constructor does NOT notify others (session) */
175 AudioPlaylist::~AudioPlaylist ()
177 _crossfades.clear ();
180 struct RegionSortByLayer {
181 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
182 return a->layer() < b->layer();
187 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, framepos_t start,
188 framecnt_t cnt, unsigned chan_n)
190 framecnt_t ret = cnt;
192 /* optimizing this memset() away involves a lot of conditionals
193 that may well cause more of a hit due to cache misses
194 and related stuff than just doing this here.
196 it would be great if someone could measure this
199 one way or another, parts of the requested area
200 that are not written to by Region::region_at()
201 for all Regions that cover the area need to be
205 memset (buf, 0, sizeof (Sample) * cnt);
207 /* this function is never called from a realtime thread, so
208 its OK to block (for short intervals).
211 Glib::RecMutex::Lock rm (region_lock);
213 framepos_t const end = start + cnt - 1;
214 framecnt_t read_frames = 0;
215 framecnt_t skip_frames = 0;
216 _read_data_count = 0;
218 _read_data_count = 0;
220 RegionList* rlist = regions_to_read (start, start+cnt);
222 if (rlist->empty()) {
227 map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
228 map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
229 vector<uint32_t> relevant_layers;
231 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ++i) {
232 if ((*i)->coverage (start, end) != OverlapNone) {
233 relevant_regions[(*i)->layer()].push_back (*i);
234 relevant_layers.push_back ((*i)->layer());
238 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
239 if ((*i)->coverage (start, end) != OverlapNone) {
240 relevant_xfades[(*i)->upper_layer()].push_back (*i);
244 // RegionSortByLayer layer_cmp;
245 // relevant_regions.sort (layer_cmp);
247 /* XXX this whole per-layer approach is a hack that
248 should be removed once Crossfades become
249 CrossfadeRegions and we just grab a list of relevant
250 regions and call read_at() on all of them.
253 sort (relevant_layers.begin(), relevant_layers.end());
255 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
257 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
258 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
261 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
262 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
263 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("read from region %1\n", ar->name()));
265 ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
266 _read_data_count += ar->read_data_count();
269 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
270 (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
272 /* don't JACK up _read_data_count, since its the same data as we just
273 read from the regions, and the OS should handle that for us.
284 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
286 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
293 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
298 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
300 if ((*i)->involves (r)) {
301 i = _crossfades.erase (i);
310 AudioPlaylist::flush_notifications (bool from_undo)
312 Playlist::flush_notifications (from_undo);
320 Crossfades::iterator a;
321 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
322 NewCrossfade (*a); /* EMIT SIGNAL */
325 _pending_xfade_adds.clear ();
331 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
333 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
334 set<boost::shared_ptr<Crossfade> > updated;
340 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
342 Crossfades::iterator tmp;
347 /* only update them once */
349 if ((*x)->involves (ar)) {
351 pair<set<boost::shared_ptr<Crossfade> >::iterator, bool> const u = updated.insert (*x);
354 /* x was successfully inserted into the set, so it has not already been updated */
359 catch (Crossfade::NoCrossfadeHere& err) {
360 // relax, Invalidated during refresh
370 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
372 boost::shared_ptr<AudioRegion> orig = boost::dynamic_pointer_cast<AudioRegion>(o);
373 boost::shared_ptr<AudioRegion> left = boost::dynamic_pointer_cast<AudioRegion>(l);
374 boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
376 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
377 Crossfades::iterator tmp;
381 boost::shared_ptr<Crossfade> fade;
383 if ((*x)->_in == orig) {
384 if (! (*x)->covers(right->position())) {
385 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, left, (*x)->_out));
387 // Overlap, the crossfade is copied on the left side of the right region instead
388 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, right, (*x)->_out));
392 if ((*x)->_out == orig) {
393 if (! (*x)->covers(right->position())) {
394 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, right));
396 // Overlap, the crossfade is copied on the right side of the left region instead
397 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, left));
402 _crossfades.remove (*x);
403 add_crossfade (fade);
410 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
412 boost::shared_ptr<AudioRegion> other;
413 boost::shared_ptr<AudioRegion> region;
414 boost::shared_ptr<AudioRegion> top;
415 boost::shared_ptr<AudioRegion> bottom;
416 boost::shared_ptr<Crossfade> xfade;
417 RegionList* touched_regions = 0;
419 if (in_set_state || in_partition) {
423 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
424 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
430 refresh_dependents (r);
434 if (!_session.config.get_auto_xfade()) {
438 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
439 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
441 if (other == region) {
445 if (other->muted() || region->muted()) {
450 if (other->layer() < region->layer()) {
458 if (!top->opaque()) {
462 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
464 delete touched_regions;
468 framecnt_t xfade_length;
473 case OverlapInternal:
474 /* {=============== top =============}
475 * [ ----- bottom ------- ]
479 case OverlapExternal:
481 /* [ -------- top ------- ]
482 * {=========== bottom =============}
485 /* to avoid discontinuities at the region boundaries of an internal
486 overlap (this region is completely within another), we create
487 two hidden crossfades at each boundary. this is not dependent
488 on the auto-xfade option, because we require it as basic
492 xfade_length = min ((framecnt_t) 720, top->length());
494 if (top_region_at (top->first_frame()) == top) {
496 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
497 add_crossfade (xfade);
500 if (top_region_at (top->last_frame() - 1) == top) {
503 only add a fade out if there is no region on top of the end of 'top' (which
507 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
508 add_crossfade (xfade);
513 /* { ==== top ============ }
514 * [---- bottom -------------------]
517 if (_session.config.get_xfade_model() == FullCrossfade) {
518 touched_regions = regions_touched (top->first_frame(), bottom->last_frame());
519 if (touched_regions->size() <= 2) {
520 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
521 add_crossfade (xfade);
525 touched_regions = regions_touched (top->first_frame(),
526 top->first_frame() + min ((framecnt_t) _session.config.get_short_xfade_seconds() * _session.frame_rate(),
528 if (touched_regions->size() <= 2) {
529 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
530 add_crossfade (xfade);
537 /* [---- top ------------------------]
538 * { ==== bottom ============ }
541 if (_session.config.get_xfade_model() == FullCrossfade) {
543 touched_regions = regions_touched (bottom->first_frame(), top->last_frame());
544 if (touched_regions->size() <= 2) {
545 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
546 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
547 add_crossfade (xfade);
551 touched_regions = regions_touched (bottom->first_frame(),
552 bottom->first_frame() + min ((framecnt_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
554 if (touched_regions->size() <= 2) {
555 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
556 add_crossfade (xfade);
561 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
562 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
563 add_crossfade (xfade);
567 catch (failed_constructor& err) {
571 catch (Crossfade::NoCrossfadeHere& err) {
577 delete touched_regions;
581 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
583 Crossfades::iterator ci;
585 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
586 if (*(*ci) == *xfade) { // Crossfade::operator==()
591 if (ci != _crossfades.end()) {
592 // it will just go away
594 _crossfades.push_back (xfade);
596 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
597 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
599 notify_crossfade_added (xfade);
603 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
605 if (g_atomic_int_get(&block_notifications)) {
606 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
608 NewCrossfade (x); /* EMIT SIGNAL */
613 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
615 Crossfades::iterator i;
616 boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
618 xfade->in()->resume_fade_in ();
619 xfade->out()->resume_fade_out ();
621 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
622 _crossfades.erase (i);
627 AudioPlaylist::set_state (const XMLNode& node, int version)
631 XMLNodeConstIterator niter;
635 Playlist::set_state (node, version);
639 nlist = node.children();
641 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
645 if (child->name() != "Crossfade") {
650 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
651 _crossfades.push_back (xfade);
652 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
653 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
657 catch (failed_constructor& err) {
658 // cout << string_compose (_("could not create crossfade object in playlist %1"),
672 AudioPlaylist::clear (bool with_signals)
674 _crossfades.clear ();
675 Playlist::clear (with_signals);
679 AudioPlaylist::state (bool full_state)
681 XMLNode& node = Playlist::state (full_state);
684 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
685 node.add_child_nocopy ((*i)->get_state());
693 AudioPlaylist::dump () const
695 boost::shared_ptr<Region>r;
696 boost::shared_ptr<Crossfade> x;
698 cerr << "Playlist \"" << _name << "\" " << endl
699 << regions.size() << " regions "
700 << _crossfades.size() << " crossfades"
703 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
705 cerr << " " << r->name() << " @ " << r << " ["
706 << r->start() << "+" << r->length()
714 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
725 << (x->active() ? "yes" : "no")
731 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
733 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
739 bool changed = false;
740 Crossfades::iterator c, ctmp;
741 set<boost::shared_ptr<Crossfade> > unique_xfades;
744 RegionLock rlock (this);
746 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
748 RegionList::iterator tmp = i;
751 if ((*i) == region) {
759 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
761 set<boost::shared_ptr<Region> >::iterator xtmp = x;
764 if ((*x) == region) {
765 all_regions.erase (x);
772 region->set_playlist (boost::shared_ptr<Playlist>());
775 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
779 if ((*c)->involves (r)) {
780 unique_xfades.insert (*c);
781 _crossfades.erase (c);
788 /* overload this, it normally means "removed", not destroyed */
789 notify_region_removed (region);
796 AudioPlaylist::crossfade_changed (const PropertyChange&)
798 if (in_flush || in_set_state) {
802 /* XXX is there a loop here? can an xfade change not happen
803 due to a playlist change? well, sure activation would
804 be an example. maybe we should check the type of change
808 notify_contents_changed ();
812 AudioPlaylist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
814 if (in_flush || in_set_state) {
818 PropertyChange our_interests;
820 our_interests.add (Properties::fade_in_active);
821 our_interests.add (Properties::fade_out_active);
822 our_interests.add (Properties::scale_amplitude);
823 our_interests.add (Properties::envelope_active);
824 our_interests.add (Properties::envelope);
825 our_interests.add (Properties::fade_in);
826 our_interests.add (Properties::fade_out);
828 bool parent_wants_notify;
830 parent_wants_notify = Playlist::region_changed (what_changed, region);
832 if (parent_wants_notify || (what_changed.contains (our_interests))) {
833 notify_contents_changed ();
840 AudioPlaylist::crossfades_at (framepos_t frame, Crossfades& clist)
842 RegionLock rlock (this);
844 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
845 framepos_t const start = (*i)->position ();
846 framepos_t const end = start + (*i)->overlap_length(); // not length(), important difference
848 if (frame >= start && frame <= end) {
849 clist.push_back (*i);
855 AudioPlaylist::foreach_crossfade (boost::function<void (boost::shared_ptr<Crossfade>)> s)
857 RegionLock rl (this, false);
858 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
864 AudioPlaylist::update (const CrossfadeListProperty::ChangeRecord& change)
866 for (CrossfadeListProperty::ChangeContainer::const_iterator i = change.added.begin(); i != change.added.end(); ++i) {
870 /* don't remove crossfades here; they will be dealt with by the dependency code */
873 boost::shared_ptr<Crossfade>
874 AudioPlaylist::find_crossfade (const PBD::ID& id) const
876 Crossfades::const_iterator i = _crossfades.begin ();
877 while (i != _crossfades.end() && (*i)->id() != id) {
881 if (i == _crossfades.end()) {
882 return boost::shared_ptr<Crossfade> ();