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)
44 const XMLProperty* prop = node.property("type");
45 assert(!prop || DataType(prop->value()) == DataType::AUDIO);
48 set_state (node, Stateful::loading_state_version);
52 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
53 : Playlist (session, name, DataType::AUDIO, hidden)
57 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
58 : Playlist (other, name, hidden)
60 RegionList::const_iterator in_o = other->regions.begin();
61 RegionList::iterator in_n = regions.begin();
63 while (in_o != other->regions.end()) {
64 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
66 // We look only for crossfades which begin with the current region, so we don't get doubles
67 for (Crossfades::const_iterator xfades = other->_crossfades.begin(); xfades != other->_crossfades.end(); ++xfades) {
68 if ((*xfades)->in() == ar) {
69 // We found one! Now copy it!
71 RegionList::const_iterator out_o = other->regions.begin();
72 RegionList::const_iterator out_n = regions.begin();
74 while (out_o != other->regions.end()) {
76 boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
78 if ((*xfades)->out() == ar2) {
79 boost::shared_ptr<AudioRegion>in = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
80 boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
81 boost::shared_ptr<Crossfade> new_fade = boost::shared_ptr<Crossfade> (new Crossfade (*xfades, in, out));
82 add_crossfade(new_fade);
89 // cerr << "HUH!? second region in the crossfade not found!" << endl;
98 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
99 : Playlist (other, start, cnt, name, hidden)
101 /* this constructor does NOT notify others (session) */
104 AudioPlaylist::~AudioPlaylist ()
106 _crossfades.clear ();
109 struct RegionSortByLayer {
110 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
111 return a->layer() < b->layer();
116 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
117 nframes_t cnt, unsigned chan_n)
121 nframes_t read_frames;
122 nframes_t skip_frames;
124 /* optimizing this memset() away involves a lot of conditionals
125 that may well cause more of a hit due to cache misses
126 and related stuff than just doing this here.
128 it would be great if someone could measure this
131 one way or another, parts of the requested area
132 that are not written to by Region::region_at()
133 for all Regions that cover the area need to be
137 memset (buf, 0, sizeof (Sample) * cnt);
139 /* this function is never called from a realtime thread, so
140 its OK to block (for short intervals).
143 Glib::RecMutex::Lock rm (region_lock);
145 end = start + cnt - 1;
148 _read_data_count = 0;
150 _read_data_count = 0;
152 RegionList* rlist = regions_to_read (start, start+cnt);
154 if (rlist->empty()) {
159 map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
160 map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
161 vector<uint32_t> relevant_layers;
163 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ++i) {
164 if ((*i)->coverage (start, end) != OverlapNone) {
165 relevant_regions[(*i)->layer()].push_back (*i);
166 relevant_layers.push_back ((*i)->layer());
170 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
171 if ((*i)->coverage (start, end) != OverlapNone) {
172 relevant_xfades[(*i)->upper_layer()].push_back (*i);
176 // RegionSortByLayer layer_cmp;
177 // relevant_regions.sort (layer_cmp);
179 /* XXX this whole per-layer approach is a hack that
180 should be removed once Crossfades become
181 CrossfadeRegions and we just grab a list of relevant
182 regions and call read_at() on all of them.
185 sort (relevant_layers.begin(), relevant_layers.end());
187 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
189 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
190 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
193 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
194 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
195 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("read from region %1\n", ar->name()));
197 ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
198 _read_data_count += ar->read_data_count();
201 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
202 (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
204 /* don't JACK up _read_data_count, since its the same data as we just
205 read from the regions, and the OS should handle that for us.
216 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
218 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
225 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
230 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
232 if ((*i)->involves (r)) {
233 i = _crossfades.erase (i);
242 AudioPlaylist::flush_notifications ()
244 Playlist::flush_notifications();
252 Crossfades::iterator a;
253 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
254 NewCrossfade (*a); /* EMIT SIGNAL */
257 _pending_xfade_adds.clear ();
263 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
265 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
266 set<boost::shared_ptr<Crossfade> > updated;
272 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
274 Crossfades::iterator tmp;
279 /* only update them once */
281 if ((*x)->involves (ar)) {
283 pair<set<boost::shared_ptr<Crossfade> >::iterator, bool> const u = updated.insert (*x);
286 /* x was successfully inserted into the set, so it has not already been updated */
291 catch (Crossfade::NoCrossfadeHere& err) {
292 // relax, Invalidated during refresh
302 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
304 boost::shared_ptr<AudioRegion> orig = boost::dynamic_pointer_cast<AudioRegion>(o);
305 boost::shared_ptr<AudioRegion> left = boost::dynamic_pointer_cast<AudioRegion>(l);
306 boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
308 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
309 Crossfades::iterator tmp;
313 boost::shared_ptr<Crossfade> fade;
315 if ((*x)->_in == orig) {
316 if (! (*x)->covers(right->position())) {
317 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, left, (*x)->_out));
319 // Overlap, the crossfade is copied on the left side of the right region instead
320 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, right, (*x)->_out));
324 if ((*x)->_out == orig) {
325 if (! (*x)->covers(right->position())) {
326 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, right));
328 // Overlap, the crossfade is copied on the right side of the left region instead
329 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, left));
334 _crossfades.remove (*x);
335 add_crossfade (fade);
342 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
344 boost::shared_ptr<AudioRegion> other;
345 boost::shared_ptr<AudioRegion> region;
346 boost::shared_ptr<AudioRegion> top;
347 boost::shared_ptr<AudioRegion> bottom;
348 boost::shared_ptr<Crossfade> xfade;
349 RegionList* touched_regions = 0;
351 if (in_set_state || in_partition) {
355 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
356 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
362 refresh_dependents (r);
366 if (!_session.config.get_auto_xfade()) {
370 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
371 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
373 if (other == region) {
377 if (other->muted() || region->muted()) {
382 if (other->layer() < region->layer()) {
390 if (!top->opaque()) {
394 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
396 delete touched_regions;
400 nframes_t xfade_length;
405 case OverlapInternal:
406 /* {=============== top =============}
407 * [ ----- bottom ------- ]
411 case OverlapExternal:
413 /* [ -------- top ------- ]
414 * {=========== bottom =============}
417 /* to avoid discontinuities at the region boundaries of an internal
418 overlap (this region is completely within another), we create
419 two hidden crossfades at each boundary. this is not dependent
420 on the auto-xfade option, because we require it as basic
424 xfade_length = min ((framecnt_t) 720, top->length());
426 if (top_region_at (top->first_frame()) == top) {
428 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
429 add_crossfade (xfade);
432 if (top_region_at (top->last_frame() - 1) == top) {
435 only add a fade out if there is no region on top of the end of 'top' (which
439 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
440 add_crossfade (xfade);
445 /* { ==== top ============ }
446 * [---- bottom -------------------]
449 if (_session.config.get_xfade_model() == FullCrossfade) {
450 touched_regions = regions_touched (top->first_frame(), bottom->last_frame());
451 if (touched_regions->size() <= 2) {
452 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
453 add_crossfade (xfade);
457 touched_regions = regions_touched (top->first_frame(),
458 top->first_frame() + min ((framecnt_t) _session.config.get_short_xfade_seconds() * _session.frame_rate(),
460 if (touched_regions->size() <= 2) {
461 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
462 add_crossfade (xfade);
469 /* [---- top ------------------------]
470 * { ==== bottom ============ }
473 if (_session.config.get_xfade_model() == FullCrossfade) {
475 touched_regions = regions_touched (bottom->first_frame(), top->last_frame());
476 if (touched_regions->size() <= 2) {
477 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
478 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
479 add_crossfade (xfade);
483 touched_regions = regions_touched (bottom->first_frame(),
484 bottom->first_frame() + min ((framecnt_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
486 if (touched_regions->size() <= 2) {
487 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
488 add_crossfade (xfade);
493 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
494 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
495 add_crossfade (xfade);
499 catch (failed_constructor& err) {
503 catch (Crossfade::NoCrossfadeHere& err) {
509 delete touched_regions;
513 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
515 Crossfades::iterator ci;
517 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
518 if (*(*ci) == *xfade) { // Crossfade::operator==()
523 if (ci != _crossfades.end()) {
524 // it will just go away
526 _crossfades.push_back (xfade);
528 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
529 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
531 notify_crossfade_added (xfade);
535 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
537 if (g_atomic_int_get(&block_notifications)) {
538 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
540 NewCrossfade (x); /* EMIT SIGNAL */
545 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
547 Crossfades::iterator i;
548 boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
550 xfade->in()->resume_fade_in ();
551 xfade->out()->resume_fade_out ();
553 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
554 _crossfades.erase (i);
559 AudioPlaylist::set_state (const XMLNode& node, int version)
563 XMLNodeConstIterator niter;
567 Playlist::set_state (node, version);
571 nlist = node.children();
573 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
577 if (child->name() != "Crossfade") {
582 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
583 _crossfades.push_back (xfade);
584 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
585 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
589 catch (failed_constructor& err) {
590 // cout << string_compose (_("could not create crossfade object in playlist %1"),
604 AudioPlaylist::clear (bool with_signals)
606 _crossfades.clear ();
607 Playlist::clear (with_signals);
611 AudioPlaylist::state (bool full_state)
613 XMLNode& node = Playlist::state (full_state);
616 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
617 node.add_child_nocopy ((*i)->get_state());
625 AudioPlaylist::dump () const
627 boost::shared_ptr<Region>r;
628 boost::shared_ptr<Crossfade> x;
630 cerr << "Playlist \"" << _name << "\" " << endl
631 << regions.size() << " regions "
632 << _crossfades.size() << " crossfades"
635 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
637 cerr << " " << r->name() << " @ " << r << " ["
638 << r->start() << "+" << r->length()
646 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
657 << (x->active() ? "yes" : "no")
663 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
665 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
671 bool changed = false;
672 Crossfades::iterator c, ctmp;
673 set<boost::shared_ptr<Crossfade> > unique_xfades;
676 RegionLock rlock (this);
678 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
680 RegionList::iterator tmp = i;
683 if ((*i) == region) {
691 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
693 set<boost::shared_ptr<Region> >::iterator xtmp = x;
696 if ((*x) == region) {
697 all_regions.erase (x);
704 region->set_playlist (boost::shared_ptr<Playlist>());
707 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
711 if ((*c)->involves (r)) {
712 unique_xfades.insert (*c);
713 _crossfades.erase (c);
720 /* overload this, it normally means "removed", not destroyed */
721 notify_region_removed (region);
728 AudioPlaylist::crossfade_changed (const PropertyChange&)
730 if (in_flush || in_set_state) {
734 /* XXX is there a loop here? can an xfade change not happen
735 due to a playlist change? well, sure activation would
736 be an example. maybe we should check the type of change
740 notify_contents_changed ();
744 AudioPlaylist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
746 if (in_flush || in_set_state) {
750 PropertyChange our_interests;
752 our_interests.add (Properties::fade_in_active);
753 our_interests.add (Properties::fade_out_active);
754 our_interests.add (Properties::scale_amplitude);
755 our_interests.add (Properties::envelope_active);
756 our_interests.add (Properties::envelope);
757 our_interests.add (Properties::fade_in);
758 our_interests.add (Properties::fade_out);
760 bool parent_wants_notify;
762 parent_wants_notify = Playlist::region_changed (what_changed, region);
764 if (parent_wants_notify || (what_changed.contains (our_interests))) {
765 notify_contents_changed ();
772 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
774 RegionLock rlock (this);
776 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
777 nframes_t start, end;
779 start = (*i)->position();
780 end = start + (*i)->overlap_length(); // not length(), important difference
782 if (frame >= start && frame <= end) {
783 clist.push_back (*i);
789 AudioPlaylist::foreach_crossfade (boost::function<void (boost::shared_ptr<Crossfade>)> s)
791 RegionLock rl (this, false);
792 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {