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;
42 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
43 : Playlist (session, node, DataType::AUDIO, hidden)
45 const XMLProperty* prop = node.property("type");
46 assert(!prop || DataType(prop->value()) == DataType::AUDIO);
49 set_state (node, Stateful::loading_state_version);
53 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
54 : Playlist (session, name, DataType::AUDIO, hidden)
58 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
59 : Playlist (other, name, hidden)
61 RegionList::const_iterator in_o = other->regions.begin();
62 RegionList::iterator in_n = regions.begin();
64 while (in_o != other->regions.end()) {
65 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
67 // We look only for crossfades which begin with the current region, so we don't get doubles
68 for (Crossfades::const_iterator xfades = other->_crossfades.begin(); xfades != other->_crossfades.end(); ++xfades) {
69 if ((*xfades)->in() == ar) {
70 // We found one! Now copy it!
72 RegionList::const_iterator out_o = other->regions.begin();
73 RegionList::const_iterator out_n = regions.begin();
75 while (out_o != other->regions.end()) {
77 boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
79 if ((*xfades)->out() == ar2) {
80 boost::shared_ptr<AudioRegion>in = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
81 boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
82 boost::shared_ptr<Crossfade> new_fade = boost::shared_ptr<Crossfade> (new Crossfade (*xfades, in, out));
83 add_crossfade(new_fade);
90 // cerr << "HUH!? second region in the crossfade not found!" << endl;
99 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
100 : Playlist (other, start, cnt, name, hidden)
102 /* this constructor does NOT notify others (session) */
105 AudioPlaylist::~AudioPlaylist ()
107 GoingAway (); /* EMIT SIGNAL */
109 /* drop connections to signals */
113 _crossfades.clear ();
116 struct RegionSortByLayer {
117 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
118 return a->layer() < b->layer();
123 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
124 nframes_t cnt, unsigned chan_n)
128 nframes_t read_frames;
129 nframes_t skip_frames;
131 /* optimizing this memset() away involves a lot of conditionals
132 that may well cause more of a hit due to cache misses
133 and related stuff than just doing this here.
135 it would be great if someone could measure this
138 one way or another, parts of the requested area
139 that are not written to by Region::region_at()
140 for all Regions that cover the area need to be
144 memset (buf, 0, sizeof (Sample) * cnt);
146 /* this function is never called from a realtime thread, so
147 its OK to block (for short intervals).
150 Glib::RecMutex::Lock rm (region_lock);
152 end = start + cnt - 1;
155 _read_data_count = 0;
157 _read_data_count = 0;
159 RegionList* rlist = regions_to_read (start, start+cnt);
161 if (rlist->empty()) {
166 map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
167 map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
168 vector<uint32_t> relevant_layers;
170 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ++i) {
171 if ((*i)->coverage (start, end) != OverlapNone) {
172 relevant_regions[(*i)->layer()].push_back (*i);
173 relevant_layers.push_back ((*i)->layer());
177 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
178 if ((*i)->coverage (start, end) != OverlapNone) {
179 relevant_xfades[(*i)->upper_layer()].push_back (*i);
183 // RegionSortByLayer layer_cmp;
184 // relevant_regions.sort (layer_cmp);
186 /* XXX this whole per-layer approach is a hack that
187 should be removed once Crossfades become
188 CrossfadeRegions and we just grab a list of relevant
189 regions and call read_at() on all of them.
192 sort (relevant_layers.begin(), relevant_layers.end());
194 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
196 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
197 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
199 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
200 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
202 ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
203 _read_data_count += ar->read_data_count();
206 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
207 (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
209 /* don't JACK up _read_data_count, since its the same data as we just
210 read from the regions, and the OS should handle that for us.
221 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
223 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
230 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
235 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
237 if ((*i)->involves (r)) {
238 i = _crossfades.erase (i);
247 AudioPlaylist::flush_notifications ()
249 Playlist::flush_notifications();
257 Crossfades::iterator a;
258 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
259 NewCrossfade (*a); /* EMIT SIGNAL */
262 _pending_xfade_adds.clear ();
268 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
270 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
271 set<boost::shared_ptr<Crossfade> > updated;
277 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
279 Crossfades::iterator tmp;
284 /* only update them once */
286 if ((*x)->involves (ar)) {
288 pair<set<boost::shared_ptr<Crossfade> >::iterator, bool> const u = updated.insert (*x);
291 /* x was successfully inserted into the set, so it has not already been updated */
296 catch (Crossfade::NoCrossfadeHere& err) {
297 // relax, Invalidated during refresh
307 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
309 boost::shared_ptr<AudioRegion> orig = boost::dynamic_pointer_cast<AudioRegion>(o);
310 boost::shared_ptr<AudioRegion> left = boost::dynamic_pointer_cast<AudioRegion>(l);
311 boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
313 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
314 Crossfades::iterator tmp;
318 boost::shared_ptr<Crossfade> fade;
320 if ((*x)->_in == orig) {
321 if (! (*x)->covers(right->position())) {
322 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, left, (*x)->_out));
324 // Overlap, the crossfade is copied on the left side of the right region instead
325 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, right, (*x)->_out));
329 if ((*x)->_out == orig) {
330 if (! (*x)->covers(right->position())) {
331 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, right));
333 // Overlap, the crossfade is copied on the right side of the left region instead
334 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, left));
339 _crossfades.remove (*x);
340 add_crossfade (fade);
347 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
349 boost::shared_ptr<AudioRegion> other;
350 boost::shared_ptr<AudioRegion> region;
351 boost::shared_ptr<AudioRegion> top;
352 boost::shared_ptr<AudioRegion> bottom;
353 boost::shared_ptr<Crossfade> xfade;
354 RegionList* touched_regions;
356 if (in_set_state || in_partition) {
360 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
361 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
367 refresh_dependents (r);
371 if (!_session.config.get_auto_xfade()) {
375 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
377 nframes_t xfade_length;
379 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
381 if (other == region) {
385 if (other->muted() || region->muted()) {
390 if (other->layer() < region->layer()) {
398 if (!top->opaque()) {
402 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
409 case OverlapInternal:
410 /* {=============== top =============}
411 * [ ----- bottom ------- ]
415 case OverlapExternal:
417 /* [ -------- top ------- ]
418 * {=========== bottom =============}
421 /* to avoid discontinuities at the region boundaries of an internal
422 overlap (this region is completely within another), we create
423 two hidden crossfades at each boundary. this is not dependent
424 on the auto-xfade option, because we require it as basic
428 xfade_length = min ((nframes_t) 720, top->length());
430 if (top_region_at (top->first_frame()) == top) {
432 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
433 add_crossfade (xfade);
436 if (top_region_at (top->last_frame() - 1) == top) {
439 only add a fade out if there is no region on top of the end of 'top' (which
443 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
444 add_crossfade (xfade);
449 /* { ==== top ============ }
450 * [---- bottom -------------------]
453 if (_session.config.get_xfade_model() == FullCrossfade) {
454 touched_regions = regions_touched (top->first_frame(), bottom->last_frame());
455 if (touched_regions->size() <= 2) {
456 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
457 add_crossfade (xfade);
461 touched_regions = regions_touched (top->first_frame(),
462 top->first_frame() + min ((nframes_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
464 if (touched_regions->size() <= 2) {
465 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
466 add_crossfade (xfade);
473 /* [---- top ------------------------]
474 * { ==== bottom ============ }
477 if (_session.config.get_xfade_model() == FullCrossfade) {
479 touched_regions = regions_touched (bottom->first_frame(), top->last_frame());
480 if (touched_regions->size() <= 2) {
481 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
482 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
483 add_crossfade (xfade);
487 touched_regions = regions_touched (bottom->first_frame(),
488 bottom->first_frame() + min ((nframes_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
490 if (touched_regions->size() <= 2) {
491 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
492 add_crossfade (xfade);
497 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
498 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
499 add_crossfade (xfade);
503 catch (failed_constructor& err) {
507 catch (Crossfade::NoCrossfadeHere& err) {
515 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
517 Crossfades::iterator ci;
519 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
520 if (*(*ci) == *xfade) { // Crossfade::operator==()
525 if (ci != _crossfades.end()) {
526 // it will just go away
528 _crossfades.push_back (xfade);
530 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
531 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
533 notify_crossfade_added (xfade);
537 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
539 if (g_atomic_int_get(&block_notifications)) {
540 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
542 NewCrossfade (x); /* EMIT SIGNAL */
547 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
549 Crossfades::iterator i;
550 boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
552 xfade->in()->resume_fade_in ();
553 xfade->out()->resume_fade_out ();
555 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
556 _crossfades.erase (i);
561 AudioPlaylist::set_state (const XMLNode& node, int version)
565 XMLNodeConstIterator niter;
569 Playlist::set_state (node, version);
573 nlist = node.children();
575 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
579 if (child->name() != "Crossfade") {
584 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
585 _crossfades.push_back (xfade);
586 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
587 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
591 catch (failed_constructor& err) {
592 // cout << string_compose (_("could not create crossfade object in playlist %1"),
606 AudioPlaylist::clear (bool with_signals)
608 _crossfades.clear ();
609 Playlist::clear (with_signals);
613 AudioPlaylist::state (bool full_state)
615 XMLNode& node = Playlist::state (full_state);
618 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
619 node.add_child_nocopy ((*i)->get_state());
627 AudioPlaylist::dump () const
629 boost::shared_ptr<Region>r;
630 boost::shared_ptr<Crossfade> x;
632 cerr << "Playlist \"" << _name << "\" " << endl
633 << regions.size() << " regions "
634 << _crossfades.size() << " crossfades"
637 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
639 cerr << " " << r->name() << " @ " << r << " ["
640 << r->start() << "+" << r->length()
648 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
659 << (x->active() ? "yes" : "no")
665 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
667 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
668 bool changed = false;
669 Crossfades::iterator c, ctmp;
670 set<boost::shared_ptr<Crossfade> > unique_xfades;
673 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
680 RegionLock rlock (this);
682 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
684 RegionList::iterator tmp = i;
687 if ((*i) == region) {
695 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
697 set<boost::shared_ptr<Region> >::iterator xtmp = x;
700 if ((*x) == region) {
701 all_regions.erase (x);
708 region->set_playlist (boost::shared_ptr<Playlist>());
711 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
715 if ((*c)->involves (r)) {
716 unique_xfades.insert (*c);
717 _crossfades.erase (c);
724 /* overload this, it normally means "removed", not destroyed */
725 notify_region_removed (region);
732 AudioPlaylist::crossfade_changed (Change)
734 if (in_flush || in_set_state) {
738 /* XXX is there a loop here? can an xfade change not happen
739 due to a playlist change? well, sure activation would
740 be an example. maybe we should check the type of change
748 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
750 if (in_flush || in_set_state) {
754 Change our_interests = Change (AudioRegion::FadeInChanged|
755 AudioRegion::FadeOutChanged|
756 AudioRegion::FadeInActiveChanged|
757 AudioRegion::FadeOutActiveChanged|
758 AudioRegion::EnvelopeActiveChanged|
759 AudioRegion::ScaleAmplitudeChanged|
760 AudioRegion::EnvelopeChanged);
761 bool parent_wants_notify;
763 parent_wants_notify = Playlist::region_changed (what_changed, region);
765 if ((parent_wants_notify || (what_changed & our_interests))) {
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 (sigc::slot<void, boost::shared_ptr<Crossfade> > s)
792 RegionLock rl (this, false);
793 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {