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::State::~State ()
46 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
47 : Playlist (session, node, DataType::AUDIO, hidden)
49 const XMLProperty* prop = node.property("type");
50 assert(!prop || DataType(prop->value()) == DataType::AUDIO);
56 save_state (_("initial state"));
59 PlaylistCreated (this); /* EMIT SIGNAL */
63 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
64 : Playlist (session, name, DataType::AUDIO, hidden)
66 save_state (_("initial state"));
69 PlaylistCreated (this); /* EMIT SIGNAL */
74 AudioPlaylist::AudioPlaylist (const AudioPlaylist& other, string name, bool hidden)
75 : Playlist (other, name, hidden)
77 save_state (_("initial state"));
79 RegionList::const_iterator in_o = other.regions.begin();
80 RegionList::iterator in_n = regions.begin();
82 while (in_o != other.regions.end()) {
83 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
85 // We look only for crossfades which begin with the current region, so we don't get doubles
86 for (list<Crossfade *>::const_iterator xfades = other._crossfades.begin(); xfades != other._crossfades.end(); ++xfades) {
87 if ((*xfades)->in() == ar) {
88 // We found one! Now copy it!
90 RegionList::const_iterator out_o = other.regions.begin();
91 RegionList::const_iterator out_n = regions.begin();
93 while (out_o != other.regions.end()) {
95 boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
97 if ((*xfades)->out() == ar2) {
98 boost::shared_ptr<AudioRegion>in = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
99 boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
100 Crossfade *new_fade = new Crossfade (*(*xfades), in, out);
101 add_crossfade(*new_fade);
108 // cerr << "HUH!? second region in the crossfade not found!" << endl;
117 PlaylistCreated (this); /* EMIT SIGNAL */
121 AudioPlaylist::AudioPlaylist (const AudioPlaylist& other, jack_nframes_t start, jack_nframes_t cnt, string name, bool hidden)
122 : Playlist (other, start, cnt, name, hidden)
124 save_state (_("initial state"));
126 /* this constructor does NOT notify others (session) */
129 AudioPlaylist::~AudioPlaylist ()
131 set<Crossfade*> all_xfades;
133 GoingAway (); /* EMIT SIGNAL */
135 /* drop connections to signals */
139 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end(); ++x) {
140 all_xfades.insert (*x);
143 for (StateMap::iterator i = states.begin(); i != states.end(); ++i) {
145 AudioPlaylist::State* apstate = dynamic_cast<AudioPlaylist::State*> (*i);
147 for (Crossfades::iterator xf = apstate->crossfades.begin(); xf != apstate->crossfades.end(); ++xf) {
148 all_xfades.insert (*xf);
154 /* delete every crossfade */
156 for (set<Crossfade *>::iterator axf = all_xfades.begin(); axf != all_xfades.end(); ++axf) {
161 struct RegionSortByLayer {
162 bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
163 return a->layer() < b->layer();
168 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, jack_nframes_t start,
169 jack_nframes_t cnt, unsigned chan_n)
171 jack_nframes_t ret = cnt;
173 jack_nframes_t read_frames;
174 jack_nframes_t skip_frames;
176 /* optimizing this memset() away involves a lot of conditionals
177 that may well cause more of a hit due to cache misses
178 and related stuff than just doing this here.
180 it would be great if someone could measure this
183 one way or another, parts of the requested area
184 that are not written to by Region::region_at()
185 for all Regions that cover the area need to be
189 memset (buf, 0, sizeof (Sample) * cnt);
191 /* this function is never called from a realtime thread, so
192 its OK to block (for short intervals).
195 Glib::Mutex::Lock rm (region_lock);
197 end = start + cnt - 1;
201 _read_data_count = 0;
203 map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
204 map<uint32_t,vector<Crossfade*> > relevant_xfades;
205 vector<uint32_t> relevant_layers;
207 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
208 if ((*i)->coverage (start, end) != OverlapNone) {
210 relevant_regions[(*i)->layer()].push_back (*i);
211 relevant_layers.push_back ((*i)->layer());
215 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
216 if ((*i)->coverage (start, end) != OverlapNone) {
217 relevant_xfades[(*i)->upper_layer()].push_back (*i);
221 // RegionSortByLayer layer_cmp;
222 // relevant_regions.sort (layer_cmp);
224 /* XXX this whole per-layer approach is a hack that
225 should be removed once Crossfades become
226 CrossfadeRegions and we just grab a list of relevant
227 regions and call read_at() on all of them.
230 sort (relevant_layers.begin(), relevant_layers.end());
232 for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
234 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
235 vector<Crossfade*>& x (relevant_xfades[*l]);
237 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
238 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
240 ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
241 _read_data_count += ar->read_data_count();
244 for (vector<Crossfade*>::iterator i = x.begin(); i != x.end(); ++i) {
245 (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
247 /* don't JACK up _read_data_count, since its the same data as we just
248 read from the regions, and the OS should handle that for us.
258 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
260 Crossfades::iterator i, tmp;
261 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
264 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
269 for (i = _crossfades.begin(); i != _crossfades.end(); ) {
273 if ((*i)->involves (r)) {
274 /* do not delete crossfades */
275 _crossfades.erase (i);
284 AudioPlaylist::flush_notifications ()
286 Playlist::flush_notifications();
294 Crossfades::iterator a;
295 for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
296 NewCrossfade (*a); /* EMIT SIGNAL */
299 _pending_xfade_adds.clear ();
305 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
307 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
308 set<Crossfade*> updated;
314 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
316 Crossfades::iterator tmp;
321 /* only update them once */
323 if ((*x)->involves (ar)) {
325 if (find (updated.begin(), updated.end(), *x) == updated.end()) {
326 if ((*x)->refresh ()) {
327 /* not invalidated by the refresh */
338 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
340 boost::shared_ptr<AudioRegion> orig = boost::dynamic_pointer_cast<AudioRegion>(o);
341 boost::shared_ptr<AudioRegion> left = boost::dynamic_pointer_cast<AudioRegion>(l);
342 boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
344 for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
345 Crossfades::iterator tmp;
351 if ((*x)->_in == orig) {
352 if (! (*x)->covers(right->position())) {
353 fade = new Crossfade (**x, left, (*x)->_out);
355 // Overlap, the crossfade is copied on the left side of the right region instead
356 fade = new Crossfade (**x, right, (*x)->_out);
360 if ((*x)->_out == orig) {
361 if (! (*x)->covers(right->position())) {
362 fade = new Crossfade (**x, (*x)->_in, right);
364 // Overlap, the crossfade is copied on the right side of the left region instead
365 fade = new Crossfade (**x, (*x)->_in, left);
370 _crossfades.remove (*x);
371 add_crossfade (*fade);
378 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
380 boost::shared_ptr<AudioRegion> other;
381 boost::shared_ptr<AudioRegion> region;
382 boost::shared_ptr<AudioRegion> top;
383 boost::shared_ptr<AudioRegion> bottom;
386 if (in_set_state || in_partition) {
390 if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
391 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
397 refresh_dependents (r);
400 if (!Config->get_auto_xfade()) {
404 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
406 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
408 if (other == region) {
412 if (other->muted() || region->muted()) {
416 if (other->layer() < region->layer()) {
426 if (top->coverage (bottom->position(), bottom->last_frame()) != OverlapNone) {
428 /* check if the upper region is within the lower region */
430 if (top->first_frame() > bottom->first_frame() &&
431 top->last_frame() < bottom->last_frame()) {
434 /* [ -------- top ------- ]
435 * {=========== bottom =============}
438 /* to avoid discontinuities at the region boundaries of an internal
439 overlap (this region is completely within another), we create
440 two hidden crossfades at each boundary. this is not dependent
441 on the auto-xfade option, because we require it as basic
445 jack_nframes_t xfade_length = min ((jack_nframes_t) 720, top->length());
448 xfade = new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn);
449 add_crossfade (*xfade);
450 xfade = new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut);
451 add_crossfade (*xfade);
455 xfade = new Crossfade (other, region, _session.get_xfade_model(), _session.get_crossfades_active());
456 add_crossfade (*xfade);
461 catch (failed_constructor& err) {
465 catch (Crossfade::NoCrossfadeHere& err) {
473 AudioPlaylist::add_crossfade (Crossfade& xfade)
475 Crossfades::iterator ci;
477 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
478 if (*(*ci) == xfade) { // Crossfade::operator==()
483 if (ci != _crossfades.end()) {
486 _crossfades.push_back (&xfade);
488 xfade.Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
489 xfade.StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
491 notify_crossfade_added (&xfade);
495 void AudioPlaylist::notify_crossfade_added (Crossfade *x)
497 if (g_atomic_int_get(&block_notifications)) {
498 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
500 NewCrossfade (x); /* EMIT SIGNAL */
505 AudioPlaylist::crossfade_invalidated (Crossfade* xfade)
507 Crossfades::iterator i;
509 xfade->in()->resume_fade_in ();
510 xfade->out()->resume_fade_out ();
512 if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
513 _crossfades.erase (i);
518 AudioPlaylist::set_state (const XMLNode& node)
522 XMLNodeConstIterator niter;
525 Playlist::set_state (node);
528 nlist = node.children();
530 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
534 if (child->name() == "Crossfade") {
539 xfade = new Crossfade (*((const Playlist *)this), *child);
542 catch (failed_constructor& err) {
543 // cout << string_compose (_("could not create crossfade object in playlist %1"),
549 Crossfades::iterator ci;
551 for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
552 if (*(*ci) == *xfade) {
557 if (ci == _crossfades.end()) {
558 _crossfades.push_back (xfade);
559 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
560 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
561 /* no need to notify here */
573 AudioPlaylist::drop_all_states ()
575 set<Crossfade*> all_xfades;
576 set<boost::shared_ptr<Region> > all_regions;
578 /* find every region we've ever used, and add it to the set of
579 all regions. same for xfades;
582 for (StateMap::iterator i = states.begin(); i != states.end(); ++i) {
584 AudioPlaylist::State* apstate = dynamic_cast<AudioPlaylist::State*> (*i);
586 for (RegionList::iterator r = apstate->regions.begin(); r != apstate->regions.end(); ++r) {
587 all_regions.insert (*r);
590 for (Crossfades::iterator xf = apstate->crossfades.begin(); xf != apstate->crossfades.end(); ++xf) {
591 all_xfades.insert (*xf);
595 /* now remove from the "all" lists every region that is in the current list. */
597 for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
598 set<boost::shared_ptr<Region> >::iterator x = all_regions.find (*i);
599 if (x != all_regions.end()) {
600 all_regions.erase (x);
604 /* ditto for every crossfade */
606 for (list<Crossfade*>::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
607 set<Crossfade*>::iterator x = all_xfades.find (*i);
608 if (x != all_xfades.end()) {
609 all_xfades.erase (x);
613 /* delete every crossfade that is left (ditto as per regions) */
615 for (set<Crossfade *>::iterator axf = all_xfades.begin(); axf != all_xfades.end(); ++axf) {
619 /* Now do the generic thing ... */
621 StateManager::drop_all_states ();
625 AudioPlaylist::state_factory (std::string why) const
627 State* state = new State (why);
629 state->regions = regions;
630 state->region_states.clear ();
631 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
632 state->region_states.push_back ((*i)->get_memento());
635 state->crossfades = _crossfades;
636 state->crossfade_states.clear ();
637 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
638 state->crossfade_states.push_back ((*i)->get_memento());
644 AudioPlaylist::restore_state (StateManager::State& state)
647 RegionLock rlock (this);
648 State* apstate = dynamic_cast<State*> (&state);
652 regions = apstate->regions;
654 for (list<UndoAction>::iterator s = apstate->region_states.begin(); s != apstate->region_states.end(); ++s) {
658 _crossfades = apstate->crossfades;
660 for (list<UndoAction>::iterator s = apstate->crossfade_states.begin(); s != apstate->crossfade_states.end(); ++s) {
664 in_set_state = false;
667 notify_length_changed ();
672 AudioPlaylist::get_memento () const
674 return sigc::bind (mem_fun (*(const_cast<AudioPlaylist*> (this)), &StateManager::use_state), _current_state_id);
678 AudioPlaylist::clear (bool with_save)
680 _crossfades.clear ();
682 Playlist::clear (with_save);
686 AudioPlaylist::state (bool full_state)
688 XMLNode& node = Playlist::state (full_state);
691 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
692 node.add_child_nocopy ((*i)->get_state());
700 AudioPlaylist::dump () const
702 boost::shared_ptr<Region>r;
705 cerr << "Playlist \"" << _name << "\" " << endl
706 << regions.size() << " regions "
707 << _crossfades.size() << " crossfades"
710 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
712 cerr << " " << r->name() << " @ " << r << " ["
713 << r->start() << "+" << r->length()
721 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
732 << (x->active() ? "yes" : "no")
738 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
740 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
741 bool changed = false;
742 Crossfades::iterator c, ctmp;
743 set<Crossfade*> unique_xfades;
746 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
753 RegionLock rlock (this);
754 RegionList::iterator i;
755 RegionList::iterator tmp;
757 for (i = regions.begin(); i != regions.end(); ) {
762 if ((*i) == region) {
771 for (c = _crossfades.begin(); c != _crossfades.end(); ) {
775 if ((*c)->involves (r)) {
776 unique_xfades.insert (*c);
777 _crossfades.erase (c);
783 for (StateMap::iterator s = states.begin(); s != states.end(); ) {
784 StateMap::iterator tmp;
789 State* astate = dynamic_cast<State*> (*s);
791 for (c = astate->crossfades.begin(); c != astate->crossfades.end(); ) {
796 if ((*c)->involves (r)) {
797 unique_xfades.insert (*c);
798 _crossfades.erase (c);
804 list<UndoAction>::iterator rsi, rsitmp;
805 RegionList::iterator ri, ritmp;
807 for (ri = astate->regions.begin(), rsi = astate->region_states.begin();
808 ri != astate->regions.end() && rsi != astate->region_states.end();) {
817 if (region == (*ri)) {
818 astate->regions.erase (ri);
819 astate->region_states.erase (rsi);
829 for (set<Crossfade*>::iterator c = unique_xfades.begin(); c != unique_xfades.end(); ++c) {
834 /* overload this, it normally means "removed", not destroyed */
835 notify_region_removed (region);
842 AudioPlaylist::crossfade_changed (Change ignored)
844 if (in_flush || in_set_state) {
848 /* XXX is there a loop here? can an xfade change not happen
849 due to a playlist change? well, sure activation would
850 be an example. maybe we should check the type of change
854 maybe_save_state (_("xfade change"));
860 AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
862 if (in_flush || in_set_state) {
866 Change our_interests = Change (AudioRegion::FadeInChanged|
867 AudioRegion::FadeOutChanged|
868 AudioRegion::FadeInActiveChanged|
869 AudioRegion::FadeOutActiveChanged|
870 AudioRegion::EnvelopeActiveChanged|
871 AudioRegion::ScaleAmplitudeChanged|
872 AudioRegion::EnvelopeChanged);
873 bool parent_wants_notify;
875 parent_wants_notify = Playlist::region_changed (what_changed, region);
877 maybe_save_state (_("region modified"));
879 if ((parent_wants_notify || (what_changed & our_interests))) {
887 AudioPlaylist::crossfades_at (jack_nframes_t frame, Crossfades& clist)
889 RegionLock rlock (this);
891 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
892 jack_nframes_t start, end;
894 start = (*i)->position();
895 end = start + (*i)->overlap_length(); // not length(), important difference
897 if (frame >= start && frame <= end) {
898 clist.push_back (*i);