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);
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 /* optimizing this memset() away involves a lot of conditionals
129 that may well cause more of a hit due to cache misses
130 and related stuff than just doing this here.
132 it would be great if someone could measure this
135 one way or another, parts of the requested area
136 that are not written to by Region::region_at()
137 for all Regions that cover the area need to be
141 memset (buf, 0, sizeof (Sample) * cnt);
143 /* this function is never called from a realtime thread, so
144 its OK to block (for short intervals).
147 Glib::Mutex::Lock rm (region_lock);
149 end = start + cnt - 1;
151 _read_data_count = 0;
153 map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
154 map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
155 vector<uint32_t> relevant_layers;
157 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
158 if ((*i)->coverage (start, end) != OverlapNone) {
159 relevant_regions[(*i)->layer()].push_back (*i);
160 relevant_layers.push_back ((*i)->layer());
164 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
165 if ((*i)->coverage (start, end) != OverlapNone) {
166 relevant_xfades[(*i)->upper_layer()].push_back (*i);
170 // RegionSortByLayer layer_cmp;
171 // relevant_regions.sort (layer_cmp);
173 /* XXX this whole per-layer approach is a hack that
174 should be removed once Crossfades become
175 CrossfadeRegions and we just grab a list of relevant
176 regions and call read_at() on all of them.
179 sort (relevant_layers.begin(), relevant_layers.end());
181 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
183 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
184 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
186 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
187 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
189 ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
190 _read_data_count += ar->read_data_count();
193 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
194 (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
196 /* don't JACK up _read_data_count, since its the same data as we just
197 read from the regions, and the OS should handle that for us.
207 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
209 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
216 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
221 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
223 if ((*i)->involves (r)) {
224 i = _crossfades.erase (i);
233 AudioPlaylist::flush_notifications ()
235 Playlist::flush_notifications();
243 Crossfades::iterator a;
244 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
245 NewCrossfade (*a); /* EMIT SIGNAL */
248 _pending_xfade_adds.clear ();
254 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
256 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
257 set<boost::shared_ptr<Crossfade> > updated;
263 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
265 Crossfades::iterator tmp;
270 /* only update them once */
272 if ((*x)->involves (ar)) {
274 if (find (updated.begin(), updated.end(), *x) == updated.end()) {
276 if ((*x)->refresh ()) {
281 catch (Crossfade::NoCrossfadeHere& err) {
282 // relax, Invalidated during refresh
292 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
294 boost::shared_ptr<AudioRegion> orig = boost::dynamic_pointer_cast<AudioRegion>(o);
295 boost::shared_ptr<AudioRegion> left = boost::dynamic_pointer_cast<AudioRegion>(l);
296 boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
298 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
299 Crossfades::iterator tmp;
303 boost::shared_ptr<Crossfade> fade;
305 if ((*x)->_in == orig) {
306 if (! (*x)->covers(right->position())) {
307 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, left, (*x)->_out));
309 // Overlap, the crossfade is copied on the left side of the right region instead
310 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, right, (*x)->_out));
314 if ((*x)->_out == orig) {
315 if (! (*x)->covers(right->position())) {
316 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, right));
318 // Overlap, the crossfade is copied on the right side of the left region instead
319 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, left));
324 _crossfades.remove (*x);
325 add_crossfade (fade);
332 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
334 boost::shared_ptr<AudioRegion> other;
335 boost::shared_ptr<AudioRegion> region;
336 boost::shared_ptr<AudioRegion> top;
337 boost::shared_ptr<AudioRegion> bottom;
338 boost::shared_ptr<Crossfade> xfade;
340 if (in_set_state || in_partition) {
344 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
345 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
351 refresh_dependents (r);
355 if (!Config->get_auto_xfade()) {
359 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
361 nframes_t xfade_length;
363 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
365 if (other == region) {
369 if (other->muted() || region->muted()) {
374 if (other->layer() < region->layer()) {
382 if (!top->opaque()) {
386 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
393 case OverlapInternal:
394 /* {=============== top =============}
395 * [ ----- bottom ------- ]
399 case OverlapExternal:
401 /* [ -------- top ------- ]
402 * {=========== bottom =============}
405 /* to avoid discontinuities at the region boundaries of an internal
406 overlap (this region is completely within another), we create
407 two hidden crossfades at each boundary. this is not dependent
408 on the auto-xfade option, because we require it as basic
412 xfade_length = min ((nframes_t) 720, top->length());
414 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
415 add_crossfade (xfade);
417 if (top_region_at (top->last_frame() - 1) == top) {
419 only add a fade out if there is no region on top of the end of 'top' (which
423 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
424 add_crossfade (xfade);
429 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active()));
430 add_crossfade (xfade);
434 catch (failed_constructor& err) {
438 catch (Crossfade::NoCrossfadeHere& err) {
446 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
448 Crossfades::iterator ci;
450 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
451 if (*(*ci) == *xfade) { // Crossfade::operator==()
456 if (ci != _crossfades.end()) {
457 // it will just go away
459 _crossfades.push_back (xfade);
461 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
462 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
464 notify_crossfade_added (xfade);
468 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
470 if (g_atomic_int_get(&block_notifications)) {
471 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
473 NewCrossfade (x); /* EMIT SIGNAL */
478 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
480 Crossfades::iterator i;
481 boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
483 xfade->in()->resume_fade_in ();
484 xfade->out()->resume_fade_out ();
486 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
487 _crossfades.erase (i);
492 AudioPlaylist::set_state (const XMLNode& node)
496 XMLNodeConstIterator niter;
501 Playlist::set_state (node);
503 nlist = node.children();
505 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
509 if (child->name() != "Crossfade") {
514 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
515 _crossfades.push_back (xfade);
516 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
517 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
521 catch (failed_constructor& err) {
522 // cout << string_compose (_("could not create crossfade object in playlist %1"),
536 AudioPlaylist::clear (bool with_signals)
538 _crossfades.clear ();
539 Playlist::clear (with_signals);
543 AudioPlaylist::state (bool full_state)
545 XMLNode& node = Playlist::state (full_state);
548 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
549 node.add_child_nocopy ((*i)->get_state());
557 AudioPlaylist::dump () const
559 boost::shared_ptr<Region>r;
560 boost::shared_ptr<Crossfade> x;
562 cerr << "Playlist \"" << _name << "\" " << endl
563 << regions.size() << " regions "
564 << _crossfades.size() << " crossfades"
567 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
569 cerr << " " << r->name() << " @ " << r << " ["
570 << r->start() << "+" << r->length()
578 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
589 << (x->active() ? "yes" : "no")
595 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
597 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
598 bool changed = false;
599 Crossfades::iterator c, ctmp;
600 set<boost::shared_ptr<Crossfade> > unique_xfades;
603 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
610 RegionLock rlock (this);
612 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
614 RegionList::iterator tmp = i;
617 if ((*i) == region) {
625 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
627 set<boost::shared_ptr<Region> >::iterator xtmp = x;
630 if ((*x) == region) {
631 all_regions.erase (x);
638 region->set_playlist (boost::shared_ptr<Playlist>());
641 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
645 if ((*c)->involves (r)) {
646 unique_xfades.insert (*c);
647 _crossfades.erase (c);
654 /* overload this, it normally means "removed", not destroyed */
655 notify_region_removed (region);
662 AudioPlaylist::crossfade_changed (Change ignored)
664 if (in_flush || in_set_state) {
668 /* XXX is there a loop here? can an xfade change not happen
669 due to a playlist change? well, sure activation would
670 be an example. maybe we should check the type of change
678 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
680 if (in_flush || in_set_state) {
684 Change our_interests = Change (AudioRegion::FadeInChanged|
685 AudioRegion::FadeOutChanged|
686 AudioRegion::FadeInActiveChanged|
687 AudioRegion::FadeOutActiveChanged|
688 AudioRegion::EnvelopeActiveChanged|
689 AudioRegion::ScaleAmplitudeChanged|
690 AudioRegion::EnvelopeChanged);
691 bool parent_wants_notify;
693 parent_wants_notify = Playlist::region_changed (what_changed, region);
695 if ((parent_wants_notify || (what_changed & our_interests))) {
703 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
705 RegionLock rlock (this);
707 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
708 nframes_t start, end;
710 start = (*i)->position();
711 end = start + (*i)->overlap_length(); // not length(), important difference
713 if (frame >= start && frame <= end) {
714 clist.push_back (*i);