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/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;
40 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
41 : Playlist (session, node, DataType::AUDIO, hidden)
43 const XMLProperty* prop = node.property("type");
44 assert(!prop || DataType(prop->value()) == DataType::AUDIO);
47 set_state (node, Stateful::loading_state_version);
51 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
52 : Playlist (session, name, DataType::AUDIO, hidden)
56 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
57 : Playlist (other, name, hidden)
59 RegionList::const_iterator in_o = other->regions.begin();
60 RegionList::iterator in_n = regions.begin();
62 while (in_o != other->regions.end()) {
63 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
65 // We look only for crossfades which begin with the current region, so we don't get doubles
66 for (Crossfades::const_iterator xfades = other->_crossfades.begin(); xfades != other->_crossfades.end(); ++xfades) {
67 if ((*xfades)->in() == ar) {
68 // We found one! Now copy it!
70 RegionList::const_iterator out_o = other->regions.begin();
71 RegionList::const_iterator out_n = regions.begin();
73 while (out_o != other->regions.end()) {
75 boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
77 if ((*xfades)->out() == ar2) {
78 boost::shared_ptr<AudioRegion>in = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
79 boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
80 boost::shared_ptr<Crossfade> new_fade = boost::shared_ptr<Crossfade> (new Crossfade (*xfades, in, out));
81 add_crossfade(new_fade);
88 // cerr << "HUH!? second region in the crossfade not found!" << endl;
97 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
98 : Playlist (other, start, cnt, name, hidden)
100 /* this constructor does NOT notify others (session) */
103 AudioPlaylist::~AudioPlaylist ()
105 _crossfades.clear ();
108 struct RegionSortByLayer {
109 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
110 return a->layer() < b->layer();
115 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
116 nframes_t cnt, unsigned chan_n)
120 nframes_t read_frames;
121 nframes_t skip_frames;
123 /* optimizing this memset() away involves a lot of conditionals
124 that may well cause more of a hit due to cache misses
125 and related stuff than just doing this here.
127 it would be great if someone could measure this
130 one way or another, parts of the requested area
131 that are not written to by Region::region_at()
132 for all Regions that cover the area need to be
136 memset (buf, 0, sizeof (Sample) * cnt);
138 /* this function is never called from a realtime thread, so
139 its OK to block (for short intervals).
142 Glib::RecMutex::Lock rm (region_lock);
144 end = start + cnt - 1;
147 _read_data_count = 0;
149 _read_data_count = 0;
151 RegionList* rlist = regions_to_read (start, start+cnt);
153 if (rlist->empty()) {
158 map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
159 map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
160 vector<uint32_t> relevant_layers;
162 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ++i) {
163 if ((*i)->coverage (start, end) != OverlapNone) {
164 relevant_regions[(*i)->layer()].push_back (*i);
165 relevant_layers.push_back ((*i)->layer());
169 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
170 if ((*i)->coverage (start, end) != OverlapNone) {
171 relevant_xfades[(*i)->upper_layer()].push_back (*i);
175 // RegionSortByLayer layer_cmp;
176 // relevant_regions.sort (layer_cmp);
178 /* XXX this whole per-layer approach is a hack that
179 should be removed once Crossfades become
180 CrossfadeRegions and we just grab a list of relevant
181 regions and call read_at() on all of them.
184 sort (relevant_layers.begin(), relevant_layers.end());
186 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
188 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
189 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
191 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
192 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
194 ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
195 _read_data_count += ar->read_data_count();
198 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
199 (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
201 /* don't JACK up _read_data_count, since its the same data as we just
202 read from the regions, and the OS should handle that for us.
213 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
215 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
222 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
227 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
229 if ((*i)->involves (r)) {
230 i = _crossfades.erase (i);
239 AudioPlaylist::flush_notifications ()
241 Playlist::flush_notifications();
249 Crossfades::iterator a;
250 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
251 NewCrossfade (*a); /* EMIT SIGNAL */
254 _pending_xfade_adds.clear ();
260 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
262 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
263 set<boost::shared_ptr<Crossfade> > updated;
269 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
271 Crossfades::iterator tmp;
276 /* only update them once */
278 if ((*x)->involves (ar)) {
280 pair<set<boost::shared_ptr<Crossfade> >::iterator, bool> const u = updated.insert (*x);
283 /* x was successfully inserted into the set, so it has not already been updated */
288 catch (Crossfade::NoCrossfadeHere& err) {
289 // relax, Invalidated during refresh
299 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
301 boost::shared_ptr<AudioRegion> orig = boost::dynamic_pointer_cast<AudioRegion>(o);
302 boost::shared_ptr<AudioRegion> left = boost::dynamic_pointer_cast<AudioRegion>(l);
303 boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
305 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
306 Crossfades::iterator tmp;
310 boost::shared_ptr<Crossfade> fade;
312 if ((*x)->_in == orig) {
313 if (! (*x)->covers(right->position())) {
314 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, left, (*x)->_out));
316 // Overlap, the crossfade is copied on the left side of the right region instead
317 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, right, (*x)->_out));
321 if ((*x)->_out == orig) {
322 if (! (*x)->covers(right->position())) {
323 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, right));
325 // Overlap, the crossfade is copied on the right side of the left region instead
326 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, left));
331 _crossfades.remove (*x);
332 add_crossfade (fade);
339 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
341 boost::shared_ptr<AudioRegion> other;
342 boost::shared_ptr<AudioRegion> region;
343 boost::shared_ptr<AudioRegion> top;
344 boost::shared_ptr<AudioRegion> bottom;
345 boost::shared_ptr<Crossfade> xfade;
346 RegionList* touched_regions = 0;
348 if (in_set_state || in_partition) {
352 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
353 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
359 refresh_dependents (r);
363 if (!_session.config.get_auto_xfade()) {
367 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
369 nframes_t xfade_length;
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;
404 case OverlapInternal:
405 /* {=============== top =============}
406 * [ ----- bottom ------- ]
410 case OverlapExternal:
412 /* [ -------- top ------- ]
413 * {=========== bottom =============}
416 /* to avoid discontinuities at the region boundaries of an internal
417 overlap (this region is completely within another), we create
418 two hidden crossfades at each boundary. this is not dependent
419 on the auto-xfade option, because we require it as basic
423 xfade_length = min ((framecnt_t) 720, top->length());
425 if (top_region_at (top->first_frame()) == top) {
427 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
428 add_crossfade (xfade);
431 if (top_region_at (top->last_frame() - 1) == top) {
434 only add a fade out if there is no region on top of the end of 'top' (which
438 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
439 add_crossfade (xfade);
444 /* { ==== top ============ }
445 * [---- bottom -------------------]
448 if (_session.config.get_xfade_model() == FullCrossfade) {
449 touched_regions = regions_touched (top->first_frame(), bottom->last_frame());
450 if (touched_regions->size() <= 2) {
451 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
452 add_crossfade (xfade);
456 touched_regions = regions_touched (top->first_frame(),
457 top->first_frame() + min ((framecnt_t) _session.config.get_short_xfade_seconds() * _session.frame_rate(),
459 if (touched_regions->size() <= 2) {
460 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
461 add_crossfade (xfade);
468 /* [---- top ------------------------]
469 * { ==== bottom ============ }
472 if (_session.config.get_xfade_model() == FullCrossfade) {
474 touched_regions = regions_touched (bottom->first_frame(), top->last_frame());
475 if (touched_regions->size() <= 2) {
476 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
477 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
478 add_crossfade (xfade);
482 touched_regions = regions_touched (bottom->first_frame(),
483 bottom->first_frame() + min ((framecnt_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
485 if (touched_regions->size() <= 2) {
486 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
487 add_crossfade (xfade);
492 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
493 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
494 add_crossfade (xfade);
498 catch (failed_constructor& err) {
502 catch (Crossfade::NoCrossfadeHere& err) {
508 delete touched_regions;
512 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
514 Crossfades::iterator ci;
516 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
517 if (*(*ci) == *xfade) { // Crossfade::operator==()
522 if (ci != _crossfades.end()) {
523 // it will just go away
525 _crossfades.push_back (xfade);
527 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
528 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
530 notify_crossfade_added (xfade);
534 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
536 if (g_atomic_int_get(&block_notifications)) {
537 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
539 NewCrossfade (x); /* EMIT SIGNAL */
544 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
546 Crossfades::iterator i;
547 boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
549 xfade->in()->resume_fade_in ();
550 xfade->out()->resume_fade_out ();
552 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
553 _crossfades.erase (i);
558 AudioPlaylist::set_state (const XMLNode& node, int version)
562 XMLNodeConstIterator niter;
566 Playlist::set_state (node, version);
570 nlist = node.children();
572 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
576 if (child->name() != "Crossfade") {
581 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
582 _crossfades.push_back (xfade);
583 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
584 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
588 catch (failed_constructor& err) {
589 // cout << string_compose (_("could not create crossfade object in playlist %1"),
603 AudioPlaylist::clear (bool with_signals)
605 _crossfades.clear ();
606 Playlist::clear (with_signals);
610 AudioPlaylist::state (bool full_state)
612 XMLNode& node = Playlist::state (full_state);
615 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
616 node.add_child_nocopy ((*i)->get_state());
624 AudioPlaylist::dump () const
626 boost::shared_ptr<Region>r;
627 boost::shared_ptr<Crossfade> x;
629 cerr << "Playlist \"" << _name << "\" " << endl
630 << regions.size() << " regions "
631 << _crossfades.size() << " crossfades"
634 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
636 cerr << " " << r->name() << " @ " << r << " ["
637 << r->start() << "+" << r->length()
645 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
656 << (x->active() ? "yes" : "no")
662 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
664 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
665 bool changed = false;
666 Crossfades::iterator c, ctmp;
667 set<boost::shared_ptr<Crossfade> > unique_xfades;
670 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
677 RegionLock rlock (this);
679 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
681 RegionList::iterator tmp = i;
684 if ((*i) == region) {
692 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
694 set<boost::shared_ptr<Region> >::iterator xtmp = x;
697 if ((*x) == region) {
698 all_regions.erase (x);
705 region->set_playlist (boost::shared_ptr<Playlist>());
708 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
712 if ((*c)->involves (r)) {
713 unique_xfades.insert (*c);
714 _crossfades.erase (c);
721 /* overload this, it normally means "removed", not destroyed */
722 notify_region_removed (region);
729 AudioPlaylist::crossfade_changed (const PropertyChange&)
731 if (in_flush || in_set_state) {
735 /* XXX is there a loop here? can an xfade change not happen
736 due to a playlist change? well, sure activation would
737 be an example. maybe we should check the type of change
741 notify_contents_changed ();
745 AudioPlaylist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
747 if (in_flush || in_set_state) {
751 PropertyChange our_interests;
753 our_interests.add (Properties::fade_in_active);
754 our_interests.add (Properties::fade_out_active);
755 our_interests.add (Properties::scale_amplitude);
756 our_interests.add (Properties::envelope_active);
757 our_interests.add (Properties::envelope);
758 our_interests.add (Properties::fade_in);
759 our_interests.add (Properties::fade_out);
761 bool parent_wants_notify;
763 parent_wants_notify = Playlist::region_changed (what_changed, region);
765 if (parent_wants_notify || (what_changed.contains (our_interests))) {
766 notify_contents_changed ();
773 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
775 RegionLock rlock (this);
777 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
778 nframes_t start, end;
780 start = (*i)->position();
781 end = start + (*i)->overlap_length(); // not length(), important difference
783 if (frame >= start && frame <= end) {
784 clist.push_back (*i);
790 AudioPlaylist::foreach_crossfade (boost::function<void (boost::shared_ptr<Crossfade>)> s)
792 RegionLock rl (this, false);
793 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {