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);
666 bool changed = false;
667 Crossfades::iterator c, ctmp;
668 set<boost::shared_ptr<Crossfade> > unique_xfades;
671 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
678 RegionLock rlock (this);
680 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
682 RegionList::iterator tmp = i;
685 if ((*i) == region) {
693 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
695 set<boost::shared_ptr<Region> >::iterator xtmp = x;
698 if ((*x) == region) {
699 all_regions.erase (x);
706 region->set_playlist (boost::shared_ptr<Playlist>());
709 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
713 if ((*c)->involves (r)) {
714 unique_xfades.insert (*c);
715 _crossfades.erase (c);
722 /* overload this, it normally means "removed", not destroyed */
723 notify_region_removed (region);
730 AudioPlaylist::crossfade_changed (const PropertyChange&)
732 if (in_flush || in_set_state) {
736 /* XXX is there a loop here? can an xfade change not happen
737 due to a playlist change? well, sure activation would
738 be an example. maybe we should check the type of change
742 notify_contents_changed ();
746 AudioPlaylist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
748 if (in_flush || in_set_state) {
752 PropertyChange our_interests;
754 our_interests.add (Properties::fade_in_active);
755 our_interests.add (Properties::fade_out_active);
756 our_interests.add (Properties::scale_amplitude);
757 our_interests.add (Properties::envelope_active);
758 our_interests.add (Properties::envelope);
759 our_interests.add (Properties::fade_in);
760 our_interests.add (Properties::fade_out);
762 bool parent_wants_notify;
764 parent_wants_notify = Playlist::region_changed (what_changed, region);
766 if (parent_wants_notify || (what_changed.contains (our_interests))) {
767 notify_contents_changed ();
774 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
776 RegionLock rlock (this);
778 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
779 nframes_t start, end;
781 start = (*i)->position();
782 end = start + (*i)->overlap_length(); // not length(), important difference
784 if (frame >= start && frame <= end) {
785 clist.push_back (*i);
791 AudioPlaylist::foreach_crossfade (boost::function<void (boost::shared_ptr<Crossfade>)> s)
793 RegionLock rl (this, false);
794 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {