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 = 0;
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());
404 delete touched_regions;
412 case OverlapInternal:
413 /* {=============== top =============}
414 * [ ----- bottom ------- ]
418 case OverlapExternal:
420 /* [ -------- top ------- ]
421 * {=========== bottom =============}
424 /* to avoid discontinuities at the region boundaries of an internal
425 overlap (this region is completely within another), we create
426 two hidden crossfades at each boundary. this is not dependent
427 on the auto-xfade option, because we require it as basic
431 xfade_length = min ((nframes_t) 720, top->length());
433 if (top_region_at (top->first_frame()) == top) {
435 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
436 add_crossfade (xfade);
439 if (top_region_at (top->last_frame() - 1) == top) {
442 only add a fade out if there is no region on top of the end of 'top' (which
446 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
447 add_crossfade (xfade);
452 /* { ==== top ============ }
453 * [---- bottom -------------------]
456 if (_session.config.get_xfade_model() == FullCrossfade) {
457 touched_regions = regions_touched (top->first_frame(), bottom->last_frame());
458 if (touched_regions->size() <= 2) {
459 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
460 add_crossfade (xfade);
464 touched_regions = regions_touched (top->first_frame(),
465 top->first_frame() + min ((nframes_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
467 if (touched_regions->size() <= 2) {
468 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
469 add_crossfade (xfade);
476 /* [---- top ------------------------]
477 * { ==== bottom ============ }
480 if (_session.config.get_xfade_model() == FullCrossfade) {
482 touched_regions = regions_touched (bottom->first_frame(), top->last_frame());
483 if (touched_regions->size() <= 2) {
484 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
485 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
486 add_crossfade (xfade);
490 touched_regions = regions_touched (bottom->first_frame(),
491 bottom->first_frame() + min ((nframes_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
493 if (touched_regions->size() <= 2) {
494 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
495 add_crossfade (xfade);
500 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
501 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
502 add_crossfade (xfade);
506 catch (failed_constructor& err) {
510 catch (Crossfade::NoCrossfadeHere& err) {
516 delete touched_regions;
520 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
522 Crossfades::iterator ci;
524 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
525 if (*(*ci) == *xfade) { // Crossfade::operator==()
530 if (ci != _crossfades.end()) {
531 // it will just go away
533 _crossfades.push_back (xfade);
535 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
536 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
538 notify_crossfade_added (xfade);
542 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
544 if (g_atomic_int_get(&block_notifications)) {
545 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
547 NewCrossfade (x); /* EMIT SIGNAL */
552 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
554 Crossfades::iterator i;
555 boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
557 xfade->in()->resume_fade_in ();
558 xfade->out()->resume_fade_out ();
560 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
561 _crossfades.erase (i);
566 AudioPlaylist::set_state (const XMLNode& node, int version)
570 XMLNodeConstIterator niter;
574 Playlist::set_state (node, version);
578 nlist = node.children();
580 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
584 if (child->name() != "Crossfade") {
589 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
590 _crossfades.push_back (xfade);
591 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
592 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
596 catch (failed_constructor& err) {
597 // cout << string_compose (_("could not create crossfade object in playlist %1"),
611 AudioPlaylist::clear (bool with_signals)
613 _crossfades.clear ();
614 Playlist::clear (with_signals);
618 AudioPlaylist::state (bool full_state)
620 XMLNode& node = Playlist::state (full_state);
623 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
624 node.add_child_nocopy ((*i)->get_state());
632 AudioPlaylist::dump () const
634 boost::shared_ptr<Region>r;
635 boost::shared_ptr<Crossfade> x;
637 cerr << "Playlist \"" << _name << "\" " << endl
638 << regions.size() << " regions "
639 << _crossfades.size() << " crossfades"
642 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
644 cerr << " " << r->name() << " @ " << r << " ["
645 << r->start() << "+" << r->length()
653 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
664 << (x->active() ? "yes" : "no")
670 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
672 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
673 bool changed = false;
674 Crossfades::iterator c, ctmp;
675 set<boost::shared_ptr<Crossfade> > unique_xfades;
678 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
685 RegionLock rlock (this);
687 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
689 RegionList::iterator tmp = i;
692 if ((*i) == region) {
700 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
702 set<boost::shared_ptr<Region> >::iterator xtmp = x;
705 if ((*x) == region) {
706 all_regions.erase (x);
713 region->set_playlist (boost::shared_ptr<Playlist>());
716 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
720 if ((*c)->involves (r)) {
721 unique_xfades.insert (*c);
722 _crossfades.erase (c);
729 /* overload this, it normally means "removed", not destroyed */
730 notify_region_removed (region);
737 AudioPlaylist::crossfade_changed (Change)
739 if (in_flush || in_set_state) {
743 /* XXX is there a loop here? can an xfade change not happen
744 due to a playlist change? well, sure activation would
745 be an example. maybe we should check the type of change
753 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
755 if (in_flush || in_set_state) {
759 Change our_interests = Change (AudioRegion::FadeInChanged|
760 AudioRegion::FadeOutChanged|
761 AudioRegion::FadeInActiveChanged|
762 AudioRegion::FadeOutActiveChanged|
763 AudioRegion::EnvelopeActiveChanged|
764 AudioRegion::ScaleAmplitudeChanged|
765 AudioRegion::EnvelopeChanged);
766 bool parent_wants_notify;
768 parent_wants_notify = Playlist::region_changed (what_changed, region);
770 if ((parent_wants_notify || (what_changed & our_interests))) {
778 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
780 RegionLock rlock (this);
782 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
783 nframes_t start, end;
785 start = (*i)->position();
786 end = start + (*i)->overlap_length(); // not length(), important difference
788 if (frame >= start && frame <= end) {
789 clist.push_back (*i);
795 AudioPlaylist::foreach_crossfade (sigc::slot<void, boost::shared_ptr<Crossfade> > s)
797 RegionLock rl (this, false);
798 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {