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.
25 #include <sigc++/bind.h>
27 #include <ardour/types.h>
28 #include <ardour/configuration.h>
29 #include <ardour/audioplaylist.h>
30 #include <ardour/audioregion.h>
31 #include <ardour/crossfade.h>
32 #include <ardour/crossfade_compare.h>
33 #include <ardour/session.h>
37 using namespace ARDOUR;
42 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
43 : Playlist (session, node, hidden)
50 PlaylistCreated (this); /* EMIT SIGNAL */
54 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
55 : Playlist (session, name, hidden)
58 PlaylistCreated (this); /* EMIT SIGNAL */
63 AudioPlaylist::AudioPlaylist (const AudioPlaylist& other, string name, bool hidden)
64 : Playlist (other, name, hidden)
66 RegionList::const_iterator in_o = other.regions.begin();
67 RegionList::iterator in_n = regions.begin();
69 while (in_o != other.regions.end()) {
70 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
72 // We look only for crossfades which begin with the current region, so we don't get doubles
73 for (list<Crossfade *>::const_iterator xfades = other._crossfades.begin(); xfades != other._crossfades.end(); ++xfades) {
74 if ((*xfades)->in() == ar) {
75 // We found one! Now copy it!
77 RegionList::const_iterator out_o = other.regions.begin();
78 RegionList::const_iterator out_n = regions.begin();
80 while (out_o != other.regions.end()) {
82 boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
84 if ((*xfades)->out() == ar2) {
85 boost::shared_ptr<AudioRegion>in = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
86 boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
87 Crossfade *new_fade = new Crossfade (*(*xfades), in, out);
88 add_crossfade(*new_fade);
95 // cerr << "HUH!? second region in the crossfade not found!" << endl;
104 PlaylistCreated (this); /* EMIT SIGNAL */
108 AudioPlaylist::AudioPlaylist (const AudioPlaylist& other, nframes_t start, nframes_t cnt, string name, bool hidden)
109 : Playlist (other, start, cnt, name, hidden)
111 /* this constructor does NOT notify others (session) */
114 AudioPlaylist::~AudioPlaylist ()
116 set<Crossfade*> all_xfades;
118 GoingAway (); /* EMIT SIGNAL */
120 /* drop connections to signals */
124 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end(); ++x) {
129 struct RegionSortByLayer {
130 bool operator() (boost::shared_ptr<Region>a, boost::shared_ptr<Region>b) {
131 return a->layer() < b->layer();
136 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
137 nframes_t cnt, unsigned chan_n)
141 nframes_t read_frames;
142 nframes_t skip_frames;
144 /* optimizing this memset() away involves a lot of conditionals
145 that may well cause more of a hit due to cache misses
146 and related stuff than just doing this here.
148 it would be great if someone could measure this
151 one way or another, parts of the requested area
152 that are not written to by Region::region_at()
153 for all Regions that cover the area need to be
157 memset (buf, 0, sizeof (Sample) * cnt);
159 /* this function is never called from a realtime thread, so
160 its OK to block (for short intervals).
163 Glib::Mutex::Lock rm (region_lock);
165 end = start + cnt - 1;
169 _read_data_count = 0;
171 map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
172 map<uint32_t,vector<Crossfade*> > relevant_xfades;
173 vector<uint32_t> relevant_layers;
175 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
176 if ((*i)->coverage (start, end) != OverlapNone) {
177 relevant_regions[(*i)->layer()].push_back (*i);
178 relevant_layers.push_back ((*i)->layer());
182 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
183 if ((*i)->coverage (start, end) != OverlapNone) {
184 relevant_xfades[(*i)->upper_layer()].push_back (*i);
188 // RegionSortByLayer layer_cmp;
189 // relevant_regions.sort (layer_cmp);
191 /* XXX this whole per-layer approach is a hack that
192 should be removed once Crossfades become
193 CrossfadeRegions and we just grab a list of relevant
194 regions and call read_at() on all of them.
197 sort (relevant_layers.begin(), relevant_layers.end());
199 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
201 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
202 vector<Crossfade*>& x (relevant_xfades[*l]);
204 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
205 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
207 ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
208 _read_data_count += ar->read_data_count();
211 for (vector<Crossfade*>::iterator i = x.begin(); i != x.end(); ++i) {
212 (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
214 /* don't JACK up _read_data_count, since its the same data as we just
215 read from the regions, and the OS should handle that for us.
225 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
227 Crossfades::iterator i, tmp;
228 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
231 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
236 for (i = _crossfades.begin(); i != _crossfades.end(); ) {
240 if ((*i)->involves (r)) {
241 /* do not delete crossfades */
242 _crossfades.erase (i);
251 AudioPlaylist::flush_notifications ()
253 Playlist::flush_notifications();
261 Crossfades::iterator a;
262 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
263 NewCrossfade (*a); /* EMIT SIGNAL */
266 _pending_xfade_adds.clear ();
272 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
274 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
275 set<Crossfade*> updated;
281 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
283 Crossfades::iterator tmp;
288 /* only update them once */
290 if ((*x)->involves (ar)) {
292 if (find (updated.begin(), updated.end(), *x) == updated.end()) {
293 if ((*x)->refresh ()) {
294 /* not invalidated by the refresh */
305 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
307 boost::shared_ptr<AudioRegion> orig = boost::dynamic_pointer_cast<AudioRegion>(o);
308 boost::shared_ptr<AudioRegion> left = boost::dynamic_pointer_cast<AudioRegion>(l);
309 boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
311 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
312 Crossfades::iterator tmp;
318 if ((*x)->_in == orig) {
319 if (! (*x)->covers(right->position())) {
320 fade = new Crossfade (**x, left, (*x)->_out);
322 // Overlap, the crossfade is copied on the left side of the right region instead
323 fade = new Crossfade (**x, right, (*x)->_out);
327 if ((*x)->_out == orig) {
328 if (! (*x)->covers(right->position())) {
329 fade = new Crossfade (**x, (*x)->_in, right);
331 // Overlap, the crossfade is copied on the right side of the left region instead
332 fade = new Crossfade (**x, (*x)->_in, left);
337 _crossfades.remove (*x);
338 add_crossfade (*fade);
345 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
347 boost::shared_ptr<AudioRegion> other;
348 boost::shared_ptr<AudioRegion> region;
349 boost::shared_ptr<AudioRegion> top;
350 boost::shared_ptr<AudioRegion> bottom;
353 if (in_set_state || in_partition) {
357 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
358 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
364 refresh_dependents (r);
367 if (!Config->get_auto_xfade()) {
371 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
373 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
375 if (other == region) {
379 if (other->muted() || region->muted()) {
383 if (other->layer() < region->layer()) {
393 if (top->coverage (bottom->position(), bottom->last_frame()) != OverlapNone) {
395 /* check if the upper region is within the lower region */
397 if (top->first_frame() > bottom->first_frame() &&
398 top->last_frame() < bottom->last_frame()) {
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 nframes_t xfade_length = min ((nframes_t) 720, top->length());
415 xfade = new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn);
416 add_crossfade (*xfade);
417 xfade = new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut);
418 add_crossfade (*xfade);
422 xfade = new Crossfade (other, region, Config->get_xfade_model(), Config->get_crossfades_active());
423 add_crossfade (*xfade);
428 catch (failed_constructor& err) {
432 catch (Crossfade::NoCrossfadeHere& err) {
440 AudioPlaylist::add_crossfade (Crossfade& xfade)
442 Crossfades::iterator ci;
444 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
445 if (*(*ci) == xfade) { // Crossfade::operator==()
450 if (ci != _crossfades.end()) {
453 _crossfades.push_back (&xfade);
455 xfade.Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
456 xfade.StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
458 notify_crossfade_added (&xfade);
462 void AudioPlaylist::notify_crossfade_added (Crossfade *x)
464 if (g_atomic_int_get(&block_notifications)) {
465 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
467 NewCrossfade (x); /* EMIT SIGNAL */
472 AudioPlaylist::crossfade_invalidated (Crossfade* xfade)
474 Crossfades::iterator i;
476 xfade->in()->resume_fade_in ();
477 xfade->out()->resume_fade_out ();
479 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
480 _crossfades.erase (i);
485 AudioPlaylist::set_state (const XMLNode& node)
489 XMLNodeConstIterator niter;
492 Playlist::set_state (node);
495 nlist = node.children();
497 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
501 if (child->name() != "Crossfade") {
508 xfade = new Crossfade (*((const Playlist *)this), *child);
511 catch (failed_constructor& err) {
512 // cout << string_compose (_("could not create crossfade object in playlist %1"),
518 Crossfades::iterator ci;
520 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
521 if (*(*ci) == *xfade) {
526 if (ci == _crossfades.end()) {
527 _crossfades.push_back (xfade);
528 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
529 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
533 /* adjust the current state of the existing crossfade */
535 (*ci)->set_state (*child);
537 /* drop the new one */
546 AudioPlaylist::clear ()
548 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
552 _crossfades.clear ();
558 AudioPlaylist::state (bool full_state)
560 XMLNode& node = Playlist::state (full_state);
563 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
564 node.add_child_nocopy ((*i)->get_state());
572 AudioPlaylist::dump () const
574 boost::shared_ptr<Region>r;
577 cerr << "Playlist \"" << _name << "\" " << endl
578 << regions.size() << " regions "
579 << _crossfades.size() << " crossfades"
582 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
584 cerr << " " << r->name() << " @ " << r << " ["
585 << r->start() << "+" << r->length()
593 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
604 << (x->active() ? "yes" : "no")
610 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
612 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
613 bool changed = false;
614 Crossfades::iterator c, ctmp;
615 set<Crossfade*> unique_xfades;
618 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
625 RegionLock rlock (this);
626 RegionList::iterator i;
627 RegionList::iterator tmp;
629 for (i = regions.begin(); i != regions.end(); ) {
634 if ((*i) == region) {
643 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
647 if ((*c)->involves (r)) {
648 unique_xfades.insert (*c);
649 _crossfades.erase (c);
655 for (set<Crossfade*>::iterator c = unique_xfades.begin(); c != unique_xfades.end(); ++c) {
660 /* overload this, it normally means "removed", not destroyed */
661 notify_region_removed (region);
668 AudioPlaylist::crossfade_changed (Change ignored)
670 if (in_flush || in_set_state) {
674 /* XXX is there a loop here? can an xfade change not happen
675 due to a playlist change? well, sure activation would
676 be an example. maybe we should check the type of change
684 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
686 if (in_flush || in_set_state) {
690 Change our_interests = Change (AudioRegion::FadeInChanged|
691 AudioRegion::FadeOutChanged|
692 AudioRegion::FadeInActiveChanged|
693 AudioRegion::FadeOutActiveChanged|
694 AudioRegion::EnvelopeActiveChanged|
695 AudioRegion::ScaleAmplitudeChanged|
696 AudioRegion::EnvelopeChanged);
697 bool parent_wants_notify;
699 parent_wants_notify = Playlist::region_changed (what_changed, region);
701 if ((parent_wants_notify || (what_changed & our_interests))) {
709 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
711 RegionLock rlock (this);
713 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
714 nframes_t start, end;
716 start = (*i)->position();
717 end = start + (*i)->overlap_length(); // not length(), important difference
719 if (frame >= start && frame <= end) {
720 clist.push_back (*i);