X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Faudio_playlist.cc;h=cb65164a9b03f2adb4be7032798227d72948e8fe;hb=f188ffffc18687c47d1d5a5c8b35bda4d7b75f5f;hp=7c4052d8ac9e6a0c3b4bab65df83231ff924aa15;hpb=fedf3d34f32264ac57c6a222b678dc90f2bb1a88;p=ardour.git diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc index 7c4052d8ac..cb65164a9b 100644 --- a/libs/ardour/audio_playlist.cc +++ b/libs/ardour/audio_playlist.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2003 Paul Davis + Copyright (C) 2003 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,93 +15,76 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ */ #include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include "ardour/types.h" +#include "ardour/debug.h" +#include "ardour/configuration.h" +#include "ardour/audioplaylist.h" +#include "ardour/audioregion.h" +#include "ardour/crossfade.h" +#include "ardour/crossfade_compare.h" +#include "ardour/session.h" +#include "pbd/enumwriter.h" #include "i18n.h" using namespace ARDOUR; -using namespace sigc; using namespace std; using namespace PBD; -AudioPlaylist::State::~State () -{ -} - AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden) : Playlist (session, node, DataType::AUDIO, hidden) { +#ifndef NDEBUG const XMLProperty* prop = node.property("type"); assert(!prop || DataType(prop->value()) == DataType::AUDIO); +#endif - in_set_state = true; - set_state (node); - in_set_state = false; - - save_state (_("initial state")); - - if (!hidden) { - PlaylistCreated (this); /* EMIT SIGNAL */ - } + in_set_state++; + set_state (node, Stateful::loading_state_version); + in_set_state--; } AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden) : Playlist (session, name, DataType::AUDIO, hidden) { - save_state (_("initial state")); - - if (!hidden) { - PlaylistCreated (this); /* EMIT SIGNAL */ - } - } -AudioPlaylist::AudioPlaylist (const AudioPlaylist& other, string name, bool hidden) +AudioPlaylist::AudioPlaylist (boost::shared_ptr other, string name, bool hidden) : Playlist (other, name, hidden) { - save_state (_("initial state")); - - RegionList::const_iterator in_o = other.regions.begin(); + RegionList::const_iterator in_o = other->regions.begin(); RegionList::iterator in_n = regions.begin(); - while (in_o != other.regions.end()) { + while (in_o != other->regions.end()) { boost::shared_ptr ar = boost::dynamic_pointer_cast(*in_o); // We look only for crossfades which begin with the current region, so we don't get doubles - for (list::const_iterator xfades = other._crossfades.begin(); xfades != other._crossfades.end(); ++xfades) { + for (Crossfades::const_iterator xfades = other->_crossfades.begin(); xfades != other->_crossfades.end(); ++xfades) { if ((*xfades)->in() == ar) { // We found one! Now copy it! - RegionList::const_iterator out_o = other.regions.begin(); + RegionList::const_iterator out_o = other->regions.begin(); RegionList::const_iterator out_n = regions.begin(); - while (out_o != other.regions.end()) { - + while (out_o != other->regions.end()) { + boost::shared_ptrar2 = boost::dynamic_pointer_cast(*out_o); - + if ((*xfades)->out() == ar2) { boost::shared_ptrin = boost::dynamic_pointer_cast(*in_n); boost::shared_ptrout = boost::dynamic_pointer_cast(*out_n); - Crossfade *new_fade = new Crossfade (*(*xfades), in, out); - add_crossfade(*new_fade); + boost::shared_ptr new_fade = boost::shared_ptr (new Crossfade (*xfades, in, out)); + add_crossfade(new_fade); break; } - + out_o++; out_n++; } @@ -112,50 +95,17 @@ AudioPlaylist::AudioPlaylist (const AudioPlaylist& other, string name, bool hidd in_o++; in_n++; } - - if (!hidden) { - PlaylistCreated (this); /* EMIT SIGNAL */ - } } -AudioPlaylist::AudioPlaylist (const AudioPlaylist& other, nframes_t start, nframes_t cnt, string name, bool hidden) +AudioPlaylist::AudioPlaylist (boost::shared_ptr other, nframes_t start, nframes_t cnt, string name, bool hidden) : Playlist (other, start, cnt, name, hidden) { - save_state (_("initial state")); - /* this constructor does NOT notify others (session) */ } AudioPlaylist::~AudioPlaylist () { - set all_xfades; - - GoingAway (); /* EMIT SIGNAL */ - - /* drop connections to signals */ - - notify_callbacks (); - - for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end(); ++x) { - all_xfades.insert (*x); - } - - for (StateMap::iterator i = states.begin(); i != states.end(); ++i) { - - AudioPlaylist::State* apstate = dynamic_cast (*i); - - for (Crossfades::iterator xf = apstate->crossfades.begin(); xf != apstate->crossfades.end(); ++xf) { - all_xfades.insert (*xf); - } - - delete apstate; - } - - /* delete every crossfade */ - - for (set::iterator axf = all_xfades.begin(); axf != all_xfades.end(); ++axf) { - delete *axf; - } + _crossfades.clear (); } struct RegionSortByLayer { @@ -174,9 +124,9 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nf nframes_t skip_frames; /* optimizing this memset() away involves a lot of conditionals - that may well cause more of a hit due to cache misses + that may well cause more of a hit due to cache misses and related stuff than just doing this here. - + it would be great if someone could measure this at some point. @@ -188,27 +138,35 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nf memset (buf, 0, sizeof (Sample) * cnt); - /* this function is never called from a realtime thread, so + /* this function is never called from a realtime thread, so its OK to block (for short intervals). */ - Glib::Mutex::Lock rm (region_lock); + Glib::RecMutex::Lock rm (region_lock); end = start + cnt - 1; - read_frames = 0; skip_frames = 0; _read_data_count = 0; + _read_data_count = 0; + + RegionList* rlist = regions_to_read (start, start+cnt); + + if (rlist->empty()) { + delete rlist; + return cnt; + } + map > > relevant_regions; - map > relevant_xfades; + map > > relevant_xfades; vector relevant_layers; - for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { + for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ++i) { if ((*i)->coverage (start, end) != OverlapNone) { relevant_regions[(*i)->layer()].push_back (*i); relevant_layers.push_back ((*i)->layer()); - } + } } for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) { @@ -231,16 +189,18 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nf for (vector::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) { vector > r (relevant_regions[*l]); - vector& x (relevant_xfades[*l]); + vector >& x (relevant_xfades[*l]); + for (vector >::iterator i = r.begin(); i != r.end(); ++i) { boost::shared_ptr ar = boost::dynamic_pointer_cast(*i); + DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("read from region %1\n", ar->name())); assert(ar); ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames); _read_data_count += ar->read_data_count(); } - - for (vector::iterator i = x.begin(); i != x.end(); ++i) { + + for (vector >::iterator i = x.begin(); i != x.end(); ++i) { (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n); /* don't JACK up _read_data_count, since its the same data as we just @@ -249,6 +209,7 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nf } } + delete rlist; return ret; } @@ -256,25 +217,25 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nf void AudioPlaylist::remove_dependents (boost::shared_ptr region) { - Crossfades::iterator i, tmp; boost::shared_ptr r = boost::dynamic_pointer_cast (region); - + + if (in_set_state) { + return; + } + if (r == 0) { fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist") << endmsg; return; } - for (i = _crossfades.begin(); i != _crossfades.end(); ) { - tmp = i; - tmp++; + for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) { if ((*i)->involves (r)) { - /* do not delete crossfades */ - _crossfades.erase (i); + i = _crossfades.erase (i); + } else { + ++i; } - - i = tmp; } } @@ -296,7 +257,7 @@ AudioPlaylist::flush_notifications () } _pending_xfade_adds.clear (); - + in_flush = false; } @@ -304,7 +265,7 @@ void AudioPlaylist::refresh_dependents (boost::shared_ptr r) { boost::shared_ptr ar = boost::dynamic_pointer_cast(r); - set updated; + set > updated; if (ar == 0) { return; @@ -313,7 +274,7 @@ AudioPlaylist::refresh_dependents (boost::shared_ptr r) for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) { Crossfades::iterator tmp; - + tmp = x; ++tmp; @@ -321,10 +282,16 @@ AudioPlaylist::refresh_dependents (boost::shared_ptr r) if ((*x)->involves (ar)) { - if (find (updated.begin(), updated.end(), *x) == updated.end()) { - if ((*x)->refresh ()) { - /* not invalidated by the refresh */ - updated.insert (*x); + pair >::iterator, bool> const u = updated.insert (*x); + + if (u.second) { + /* x was successfully inserted into the set, so it has not already been updated */ + try { + (*x)->refresh (); + } + + catch (Crossfade::NoCrossfadeHere& err) { + // relax, Invalidated during refresh } } } @@ -345,29 +312,29 @@ AudioPlaylist::finalize_split_region (boost::shared_ptr o, boost::shared tmp = x; ++tmp; - Crossfade *fade = 0; - + boost::shared_ptr fade; + if ((*x)->_in == orig) { if (! (*x)->covers(right->position())) { - fade = new Crossfade (**x, left, (*x)->_out); + fade = boost::shared_ptr (new Crossfade (*x, left, (*x)->_out)); } else { // Overlap, the crossfade is copied on the left side of the right region instead - fade = new Crossfade (**x, right, (*x)->_out); + fade = boost::shared_ptr (new Crossfade (*x, right, (*x)->_out)); } } - + if ((*x)->_out == orig) { if (! (*x)->covers(right->position())) { - fade = new Crossfade (**x, (*x)->_in, right); + fade = boost::shared_ptr (new Crossfade (*x, (*x)->_in, right)); } else { // Overlap, the crossfade is copied on the right side of the left region instead - fade = new Crossfade (**x, (*x)->_in, left); + fade = boost::shared_ptr (new Crossfade (*x, (*x)->_in, left)); } } - + if (fade) { _crossfades.remove (*x); - add_crossfade (*fade); + add_crossfade (fade); } x = tmp; } @@ -380,7 +347,8 @@ AudioPlaylist::check_dependents (boost::shared_ptr r, bool norefresh) boost::shared_ptr region; boost::shared_ptr top; boost::shared_ptr bottom; - Crossfade* xfade; + boost::shared_ptr xfade; + RegionList* touched_regions = 0; if (in_set_state || in_partition) { return; @@ -396,12 +364,12 @@ AudioPlaylist::check_dependents (boost::shared_ptr r, bool norefresh) refresh_dependents (r); } - if (!Config->get_auto_xfade()) { + + if (!_session.config.get_auto_xfade()) { return; } for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { - other = boost::dynamic_pointer_cast (*i); if (other == region) { @@ -412,6 +380,7 @@ AudioPlaylist::check_dependents (boost::shared_ptr r, bool norefresh) continue; } + if (other->layer() < region->layer()) { top = region; bottom = other; @@ -420,78 +389,152 @@ AudioPlaylist::check_dependents (boost::shared_ptr r, bool norefresh) bottom = region; } + if (!top->opaque()) { + continue; + } + + OverlapType c = top->coverage (bottom->position(), bottom->last_frame()); + + delete touched_regions; + touched_regions = 0; + try { - - if (top->coverage (bottom->position(), bottom->last_frame()) != OverlapNone) { - - /* check if the upper region is within the lower region */ - - if (top->first_frame() > bottom->first_frame() && - top->last_frame() < bottom->last_frame()) { - - - /* [ -------- top ------- ] - * {=========== bottom =============} - */ - - /* to avoid discontinuities at the region boundaries of an internal - overlap (this region is completely within another), we create - two hidden crossfades at each boundary. this is not dependent - on the auto-xfade option, because we require it as basic - audio engineering. + nframes_t xfade_length; + switch (c) { + case OverlapNone: + break; + + case OverlapInternal: + /* {=============== top =============} + * [ ----- bottom ------- ] + */ + break; + + case OverlapExternal: + + /* [ -------- top ------- ] + * {=========== bottom =============} + */ + + /* to avoid discontinuities at the region boundaries of an internal + overlap (this region is completely within another), we create + two hidden crossfades at each boundary. this is not dependent + on the auto-xfade option, because we require it as basic + audio engineering. + */ + + xfade_length = min ((framecnt_t) 720, top->length()); + + if (top_region_at (top->first_frame()) == top) { + + xfade = boost::shared_ptr (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn)); + add_crossfade (xfade); + } + + if (top_region_at (top->last_frame() - 1) == top) { + + /* + only add a fade out if there is no region on top of the end of 'top' (which + would cover it). */ - - nframes_t xfade_length = min ((nframes_t) 720, top->length()); - - /* in, out */ - xfade = new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn); - add_crossfade (*xfade); - xfade = new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut); - add_crossfade (*xfade); - + + xfade = boost::shared_ptr (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut)); + add_crossfade (xfade); + } + break; + case OverlapStart: + + /* { ==== top ============ } + * [---- bottom -------------------] + */ + + if (_session.config.get_xfade_model() == FullCrossfade) { + touched_regions = regions_touched (top->first_frame(), bottom->last_frame()); + if (touched_regions->size() <= 2) { + xfade = boost::shared_ptr (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active())); + add_crossfade (xfade); + } } else { - - xfade = new Crossfade (other, region, Config->get_xfade_model(), Config->get_crossfades_active()); - add_crossfade (*xfade); + + touched_regions = regions_touched (top->first_frame(), + top->first_frame() + min ((framecnt_t) _session.config.get_short_xfade_seconds() * _session.frame_rate(), + top->length())); + if (touched_regions->size() <= 2) { + xfade = boost::shared_ptr (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active())); + add_crossfade (xfade); + } } - } + break; + case OverlapEnd: + + + /* [---- top ------------------------] + * { ==== bottom ============ } + */ + + if (_session.config.get_xfade_model() == FullCrossfade) { + + touched_regions = regions_touched (bottom->first_frame(), top->last_frame()); + if (touched_regions->size() <= 2) { + xfade = boost::shared_ptr (new Crossfade (region, other, + _session.config.get_xfade_model(), _session.config.get_xfades_active())); + add_crossfade (xfade); + } + + } else { + touched_regions = regions_touched (bottom->first_frame(), + bottom->first_frame() + min ((framecnt_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(), + bottom->length())); + if (touched_regions->size() <= 2) { + xfade = boost::shared_ptr (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active())); + add_crossfade (xfade); + } + } + break; + default: + xfade = boost::shared_ptr (new Crossfade (region, other, + _session.config.get_xfade_model(), _session.config.get_xfades_active())); + add_crossfade (xfade); + } } - + catch (failed_constructor& err) { continue; } - + catch (Crossfade::NoCrossfadeHere& err) { continue; } - + } + + delete touched_regions; } void -AudioPlaylist::add_crossfade (Crossfade& xfade) +AudioPlaylist::add_crossfade (boost::shared_ptr xfade) { Crossfades::iterator ci; for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) { - if (*(*ci) == xfade) { // Crossfade::operator==() + if (*(*ci) == *xfade) { // Crossfade::operator==() break; } } - + if (ci != _crossfades.end()) { - delete &xfade; + // it will just go away } else { - _crossfades.push_back (&xfade); + _crossfades.push_back (xfade); - xfade.Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated)); - xfade.StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed)); + xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1)); + xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1)); - notify_crossfade_added (&xfade); + notify_crossfade_added (xfade); } } - -void AudioPlaylist::notify_crossfade_added (Crossfade *x) + +void AudioPlaylist::notify_crossfade_added (boost::shared_ptr x) { if (g_atomic_int_get(&block_notifications)) { _pending_xfade_adds.insert (_pending_xfade_adds.end(), x); @@ -501,9 +544,10 @@ void AudioPlaylist::notify_crossfade_added (Crossfade *x) } void -AudioPlaylist::crossfade_invalidated (Crossfade* xfade) +AudioPlaylist::crossfade_invalidated (boost::shared_ptr r) { Crossfades::iterator i; + boost::shared_ptr xfade = boost::dynamic_pointer_cast (r); xfade->in()->resume_fade_in (); xfade->out()->resume_fade_out (); @@ -514,15 +558,17 @@ AudioPlaylist::crossfade_invalidated (Crossfade* xfade) } int -AudioPlaylist::set_state (const XMLNode& node) +AudioPlaylist::set_state (const XMLNode& node, int version) { XMLNode *child; XMLNodeList nlist; XMLNodeConstIterator niter; - if (!in_set_state) { - Playlist::set_state (node); - } + in_set_state++; + + Playlist::set_state (node, version); + + freeze (); nlist = node.children(); @@ -530,155 +576,37 @@ AudioPlaylist::set_state (const XMLNode& node) child = *niter; - if (child->name() == "Crossfade") { - - Crossfade *xfade; - - try { - xfade = new Crossfade (*((const Playlist *)this), *child); - } - - catch (failed_constructor& err) { - // cout << string_compose (_("could not create crossfade object in playlist %1"), - // _name) - // << endl; - continue; - } - - Crossfades::iterator ci; - - for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) { - if (*(*ci) == *xfade) { - break; - } - } - - if (ci == _crossfades.end()) { - _crossfades.push_back (xfade); - xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated)); - xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed)); - NewCrossfade(xfade); - } else { - delete xfade; - } - } - - } - - return 0; -} - -void -AudioPlaylist::drop_all_states () -{ - set all_xfades; - set > all_regions; - - /* find every region we've ever used, and add it to the set of - all regions. same for xfades; - */ - - for (StateMap::iterator i = states.begin(); i != states.end(); ++i) { - - AudioPlaylist::State* apstate = dynamic_cast (*i); - - for (RegionList::iterator r = apstate->regions.begin(); r != apstate->regions.end(); ++r) { - all_regions.insert (*r); - } - - for (Crossfades::iterator xf = apstate->crossfades.begin(); xf != apstate->crossfades.end(); ++xf) { - all_xfades.insert (*xf); - } - } - - /* now remove from the "all" lists every region that is in the current list. */ - - for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { - set >::iterator x = all_regions.find (*i); - if (x != all_regions.end()) { - all_regions.erase (x); + if (child->name() != "Crossfade") { + continue; } - } - /* ditto for every crossfade */ - - for (list::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) { - set::iterator x = all_xfades.find (*i); - if (x != all_xfades.end()) { - all_xfades.erase (x); - } - } - - /* delete every crossfade that is left (ditto as per regions) */ - - for (set::iterator axf = all_xfades.begin(); axf != all_xfades.end(); ++axf) { - delete *axf; - } - - /* Now do the generic thing ... */ - - StateManager::drop_all_states (); -} - -StateManager::State* -AudioPlaylist::state_factory (std::string why) const -{ - State* state = new State (why); - - state->regions = regions; - state->region_states.clear (); - for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) { - state->region_states.push_back ((*i)->get_memento()); - } - - state->crossfades = _crossfades; - state->crossfade_states.clear (); - for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) { - state->crossfade_states.push_back ((*i)->get_memento()); - } - return state; -} - -Change -AudioPlaylist::restore_state (StateManager::State& state) -{ - { - RegionLock rlock (this); - State* apstate = dynamic_cast (&state); - - in_set_state = true; - - regions = apstate->regions; - - for (list::iterator s = apstate->region_states.begin(); s != apstate->region_states.end(); ++s) { - (*s) (); + try { + boost::shared_ptr xfade = boost::shared_ptr (new Crossfade (*((const Playlist *)this), *child)); + _crossfades.push_back (xfade); + xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1)); + xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1)); + NewCrossfade(xfade); } - _crossfades = apstate->crossfades; - - for (list::iterator s = apstate->crossfade_states.begin(); s != apstate->crossfade_states.end(); ++s) { - (*s) (); + catch (failed_constructor& err) { + // cout << string_compose (_("could not create crossfade object in playlist %1"), + // _name) + // << endl; + continue; } - - in_set_state = false; } - notify_length_changed (); - return Change (~0); -} + thaw (); + in_set_state--; -UndoAction -AudioPlaylist::get_memento () const -{ - return sigc::bind (mem_fun (*(const_cast (this)), &StateManager::use_state), _current_state_id); + return 0; } void -AudioPlaylist::clear (bool with_save) +AudioPlaylist::clear (bool with_signals) { _crossfades.clear (); - - Playlist::clear (with_save); + Playlist::clear (with_signals); } XMLNode& @@ -691,7 +619,7 @@ AudioPlaylist::state (bool full_state) node.add_child_nocopy ((*i)->get_state()); } } - + return node; } @@ -699,7 +627,7 @@ void AudioPlaylist::dump () const { boost::shared_ptrr; - Crossfade *x; + boost::shared_ptr x; cerr << "Playlist \"" << _name << "\" " << endl << regions.size() << " regions " @@ -708,9 +636,9 @@ AudioPlaylist::dump () const for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) { r = *i; - cerr << " " << r->name() << " @ " << r << " [" - << r->start() << "+" << r->length() - << "] at " + cerr << " " << r->name() << " @ " << r << " [" + << r->start() << "+" << r->length() + << "] at " << r->position() << " on layer " << r->layer () @@ -719,13 +647,13 @@ AudioPlaylist::dump () const for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) { x = *i; - cerr << " xfade [" + cerr << " xfade [" << x->out()->name() << ',' << x->in()->name() << " @ " << x->position() - << " length = " + << " length = " << x->length () << " active ? " << (x->active() ? "yes" : "no") @@ -737,96 +665,57 @@ bool AudioPlaylist::destroy_region (boost::shared_ptr region) { boost::shared_ptr r = boost::dynamic_pointer_cast (region); + + if (!r) { + return false; + } + bool changed = false; Crossfades::iterator c, ctmp; - set unique_xfades; - - if (r == 0) { - fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist") - << endmsg; - /*NOTREACHED*/ - return false; - } + set > unique_xfades; - { + { RegionLock rlock (this); - RegionList::iterator i; - RegionList::iterator tmp; - for (i = regions.begin(); i != regions.end(); ) { - - tmp = i; + for (RegionList::iterator i = regions.begin(); i != regions.end(); ) { + + RegionList::iterator tmp = i; ++tmp; - + if ((*i) == region) { regions.erase (i); changed = true; } - - i = tmp; - } - } - for (c = _crossfades.begin(); c != _crossfades.end(); ) { - ctmp = c; - ++ctmp; - - if ((*c)->involves (r)) { - unique_xfades.insert (*c); - _crossfades.erase (c); + i = tmp; } - - c = ctmp; - } - - for (StateMap::iterator s = states.begin(); s != states.end(); ) { - StateMap::iterator tmp; - tmp = s; - ++tmp; + for (set >::iterator x = all_regions.begin(); x != all_regions.end(); ) { - State* astate = dynamic_cast (*s); - - for (c = astate->crossfades.begin(); c != astate->crossfades.end(); ) { + set >::iterator xtmp = x; + ++xtmp; - ctmp = c; - ++ctmp; - - if ((*c)->involves (r)) { - unique_xfades.insert (*c); - _crossfades.erase (c); + if ((*x) == region) { + all_regions.erase (x); + changed = true; } - c = ctmp; + x = xtmp; } - list::iterator rsi, rsitmp; - RegionList::iterator ri, ritmp; - - for (ri = astate->regions.begin(), rsi = astate->region_states.begin(); - ri != astate->regions.end() && rsi != astate->region_states.end();) { - - - ritmp = ri; - ++ritmp; - - rsitmp = rsi; - ++rsitmp; + region->set_playlist (boost::shared_ptr()); + } - if (region == (*ri)) { - astate->regions.erase (ri); - astate->region_states.erase (rsi); - } + for (c = _crossfades.begin(); c != _crossfades.end(); ) { + ctmp = c; + ++ctmp; - ri = ritmp; - rsi = rsitmp; + if ((*c)->involves (r)) { + unique_xfades.insert (*c); + _crossfades.erase (c); } - - s = tmp; - } - for (set::iterator c = unique_xfades.begin(); c != unique_xfades.end(); ++c) { - delete *c; + c = ctmp; } if (changed) { @@ -838,7 +727,7 @@ AudioPlaylist::destroy_region (boost::shared_ptr region) } void -AudioPlaylist::crossfade_changed (Change ignored) +AudioPlaylist::crossfade_changed (const PropertyChange&) { if (in_flush || in_set_state) { return; @@ -850,36 +739,35 @@ AudioPlaylist::crossfade_changed (Change ignored) that occured. */ - maybe_save_state (_("xfade change")); - - notify_modified (); + notify_contents_changed (); } bool -AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr region) +AudioPlaylist::region_changed (const PropertyChange& what_changed, boost::shared_ptr region) { if (in_flush || in_set_state) { return false; } - Change our_interests = Change (AudioRegion::FadeInChanged| - AudioRegion::FadeOutChanged| - AudioRegion::FadeInActiveChanged| - AudioRegion::FadeOutActiveChanged| - AudioRegion::EnvelopeActiveChanged| - AudioRegion::ScaleAmplitudeChanged| - AudioRegion::EnvelopeChanged); + PropertyChange our_interests; + + our_interests.add (Properties::fade_in_active); + our_interests.add (Properties::fade_out_active); + our_interests.add (Properties::scale_amplitude); + our_interests.add (Properties::envelope_active); + our_interests.add (Properties::envelope); + our_interests.add (Properties::fade_in); + our_interests.add (Properties::fade_out); + bool parent_wants_notify; parent_wants_notify = Playlist::region_changed (what_changed, region); - maybe_save_state (_("region modified")); - - if ((parent_wants_notify || (what_changed & our_interests))) { - notify_modified (); + if (parent_wants_notify || (what_changed.contains (our_interests))) { + notify_contents_changed (); } - return true; + return true; } void @@ -895,7 +783,15 @@ AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist) if (frame >= start && frame <= end) { clist.push_back (*i); - } + } } } +void +AudioPlaylist::foreach_crossfade (boost::function)> s) +{ + RegionLock rl (this, false); + for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) { + s (*i); + } +}