+ RegionList here;
+ for (set<framepos_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
+
+ here.clear ();
+
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("++++ Considering %1\n", *t));
+
+ for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
+
+ if ((*x)->covers (*t)) {
+ here.push_back (*x);
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 covers %2\n",
+ (*x)->name(),
+ (*t)));
+ } else {
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 does NOT covers %2\n",
+ (*x)->name(),
+ (*t)));
+ }
+
+ }
+
+ RegionSortByLayer cmp;
+ here.sort (cmp);
+
+ /* ... and get the top/transparent regions at "here" */
+
+ for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
+
+ unique.insert (*c);
+
+ if ((*c)->opaque()) {
+
+ /* the other regions at this position are hidden by this one */
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("%1 is opaque, ignore all others\n",
+ (*c)->name()));
+ break;
+ }
+ }
+ }
+
+ for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
+ rlist->push_back (*s);
+ }
+
+ if (rlist->size() > 1) {
+ /* now sort by time order */
+
+ RegionSortByPosition cmp;
+ rlist->sort (cmp);
+ }
+ }
+
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("<<<<< REGIONS TO READ returns %1\n", rlist->size()));
+
+ return rlist;
+}
+
+Playlist::RegionList *
+Playlist::find_regions_at (framepos_t frame)
+{
+ /* Caller must hold lock */
+
+ RegionList *rlist = new RegionList;
+
+ for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+ if ((*i)->covers (frame)) {
+ rlist->push_back (*i);
+ }
+ }
+
+ return rlist;
+}
+
+Playlist::RegionList *
+Playlist::regions_touched (framepos_t start, framepos_t end)
+{
+ RegionLock rlock (this);
+ RegionList *rlist = new RegionList;
+
+ for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+ if ((*i)->coverage (start, end) != OverlapNone) {
+ rlist->push_back (*i);
+ }
+ }
+
+ return rlist;
+}
+
+framepos_t
+Playlist::find_next_transient (framepos_t from, int dir)
+{
+ RegionLock rlock (this);
+ AnalysisFeatureList points;
+ AnalysisFeatureList these_points;
+
+ for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+ if (dir > 0) {
+ if ((*i)->last_frame() < from) {
+ continue;
+ }
+ } else {
+ if ((*i)->first_frame() > from) {
+ continue;
+ }
+ }
+
+ (*i)->get_transients (these_points);
+
+ /* add first frame, just, err, because */
+
+ these_points.push_back ((*i)->first_frame());
+
+ points.insert (points.end(), these_points.begin(), these_points.end());
+ these_points.clear ();
+ }
+
+ if (points.empty()) {
+ return -1;
+ }
+
+ TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0);
+ bool reached = false;
+
+ if (dir > 0) {
+ for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) {
+ if ((*x) >= from) {
+ reached = true;
+ }
+
+ if (reached && (*x) > from) {
+ return *x;
+ }
+ }
+ } else {
+ for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) {
+ if ((*x) <= from) {
+ reached = true;
+ }
+
+ if (reached && (*x) < from) {
+ return *x;
+ }
+ }
+ }
+
+ return -1;
+}
+
+boost::shared_ptr<Region>
+Playlist::find_next_region (framepos_t frame, RegionPoint point, int dir)
+{
+ RegionLock rlock (this);
+ boost::shared_ptr<Region> ret;
+ framepos_t closest = max_frames;
+
+ bool end_iter = false;
+
+ for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+
+ if(end_iter) break;
+
+ frameoffset_t distance;
+ boost::shared_ptr<Region> r = (*i);
+ framepos_t pos = 0;
+
+ switch (point) {
+ case Start:
+ pos = r->first_frame ();
+ break;
+ case End:
+ pos = r->last_frame ();
+ break;
+ case SyncPoint:
+ pos = r->sync_position ();
+ // r->adjust_to_sync (r->first_frame());
+ break;
+ }
+
+ switch (dir) {
+ case 1: /* forwards */
+
+ if (pos > frame) {
+ if ((distance = pos - frame) < closest) {
+ closest = distance;
+ ret = r;
+ end_iter = true;
+ }
+ }
+
+ break;
+
+ default: /* backwards */
+
+ if (pos < frame) {
+ if ((distance = frame - pos) < closest) {
+ closest = distance;
+ ret = r;
+ }
+ }
+ else {
+ end_iter = true;
+ }
+
+ break;
+ }
+ }
+
+ return ret;
+}
+
+framepos_t
+Playlist::find_next_region_boundary (framepos_t frame, int dir)
+{
+ RegionLock rlock (this);
+
+ framepos_t closest = max_frames;
+ framepos_t ret = -1;
+
+ if (dir > 0) {
+
+ for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+
+ boost::shared_ptr<Region> r = (*i);
+ frameoffset_t distance;
+
+ if (r->first_frame() > frame) {
+
+ distance = r->first_frame() - frame;
+
+ if (distance < closest) {
+ ret = r->first_frame();
+ closest = distance;
+ }
+ }
+
+ if (r->last_frame () > frame) {
+
+ distance = r->last_frame () - frame;
+
+ if (distance < closest) {
+ ret = r->last_frame ();
+ closest = distance;
+ }
+ }
+ }
+
+ } else {
+
+ for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) {
+
+ boost::shared_ptr<Region> r = (*i);
+ frameoffset_t distance;
+
+ if (r->last_frame() < frame) {
+
+ distance = frame - r->last_frame();
+
+ if (distance < closest) {
+ ret = r->last_frame();
+ closest = distance;
+ }
+ }
+
+ if (r->first_frame() < frame) {
+
+ distance = frame - r->first_frame();
+
+ if (distance < closest) {
+ ret = r->first_frame();
+ closest = distance;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+/***********************************************************************/
+
+
+
+
+void
+Playlist::mark_session_dirty ()
+{
+ if (!in_set_state && !holding_state ()) {
+ _session.set_dirty();
+ }
+}
+
+bool
+Playlist::set_property (const PropertyBase& prop)
+{
+ if (prop == Properties::regions.property_id) {
+ const RegionListProperty::ChangeRecord& change (dynamic_cast<const RegionListProperty*>(&prop)->change());
+ regions.update (change);
+ return (!change.added.empty() && !change.removed.empty());
+ }
+ return false;
+}
+
+void
+Playlist::rdiff (vector<StatefulDiffCommand*>& cmds) const
+{
+ RegionLock rlock (const_cast<Playlist *> (this));
+
+ for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
+ if ((*i)->changed ()) {
+ StatefulDiffCommand* sdc = new StatefulDiffCommand (*i);
+ cmds.push_back (sdc);
+ }
+ }
+}
+
+void
+Playlist::clear_owned_history ()
+{
+ RegionLock rlock (this);
+
+ for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+ (*i)->clear_history ();
+ }
+}
+
+void
+Playlist::update (const RegionListProperty::ChangeRecord& change)
+{
+ DEBUG_TRACE (DEBUG::Properties, string_compose ("Playlist %1 updates from a change record with %2 adds %3 removes\n",
+ name(), change.added.size(), change.removed.size()));
+
+ freeze ();
+ /* add the added regions */
+ for (RegionListProperty::ChangeContainer::iterator i = change.added.begin(); i != change.added.end(); ++i) {
+ add_region ((*i), (*i)->position());
+ }
+ /* remove the removed regions */
+ for (RegionListProperty::ChangeContainer::iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
+ remove_region (*i);
+ }
+
+ thaw ();
+}
+
+PropertyList*
+Playlist::property_factory (const XMLNode& history_node) const
+{
+ const XMLNodeList& children (history_node.children());
+ PropertyList* prop_list = 0;
+
+ for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
+
+ if ((*i)->name() == capitalize (regions.property_name())) {
+
+ RegionListProperty* rlp = new RegionListProperty (*const_cast<Playlist*> (this));
+
+ if (rlp->load_history_state (**i)) {
+ if (!prop_list) {
+ prop_list = new PropertyList();
+ }
+ prop_list->add (rlp);
+ } else {
+ delete rlp;
+ }
+ }
+ }
+
+ return prop_list;
+}
+
+int
+Playlist::set_state (const XMLNode& node, int version)
+{
+ XMLNode *child;
+ XMLNodeList nlist;
+ XMLNodeConstIterator niter;