fix up file renaming code a little bit
[ArdourMidi.git] / libs / ardour / audio_playlist.cc
blobcb65164a9b03f2adb4be7032798227d72948e8fe
1 /*
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.
20 #include <algorithm>
22 #include <cstdlib>
25 #include "ardour/types.h"
26 #include "ardour/debug.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"
35 #include "i18n.h"
37 using namespace ARDOUR;
38 using namespace std;
39 using namespace PBD;
41 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
42 : Playlist (session, node, DataType::AUDIO, hidden)
44 #ifndef NDEBUG
45 const XMLProperty* prop = node.property("type");
46 assert(!prop || DataType(prop->value()) == DataType::AUDIO);
47 #endif
49 in_set_state++;
50 set_state (node, Stateful::loading_state_version);
51 in_set_state--;
54 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
55 : Playlist (session, name, DataType::AUDIO, hidden)
59 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
60 : Playlist (other, name, hidden)
62 RegionList::const_iterator in_o = other->regions.begin();
63 RegionList::iterator in_n = regions.begin();
65 while (in_o != other->regions.end()) {
66 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
68 // We look only for crossfades which begin with the current region, so we don't get doubles
69 for (Crossfades::const_iterator xfades = other->_crossfades.begin(); xfades != other->_crossfades.end(); ++xfades) {
70 if ((*xfades)->in() == ar) {
71 // We found one! Now copy it!
73 RegionList::const_iterator out_o = other->regions.begin();
74 RegionList::const_iterator out_n = regions.begin();
76 while (out_o != other->regions.end()) {
78 boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
80 if ((*xfades)->out() == ar2) {
81 boost::shared_ptr<AudioRegion>in = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
82 boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
83 boost::shared_ptr<Crossfade> new_fade = boost::shared_ptr<Crossfade> (new Crossfade (*xfades, in, out));
84 add_crossfade(new_fade);
85 break;
88 out_o++;
89 out_n++;
91 // cerr << "HUH!? second region in the crossfade not found!" << endl;
95 in_o++;
96 in_n++;
100 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
101 : Playlist (other, start, cnt, name, hidden)
103 /* this constructor does NOT notify others (session) */
106 AudioPlaylist::~AudioPlaylist ()
108 _crossfades.clear ();
111 struct RegionSortByLayer {
112 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
113 return a->layer() < b->layer();
117 ARDOUR::nframes_t
118 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
119 nframes_t cnt, unsigned chan_n)
121 nframes_t ret = cnt;
122 nframes_t end;
123 nframes_t read_frames;
124 nframes_t skip_frames;
126 /* optimizing this memset() away involves a lot of conditionals
127 that may well cause more of a hit due to cache misses
128 and related stuff than just doing this here.
130 it would be great if someone could measure this
131 at some point.
133 one way or another, parts of the requested area
134 that are not written to by Region::region_at()
135 for all Regions that cover the area need to be
136 zeroed.
139 memset (buf, 0, sizeof (Sample) * cnt);
141 /* this function is never called from a realtime thread, so
142 its OK to block (for short intervals).
145 Glib::RecMutex::Lock rm (region_lock);
147 end = start + cnt - 1;
148 read_frames = 0;
149 skip_frames = 0;
150 _read_data_count = 0;
152 _read_data_count = 0;
154 RegionList* rlist = regions_to_read (start, start+cnt);
156 if (rlist->empty()) {
157 delete rlist;
158 return cnt;
161 map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
162 map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
163 vector<uint32_t> relevant_layers;
165 for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ++i) {
166 if ((*i)->coverage (start, end) != OverlapNone) {
167 relevant_regions[(*i)->layer()].push_back (*i);
168 relevant_layers.push_back ((*i)->layer());
172 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
173 if ((*i)->coverage (start, end) != OverlapNone) {
174 relevant_xfades[(*i)->upper_layer()].push_back (*i);
178 // RegionSortByLayer layer_cmp;
179 // relevant_regions.sort (layer_cmp);
181 /* XXX this whole per-layer approach is a hack that
182 should be removed once Crossfades become
183 CrossfadeRegions and we just grab a list of relevant
184 regions and call read_at() on all of them.
187 sort (relevant_layers.begin(), relevant_layers.end());
189 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
191 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
192 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
195 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
196 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
197 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("read from region %1\n", ar->name()));
198 assert(ar);
199 ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
200 _read_data_count += ar->read_data_count();
203 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
204 (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
206 /* don't JACK up _read_data_count, since its the same data as we just
207 read from the regions, and the OS should handle that for us.
212 delete rlist;
213 return ret;
217 void
218 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
220 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
222 if (in_set_state) {
223 return;
226 if (r == 0) {
227 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
228 << endmsg;
229 return;
232 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
234 if ((*i)->involves (r)) {
235 i = _crossfades.erase (i);
236 } else {
237 ++i;
243 void
244 AudioPlaylist::flush_notifications ()
246 Playlist::flush_notifications();
248 if (in_flush) {
249 return;
252 in_flush = true;
254 Crossfades::iterator a;
255 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
256 NewCrossfade (*a); /* EMIT SIGNAL */
259 _pending_xfade_adds.clear ();
261 in_flush = false;
264 void
265 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
267 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
268 set<boost::shared_ptr<Crossfade> > updated;
270 if (ar == 0) {
271 return;
274 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
276 Crossfades::iterator tmp;
278 tmp = x;
279 ++tmp;
281 /* only update them once */
283 if ((*x)->involves (ar)) {
285 pair<set<boost::shared_ptr<Crossfade> >::iterator, bool> const u = updated.insert (*x);
287 if (u.second) {
288 /* x was successfully inserted into the set, so it has not already been updated */
289 try {
290 (*x)->refresh ();
293 catch (Crossfade::NoCrossfadeHere& err) {
294 // relax, Invalidated during refresh
299 x = tmp;
303 void
304 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
306 boost::shared_ptr<AudioRegion> orig = boost::dynamic_pointer_cast<AudioRegion>(o);
307 boost::shared_ptr<AudioRegion> left = boost::dynamic_pointer_cast<AudioRegion>(l);
308 boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
310 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
311 Crossfades::iterator tmp;
312 tmp = x;
313 ++tmp;
315 boost::shared_ptr<Crossfade> fade;
317 if ((*x)->_in == orig) {
318 if (! (*x)->covers(right->position())) {
319 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, left, (*x)->_out));
320 } else {
321 // Overlap, the crossfade is copied on the left side of the right region instead
322 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, right, (*x)->_out));
326 if ((*x)->_out == orig) {
327 if (! (*x)->covers(right->position())) {
328 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, right));
329 } else {
330 // Overlap, the crossfade is copied on the right side of the left region instead
331 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, left));
335 if (fade) {
336 _crossfades.remove (*x);
337 add_crossfade (fade);
339 x = tmp;
343 void
344 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
346 boost::shared_ptr<AudioRegion> other;
347 boost::shared_ptr<AudioRegion> region;
348 boost::shared_ptr<AudioRegion> top;
349 boost::shared_ptr<AudioRegion> bottom;
350 boost::shared_ptr<Crossfade> xfade;
351 RegionList* touched_regions = 0;
353 if (in_set_state || in_partition) {
354 return;
357 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
358 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
359 << endmsg;
360 return;
363 if (!norefresh) {
364 refresh_dependents (r);
368 if (!_session.config.get_auto_xfade()) {
369 return;
372 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
373 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
375 if (other == region) {
376 continue;
379 if (other->muted() || region->muted()) {
380 continue;
384 if (other->layer() < region->layer()) {
385 top = region;
386 bottom = other;
387 } else {
388 top = other;
389 bottom = region;
392 if (!top->opaque()) {
393 continue;
396 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
398 delete touched_regions;
399 touched_regions = 0;
401 try {
402 nframes_t xfade_length;
403 switch (c) {
404 case OverlapNone:
405 break;
407 case OverlapInternal:
408 /* {=============== top =============}
409 * [ ----- bottom ------- ]
411 break;
413 case OverlapExternal:
415 /* [ -------- top ------- ]
416 * {=========== bottom =============}
419 /* to avoid discontinuities at the region boundaries of an internal
420 overlap (this region is completely within another), we create
421 two hidden crossfades at each boundary. this is not dependent
422 on the auto-xfade option, because we require it as basic
423 audio engineering.
426 xfade_length = min ((framecnt_t) 720, top->length());
428 if (top_region_at (top->first_frame()) == top) {
430 xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
431 add_crossfade (xfade);
434 if (top_region_at (top->last_frame() - 1) == top) {
437 only add a fade out if there is no region on top of the end of 'top' (which
438 would cover it).
441 xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
442 add_crossfade (xfade);
444 break;
445 case OverlapStart:
447 /* { ==== top ============ }
448 * [---- bottom -------------------]
451 if (_session.config.get_xfade_model() == FullCrossfade) {
452 touched_regions = regions_touched (top->first_frame(), bottom->last_frame());
453 if (touched_regions->size() <= 2) {
454 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
455 add_crossfade (xfade);
457 } else {
459 touched_regions = regions_touched (top->first_frame(),
460 top->first_frame() + min ((framecnt_t) _session.config.get_short_xfade_seconds() * _session.frame_rate(),
461 top->length()));
462 if (touched_regions->size() <= 2) {
463 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
464 add_crossfade (xfade);
467 break;
468 case OverlapEnd:
471 /* [---- top ------------------------]
472 * { ==== bottom ============ }
475 if (_session.config.get_xfade_model() == FullCrossfade) {
477 touched_regions = regions_touched (bottom->first_frame(), top->last_frame());
478 if (touched_regions->size() <= 2) {
479 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
480 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
481 add_crossfade (xfade);
484 } else {
485 touched_regions = regions_touched (bottom->first_frame(),
486 bottom->first_frame() + min ((framecnt_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
487 bottom->length()));
488 if (touched_regions->size() <= 2) {
489 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
490 add_crossfade (xfade);
493 break;
494 default:
495 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
496 _session.config.get_xfade_model(), _session.config.get_xfades_active()));
497 add_crossfade (xfade);
501 catch (failed_constructor& err) {
502 continue;
505 catch (Crossfade::NoCrossfadeHere& err) {
506 continue;
511 delete touched_regions;
514 void
515 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
517 Crossfades::iterator ci;
519 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
520 if (*(*ci) == *xfade) { // Crossfade::operator==()
521 break;
525 if (ci != _crossfades.end()) {
526 // it will just go away
527 } else {
528 _crossfades.push_back (xfade);
530 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
531 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
533 notify_crossfade_added (xfade);
537 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
539 if (g_atomic_int_get(&block_notifications)) {
540 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
541 } else {
542 NewCrossfade (x); /* EMIT SIGNAL */
546 void
547 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
549 Crossfades::iterator i;
550 boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
552 xfade->in()->resume_fade_in ();
553 xfade->out()->resume_fade_out ();
555 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
556 _crossfades.erase (i);
561 AudioPlaylist::set_state (const XMLNode& node, int version)
563 XMLNode *child;
564 XMLNodeList nlist;
565 XMLNodeConstIterator niter;
567 in_set_state++;
569 Playlist::set_state (node, version);
571 freeze ();
573 nlist = node.children();
575 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
577 child = *niter;
579 if (child->name() != "Crossfade") {
580 continue;
583 try {
584 boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
585 _crossfades.push_back (xfade);
586 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
587 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
588 NewCrossfade(xfade);
591 catch (failed_constructor& err) {
592 // cout << string_compose (_("could not create crossfade object in playlist %1"),
593 // _name)
594 // << endl;
595 continue;
599 thaw ();
600 in_set_state--;
602 return 0;
605 void
606 AudioPlaylist::clear (bool with_signals)
608 _crossfades.clear ();
609 Playlist::clear (with_signals);
612 XMLNode&
613 AudioPlaylist::state (bool full_state)
615 XMLNode& node = Playlist::state (full_state);
617 if (full_state) {
618 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
619 node.add_child_nocopy ((*i)->get_state());
623 return node;
626 void
627 AudioPlaylist::dump () const
629 boost::shared_ptr<Region>r;
630 boost::shared_ptr<Crossfade> x;
632 cerr << "Playlist \"" << _name << "\" " << endl
633 << regions.size() << " regions "
634 << _crossfades.size() << " crossfades"
635 << endl;
637 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
638 r = *i;
639 cerr << " " << r->name() << " @ " << r << " ["
640 << r->start() << "+" << r->length()
641 << "] at "
642 << r->position()
643 << " on layer "
644 << r->layer ()
645 << endl;
648 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
649 x = *i;
650 cerr << " xfade ["
651 << x->out()->name()
652 << ','
653 << x->in()->name()
654 << " @ "
655 << x->position()
656 << " length = "
657 << x->length ()
658 << " active ? "
659 << (x->active() ? "yes" : "no")
660 << endl;
664 bool
665 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
667 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
669 if (!r) {
670 return false;
673 bool changed = false;
674 Crossfades::iterator c, ctmp;
675 set<boost::shared_ptr<Crossfade> > unique_xfades;
678 RegionLock rlock (this);
680 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
682 RegionList::iterator tmp = i;
683 ++tmp;
685 if ((*i) == region) {
686 regions.erase (i);
687 changed = true;
690 i = tmp;
693 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
695 set<boost::shared_ptr<Region> >::iterator xtmp = x;
696 ++xtmp;
698 if ((*x) == region) {
699 all_regions.erase (x);
700 changed = true;
703 x = xtmp;
706 region->set_playlist (boost::shared_ptr<Playlist>());
709 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
710 ctmp = c;
711 ++ctmp;
713 if ((*c)->involves (r)) {
714 unique_xfades.insert (*c);
715 _crossfades.erase (c);
718 c = ctmp;
721 if (changed) {
722 /* overload this, it normally means "removed", not destroyed */
723 notify_region_removed (region);
726 return changed;
729 void
730 AudioPlaylist::crossfade_changed (const PropertyChange&)
732 if (in_flush || in_set_state) {
733 return;
736 /* XXX is there a loop here? can an xfade change not happen
737 due to a playlist change? well, sure activation would
738 be an example. maybe we should check the type of change
739 that occured.
742 notify_contents_changed ();
745 bool
746 AudioPlaylist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
748 if (in_flush || in_set_state) {
749 return false;
752 PropertyChange our_interests;
754 our_interests.add (Properties::fade_in_active);
755 our_interests.add (Properties::fade_out_active);
756 our_interests.add (Properties::scale_amplitude);
757 our_interests.add (Properties::envelope_active);
758 our_interests.add (Properties::envelope);
759 our_interests.add (Properties::fade_in);
760 our_interests.add (Properties::fade_out);
762 bool parent_wants_notify;
764 parent_wants_notify = Playlist::region_changed (what_changed, region);
766 if (parent_wants_notify || (what_changed.contains (our_interests))) {
767 notify_contents_changed ();
770 return true;
773 void
774 AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
776 RegionLock rlock (this);
778 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
779 nframes_t start, end;
781 start = (*i)->position();
782 end = start + (*i)->overlap_length(); // not length(), important difference
784 if (frame >= start && frame <= end) {
785 clist.push_back (*i);
790 void
791 AudioPlaylist::foreach_crossfade (boost::function<void (boost::shared_ptr<Crossfade>)> s)
793 RegionLock rl (this, false);
794 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
795 s (*i);