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>
36 using namespace ARDOUR;
41 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
42 : Playlist (session, node, hidden)
49 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
50 : Playlist (session, name, hidden)
54 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
55 : Playlist (other, name, hidden)
57 RegionList::const_iterator in_o = other->regions.begin();
58 RegionList::iterator in_n = regions.begin();
60 while (in_o != other->regions.end()) {
61 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
63 // We look only for crossfades which begin with the current region, so we don't get doubles
64 for (Crossfades::const_iterator xfades = other->_crossfades.begin(); xfades != other->_crossfades.end(); ++xfades) {
65 if ((*xfades)->in() == ar) {
66 // We found one! Now copy it!
68 RegionList::const_iterator out_o = other->regions.begin();
69 RegionList::const_iterator out_n = regions.begin();
71 while (out_o != other->regions.end()) {
73 boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
75 if ((*xfades)->out() == ar2) {
76 boost::shared_ptr<AudioRegion>in = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
77 boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
78 boost::shared_ptr<Crossfade> new_fade = boost::shared_ptr<Crossfade> (new Crossfade (*(*xfades), in, out));
79 add_crossfade(new_fade);
86 // cerr << "HUH!? second region in the crossfade not found!" << endl;
95 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
96 : Playlist (other, start, cnt, name, hidden)
98 /* this constructor does NOT notify others (session) */
101 AudioPlaylist::~AudioPlaylist ()
103 GoingAway (); /* EMIT SIGNAL */
105 /* drop connections to signals */
109 _crossfades.clear ();
112 struct RegionSortByLayer {
113 bool operator() (boost::shared_ptr<Region>a, boost::shared_ptr<Region>b) {
114 return a->layer() < b->layer();
119 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
120 nframes_t cnt, unsigned chan_n)
124 nframes_t read_frames;
125 nframes_t skip_frames;
127 /* optimizing this memset() away involves a lot of conditionals
128 that may well cause more of a hit due to cache misses
129 and related stuff than just doing this here.
131 it would be great if someone could measure this
134 one way or another, parts of the requested area
135 that are not written to by Region::region_at()
136 for all Regions that cover the area need to be
140 memset (buf, 0, sizeof (Sample) * cnt);
142 /* this function is never called from a realtime thread, so
143 its OK to block (for short intervals).
146 Glib::Mutex::Lock rm (region_lock);
148 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, read_frames, skip_frames);
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()) {
384 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
391 case OverlapInternal:
392 /* {=============== top =============}
393 * [ ----- bottom ------- ]
397 case OverlapExternal:
399 /* [ -------- top ------- ]
400 * {=========== bottom =============}
403 /* to avoid discontinuities at the region boundaries of an internal
404 overlap (this region is completely within another), we create
405 two hidden crossfades at each boundary. this is not dependent
406 on the auto-xfade option, because we require it as basic
410 xfade_length = min ((nframes_t) 720, top->length());
412 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
413 add_crossfade (xfade);
415 if (top_region_at (top->last_frame() - 1) == top) {
417 only add a fade out if there is no region on top of the end of 'top' (which
421 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
422 add_crossfade (xfade);
427 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active()));
428 add_crossfade (xfade);
432 catch (failed_constructor& err) {
436 catch (Crossfade::NoCrossfadeHere& err) {
444 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
446 Crossfades::iterator ci;
448 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
449 if (*(*ci) == *xfade) { // Crossfade::operator==()
454 if (ci != _crossfades.end()) {
455 // it will just go away
457 _crossfades.push_back (xfade);
459 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
460 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
462 notify_crossfade_added (xfade);
466 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
468 if (g_atomic_int_get(&block_notifications)) {
469 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
471 NewCrossfade (x); /* EMIT SIGNAL */
476 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Crossfade> xfade)
478 Crossfades::iterator i;
480 xfade->in()->resume_fade_in ();
481 xfade->out()->resume_fade_out ();
483 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
484 _crossfades.erase (i);
489 AudioPlaylist::set_state (const XMLNode& node)
493 XMLNodeConstIterator niter;
498 Playlist::set_state (node);
500 nlist = node.children();
502 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
506 if (child->name() != "Crossfade") {
511 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
512 _crossfades.push_back (xfade);
513 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
514 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
518 catch (failed_constructor& err) {
519 // cout << string_compose (_("could not create crossfade object in playlist %1"),
533 AudioPlaylist::clear (bool with_signals)
535 _crossfades.clear ();
536 Playlist::clear (with_signals);
540 AudioPlaylist::state (bool full_state)
542 XMLNode& node = Playlist::state (full_state);
545 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
546 node.add_child_nocopy ((*i)->get_state());
554 AudioPlaylist::dump () const
556 boost::shared_ptr<Region>r;
557 boost::shared_ptr<Crossfade> x;
559 cerr << "Playlist \"" << _name << "\" " << endl
560 << regions.size() << " regions "
561 << _crossfades.size() << " crossfades"
564 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
566 cerr << " " << r->name() << " @ " << r << " ["
567 << r->start() << "+" << r->length()
575 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
586 << (x->active() ? "yes" : "no")
592 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
594 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
595 bool changed = false;
596 Crossfades::iterator c, ctmp;
597 set<boost::shared_ptr<Crossfade> > unique_xfades;
600 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
607 RegionLock rlock (this);
609 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
611 RegionList::iterator tmp = i;
614 if ((*i) == region) {
622 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
624 set<boost::shared_ptr<Region> >::iterator xtmp = x;
627 if ((*x) == region) {
628 all_regions.erase (x);
635 region->set_playlist (boost::shared_ptr<Playlist>());
638 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
642 if ((*c)->involves (r)) {
643 unique_xfades.insert (*c);
644 _crossfades.erase (c);
651 /* overload this, it normally means "removed", not destroyed */
652 notify_region_removed (region);
659 AudioPlaylist::crossfade_changed (Change ignored)
661 if (in_flush || in_set_state) {
665 /* XXX is there a loop here? can an xfade change not happen
666 due to a playlist change? well, sure activation would
667 be an example. maybe we should check the type of change
675 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
677 if (in_flush || in_set_state) {
681 Change our_interests = Change (AudioRegion::FadeInChanged|
682 AudioRegion::FadeOutChanged|
683 AudioRegion::FadeInActiveChanged|
684 AudioRegion::FadeOutActiveChanged|
685 AudioRegion::EnvelopeActiveChanged|
686 AudioRegion::ScaleAmplitudeChanged|
687 AudioRegion::EnvelopeChanged);
688 bool parent_wants_notify;
690 parent_wants_notify = Playlist::region_changed (what_changed, region);
692 if ((parent_wants_notify || (what_changed & our_interests))) {
700 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
702 RegionLock rlock (this);
704 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
705 nframes_t start, end;
707 start = (*i)->position();
708 end = start + (*i)->overlap_length(); // not length(), important difference
710 if (frame >= start && frame <= end) {
711 clist.push_back (*i);