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(); ) {
125 Crossfades::iterator tmp;
136 struct RegionSortByLayer {
137 bool operator() (boost::shared_ptr<Region>a, boost::shared_ptr<Region>b) {
138 return a->layer() < b->layer();
143 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
144 nframes_t cnt, unsigned chan_n)
148 nframes_t read_frames;
149 nframes_t skip_frames;
151 /* optimizing this memset() away involves a lot of conditionals
152 that may well cause more of a hit due to cache misses
153 and related stuff than just doing this here.
155 it would be great if someone could measure this
158 one way or another, parts of the requested area
159 that are not written to by Region::region_at()
160 for all Regions that cover the area need to be
164 memset (buf, 0, sizeof (Sample) * cnt);
166 /* this function is never called from a realtime thread, so
167 its OK to block (for short intervals).
170 Glib::Mutex::Lock rm (region_lock);
172 end = start + cnt - 1;
176 _read_data_count = 0;
178 map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
179 map<uint32_t,vector<Crossfade*> > relevant_xfades;
180 vector<uint32_t> relevant_layers;
182 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
183 if ((*i)->coverage (start, end) != OverlapNone) {
184 relevant_regions[(*i)->layer()].push_back (*i);
185 relevant_layers.push_back ((*i)->layer());
189 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
190 if ((*i)->coverage (start, end) != OverlapNone) {
191 relevant_xfades[(*i)->upper_layer()].push_back (*i);
195 // RegionSortByLayer layer_cmp;
196 // relevant_regions.sort (layer_cmp);
198 /* XXX this whole per-layer approach is a hack that
199 should be removed once Crossfades become
200 CrossfadeRegions and we just grab a list of relevant
201 regions and call read_at() on all of them.
204 sort (relevant_layers.begin(), relevant_layers.end());
206 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
208 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
209 vector<Crossfade*>& x (relevant_xfades[*l]);
211 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
212 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
214 ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
215 _read_data_count += ar->read_data_count();
218 for (vector<Crossfade*>::iterator i = x.begin(); i != x.end(); ++i) {
219 (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
221 /* don't JACK up _read_data_count, since its the same data as we just
222 read from the regions, and the OS should handle that for us.
232 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
234 Crossfades::iterator i, tmp;
235 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
242 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
247 for (i = _crossfades.begin(); i != _crossfades.end(); ) {
252 if ((*i)->involves (r)) {
262 AudioPlaylist::flush_notifications ()
264 Playlist::flush_notifications();
272 Crossfades::iterator a;
273 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
274 NewCrossfade (*a); /* EMIT SIGNAL */
277 _pending_xfade_adds.clear ();
283 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
285 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
286 set<Crossfade*> updated;
292 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
294 Crossfades::iterator tmp;
299 /* only update them once */
301 if ((*x)->involves (ar)) {
303 if (find (updated.begin(), updated.end(), *x) == updated.end()) {
304 if ((*x)->refresh ()) {
305 /* not invalidated by the refresh */
316 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
318 boost::shared_ptr<AudioRegion> orig = boost::dynamic_pointer_cast<AudioRegion>(o);
319 boost::shared_ptr<AudioRegion> left = boost::dynamic_pointer_cast<AudioRegion>(l);
320 boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
322 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
323 Crossfades::iterator tmp;
329 if ((*x)->_in == orig) {
330 if (! (*x)->covers(right->position())) {
331 fade = new Crossfade (**x, left, (*x)->_out);
333 // Overlap, the crossfade is copied on the left side of the right region instead
334 fade = new Crossfade (**x, right, (*x)->_out);
338 if ((*x)->_out == orig) {
339 if (! (*x)->covers(right->position())) {
340 fade = new Crossfade (**x, (*x)->_in, right);
342 // Overlap, the crossfade is copied on the right side of the left region instead
343 fade = new Crossfade (**x, (*x)->_in, left);
348 _crossfades.remove (*x);
349 add_crossfade (*fade);
356 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
358 boost::shared_ptr<AudioRegion> other;
359 boost::shared_ptr<AudioRegion> region;
360 boost::shared_ptr<AudioRegion> top;
361 boost::shared_ptr<AudioRegion> bottom;
364 if (in_set_state || in_partition) {
368 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
369 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
375 refresh_dependents (r);
378 if (!Config->get_auto_xfade()) {
382 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
384 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
386 if (other == region) {
390 if (other->muted() || region->muted()) {
394 if (other->layer() < region->layer()) {
404 if (top->coverage (bottom->position(), bottom->last_frame()) != OverlapNone) {
406 /* check if the upper region is within the lower region */
408 if (top->first_frame() > bottom->first_frame() &&
409 top->last_frame() < bottom->last_frame()) {
412 /* [ -------- top ------- ]
413 * {=========== bottom =============}
416 /* to avoid discontinuities at the region boundaries of an internal
417 overlap (this region is completely within another), we create
418 two hidden crossfades at each boundary. this is not dependent
419 on the auto-xfade option, because we require it as basic
423 nframes_t xfade_length = min ((nframes_t) 720, top->length());
426 xfade = new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn);
427 add_crossfade (*xfade);
428 xfade = new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut);
429 add_crossfade (*xfade);
433 xfade = new Crossfade (other, region, Config->get_xfade_model(), Config->get_xfades_active());
434 add_crossfade (*xfade);
439 catch (failed_constructor& err) {
443 catch (Crossfade::NoCrossfadeHere& err) {
451 AudioPlaylist::add_crossfade (Crossfade& xfade)
453 Crossfades::iterator ci;
455 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
456 if (*(*ci) == xfade) { // Crossfade::operator==()
461 if (ci != _crossfades.end()) {
464 _crossfades.push_back (&xfade);
466 xfade.Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
467 xfade.StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
469 notify_crossfade_added (&xfade);
473 void AudioPlaylist::notify_crossfade_added (Crossfade *x)
475 if (g_atomic_int_get(&block_notifications)) {
476 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
478 NewCrossfade (x); /* EMIT SIGNAL */
483 AudioPlaylist::crossfade_invalidated (Crossfade* xfade)
485 Crossfades::iterator i;
487 xfade->in()->resume_fade_in ();
488 xfade->out()->resume_fade_out ();
490 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
491 _crossfades.erase (i);
496 AudioPlaylist::set_state (const XMLNode& node)
500 XMLNodeConstIterator niter;
505 Playlist::set_state (node);
507 nlist = node.children();
509 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
513 if (child->name() != "Crossfade") {
518 Crossfade* xfade = new Crossfade (*((const Playlist *)this), *child);
519 _crossfades.push_back (xfade);
520 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
521 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
525 catch (failed_constructor& err) {
526 // cout << string_compose (_("could not create crossfade object in playlist %1"),
540 AudioPlaylist::clear (bool with_signals)
542 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
544 Crossfades::iterator tmp;
553 _crossfades.clear ();
555 Playlist::clear (with_signals);
559 AudioPlaylist::state (bool full_state)
561 XMLNode& node = Playlist::state (full_state);
564 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
565 node.add_child_nocopy ((*i)->get_state());
573 AudioPlaylist::dump () const
575 boost::shared_ptr<Region>r;
578 cerr << "Playlist \"" << _name << "\" " << endl
579 << regions.size() << " regions "
580 << _crossfades.size() << " crossfades"
583 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
585 cerr << " " << r->name() << " @ " << r << " ["
586 << r->start() << "+" << r->length()
594 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
605 << (x->active() ? "yes" : "no")
611 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
613 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
614 bool changed = false;
615 Crossfades::iterator c, ctmp;
616 set<Crossfade*> unique_xfades;
619 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
626 RegionLock rlock (this);
627 RegionList::iterator i;
628 RegionList::iterator tmp;
630 for (i = regions.begin(); i != regions.end(); ) {
635 if ((*i) == region) {
644 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
648 if ((*c)->involves (r)) {
649 unique_xfades.insert (*c);
650 _crossfades.erase (c);
656 for (set<Crossfade*>::iterator c = unique_xfades.begin(); c != unique_xfades.end(); ++c) {
661 /* overload this, it normally means "removed", not destroyed */
662 notify_region_removed (region);
669 AudioPlaylist::crossfade_changed (Change ignored)
671 if (in_flush || in_set_state) {
675 /* XXX is there a loop here? can an xfade change not happen
676 due to a playlist change? well, sure activation would
677 be an example. maybe we should check the type of change
685 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
687 if (in_flush || in_set_state) {
691 Change our_interests = Change (AudioRegion::FadeInChanged|
692 AudioRegion::FadeOutChanged|
693 AudioRegion::FadeInActiveChanged|
694 AudioRegion::FadeOutActiveChanged|
695 AudioRegion::EnvelopeActiveChanged|
696 AudioRegion::ScaleAmplitudeChanged|
697 AudioRegion::EnvelopeChanged);
698 bool parent_wants_notify;
700 parent_wants_notify = Playlist::region_changed (what_changed, region);
702 if ((parent_wants_notify || (what_changed & our_interests))) {
710 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
712 RegionLock rlock (this);
714 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
715 nframes_t start, end;
717 start = (*i)->position();
718 end = start + (*i)->overlap_length(); // not length(), important difference
720 if (frame >= start && frame <= end) {
721 clist.push_back (*i);