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/crossfade_compare.h"
31 #include "ardour/session.h"
32 #include "pbd/enumwriter.h"
36 using namespace ARDOUR;
41 namespace Properties {
42 PBD::PropertyDescriptor<bool> crossfades;
47 AudioPlaylist::make_property_quarks ()
49 Properties::crossfades.property_id = g_quark_from_static_string (X_("crossfades"));
50 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for crossfades = %1\n", Properties::crossfades.property_id));
53 CrossfadeListProperty::CrossfadeListProperty (AudioPlaylist& pl)
54 : SequenceProperty<std::list<boost::shared_ptr<Crossfade> > > (Properties::crossfades.property_id, boost::bind (&AudioPlaylist::update, &pl, _1))
60 CrossfadeListProperty::CrossfadeListProperty (CrossfadeListProperty const & p)
61 : PBD::SequenceProperty<std::list<boost::shared_ptr<Crossfade> > > (p)
62 , _playlist (p._playlist)
68 CrossfadeListProperty *
69 CrossfadeListProperty::create () const
71 return new CrossfadeListProperty (_playlist);
74 CrossfadeListProperty *
75 CrossfadeListProperty::clone () const
77 return new CrossfadeListProperty (*this);
81 CrossfadeListProperty::get_content_as_xml (boost::shared_ptr<Crossfade> xfade, XMLNode & node) const
83 /* Crossfades are not written to any state when they are no
84 longer in use, so we must write their state here.
87 XMLNode& c = xfade->get_state ();
88 node.add_child_nocopy (c);
91 boost::shared_ptr<Crossfade>
92 CrossfadeListProperty::get_content_from_xml (XMLNode const & node) const
94 XMLNodeList const c = node.children ();
95 assert (c.size() == 1);
96 return boost::shared_ptr<Crossfade> (new Crossfade (_playlist, *c.front()));
100 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
101 : Playlist (session, node, DataType::AUDIO, hidden)
102 , _crossfades (*this)
105 const XMLProperty* prop = node.property("type");
106 assert(!prop || DataType(prop->value()) == DataType::AUDIO);
109 add_property (_crossfades);
112 set_state (node, Stateful::loading_state_version);
116 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
117 : Playlist (session, name, DataType::AUDIO, hidden)
118 , _crossfades (*this)
120 add_property (_crossfades);
123 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
124 : Playlist (other, name, hidden)
125 , _crossfades (*this)
127 add_property (_crossfades);
129 RegionList::const_iterator in_o = other->regions.begin();
130 RegionList::iterator in_n = regions.begin();
132 while (in_o != other->regions.end()) {
133 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
135 // We look only for crossfades which begin with the current region, so we don't get doubles
136 for (Crossfades::const_iterator xfades = other->_crossfades.begin(); xfades != other->_crossfades.end(); ++xfades) {
137 if ((*xfades)->in() == ar) {
138 // We found one! Now copy it!
140 RegionList::const_iterator out_o = other->regions.begin();
141 RegionList::const_iterator out_n = regions.begin();
143 while (out_o != other->regions.end()) {
145 boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
147 if ((*xfades)->out() == ar2) {
148 boost::shared_ptr<AudioRegion>in = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
149 boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
150 boost::shared_ptr<Crossfade> new_fade = boost::shared_ptr<Crossfade> (new Crossfade (*xfades, in, out));
151 add_crossfade(new_fade);
158 // cerr << "HUH!? second region in the crossfade not found!" << endl;
167 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
168 : Playlist (other, start, cnt, name, hidden)
169 , _crossfades (*this)
171 add_property (_crossfades);
173 /* this constructor does NOT notify others (session) */
176 AudioPlaylist::~AudioPlaylist ()
178 _crossfades.clear ();
181 struct RegionSortByLayer {
182 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
183 return a->layer() < b->layer();
188 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
189 nframes_t cnt, unsigned chan_n)
193 nframes_t read_frames;
194 nframes_t skip_frames;
196 /* optimizing this memset() away involves a lot of conditionals
197 that may well cause more of a hit due to cache misses
198 and related stuff than just doing this here.
200 it would be great if someone could measure this
203 one way or another, parts of the requested area
204 that are not written to by Region::region_at()
205 for all Regions that cover the area need to be
209 memset (buf, 0, sizeof (Sample) * cnt);
211 /* this function is never called from a realtime thread, so
212 its OK to block (for short intervals).
215 Glib::RecMutex::Lock rm (region_lock);
217 end = start + cnt - 1;
220 _read_data_count = 0;
222 _read_data_count = 0;
224 RegionList* rlist = regions_to_read (start, start+cnt);
226 if (rlist->empty()) {
231 map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
232 map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
233 vector<uint32_t> relevant_layers;
235 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ++i) {
236 if ((*i)->coverage (start, end) != OverlapNone) {
237 relevant_regions[(*i)->layer()].push_back (*i);
238 relevant_layers.push_back ((*i)->layer());
242 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
243 if ((*i)->coverage (start, end) != OverlapNone) {
244 relevant_xfades[(*i)->upper_layer()].push_back (*i);
248 // RegionSortByLayer layer_cmp;
249 // relevant_regions.sort (layer_cmp);
251 /* XXX this whole per-layer approach is a hack that
252 should be removed once Crossfades become
253 CrossfadeRegions and we just grab a list of relevant
254 regions and call read_at() on all of them.
257 sort (relevant_layers.begin(), relevant_layers.end());
259 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
261 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
262 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
265 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
266 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
267 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("read from region %1\n", ar->name()));
269 ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
270 _read_data_count += ar->read_data_count();
273 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
274 (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
276 /* don't JACK up _read_data_count, since its the same data as we just
277 read from the regions, and the OS should handle that for us.
288 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
290 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
297 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
302 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
304 if ((*i)->involves (r)) {
305 i = _crossfades.erase (i);
314 AudioPlaylist::flush_notifications (bool from_undo)
316 Playlist::flush_notifications (from_undo);
324 Crossfades::iterator a;
325 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
326 NewCrossfade (*a); /* EMIT SIGNAL */
329 _pending_xfade_adds.clear ();
335 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
337 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
338 set<boost::shared_ptr<Crossfade> > updated;
344 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
346 Crossfades::iterator tmp;
351 /* only update them once */
353 if ((*x)->involves (ar)) {
355 pair<set<boost::shared_ptr<Crossfade> >::iterator, bool> const u = updated.insert (*x);
358 /* x was successfully inserted into the set, so it has not already been updated */
363 catch (Crossfade::NoCrossfadeHere& err) {
364 // relax, Invalidated during refresh
374 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
376 boost::shared_ptr<AudioRegion> orig = boost::dynamic_pointer_cast<AudioRegion>(o);
377 boost::shared_ptr<AudioRegion> left = boost::dynamic_pointer_cast<AudioRegion>(l);
378 boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
380 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
381 Crossfades::iterator tmp;
385 boost::shared_ptr<Crossfade> fade;
387 if ((*x)->_in == orig) {
388 if (! (*x)->covers(right->position())) {
389 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, left, (*x)->_out));
391 // Overlap, the crossfade is copied on the left side of the right region instead
392 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, right, (*x)->_out));
396 if ((*x)->_out == orig) {
397 if (! (*x)->covers(right->position())) {
398 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, right));
400 // Overlap, the crossfade is copied on the right side of the left region instead
401 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, left));
406 _crossfades.remove (*x);
407 add_crossfade (fade);
414 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
416 boost::shared_ptr<AudioRegion> other;
417 boost::shared_ptr<AudioRegion> region;
418 boost::shared_ptr<AudioRegion> top;
419 boost::shared_ptr<AudioRegion> bottom;
420 boost::shared_ptr<Crossfade> xfade;
421 RegionList* touched_regions = 0;
423 if (in_set_state || in_partition) {
427 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
428 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
434 refresh_dependents (r);
438 if (!_session.config.get_auto_xfade()) {
442 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
443 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
445 if (other == region) {
449 if (other->muted() || region->muted()) {
454 if (other->layer() < region->layer()) {
462 if (!top->opaque()) {
466 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
468 delete touched_regions;
472 framecnt_t xfade_length;
477 case OverlapInternal:
478 /* {=============== top =============}
479 * [ ----- bottom ------- ]
483 case OverlapExternal:
485 /* [ -------- top ------- ]
486 * {=========== bottom =============}
489 /* to avoid discontinuities at the region boundaries of an internal
490 overlap (this region is completely within another), we create
491 two hidden crossfades at each boundary. this is not dependent
492 on the auto-xfade option, because we require it as basic
496 xfade_length = min ((framecnt_t) 720, top->length());
498 if (top_region_at (top->first_frame()) == top) {
500 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
501 add_crossfade (xfade);
504 if (top_region_at (top->last_frame() - 1) == top) {
507 only add a fade out if there is no region on top of the end of 'top' (which
511 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
512 add_crossfade (xfade);
517 /* { ==== top ============ }
518 * [---- bottom -------------------]
521 if (_session.config.get_xfade_model() == FullCrossfade) {
522 touched_regions = regions_touched (top->first_frame(), bottom->last_frame());
523 if (touched_regions->size() <= 2) {
524 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
525 add_crossfade (xfade);
529 touched_regions = regions_touched (top->first_frame(),
530 top->first_frame() + min ((framecnt_t) _session.config.get_short_xfade_seconds() * _session.frame_rate(),
532 if (touched_regions->size() <= 2) {
533 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
534 add_crossfade (xfade);
541 /* [---- top ------------------------]
542 * { ==== bottom ============ }
545 if (_session.config.get_xfade_model() == FullCrossfade) {
547 touched_regions = regions_touched (bottom->first_frame(), top->last_frame());
548 if (touched_regions->size() <= 2) {
549 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
550 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
551 add_crossfade (xfade);
555 touched_regions = regions_touched (bottom->first_frame(),
556 bottom->first_frame() + min ((framecnt_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
558 if (touched_regions->size() <= 2) {
559 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
560 add_crossfade (xfade);
565 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
566 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
567 add_crossfade (xfade);
571 catch (failed_constructor& err) {
575 catch (Crossfade::NoCrossfadeHere& err) {
581 delete touched_regions;
585 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
587 Crossfades::iterator ci;
589 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
590 if (*(*ci) == *xfade) { // Crossfade::operator==()
595 if (ci != _crossfades.end()) {
596 // it will just go away
598 _crossfades.push_back (xfade);
600 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
601 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
603 notify_crossfade_added (xfade);
607 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
609 if (g_atomic_int_get(&block_notifications)) {
610 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
612 NewCrossfade (x); /* EMIT SIGNAL */
617 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
619 Crossfades::iterator i;
620 boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
622 xfade->in()->resume_fade_in ();
623 xfade->out()->resume_fade_out ();
625 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
626 _crossfades.erase (i);
631 AudioPlaylist::set_state (const XMLNode& node, int version)
635 XMLNodeConstIterator niter;
639 Playlist::set_state (node, version);
643 nlist = node.children();
645 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
649 if (child->name() != "Crossfade") {
654 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
655 _crossfades.push_back (xfade);
656 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
657 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
661 catch (failed_constructor& err) {
662 // cout << string_compose (_("could not create crossfade object in playlist %1"),
676 AudioPlaylist::clear (bool with_signals)
678 _crossfades.clear ();
679 Playlist::clear (with_signals);
683 AudioPlaylist::state (bool full_state)
685 XMLNode& node = Playlist::state (full_state);
688 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
689 node.add_child_nocopy ((*i)->get_state());
697 AudioPlaylist::dump () const
699 boost::shared_ptr<Region>r;
700 boost::shared_ptr<Crossfade> x;
702 cerr << "Playlist \"" << _name << "\" " << endl
703 << regions.size() << " regions "
704 << _crossfades.size() << " crossfades"
707 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
709 cerr << " " << r->name() << " @ " << r << " ["
710 << r->start() << "+" << r->length()
718 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
729 << (x->active() ? "yes" : "no")
735 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
737 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
743 bool changed = false;
744 Crossfades::iterator c, ctmp;
745 set<boost::shared_ptr<Crossfade> > unique_xfades;
748 RegionLock rlock (this);
750 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
752 RegionList::iterator tmp = i;
755 if ((*i) == region) {
763 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
765 set<boost::shared_ptr<Region> >::iterator xtmp = x;
768 if ((*x) == region) {
769 all_regions.erase (x);
776 region->set_playlist (boost::shared_ptr<Playlist>());
779 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
783 if ((*c)->involves (r)) {
784 unique_xfades.insert (*c);
785 _crossfades.erase (c);
792 /* overload this, it normally means "removed", not destroyed */
793 notify_region_removed (region);
800 AudioPlaylist::crossfade_changed (const PropertyChange&)
802 if (in_flush || in_set_state) {
806 /* XXX is there a loop here? can an xfade change not happen
807 due to a playlist change? well, sure activation would
808 be an example. maybe we should check the type of change
812 notify_contents_changed ();
816 AudioPlaylist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
818 if (in_flush || in_set_state) {
822 PropertyChange our_interests;
824 our_interests.add (Properties::fade_in_active);
825 our_interests.add (Properties::fade_out_active);
826 our_interests.add (Properties::scale_amplitude);
827 our_interests.add (Properties::envelope_active);
828 our_interests.add (Properties::envelope);
829 our_interests.add (Properties::fade_in);
830 our_interests.add (Properties::fade_out);
832 bool parent_wants_notify;
834 parent_wants_notify = Playlist::region_changed (what_changed, region);
836 if (parent_wants_notify || (what_changed.contains (our_interests))) {
837 notify_contents_changed ();
844 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
846 RegionLock rlock (this);
848 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
849 nframes_t start, end;
851 start = (*i)->position();
852 end = start + (*i)->overlap_length(); // not length(), important difference
854 if (frame >= start && frame <= end) {
855 clist.push_back (*i);
861 AudioPlaylist::foreach_crossfade (boost::function<void (boost::shared_ptr<Crossfade>)> s)
863 RegionLock rl (this, false);
864 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
870 AudioPlaylist::update (const CrossfadeListProperty::ChangeRecord& change)
872 for (CrossfadeListProperty::ChangeContainer::const_iterator i = change.added.begin(); i != change.added.end(); ++i) {
876 /* don't remove crossfades here; they will be dealt with by the dependency code */
879 boost::shared_ptr<Crossfade>
880 AudioPlaylist::find_crossfade (const PBD::ID& id) const
882 Crossfades::const_iterator i = _crossfades.begin ();
883 while (i != _crossfades.end() && (*i)->id() != id) {
887 if (i == _crossfades.end()) {
888 return boost::shared_ptr<Crossfade> ();