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 ()
107 /* drop connections to signals */
109 _crossfades.clear ();
112 struct RegionSortByLayer {
113 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
114 return a->layer() < b->layer();
119 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
120 nframes_t cnt, unsigned chan_n)
124 nframes_t read_frames;
125 nframes_t skip_frames;
127 /* optimizing this memset() away involves a lot of conditionals
128 that may well cause more of a hit due to cache misses
129 and related stuff than just doing this here.
131 it would be great if someone could measure this
134 one way or another, parts of the requested area
135 that are not written to by Region::region_at()
136 for all Regions that cover the area need to be
140 memset (buf, 0, sizeof (Sample) * cnt);
142 /* this function is never called from a realtime thread, so
143 its OK to block (for short intervals).
146 Glib::RecMutex::Lock rm (region_lock);
148 end = start + cnt - 1;
151 _read_data_count = 0;
153 _read_data_count = 0;
155 RegionList* rlist = regions_to_read (start, start+cnt);
157 if (rlist->empty()) {
162 map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
163 map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
164 vector<uint32_t> relevant_layers;
166 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ++i) {
167 if ((*i)->coverage (start, end) != OverlapNone) {
168 relevant_regions[(*i)->layer()].push_back (*i);
169 relevant_layers.push_back ((*i)->layer());
173 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
174 if ((*i)->coverage (start, end) != OverlapNone) {
175 relevant_xfades[(*i)->upper_layer()].push_back (*i);
179 // RegionSortByLayer layer_cmp;
180 // relevant_regions.sort (layer_cmp);
182 /* XXX this whole per-layer approach is a hack that
183 should be removed once Crossfades become
184 CrossfadeRegions and we just grab a list of relevant
185 regions and call read_at() on all of them.
188 sort (relevant_layers.begin(), relevant_layers.end());
190 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
192 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
193 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
195 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
196 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
198 ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
199 _read_data_count += ar->read_data_count();
202 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
203 (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
205 /* don't JACK up _read_data_count, since its the same data as we just
206 read from the regions, and the OS should handle that for us.
217 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
219 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
226 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
231 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
233 if ((*i)->involves (r)) {
234 i = _crossfades.erase (i);
243 AudioPlaylist::flush_notifications ()
245 Playlist::flush_notifications();
253 Crossfades::iterator a;
254 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
255 NewCrossfade (*a); /* EMIT SIGNAL */
258 _pending_xfade_adds.clear ();
264 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
266 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
267 set<boost::shared_ptr<Crossfade> > updated;
273 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
275 Crossfades::iterator tmp;
280 /* only update them once */
282 if ((*x)->involves (ar)) {
284 pair<set<boost::shared_ptr<Crossfade> >::iterator, bool> const u = updated.insert (*x);
287 /* x was successfully inserted into the set, so it has not already been updated */
292 catch (Crossfade::NoCrossfadeHere& err) {
293 // relax, Invalidated during refresh
303 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
305 boost::shared_ptr<AudioRegion> orig = boost::dynamic_pointer_cast<AudioRegion>(o);
306 boost::shared_ptr<AudioRegion> left = boost::dynamic_pointer_cast<AudioRegion>(l);
307 boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
309 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
310 Crossfades::iterator tmp;
314 boost::shared_ptr<Crossfade> fade;
316 if ((*x)->_in == orig) {
317 if (! (*x)->covers(right->position())) {
318 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, left, (*x)->_out));
320 // Overlap, the crossfade is copied on the left side of the right region instead
321 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, right, (*x)->_out));
325 if ((*x)->_out == orig) {
326 if (! (*x)->covers(right->position())) {
327 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, right));
329 // Overlap, the crossfade is copied on the right side of the left region instead
330 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, left));
335 _crossfades.remove (*x);
336 add_crossfade (fade);
343 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
345 boost::shared_ptr<AudioRegion> other;
346 boost::shared_ptr<AudioRegion> region;
347 boost::shared_ptr<AudioRegion> top;
348 boost::shared_ptr<AudioRegion> bottom;
349 boost::shared_ptr<Crossfade> xfade;
350 RegionList* touched_regions = 0;
352 if (in_set_state || in_partition) {
356 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
357 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
363 refresh_dependents (r);
367 if (!_session.config.get_auto_xfade()) {
371 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
373 nframes_t xfade_length;
375 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
377 if (other == region) {
381 if (other->muted() || region->muted()) {
386 if (other->layer() < region->layer()) {
394 if (!top->opaque()) {
398 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
400 delete touched_regions;
408 case OverlapInternal:
409 /* {=============== top =============}
410 * [ ----- bottom ------- ]
414 case OverlapExternal:
416 /* [ -------- top ------- ]
417 * {=========== bottom =============}
420 /* to avoid discontinuities at the region boundaries of an internal
421 overlap (this region is completely within another), we create
422 two hidden crossfades at each boundary. this is not dependent
423 on the auto-xfade option, because we require it as basic
427 xfade_length = min ((nframes_t) 720, top->length());
429 if (top_region_at (top->first_frame()) == top) {
431 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
432 add_crossfade (xfade);
435 if (top_region_at (top->last_frame() - 1) == top) {
438 only add a fade out if there is no region on top of the end of 'top' (which
442 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
443 add_crossfade (xfade);
448 /* { ==== top ============ }
449 * [---- bottom -------------------]
452 if (_session.config.get_xfade_model() == FullCrossfade) {
453 touched_regions = regions_touched (top->first_frame(), bottom->last_frame());
454 if (touched_regions->size() <= 2) {
455 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
456 add_crossfade (xfade);
460 touched_regions = regions_touched (top->first_frame(),
461 top->first_frame() + min ((nframes_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
463 if (touched_regions->size() <= 2) {
464 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
465 add_crossfade (xfade);
472 /* [---- top ------------------------]
473 * { ==== bottom ============ }
476 if (_session.config.get_xfade_model() == FullCrossfade) {
478 touched_regions = regions_touched (bottom->first_frame(), top->last_frame());
479 if (touched_regions->size() <= 2) {
480 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
481 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
482 add_crossfade (xfade);
486 touched_regions = regions_touched (bottom->first_frame(),
487 bottom->first_frame() + min ((nframes_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
489 if (touched_regions->size() <= 2) {
490 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
491 add_crossfade (xfade);
496 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
497 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
498 add_crossfade (xfade);
502 catch (failed_constructor& err) {
506 catch (Crossfade::NoCrossfadeHere& err) {
512 delete touched_regions;
516 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
518 Crossfades::iterator ci;
520 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
521 if (*(*ci) == *xfade) { // Crossfade::operator==()
526 if (ci != _crossfades.end()) {
527 // it will just go away
529 _crossfades.push_back (xfade);
531 xfade->Invalidated.connect (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
532 xfade->StateChanged.connect (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
534 notify_crossfade_added (xfade);
538 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
540 if (g_atomic_int_get(&block_notifications)) {
541 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
543 NewCrossfade (x); /* EMIT SIGNAL */
548 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
550 Crossfades::iterator i;
551 boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
553 xfade->in()->resume_fade_in ();
554 xfade->out()->resume_fade_out ();
556 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
557 _crossfades.erase (i);
562 AudioPlaylist::set_state (const XMLNode& node, int version)
566 XMLNodeConstIterator niter;
570 Playlist::set_state (node, version);
574 nlist = node.children();
576 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
580 if (child->name() != "Crossfade") {
585 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
586 _crossfades.push_back (xfade);
587 xfade->Invalidated.connect (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
588 xfade->StateChanged.connect (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
592 catch (failed_constructor& err) {
593 // cout << string_compose (_("could not create crossfade object in playlist %1"),
607 AudioPlaylist::clear (bool with_signals)
609 _crossfades.clear ();
610 Playlist::clear (with_signals);
614 AudioPlaylist::state (bool full_state)
616 XMLNode& node = Playlist::state (full_state);
619 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
620 node.add_child_nocopy ((*i)->get_state());
628 AudioPlaylist::dump () const
630 boost::shared_ptr<Region>r;
631 boost::shared_ptr<Crossfade> x;
633 cerr << "Playlist \"" << _name << "\" " << endl
634 << regions.size() << " regions "
635 << _crossfades.size() << " crossfades"
638 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
640 cerr << " " << r->name() << " @ " << r << " ["
641 << r->start() << "+" << r->length()
649 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
660 << (x->active() ? "yes" : "no")
666 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
668 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
669 bool changed = false;
670 Crossfades::iterator c, ctmp;
671 set<boost::shared_ptr<Crossfade> > unique_xfades;
674 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
681 RegionLock rlock (this);
683 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
685 RegionList::iterator tmp = i;
688 if ((*i) == region) {
696 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
698 set<boost::shared_ptr<Region> >::iterator xtmp = x;
701 if ((*x) == region) {
702 all_regions.erase (x);
709 region->set_playlist (boost::shared_ptr<Playlist>());
712 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
716 if ((*c)->involves (r)) {
717 unique_xfades.insert (*c);
718 _crossfades.erase (c);
725 /* overload this, it normally means "removed", not destroyed */
726 notify_region_removed (region);
733 AudioPlaylist::crossfade_changed (Change)
735 if (in_flush || in_set_state) {
739 /* XXX is there a loop here? can an xfade change not happen
740 due to a playlist change? well, sure activation would
741 be an example. maybe we should check the type of change
749 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
751 if (in_flush || in_set_state) {
755 Change our_interests = Change (AudioRegion::FadeInChanged|
756 AudioRegion::FadeOutChanged|
757 AudioRegion::FadeInActiveChanged|
758 AudioRegion::FadeOutActiveChanged|
759 AudioRegion::EnvelopeActiveChanged|
760 AudioRegion::ScaleAmplitudeChanged|
761 AudioRegion::EnvelopeChanged);
762 bool parent_wants_notify;
764 parent_wants_notify = Playlist::region_changed (what_changed, region);
766 if ((parent_wants_notify || (what_changed & our_interests))) {
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) {