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.
24 #include <sigc++/bind.h>
26 #include "ardour/types.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 GoingAway (); /* EMIT SIGNAL */
108 /* drop connections to signals */
112 _crossfades.clear ();
115 struct RegionSortByLayer {
116 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
117 return a->layer() < b->layer();
122 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
123 nframes_t cnt, unsigned chan_n)
127 nframes_t read_frames;
128 nframes_t skip_frames;
130 /* optimizing this memset() away involves a lot of conditionals
131 that may well cause more of a hit due to cache misses
132 and related stuff than just doing this here.
134 it would be great if someone could measure this
137 one way or another, parts of the requested area
138 that are not written to by Region::region_at()
139 for all Regions that cover the area need to be
143 memset (buf, 0, sizeof (Sample) * cnt);
145 /* this function is never called from a realtime thread, so
146 its OK to block (for short intervals).
149 Glib::RecMutex::Lock rm (region_lock);
151 end = start + cnt - 1;
154 _read_data_count = 0;
156 _read_data_count = 0;
158 RegionList* rlist = regions_to_read (start, start+cnt);
160 if (rlist->empty()) {
165 map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
166 map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
167 vector<uint32_t> relevant_layers;
169 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ++i) {
170 if ((*i)->coverage (start, end) != OverlapNone) {
171 relevant_regions[(*i)->layer()].push_back (*i);
172 relevant_layers.push_back ((*i)->layer());
176 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
177 if ((*i)->coverage (start, end) != OverlapNone) {
178 relevant_xfades[(*i)->upper_layer()].push_back (*i);
182 // RegionSortByLayer layer_cmp;
183 // relevant_regions.sort (layer_cmp);
185 /* XXX this whole per-layer approach is a hack that
186 should be removed once Crossfades become
187 CrossfadeRegions and we just grab a list of relevant
188 regions and call read_at() on all of them.
191 sort (relevant_layers.begin(), relevant_layers.end());
193 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
195 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
196 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
198 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
199 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
201 ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
202 _read_data_count += ar->read_data_count();
205 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
206 (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
208 /* don't JACK up _read_data_count, since its the same data as we just
209 read from the regions, and the OS should handle that for us.
220 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
222 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
229 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
234 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
236 if ((*i)->involves (r)) {
237 i = _crossfades.erase (i);
246 AudioPlaylist::flush_notifications ()
248 Playlist::flush_notifications();
256 Crossfades::iterator a;
257 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
258 NewCrossfade (*a); /* EMIT SIGNAL */
261 _pending_xfade_adds.clear ();
267 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
269 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
270 set<boost::shared_ptr<Crossfade> > updated;
276 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
278 Crossfades::iterator tmp;
283 /* only update them once */
285 if ((*x)->involves (ar)) {
287 pair<set<boost::shared_ptr<Crossfade> >::iterator, bool> const u = updated.insert (*x);
290 /* x was successfully inserted into the set, so it has not already been updated */
295 catch (Crossfade::NoCrossfadeHere& err) {
296 // relax, Invalidated during refresh
306 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
308 boost::shared_ptr<AudioRegion> orig = boost::dynamic_pointer_cast<AudioRegion>(o);
309 boost::shared_ptr<AudioRegion> left = boost::dynamic_pointer_cast<AudioRegion>(l);
310 boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
312 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
313 Crossfades::iterator tmp;
317 boost::shared_ptr<Crossfade> fade;
319 if ((*x)->_in == orig) {
320 if (! (*x)->covers(right->position())) {
321 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, left, (*x)->_out));
323 // Overlap, the crossfade is copied on the left side of the right region instead
324 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, right, (*x)->_out));
328 if ((*x)->_out == orig) {
329 if (! (*x)->covers(right->position())) {
330 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, right));
332 // Overlap, the crossfade is copied on the right side of the left region instead
333 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, left));
338 _crossfades.remove (*x);
339 add_crossfade (fade);
346 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
348 boost::shared_ptr<AudioRegion> other;
349 boost::shared_ptr<AudioRegion> region;
350 boost::shared_ptr<AudioRegion> top;
351 boost::shared_ptr<AudioRegion> bottom;
352 boost::shared_ptr<Crossfade> xfade;
353 RegionList* touched_regions = 0;
355 if (in_set_state || in_partition) {
359 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
360 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
366 refresh_dependents (r);
370 if (!_session.config.get_auto_xfade()) {
374 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
376 nframes_t xfade_length;
378 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
380 if (other == region) {
384 if (other->muted() || region->muted()) {
389 if (other->layer() < region->layer()) {
397 if (!top->opaque()) {
401 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
403 delete touched_regions;
411 case OverlapInternal:
412 /* {=============== top =============}
413 * [ ----- bottom ------- ]
417 case OverlapExternal:
419 /* [ -------- top ------- ]
420 * {=========== bottom =============}
423 /* to avoid discontinuities at the region boundaries of an internal
424 overlap (this region is completely within another), we create
425 two hidden crossfades at each boundary. this is not dependent
426 on the auto-xfade option, because we require it as basic
430 xfade_length = min ((nframes_t) 720, top->length());
432 if (top_region_at (top->first_frame()) == top) {
434 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
435 add_crossfade (xfade);
438 if (top_region_at (top->last_frame() - 1) == top) {
441 only add a fade out if there is no region on top of the end of 'top' (which
445 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
446 add_crossfade (xfade);
451 /* { ==== top ============ }
452 * [---- bottom -------------------]
455 if (_session.config.get_xfade_model() == FullCrossfade) {
456 touched_regions = regions_touched (top->first_frame(), bottom->last_frame());
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);
463 touched_regions = regions_touched (top->first_frame(),
464 top->first_frame() + min ((nframes_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
466 if (touched_regions->size() <= 2) {
467 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
468 add_crossfade (xfade);
475 /* [---- top ------------------------]
476 * { ==== bottom ============ }
479 if (_session.config.get_xfade_model() == FullCrossfade) {
481 touched_regions = regions_touched (bottom->first_frame(), top->last_frame());
482 if (touched_regions->size() <= 2) {
483 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
484 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
485 add_crossfade (xfade);
489 touched_regions = regions_touched (bottom->first_frame(),
490 bottom->first_frame() + min ((nframes_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
492 if (touched_regions->size() <= 2) {
493 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
494 add_crossfade (xfade);
499 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
500 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
501 add_crossfade (xfade);
505 catch (failed_constructor& err) {
509 catch (Crossfade::NoCrossfadeHere& err) {
515 delete touched_regions;
519 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
521 Crossfades::iterator ci;
523 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
524 if (*(*ci) == *xfade) { // Crossfade::operator==()
529 if (ci != _crossfades.end()) {
530 // it will just go away
532 _crossfades.push_back (xfade);
534 xfade->Invalidated.connect (sigc::mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
535 xfade->StateChanged.connect (sigc::mem_fun (*this, &AudioPlaylist::crossfade_changed));
537 notify_crossfade_added (xfade);
541 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
543 if (g_atomic_int_get(&block_notifications)) {
544 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
546 NewCrossfade (x); /* EMIT SIGNAL */
551 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
553 Crossfades::iterator i;
554 boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
556 xfade->in()->resume_fade_in ();
557 xfade->out()->resume_fade_out ();
559 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
560 _crossfades.erase (i);
565 AudioPlaylist::set_state (const XMLNode& node, int version)
569 XMLNodeConstIterator niter;
573 Playlist::set_state (node, version);
577 nlist = node.children();
579 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
583 if (child->name() != "Crossfade") {
588 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
589 _crossfades.push_back (xfade);
590 xfade->Invalidated.connect (sigc::mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
591 xfade->StateChanged.connect (sigc::mem_fun (*this, &AudioPlaylist::crossfade_changed));
595 catch (failed_constructor& err) {
596 // cout << string_compose (_("could not create crossfade object in playlist %1"),
610 AudioPlaylist::clear (bool with_signals)
612 _crossfades.clear ();
613 Playlist::clear (with_signals);
617 AudioPlaylist::state (bool full_state)
619 XMLNode& node = Playlist::state (full_state);
622 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
623 node.add_child_nocopy ((*i)->get_state());
631 AudioPlaylist::dump () const
633 boost::shared_ptr<Region>r;
634 boost::shared_ptr<Crossfade> x;
636 cerr << "Playlist \"" << _name << "\" " << endl
637 << regions.size() << " regions "
638 << _crossfades.size() << " crossfades"
641 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
643 cerr << " " << r->name() << " @ " << r << " ["
644 << r->start() << "+" << r->length()
652 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
663 << (x->active() ? "yes" : "no")
669 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
671 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
672 bool changed = false;
673 Crossfades::iterator c, ctmp;
674 set<boost::shared_ptr<Crossfade> > unique_xfades;
677 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
684 RegionLock rlock (this);
686 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
688 RegionList::iterator tmp = i;
691 if ((*i) == region) {
699 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
701 set<boost::shared_ptr<Region> >::iterator xtmp = x;
704 if ((*x) == region) {
705 all_regions.erase (x);
712 region->set_playlist (boost::shared_ptr<Playlist>());
715 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
719 if ((*c)->involves (r)) {
720 unique_xfades.insert (*c);
721 _crossfades.erase (c);
728 /* overload this, it normally means "removed", not destroyed */
729 notify_region_removed (region);
736 AudioPlaylist::crossfade_changed (Change)
738 if (in_flush || in_set_state) {
742 /* XXX is there a loop here? can an xfade change not happen
743 due to a playlist change? well, sure activation would
744 be an example. maybe we should check the type of change
752 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
754 if (in_flush || in_set_state) {
758 Change our_interests = Change (AudioRegion::FadeInChanged|
759 AudioRegion::FadeOutChanged|
760 AudioRegion::FadeInActiveChanged|
761 AudioRegion::FadeOutActiveChanged|
762 AudioRegion::EnvelopeActiveChanged|
763 AudioRegion::ScaleAmplitudeChanged|
764 AudioRegion::EnvelopeChanged);
765 bool parent_wants_notify;
767 parent_wants_notify = Playlist::region_changed (what_changed, region);
769 if ((parent_wants_notify || (what_changed & our_interests))) {
777 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
779 RegionLock rlock (this);
781 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
782 nframes_t start, end;
784 start = (*i)->position();
785 end = start + (*i)->overlap_length(); // not length(), important difference
787 if (frame >= start && frame <= end) {
788 clist.push_back (*i);
794 AudioPlaylist::foreach_crossfade (sigc::slot<void, boost::shared_ptr<Crossfade> > s)
796 RegionLock rl (this, false);
797 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {