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) {
368 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
370 if (other == region) {
374 if (other->muted() || region->muted()) {
379 if (other->layer() < region->layer()) {
387 if (!top->opaque()) {
391 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
393 delete touched_regions;
397 nframes_t xfade_length;
402 case OverlapInternal:
403 /* {=============== top =============}
404 * [ ----- bottom ------- ]
408 case OverlapExternal:
410 /* [ -------- top ------- ]
411 * {=========== bottom =============}
414 /* to avoid discontinuities at the region boundaries of an internal
415 overlap (this region is completely within another), we create
416 two hidden crossfades at each boundary. this is not dependent
417 on the auto-xfade option, because we require it as basic
421 xfade_length = min ((framecnt_t) 720, top->length());
423 if (top_region_at (top->first_frame()) == top) {
425 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
426 add_crossfade (xfade);
429 if (top_region_at (top->last_frame() - 1) == top) {
432 only add a fade out if there is no region on top of the end of 'top' (which
436 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
437 add_crossfade (xfade);
442 /* { ==== top ============ }
443 * [---- bottom -------------------]
446 if (_session.config.get_xfade_model() == FullCrossfade) {
447 touched_regions = regions_touched (top->first_frame(), bottom->last_frame());
448 if (touched_regions->size() <= 2) {
449 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
450 add_crossfade (xfade);
454 touched_regions = regions_touched (top->first_frame(),
455 top->first_frame() + min ((framecnt_t) _session.config.get_short_xfade_seconds() * _session.frame_rate(),
457 if (touched_regions->size() <= 2) {
458 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
459 add_crossfade (xfade);
466 /* [---- top ------------------------]
467 * { ==== bottom ============ }
470 if (_session.config.get_xfade_model() == FullCrossfade) {
472 touched_regions = regions_touched (bottom->first_frame(), top->last_frame());
473 if (touched_regions->size() <= 2) {
474 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
475 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
476 add_crossfade (xfade);
480 touched_regions = regions_touched (bottom->first_frame(),
481 bottom->first_frame() + min ((framecnt_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
483 if (touched_regions->size() <= 2) {
484 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
485 add_crossfade (xfade);
490 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
491 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
492 add_crossfade (xfade);
496 catch (failed_constructor& err) {
500 catch (Crossfade::NoCrossfadeHere& err) {
506 delete touched_regions;
510 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
512 Crossfades::iterator ci;
514 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
515 if (*(*ci) == *xfade) { // Crossfade::operator==()
520 if (ci != _crossfades.end()) {
521 // it will just go away
523 _crossfades.push_back (xfade);
525 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
526 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
528 notify_crossfade_added (xfade);
532 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
534 if (g_atomic_int_get(&block_notifications)) {
535 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
537 NewCrossfade (x); /* EMIT SIGNAL */
542 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
544 Crossfades::iterator i;
545 boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
547 xfade->in()->resume_fade_in ();
548 xfade->out()->resume_fade_out ();
550 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
551 _crossfades.erase (i);
556 AudioPlaylist::set_state (const XMLNode& node, int version)
560 XMLNodeConstIterator niter;
564 Playlist::set_state (node, version);
568 nlist = node.children();
570 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
574 if (child->name() != "Crossfade") {
579 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
580 _crossfades.push_back (xfade);
581 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
582 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
586 catch (failed_constructor& err) {
587 // cout << string_compose (_("could not create crossfade object in playlist %1"),
601 AudioPlaylist::clear (bool with_signals)
603 _crossfades.clear ();
604 Playlist::clear (with_signals);
608 AudioPlaylist::state (bool full_state)
610 XMLNode& node = Playlist::state (full_state);
613 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
614 node.add_child_nocopy ((*i)->get_state());
622 AudioPlaylist::dump () const
624 boost::shared_ptr<Region>r;
625 boost::shared_ptr<Crossfade> x;
627 cerr << "Playlist \"" << _name << "\" " << endl
628 << regions.size() << " regions "
629 << _crossfades.size() << " crossfades"
632 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
634 cerr << " " << r->name() << " @ " << r << " ["
635 << r->start() << "+" << r->length()
643 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
654 << (x->active() ? "yes" : "no")
660 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
662 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
663 bool changed = false;
664 Crossfades::iterator c, ctmp;
665 set<boost::shared_ptr<Crossfade> > unique_xfades;
668 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
675 RegionLock rlock (this);
677 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
679 RegionList::iterator tmp = i;
682 if ((*i) == region) {
690 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
692 set<boost::shared_ptr<Region> >::iterator xtmp = x;
695 if ((*x) == region) {
696 all_regions.erase (x);
703 region->set_playlist (boost::shared_ptr<Playlist>());
706 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
710 if ((*c)->involves (r)) {
711 unique_xfades.insert (*c);
712 _crossfades.erase (c);
719 /* overload this, it normally means "removed", not destroyed */
720 notify_region_removed (region);
727 AudioPlaylist::crossfade_changed (const PropertyChange&)
729 if (in_flush || in_set_state) {
733 /* XXX is there a loop here? can an xfade change not happen
734 due to a playlist change? well, sure activation would
735 be an example. maybe we should check the type of change
739 notify_contents_changed ();
743 AudioPlaylist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
745 if (in_flush || in_set_state) {
749 PropertyChange our_interests;
751 our_interests.add (Properties::fade_in_active);
752 our_interests.add (Properties::fade_out_active);
753 our_interests.add (Properties::scale_amplitude);
754 our_interests.add (Properties::envelope_active);
755 our_interests.add (Properties::envelope);
756 our_interests.add (Properties::fade_in);
757 our_interests.add (Properties::fade_out);
759 bool parent_wants_notify;
761 parent_wants_notify = Playlist::region_changed (what_changed, region);
763 if (parent_wants_notify || (what_changed.contains (our_interests))) {
764 notify_contents_changed ();
771 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
773 RegionLock rlock (this);
775 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
776 nframes_t start, end;
778 start = (*i)->position();
779 end = start + (*i)->overlap_length(); // not length(), important difference
781 if (frame >= start && frame <= end) {
782 clist.push_back (*i);
788 AudioPlaylist::foreach_crossfade (boost::function<void (boost::shared_ptr<Crossfade>)> s)
790 RegionLock rl (this, false);
791 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {