X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Faudio_playlist.cc;h=19609da2a4c6df4f70fc236d930b4f20e9fa3c81;hb=41d8747e9d4bbf10f848d907b879ba2211c89b8e;hp=9c68c6111405ebb86ae6e3a3e55b76ea57c364af;hpb=a20f41ab39cc034740ccd564c1057d8737d763d5;p=ardour.git diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc index 9c68c61114..19609da2a4 100644 --- a/libs/ardour/audio_playlist.cc +++ b/libs/ardour/audio_playlist.cc @@ -20,7 +20,7 @@ #include -#include +#include #include @@ -37,19 +37,14 @@ using namespace ARDOUR; using namespace sigc; using namespace std; - -AudioPlaylist::State::~State () -{ -} +using namespace PBD; AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden) : Playlist (session, node, hidden) { - in_set_state = true; + in_set_state++; set_state (node); - in_set_state = false; - - save_state (_("initial state")); + in_set_state--; if (!hidden) { PlaylistCreated (this); /* EMIT SIGNAL */ @@ -59,8 +54,6 @@ AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden) : Playlist (session, name, hidden) { - save_state (_("initial state")); - if (!hidden) { PlaylistCreated (this); /* EMIT SIGNAL */ } @@ -70,82 +63,90 @@ AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden) AudioPlaylist::AudioPlaylist (const AudioPlaylist& other, string name, bool hidden) : Playlist (other, name, hidden) { - save_state (_("initial state")); + RegionList::const_iterator in_o = other.regions.begin(); + RegionList::iterator in_n = regions.begin(); + + 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) { + if ((*xfades)->in() == ar) { + // We found one! Now copy it! + + RegionList::const_iterator out_o = other.regions.begin(); + RegionList::const_iterator out_n = regions.begin(); + + 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); + break; + } + + out_o++; + out_n++; + } +// cerr << "HUH!? second region in the crossfade not found!" << endl; + } + } + + in_o++; + in_n++; + } if (!hidden) { PlaylistCreated (this); /* EMIT SIGNAL */ } } -AudioPlaylist::AudioPlaylist (const AudioPlaylist& other, jack_nframes_t start, jack_nframes_t cnt, string name, bool hidden) +AudioPlaylist::AudioPlaylist (const AudioPlaylist& 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; - set all_regions; - GoingAway (this); + GoingAway (); /* EMIT SIGNAL */ - /* find every region we've ever used, and add it to the set of - all regions. same for xfades; - */ - - for (RegionList::iterator x = regions.begin(); x != regions.end(); ++x) { - all_regions.insert (*x); - } + /* drop connections to signals */ - 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); + notify_callbacks (); - 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); - } - - delete apstate; - } - - /* delete every region */ + for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end(); ) { + Crossfades::iterator tmp; - for (set::iterator ar = all_regions.begin(); ar != all_regions.end(); ++ar) { - (*ar)->unlock_sources (); - delete *ar; - } + tmp = x; + ++tmp; - /* delete every crossfade */ + delete *x; - for (set::iterator axf = all_xfades.begin(); axf != all_xfades.end(); ++axf) { - delete *axf; + x = tmp; } } struct RegionSortByLayer { - bool operator() (Region *a, Region *b) { + bool operator() (boost::shared_ptra, boost::shared_ptrb) { return a->layer() < b->layer(); } }; -jack_nframes_t -AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, jack_nframes_t start, - jack_nframes_t cnt, unsigned chan_n) +nframes_t +AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start, + nframes_t cnt, unsigned chan_n) { - jack_nframes_t ret = cnt; - jack_nframes_t end; - jack_nframes_t read_frames; - jack_nframes_t skip_frames; + nframes_t ret = cnt; + nframes_t end; + nframes_t read_frames; + 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 @@ -166,7 +167,7 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, ja its OK to block (for short intervals). */ - LockMonitor rm (region_lock, __LINE__, __FILE__); + Glib::Mutex::Lock rm (region_lock); end = start + cnt - 1; @@ -174,13 +175,12 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, ja skip_frames = 0; _read_data_count = 0; - map > relevant_regions; + map > > relevant_regions; map > relevant_xfades; vector relevant_layers; for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { if ((*i)->coverage (start, end) != OverlapNone) { - relevant_regions[(*i)->layer()].push_back (*i); relevant_layers.push_back ((*i)->layer()); } @@ -205,16 +205,17 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, ja for (vector::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) { - vector& r (relevant_regions[*l]); + vector > r (relevant_regions[*l]); vector& x (relevant_xfades[*l]); - for (vector::iterator i = r.begin(); i != r.end(); ++i) { - (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames); - _read_data_count += (*i)->read_data_count(); + for (vector >::iterator i = r.begin(); i != r.end(); ++i) { + boost::shared_ptr ar = boost::dynamic_pointer_cast(*i); + 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) { - (*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 @@ -228,10 +229,14 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, ja void -AudioPlaylist::remove_dependents (Region& region) +AudioPlaylist::remove_dependents (boost::shared_ptr region) { Crossfades::iterator i, tmp; - AudioRegion* r = dynamic_cast (®ion); + 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") @@ -243,9 +248,9 @@ AudioPlaylist::remove_dependents (Region& region) tmp = i; tmp++; - if ((*i)->involves (*r)) { - /* do not delete crossfades */ - _crossfades.erase (i); + + if ((*i)->involves (r)) { + delete *i; } i = tmp; @@ -275,9 +280,9 @@ AudioPlaylist::flush_notifications () } void -AudioPlaylist::refresh_dependents (Region& r) +AudioPlaylist::refresh_dependents (boost::shared_ptr r) { - AudioRegion* ar = dynamic_cast(&r); + boost::shared_ptr ar = boost::dynamic_pointer_cast(r); set updated; if (ar == 0) { @@ -293,7 +298,7 @@ AudioPlaylist::refresh_dependents (Region& r) /* only update them once */ - if ((*x)->involves (*ar)) { + if ((*x)->involves (ar)) { if (find (updated.begin(), updated.end(), *x) == updated.end()) { if ((*x)->refresh ()) { @@ -308,19 +313,59 @@ AudioPlaylist::refresh_dependents (Region& r) } void -AudioPlaylist::check_dependents (Region& r, bool norefresh) +AudioPlaylist::finalize_split_region (boost::shared_ptr o, boost::shared_ptr l, boost::shared_ptr r) +{ + boost::shared_ptr orig = boost::dynamic_pointer_cast(o); + boost::shared_ptr left = boost::dynamic_pointer_cast(l); + boost::shared_ptr right = boost::dynamic_pointer_cast(r); + + for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) { + Crossfades::iterator tmp; + tmp = x; + ++tmp; + + Crossfade *fade = 0; + + if ((*x)->_in == orig) { + if (! (*x)->covers(right->position())) { + fade = 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); + } + } + + if ((*x)->_out == orig) { + if (! (*x)->covers(right->position())) { + fade = 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); + } + } + + if (fade) { + _crossfades.remove (*x); + add_crossfade (*fade); + } + x = tmp; + } +} + +void +AudioPlaylist::check_dependents (boost::shared_ptr r, bool norefresh) { - AudioRegion* other; - AudioRegion* region; - AudioRegion* top; - AudioRegion* bottom; + boost::shared_ptr other; + boost::shared_ptr region; + boost::shared_ptr top; + boost::shared_ptr bottom; Crossfade* xfade; if (in_set_state || in_partition) { return; } - if ((region = dynamic_cast (&r)) == 0) { + if ((region = boost::dynamic_pointer_cast (r)) == 0) { fatal << _("programming error: non-audio Region tested for overlap in audio playlist") << endmsg; return; @@ -336,7 +381,7 @@ AudioPlaylist::check_dependents (Region& r, bool norefresh) for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { - other = dynamic_cast (*i); + other = boost::dynamic_pointer_cast (*i); if (other == region) { continue; @@ -375,17 +420,17 @@ AudioPlaylist::check_dependents (Region& r, bool norefresh) audio engineering. */ - jack_nframes_t xfade_length = min ((jack_nframes_t) 720, top->length()); + nframes_t xfade_length = min ((nframes_t) 720, top->length()); /* in, out */ - xfade = new Crossfade (*top, *bottom, xfade_length, top->first_frame(), StartOfIn); + 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); + xfade = new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut); add_crossfade (*xfade); } else { - - xfade = new Crossfade (*other, *region, _session.get_xfade_model(), _session.get_crossfades_active()); + + xfade = new Crossfade (other, region, Config->get_xfade_model(), Config->get_xfades_active()); add_crossfade (*xfade); } } @@ -427,7 +472,7 @@ AudioPlaylist::add_crossfade (Crossfade& xfade) void AudioPlaylist::notify_crossfade_added (Crossfade *x) { - if (atomic_read(&block_notifications)) { + if (g_atomic_int_get(&block_notifications)) { _pending_xfade_adds.insert (_pending_xfade_adds.end(), x); } else { NewCrossfade (x); /* EMIT SIGNAL */ @@ -439,8 +484,8 @@ AudioPlaylist::crossfade_invalidated (Crossfade* xfade) { Crossfades::iterator i; - xfade->in().resume_fade_in (); - xfade->out().resume_fade_out (); + xfade->in()->resume_fade_in (); + xfade->out()->resume_fade_out (); if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) { _crossfades.erase (i); @@ -454,9 +499,10 @@ AudioPlaylist::set_state (const XMLNode& node) XMLNodeList nlist; XMLNodeConstIterator niter; - if (!in_set_state) { - Playlist::set_state (node); - } + in_set_state++; + freeze (); + + Playlist::set_state (node); nlist = node.children(); @@ -464,167 +510,49 @@ 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)); - /* no need to notify here */ - } 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); + if (child->name() != "Crossfade") { + continue; } - } - /* now remove from the "all" lists every region that is in the current list. */ - - for (list::iterator i = regions.begin(); i != regions.end(); ++i) { - set::iterator x = all_regions.find (*i); - if (x != all_regions.end()) { - all_regions.erase (x); + try { + Crossfade* xfade = new Crossfade (*((const Playlist *)this), *child); + _crossfades.push_back (xfade); + xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated)); + xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed)); + NewCrossfade(xfade); } - } - - /* 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); + + catch (failed_constructor& err) { + // cout << string_compose (_("could not create crossfade object in playlist %1"), + // _name) + // << endl; + continue; } } - /* delete every region that is left - these are all things that are part of our "history" */ - - for (set::iterator ar = all_regions.begin(); ar != all_regions.end(); ++ar) { - (*ar)->unlock_sources (); - delete *ar; - } - - /* 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 ... */ + thaw (); + in_set_state++; - StateManager::drop_all_states (); + return 0; } -StateManager::State* -AudioPlaylist::state_factory (std::string why) const +void +AudioPlaylist::clear (bool with_signals) { - 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()); - } + for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) { - 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) (); - } - - _crossfades = apstate->crossfades; - - for (list::iterator s = apstate->crossfade_states.begin(); s != apstate->crossfade_states.end(); ++s) { - (*s) (); - } - - in_set_state = false; - } + Crossfades::iterator tmp; + tmp = i; + ++tmp; - notify_length_changed (); - return Change (~0); -} + delete *i; -UndoAction -AudioPlaylist::get_memento () const -{ - return sigc::bind (mem_fun (*(const_cast (this)), &StateManager::use_state), _current_state_id); -} - -void -AudioPlaylist::clear (bool with_delete, bool with_save) -{ - if (with_delete) { - for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) { - delete *i; - } + i = tmp; } _crossfades.clear (); - Playlist::clear (with_delete, with_save); + Playlist::clear (with_signals); } XMLNode& @@ -644,7 +572,7 @@ AudioPlaylist::state (bool full_state) void AudioPlaylist::dump () const { - Region *r; + boost::shared_ptrr; Crossfade *x; cerr << "Playlist \"" << _name << "\" " << endl @@ -666,9 +594,9 @@ AudioPlaylist::dump () const for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) { x = *i; cerr << " xfade [" - << x->out().name() + << x->out()->name() << ',' - << x->in().name() + << x->in()->name() << " @ " << x->position() << " length = " @@ -680,9 +608,9 @@ AudioPlaylist::dump () const } bool -AudioPlaylist::destroy_region (Region* region) +AudioPlaylist::destroy_region (boost::shared_ptr region) { - AudioRegion* r = dynamic_cast (region); + boost::shared_ptr r = boost::dynamic_pointer_cast (region); bool changed = false; Crossfades::iterator c, ctmp; set unique_xfades; @@ -705,7 +633,6 @@ AudioPlaylist::destroy_region (Region* region) ++tmp; if ((*i) == region) { - (*i)->unlock_sources (); regions.erase (i); changed = true; } @@ -718,7 +645,7 @@ AudioPlaylist::destroy_region (Region* region) ctmp = c; ++ctmp; - if ((*c)->involves (*r)) { + if ((*c)->involves (r)) { unique_xfades.insert (*c); _crossfades.erase (c); } @@ -726,52 +653,6 @@ AudioPlaylist::destroy_region (Region* region) c = ctmp; } - for (StateMap::iterator s = states.begin(); s != states.end(); ) { - StateMap::iterator tmp; - - tmp = s; - ++tmp; - - State* astate = dynamic_cast (*s); - - for (c = astate->crossfades.begin(); c != astate->crossfades.end(); ) { - - ctmp = c; - ++ctmp; - - if ((*c)->involves (*r)) { - unique_xfades.insert (*c); - _crossfades.erase (c); - } - - c = ctmp; - } - - 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; - - if (region == (*ri)) { - astate->regions.erase (ri); - astate->region_states.erase (rsi); - } - - ri = ritmp; - rsi = rsitmp; - } - - s = tmp; - } - for (set::iterator c = unique_xfades.begin(); c != unique_xfades.end(); ++c) { delete *c; } @@ -787,7 +668,7 @@ AudioPlaylist::destroy_region (Region* region) void AudioPlaylist::crossfade_changed (Change ignored) { - if (in_flush) { + if (in_flush || in_set_state) { return; } @@ -797,38 +678,11 @@ AudioPlaylist::crossfade_changed (Change ignored) that occured. */ - maybe_save_state (_("xfade change")); notify_modified (); } -void -AudioPlaylist::get_equivalent_regions (const AudioRegion& other, vector& results) -{ - for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { - - AudioRegion* ar = dynamic_cast (*i); - - if (ar && ar->equivalent (other)) { - results.push_back (ar); - } - } -} - -void -AudioPlaylist::get_region_list_equivalent_regions (const AudioRegion& other, vector& results) -{ - for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { - - AudioRegion* ar = dynamic_cast (*i); - - if (ar && ar->region_list_equivalent (other)) { - results.push_back (ar); - } - } -} - bool -AudioPlaylist::region_changed (Change what_changed, Region* region) +AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr region) { if (in_flush || in_set_state) { return false; @@ -845,9 +699,7 @@ AudioPlaylist::region_changed (Change what_changed, Region* region) parent_wants_notify = Playlist::region_changed (what_changed, region); - maybe_save_state (_("region modified")); - - if (parent_wants_notify || (what_changed & our_interests)) { + if ((parent_wants_notify || (what_changed & our_interests))) { notify_modified (); } @@ -855,12 +707,12 @@ AudioPlaylist::region_changed (Change what_changed, Region* region) } void -AudioPlaylist::crossfades_at (jack_nframes_t frame, Crossfades& clist) +AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist) { RegionLock rlock (this); for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) { - jack_nframes_t start, end; + nframes_t start, end; start = (*i)->position(); end = start + (*i)->overlap_length(); // not length(), important difference @@ -870,3 +722,4 @@ AudioPlaylist::crossfades_at (jack_nframes_t frame, Crossfades& clist) } } } +