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)
129 /* optimizing this memset() away involves a lot of conditionals
130 that may well cause more of a hit due to cache misses
131 and related stuff than just doing this here.
133 it would be great if someone could measure this
136 one way or another, parts of the requested area
137 that are not written to by Region::region_at()
138 for all Regions that cover the area need to be
142 memset (buf, 0, sizeof (Sample) * cnt);
144 /* this function is never called from a realtime thread, so
145 its OK to block (for short intervals).
148 Glib::Mutex::Lock rm (region_lock);
150 end = start + cnt - 1;
152 _read_data_count = 0;
154 map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
155 map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
156 vector<uint32_t> relevant_layers;
158 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
159 if ((*i)->coverage (start, end) != OverlapNone) {
160 relevant_regions[(*i)->layer()].push_back (*i);
161 relevant_layers.push_back ((*i)->layer());
165 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
166 if ((*i)->coverage (start, end) != OverlapNone) {
167 relevant_xfades[(*i)->upper_layer()].push_back (*i);
171 // RegionSortByLayer layer_cmp;
172 // relevant_regions.sort (layer_cmp);
174 /* XXX this whole per-layer approach is a hack that
175 should be removed once Crossfades become
176 CrossfadeRegions and we just grab a list of relevant
177 regions and call read_at() on all of them.
180 sort (relevant_layers.begin(), relevant_layers.end());
182 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
184 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
185 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
187 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
188 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
190 ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
191 _read_data_count += ar->read_data_count();
194 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
195 (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
197 /* don't JACK up _read_data_count, since its the same data as we just
198 read from the regions, and the OS should handle that for us.
208 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
210 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
217 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
222 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
224 if ((*i)->involves (r)) {
225 i = _crossfades.erase (i);
234 AudioPlaylist::flush_notifications ()
236 Playlist::flush_notifications();
244 Crossfades::iterator a;
245 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
246 NewCrossfade (*a); /* EMIT SIGNAL */
249 _pending_xfade_adds.clear ();
255 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
257 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
258 set<boost::shared_ptr<Crossfade> > updated;
264 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
266 Crossfades::iterator tmp;
271 /* only update them once */
273 if ((*x)->involves (ar)) {
275 if (find (updated.begin(), updated.end(), *x) == updated.end()) {
277 if ((*x)->refresh ()) {
282 catch (Crossfade::NoCrossfadeHere& err) {
283 // relax, Invalidated during refresh
293 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
295 boost::shared_ptr<AudioRegion> orig = boost::dynamic_pointer_cast<AudioRegion>(o);
296 boost::shared_ptr<AudioRegion> left = boost::dynamic_pointer_cast<AudioRegion>(l);
297 boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
299 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
300 Crossfades::iterator tmp;
304 boost::shared_ptr<Crossfade> fade;
306 if ((*x)->_in == orig) {
307 if (! (*x)->covers(right->position())) {
308 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, left, (*x)->_out));
310 // Overlap, the crossfade is copied on the left side of the right region instead
311 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, right, (*x)->_out));
315 if ((*x)->_out == orig) {
316 if (! (*x)->covers(right->position())) {
317 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, right));
319 // Overlap, the crossfade is copied on the right side of the left region instead
320 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, left));
325 _crossfades.remove (*x);
326 add_crossfade (fade);
333 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
335 boost::shared_ptr<AudioRegion> other;
336 boost::shared_ptr<AudioRegion> region;
337 boost::shared_ptr<AudioRegion> top;
338 boost::shared_ptr<AudioRegion> bottom;
339 boost::shared_ptr<Crossfade> xfade;
341 if (in_set_state || in_partition) {
345 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
346 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
352 refresh_dependents (r);
356 if (!Config->get_auto_xfade()) {
360 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
362 nframes_t xfade_length;
364 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
366 if (other == region) {
370 if (other->muted() || region->muted()) {
375 if (other->layer() < region->layer()) {
385 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
392 case OverlapInternal:
393 /* {=============== top =============}
394 * [ ----- bottom ------- ]
398 case OverlapExternal:
400 /* [ -------- top ------- ]
401 * {=========== bottom =============}
404 /* to avoid discontinuities at the region boundaries of an internal
405 overlap (this region is completely within another), we create
406 two hidden crossfades at each boundary. this is not dependent
407 on the auto-xfade option, because we require it as basic
411 xfade_length = min ((nframes_t) 720, top->length());
413 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
414 add_crossfade (xfade);
416 if (top_region_at (top->last_frame() - 1) == top) {
418 only add a fade out if there is no region on top of the end of 'top' (which
422 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
423 add_crossfade (xfade);
428 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active()));
429 add_crossfade (xfade);
433 catch (failed_constructor& err) {
437 catch (Crossfade::NoCrossfadeHere& err) {
445 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
447 Crossfades::iterator ci;
449 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
450 if (*(*ci) == *xfade) { // Crossfade::operator==()
455 if (ci != _crossfades.end()) {
456 // it will just go away
458 _crossfades.push_back (xfade);
460 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
461 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
463 notify_crossfade_added (xfade);
467 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
469 if (g_atomic_int_get(&block_notifications)) {
470 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
472 NewCrossfade (x); /* EMIT SIGNAL */
477 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
479 Crossfades::iterator i;
480 boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
482 xfade->in()->resume_fade_in ();
483 xfade->out()->resume_fade_out ();
485 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
486 _crossfades.erase (i);
491 AudioPlaylist::set_state (const XMLNode& node)
495 XMLNodeConstIterator niter;
500 Playlist::set_state (node);
502 nlist = node.children();
504 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
508 if (child->name() != "Crossfade") {
513 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
514 _crossfades.push_back (xfade);
515 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
516 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
520 catch (failed_constructor& err) {
521 // cout << string_compose (_("could not create crossfade object in playlist %1"),
535 AudioPlaylist::clear (bool with_signals)
537 _crossfades.clear ();
538 Playlist::clear (with_signals);
542 AudioPlaylist::state (bool full_state)
544 XMLNode& node = Playlist::state (full_state);
547 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
548 node.add_child_nocopy ((*i)->get_state());
556 AudioPlaylist::dump () const
558 boost::shared_ptr<Region>r;
559 boost::shared_ptr<Crossfade> x;
561 cerr << "Playlist \"" << _name << "\" " << endl
562 << regions.size() << " regions "
563 << _crossfades.size() << " crossfades"
566 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
568 cerr << " " << r->name() << " @ " << r << " ["
569 << r->start() << "+" << r->length()
577 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
588 << (x->active() ? "yes" : "no")
594 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
596 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
597 bool changed = false;
598 Crossfades::iterator c, ctmp;
599 set<boost::shared_ptr<Crossfade> > unique_xfades;
602 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
609 RegionLock rlock (this);
611 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
613 RegionList::iterator tmp = i;
616 if ((*i) == region) {
624 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
626 set<boost::shared_ptr<Region> >::iterator xtmp = x;
629 if ((*x) == region) {
630 all_regions.erase (x);
637 region->set_playlist (boost::shared_ptr<Playlist>());
640 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
644 if ((*c)->involves (r)) {
645 unique_xfades.insert (*c);
646 _crossfades.erase (c);
653 /* overload this, it normally means "removed", not destroyed */
654 notify_region_removed (region);
661 AudioPlaylist::crossfade_changed (Change ignored)
663 if (in_flush || in_set_state) {
667 /* XXX is there a loop here? can an xfade change not happen
668 due to a playlist change? well, sure activation would
669 be an example. maybe we should check the type of change
677 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
679 if (in_flush || in_set_state) {
683 Change our_interests = Change (AudioRegion::FadeInChanged|
684 AudioRegion::FadeOutChanged|
685 AudioRegion::FadeInActiveChanged|
686 AudioRegion::FadeOutActiveChanged|
687 AudioRegion::EnvelopeActiveChanged|
688 AudioRegion::ScaleAmplitudeChanged|
689 AudioRegion::EnvelopeChanged);
690 bool parent_wants_notify;
692 parent_wants_notify = Playlist::region_changed (what_changed, region);
694 if ((parent_wants_notify || (what_changed & our_interests))) {
702 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
704 RegionLock rlock (this);
706 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
707 nframes_t start, end;
709 start = (*i)->position();
710 end = start + (*i)->overlap_length(); // not length(), important difference
712 if (frame >= start && frame <= end) {
713 clist.push_back (*i);