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))
61 CrossfadeListProperty *
62 CrossfadeListProperty::create () const
64 return new CrossfadeListProperty (_playlist);
67 CrossfadeListProperty *
68 CrossfadeListProperty::clone () const
70 return new CrossfadeListProperty (*this);
74 CrossfadeListProperty::get_content_as_xml (boost::shared_ptr<Crossfade> xfade, XMLNode & node) const
76 /* Crossfades are not written to any state when they are no
77 longer in use, so we must write their state here.
80 XMLNode& c = xfade->get_state ();
81 node.add_child_nocopy (c);
84 boost::shared_ptr<Crossfade>
85 CrossfadeListProperty::get_content_from_xml (XMLNode const & node) const
87 XMLNodeList const c = node.children ();
88 assert (c.size() == 1);
89 return boost::shared_ptr<Crossfade> (new Crossfade (_playlist, *c.front()));
93 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
94 : Playlist (session, node, DataType::AUDIO, hidden)
98 const XMLProperty* prop = node.property("type");
99 assert(!prop || DataType(prop->value()) == DataType::AUDIO);
102 add_property (_crossfades);
105 set_state (node, Stateful::loading_state_version);
109 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
110 : Playlist (session, name, DataType::AUDIO, hidden)
111 , _crossfades (*this)
113 add_property (_crossfades);
116 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
117 : Playlist (other, name, hidden)
118 , _crossfades (*this)
120 add_property (_crossfades);
122 RegionList::const_iterator in_o = other->regions.begin();
123 RegionList::iterator in_n = regions.begin();
125 while (in_o != other->regions.end()) {
126 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
128 // We look only for crossfades which begin with the current region, so we don't get doubles
129 for (Crossfades::const_iterator xfades = other->_crossfades.begin(); xfades != other->_crossfades.end(); ++xfades) {
130 if ((*xfades)->in() == ar) {
131 // We found one! Now copy it!
133 RegionList::const_iterator out_o = other->regions.begin();
134 RegionList::const_iterator out_n = regions.begin();
136 while (out_o != other->regions.end()) {
138 boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
140 if ((*xfades)->out() == ar2) {
141 boost::shared_ptr<AudioRegion>in = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
142 boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
143 boost::shared_ptr<Crossfade> new_fade = boost::shared_ptr<Crossfade> (new Crossfade (*xfades, in, out));
144 add_crossfade(new_fade);
151 // cerr << "HUH!? second region in the crossfade not found!" << endl;
160 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
161 : Playlist (other, start, cnt, name, hidden)
162 , _crossfades (*this)
164 add_property (_crossfades);
166 /* this constructor does NOT notify others (session) */
169 AudioPlaylist::~AudioPlaylist ()
171 _crossfades.clear ();
174 struct RegionSortByLayer {
175 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
176 return a->layer() < b->layer();
181 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
182 nframes_t cnt, unsigned chan_n)
186 nframes_t read_frames;
187 nframes_t skip_frames;
189 /* optimizing this memset() away involves a lot of conditionals
190 that may well cause more of a hit due to cache misses
191 and related stuff than just doing this here.
193 it would be great if someone could measure this
196 one way or another, parts of the requested area
197 that are not written to by Region::region_at()
198 for all Regions that cover the area need to be
202 memset (buf, 0, sizeof (Sample) * cnt);
204 /* this function is never called from a realtime thread, so
205 its OK to block (for short intervals).
208 Glib::RecMutex::Lock rm (region_lock);
210 end = start + cnt - 1;
213 _read_data_count = 0;
215 _read_data_count = 0;
217 RegionList* rlist = regions_to_read (start, start+cnt);
219 if (rlist->empty()) {
224 map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
225 map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
226 vector<uint32_t> relevant_layers;
228 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ++i) {
229 if ((*i)->coverage (start, end) != OverlapNone) {
230 relevant_regions[(*i)->layer()].push_back (*i);
231 relevant_layers.push_back ((*i)->layer());
235 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
236 if ((*i)->coverage (start, end) != OverlapNone) {
237 relevant_xfades[(*i)->upper_layer()].push_back (*i);
241 // RegionSortByLayer layer_cmp;
242 // relevant_regions.sort (layer_cmp);
244 /* XXX this whole per-layer approach is a hack that
245 should be removed once Crossfades become
246 CrossfadeRegions and we just grab a list of relevant
247 regions and call read_at() on all of them.
250 sort (relevant_layers.begin(), relevant_layers.end());
252 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
254 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
255 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
258 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
259 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
260 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("read from region %1\n", ar->name()));
262 ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
263 _read_data_count += ar->read_data_count();
266 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
267 (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
269 /* don't JACK up _read_data_count, since its the same data as we just
270 read from the regions, and the OS should handle that for us.
281 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
283 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
290 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
295 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
297 if ((*i)->involves (r)) {
298 i = _crossfades.erase (i);
307 AudioPlaylist::flush_notifications (bool from_undo)
309 Playlist::flush_notifications (from_undo);
317 Crossfades::iterator a;
318 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
319 NewCrossfade (*a); /* EMIT SIGNAL */
322 _pending_xfade_adds.clear ();
328 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
330 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
331 set<boost::shared_ptr<Crossfade> > updated;
337 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
339 Crossfades::iterator tmp;
344 /* only update them once */
346 if ((*x)->involves (ar)) {
348 pair<set<boost::shared_ptr<Crossfade> >::iterator, bool> const u = updated.insert (*x);
351 /* x was successfully inserted into the set, so it has not already been updated */
356 catch (Crossfade::NoCrossfadeHere& err) {
357 // relax, Invalidated during refresh
367 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
369 boost::shared_ptr<AudioRegion> orig = boost::dynamic_pointer_cast<AudioRegion>(o);
370 boost::shared_ptr<AudioRegion> left = boost::dynamic_pointer_cast<AudioRegion>(l);
371 boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
373 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
374 Crossfades::iterator tmp;
378 boost::shared_ptr<Crossfade> fade;
380 if ((*x)->_in == orig) {
381 if (! (*x)->covers(right->position())) {
382 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, left, (*x)->_out));
384 // Overlap, the crossfade is copied on the left side of the right region instead
385 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, right, (*x)->_out));
389 if ((*x)->_out == orig) {
390 if (! (*x)->covers(right->position())) {
391 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, right));
393 // Overlap, the crossfade is copied on the right side of the left region instead
394 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, left));
399 _crossfades.remove (*x);
400 add_crossfade (fade);
407 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
409 boost::shared_ptr<AudioRegion> other;
410 boost::shared_ptr<AudioRegion> region;
411 boost::shared_ptr<AudioRegion> top;
412 boost::shared_ptr<AudioRegion> bottom;
413 boost::shared_ptr<Crossfade> xfade;
414 RegionList* touched_regions = 0;
416 if (in_set_state || in_partition) {
420 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
421 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
427 refresh_dependents (r);
431 if (!_session.config.get_auto_xfade()) {
435 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
436 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
438 if (other == region) {
442 if (other->muted() || region->muted()) {
447 if (other->layer() < region->layer()) {
455 if (!top->opaque()) {
459 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
461 delete touched_regions;
465 framecnt_t xfade_length;
470 case OverlapInternal:
471 /* {=============== top =============}
472 * [ ----- bottom ------- ]
476 case OverlapExternal:
478 /* [ -------- top ------- ]
479 * {=========== bottom =============}
482 /* to avoid discontinuities at the region boundaries of an internal
483 overlap (this region is completely within another), we create
484 two hidden crossfades at each boundary. this is not dependent
485 on the auto-xfade option, because we require it as basic
489 xfade_length = min ((framecnt_t) 720, top->length());
491 if (top_region_at (top->first_frame()) == top) {
493 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
494 add_crossfade (xfade);
497 if (top_region_at (top->last_frame() - 1) == top) {
500 only add a fade out if there is no region on top of the end of 'top' (which
504 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
505 add_crossfade (xfade);
510 /* { ==== top ============ }
511 * [---- bottom -------------------]
514 if (_session.config.get_xfade_model() == FullCrossfade) {
515 touched_regions = regions_touched (top->first_frame(), bottom->last_frame());
516 if (touched_regions->size() <= 2) {
517 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
518 add_crossfade (xfade);
522 touched_regions = regions_touched (top->first_frame(),
523 top->first_frame() + min ((framecnt_t) _session.config.get_short_xfade_seconds() * _session.frame_rate(),
525 if (touched_regions->size() <= 2) {
526 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
527 add_crossfade (xfade);
534 /* [---- top ------------------------]
535 * { ==== bottom ============ }
538 if (_session.config.get_xfade_model() == FullCrossfade) {
540 touched_regions = regions_touched (bottom->first_frame(), top->last_frame());
541 if (touched_regions->size() <= 2) {
542 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
543 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
544 add_crossfade (xfade);
548 touched_regions = regions_touched (bottom->first_frame(),
549 bottom->first_frame() + min ((framecnt_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
551 if (touched_regions->size() <= 2) {
552 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
553 add_crossfade (xfade);
558 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
559 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
560 add_crossfade (xfade);
564 catch (failed_constructor& err) {
568 catch (Crossfade::NoCrossfadeHere& err) {
574 delete touched_regions;
578 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
580 Crossfades::iterator ci;
582 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
583 if (*(*ci) == *xfade) { // Crossfade::operator==()
588 if (ci != _crossfades.end()) {
589 // it will just go away
591 _crossfades.push_back (xfade);
593 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
594 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
596 notify_crossfade_added (xfade);
600 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
602 if (g_atomic_int_get(&block_notifications)) {
603 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
605 NewCrossfade (x); /* EMIT SIGNAL */
610 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
612 Crossfades::iterator i;
613 boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
615 xfade->in()->resume_fade_in ();
616 xfade->out()->resume_fade_out ();
618 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
619 _crossfades.erase (i);
624 AudioPlaylist::set_state (const XMLNode& node, int version)
628 XMLNodeConstIterator niter;
632 Playlist::set_state (node, version);
636 nlist = node.children();
638 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
642 if (child->name() != "Crossfade") {
647 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
648 _crossfades.push_back (xfade);
649 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
650 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
654 catch (failed_constructor& err) {
655 // cout << string_compose (_("could not create crossfade object in playlist %1"),
669 AudioPlaylist::clear (bool with_signals)
671 _crossfades.clear ();
672 Playlist::clear (with_signals);
676 AudioPlaylist::state (bool full_state)
678 XMLNode& node = Playlist::state (full_state);
681 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
682 node.add_child_nocopy ((*i)->get_state());
690 AudioPlaylist::dump () const
692 boost::shared_ptr<Region>r;
693 boost::shared_ptr<Crossfade> x;
695 cerr << "Playlist \"" << _name << "\" " << endl
696 << regions.size() << " regions "
697 << _crossfades.size() << " crossfades"
700 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
702 cerr << " " << r->name() << " @ " << r << " ["
703 << r->start() << "+" << r->length()
711 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
722 << (x->active() ? "yes" : "no")
728 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
730 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
736 bool changed = false;
737 Crossfades::iterator c, ctmp;
738 set<boost::shared_ptr<Crossfade> > unique_xfades;
741 RegionLock rlock (this);
743 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
745 RegionList::iterator tmp = i;
748 if ((*i) == region) {
756 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
758 set<boost::shared_ptr<Region> >::iterator xtmp = x;
761 if ((*x) == region) {
762 all_regions.erase (x);
769 region->set_playlist (boost::shared_ptr<Playlist>());
772 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
776 if ((*c)->involves (r)) {
777 unique_xfades.insert (*c);
778 _crossfades.erase (c);
785 /* overload this, it normally means "removed", not destroyed */
786 notify_region_removed (region);
793 AudioPlaylist::crossfade_changed (const PropertyChange&)
795 if (in_flush || in_set_state) {
799 /* XXX is there a loop here? can an xfade change not happen
800 due to a playlist change? well, sure activation would
801 be an example. maybe we should check the type of change
805 notify_contents_changed ();
809 AudioPlaylist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
811 if (in_flush || in_set_state) {
815 PropertyChange our_interests;
817 our_interests.add (Properties::fade_in_active);
818 our_interests.add (Properties::fade_out_active);
819 our_interests.add (Properties::scale_amplitude);
820 our_interests.add (Properties::envelope_active);
821 our_interests.add (Properties::envelope);
822 our_interests.add (Properties::fade_in);
823 our_interests.add (Properties::fade_out);
825 bool parent_wants_notify;
827 parent_wants_notify = Playlist::region_changed (what_changed, region);
829 if (parent_wants_notify || (what_changed.contains (our_interests))) {
830 notify_contents_changed ();
837 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
839 RegionLock rlock (this);
841 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
842 nframes_t start, end;
844 start = (*i)->position();
845 end = start + (*i)->overlap_length(); // not length(), important difference
847 if (frame >= start && frame <= end) {
848 clist.push_back (*i);
854 AudioPlaylist::foreach_crossfade (boost::function<void (boost::shared_ptr<Crossfade>)> s)
856 RegionLock rl (this, false);
857 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
863 AudioPlaylist::update (const CrossfadeListProperty::ChangeRecord& change)
865 for (CrossfadeListProperty::ChangeContainer::const_iterator i = change.added.begin(); i != change.added.end(); ++i) {
869 /* don't remove crossfades here; they will be dealt with by the dependency code */