2 Copyright (C) 2000 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.
22 #include <cstdio> /* for sprintf */
28 #include "pbd/convert.h"
29 #include "pbd/stl_delete.h"
30 #include "pbd/xml++.h"
31 #include "pbd/enumwriter.h"
33 #include "ardour/location.h"
34 #include "ardour/midi_scene_change.h"
35 #include "ardour/session.h"
36 #include "ardour/audiofilesource.h"
37 #include "ardour/tempo.h"
42 using namespace ARDOUR;
45 PBD::Signal0<void> Location::scene_changed;
46 PBD::Signal1<void,Location*> Location::name_changed;
47 PBD::Signal1<void,Location*> Location::end_changed;
48 PBD::Signal1<void,Location*> Location::start_changed;
49 PBD::Signal1<void,Location*> Location::flags_changed;
50 PBD::Signal1<void,Location*> Location::lock_changed;
51 PBD::Signal1<void,Location*> Location::position_lock_style_changed;
52 PBD::Signal1<void,Location*> Location::changed;
54 Location::Location (Session& s)
55 : SessionHandleRef (s)
60 , _position_lock_style (AudioTime)
66 /** Construct a new Location, giving it the position lock style determined by glue-new-markers-to-bars-and-beats */
67 Location::Location (Session& s, framepos_t sample_start, framepos_t sample_end, const std::string &name, Flags bits)
68 : SessionHandleRef (s)
70 , _start (sample_start)
74 , _position_lock_style (s.config.get_glue_new_markers_to_bars_and_beats() ? MusicTime : AudioTime)
77 recompute_bbt_from_frames ();
83 Location::Location (const Location& other)
84 : SessionHandleRef (other._session)
85 , StatefulDestructible()
87 , _start (other._start)
88 , _bbt_start (other._bbt_start)
90 , _bbt_end (other._bbt_end)
91 , _flags (other._flags)
92 , _position_lock_style (other._position_lock_style)
95 /* copy is not locked even if original was */
102 /* scene change is NOT COPIED */
105 Location::Location (Session& s, const XMLNode& node)
106 : SessionHandleRef (s)
107 , _position_lock_style (AudioTime)
109 /* Note: _position_lock_style is initialised above in case set_state doesn't set it
110 (for 2.X session file compatibility).
113 if (set_state (node, Stateful::loading_state_version)) {
114 throw failed_constructor ();
117 assert (_start >= 0);
122 Location::operator== (const Location& other)
124 if (_name != other._name ||
125 _start != other._start ||
126 _end != other._end ||
127 _bbt_start != other._bbt_start ||
128 _bbt_end != other._bbt_end ||
129 _flags != other._flags ||
130 _position_lock_style != other._position_lock_style) {
137 Location::operator= (const Location& other)
139 if (this == &other) {
144 _start = other._start;
145 _bbt_start = other._bbt_start;
147 _bbt_end = other._bbt_end;
148 _flags = other._flags;
149 _position_lock_style = other._position_lock_style;
151 /* XXX need to copy scene change */
153 /* copy is not locked even if original was */
157 /* "changed" not emitted on purpose */
159 assert (_start >= 0);
165 /** Set location name
169 Location::set_name (const std::string& str)
173 name_changed (this); /* EMIT SIGNAL */
174 NameChanged (); /* EMIT SIGNAL */
177 /** Set start position.
178 * @param s New start.
179 * @param force true to force setting, even if the given new start is after the current end.
180 * @param allow_bbt_recompute True to recompute BBT start time from the new given start time.
183 Location::set_start (framepos_t s, bool force, bool allow_bbt_recompute)
194 if (((is_auto_punch() || is_auto_loop()) && s >= _end) || (!is_mark() && s > _end)) {
203 if (allow_bbt_recompute) {
204 recompute_bbt_from_frames ();
207 start_changed (this); /* EMIT SIGNAL */
208 StartChanged (); /* EMIT SIGNAL */
209 end_changed (this); /* EMIT SIGNAL */
210 EndChanged (); /* EMIT SIGNAL */
213 /* moving the start (position) of a marker with a scene change
214 requires an update in the Scene Changer.
218 scene_changed (); /* EMIT SIGNAL */
221 assert (_start >= 0);
226 /* range locations must exceed a minimum duration */
227 if (_end - s < Config->get_range_location_minimum()) {
234 framepos_t const old = _start;
237 if (allow_bbt_recompute) {
238 recompute_bbt_from_frames ();
240 start_changed (this); /* EMIT SIGNAL */
241 StartChanged (); /* EMIT SIGNAL */
243 if (is_session_range ()) {
244 Session::StartTimeChanged (old); /* EMIT SIGNAL */
245 AudioFileSource::set_header_position_offset (s);
249 assert (_start >= 0);
254 /** Set end position.
256 * @param force true to force setting, even if the given new end is before the current start.
257 * @param allow_bbt_recompute True to recompute BBT end time from the new given end time.
260 Location::set_end (framepos_t e, bool force, bool allow_bbt_recompute)
271 if (((is_auto_punch() || is_auto_loop()) && e <= _start) || e < _start) {
280 if (allow_bbt_recompute) {
281 recompute_bbt_from_frames ();
283 start_changed (this); /* EMIT SIGNAL */
284 StartChanged (); /* EMIT SIGNAL */
285 end_changed (this); /* EMIT SIGNAL */
286 EndChanged (); /* EMIT SIGNAL */
289 assert (_start >= 0);
294 /* range locations must exceed a minimum duration */
295 if (e - _start < Config->get_range_location_minimum()) {
302 framepos_t const old = _end;
305 if (allow_bbt_recompute) {
306 recompute_bbt_from_frames ();
309 end_changed(this); /* EMIT SIGNAL */
310 EndChanged(); /* EMIT SIGNAL */
312 if (is_session_range()) {
313 Session::EndTimeChanged (old); /* EMIT SIGNAL */
323 Location::set (framepos_t s, framepos_t e, bool allow_bbt_recompute)
325 if (s < 0 || e < 0) {
330 if (((is_auto_punch() || is_auto_loop()) && s >= e) || (!is_mark() && s > e)) {
334 bool start_change = false;
335 bool end_change = false;
343 if (allow_bbt_recompute) {
344 recompute_bbt_from_frames ();
351 assert (_start >= 0);
356 /* range locations must exceed a minimum duration */
357 if (e - s < Config->get_range_location_minimum()) {
363 framepos_t const old = _start;
366 if (allow_bbt_recompute) {
367 recompute_bbt_from_frames ();
372 if (is_session_range ()) {
373 Session::StartTimeChanged (old); /* EMIT SIGNAL */
374 AudioFileSource::set_header_position_offset (s);
381 framepos_t const old = _end;
384 if (allow_bbt_recompute) {
385 recompute_bbt_from_frames ();
390 if (is_session_range()) {
391 Session::EndTimeChanged (old); /* EMIT SIGNAL */
399 start_changed(this); /* EMIT SIGNAL */
400 StartChanged(); /* EMIT SIGNAL */
404 end_changed(this); /* EMIT SIGNAL */
405 EndChanged(); /* EMIT SIGNAL */
408 if (start_change && end_change) {
417 Location::move_to (framepos_t pos)
429 _end = _start + length();
430 recompute_bbt_from_frames ();
432 changed (this); /* EMIT SIGNAL */
433 Changed (); /* EMIT SIGNAL */
436 assert (_start >= 0);
443 Location::set_hidden (bool yn, void*)
445 if (set_flag_internal (yn, IsHidden)) {
446 flags_changed (this); /* EMIT SIGNAL */
452 Location::set_cd (bool yn, void*)
454 // XXX this really needs to be session start
455 // but its not available here - leave to GUI
457 if (yn && _start == 0) {
458 error << _("You cannot put a CD marker at this position") << endmsg;
462 if (set_flag_internal (yn, IsCDMarker)) {
463 flags_changed (this); /* EMIT SIGNAL */
469 Location::set_is_range_marker (bool yn, void*)
471 if (set_flag_internal (yn, IsRangeMarker)) {
472 flags_changed (this);
473 FlagsChanged (); /* EMIT SIGNAL */
478 Location::set_skip (bool yn)
480 if (is_range_marker() && length() > 0) {
481 if (set_flag_internal (yn, IsSkip)) {
482 flags_changed (this);
489 Location::set_skipping (bool yn)
491 if (is_range_marker() && is_skip() && length() > 0) {
492 if (set_flag_internal (yn, IsSkipping)) {
493 flags_changed (this);
500 Location::set_auto_punch (bool yn, void*)
502 if (is_mark() || _start == _end) {
506 if (set_flag_internal (yn, IsAutoPunch)) {
507 flags_changed (this); /* EMIT SIGNAL */
508 FlagsChanged (); /* EMIT SIGNAL */
513 Location::set_auto_loop (bool yn, void*)
515 if (is_mark() || _start == _end) {
519 if (set_flag_internal (yn, IsAutoLoop)) {
520 flags_changed (this); /* EMIT SIGNAL */
521 FlagsChanged (); /* EMIT SIGNAL */
526 Location::set_flag_internal (bool yn, Flags flag)
529 if (!(_flags & flag)) {
530 _flags = Flags (_flags | flag);
535 _flags = Flags (_flags & ~flag);
543 Location::set_mark (bool yn)
545 /* This function is private, and so does not emit signals */
547 if (_start != _end) {
551 set_flag_internal (yn, IsMark);
556 Location::cd_info_node(const string & name, const string & value)
558 XMLNode* root = new XMLNode("CD-Info");
560 root->add_property("name", name);
561 root->add_property("value", value);
568 Location::get_state ()
570 XMLNode *node = new XMLNode ("Location");
573 typedef map<string, string>::const_iterator CI;
575 for(CI m = cd_info.begin(); m != cd_info.end(); ++m){
576 node->add_child_nocopy(cd_info_node(m->first, m->second));
579 id().print (buf, sizeof (buf));
580 node->add_property("id", buf);
581 node->add_property ("name", name());
582 snprintf (buf, sizeof (buf), "%" PRId64, start());
583 node->add_property ("start", buf);
584 snprintf (buf, sizeof (buf), "%" PRId64, end());
585 node->add_property ("end", buf);
586 node->add_property ("flags", enum_2_string (_flags));
587 node->add_property ("locked", (_locked ? "yes" : "no"));
588 node->add_property ("position-lock-style", enum_2_string (_position_lock_style));
591 node->add_child_nocopy (_scene_change->get_state());
598 Location::set_state (const XMLNode& node, int version)
600 const XMLProperty *prop;
602 XMLNodeList cd_list = node.children();
603 XMLNodeConstIterator cd_iter;
609 if (node.name() != "Location") {
610 error << _("incorrect XML node passed to Location::set_state") << endmsg;
614 if (!set_id (node)) {
615 warning << _("XML node for Location has no ID information") << endmsg;
618 if ((prop = node.property ("name")) == 0) {
619 error << _("XML node for Location has no name information") << endmsg;
623 set_name (prop->value());
625 if ((prop = node.property ("start")) == 0) {
626 error << _("XML node for Location has no start information") << endmsg;
630 /* can't use set_start() here, because _end
631 may make the value of _start illegal.
634 sscanf (prop->value().c_str(), "%" PRId64, &_start);
636 if ((prop = node.property ("end")) == 0) {
637 error << _("XML node for Location has no end information") << endmsg;
641 sscanf (prop->value().c_str(), "%" PRId64, &_end);
643 if ((prop = node.property ("flags")) == 0) {
644 error << _("XML node for Location has no flags information") << endmsg;
648 Flags old_flags (_flags);
649 _flags = Flags (string_2_enum (prop->value(), _flags));
651 if (old_flags != _flags) {
655 if ((prop = node.property ("locked")) != 0) {
656 _locked = string_is_affirmative (prop->value());
661 for (cd_iter = cd_list.begin(); cd_iter != cd_list.end(); ++cd_iter) {
665 if (cd_node->name() != "CD-Info") {
669 if ((prop = cd_node->property ("name")) != 0) {
670 cd_name = prop->value();
672 throw failed_constructor ();
675 if ((prop = cd_node->property ("value")) != 0) {
676 cd_value = prop->value();
678 throw failed_constructor ();
682 cd_info[cd_name] = cd_value;
685 if ((prop = node.property ("position-lock-style")) != 0) {
686 _position_lock_style = PositionLockStyle (string_2_enum (prop->value(), _position_lock_style));
689 XMLNode* scene_child = find_named_node (node, SceneChange::xml_node_name);
692 _scene_change = SceneChange::factory (*scene_child, version);
695 recompute_bbt_from_frames ();
697 changed (this); /* EMIT SIGNAL */
698 Changed (); /* EMIT SIGNAL */
700 assert (_start >= 0);
707 Location::set_position_lock_style (PositionLockStyle ps)
709 if (_position_lock_style == ps) {
713 _position_lock_style = ps;
715 recompute_bbt_from_frames ();
717 position_lock_style_changed (this); /* EMIT SIGNAL */
718 PositionLockStyleChanged (); /* EMIT SIGNAL */
722 Location::recompute_bbt_from_frames ()
724 if (_position_lock_style != MusicTime) {
728 _session.bbt_time (_start, _bbt_start);
729 _session.bbt_time (_end, _bbt_end);
733 Location::recompute_frames_from_bbt ()
735 if (_position_lock_style != MusicTime) {
739 TempoMap& map (_session.tempo_map());
740 set (map.frame_time (_bbt_start), map.frame_time (_bbt_end), false);
760 Location::set_scene_change (boost::shared_ptr<SceneChange> sc)
762 if (_scene_change != sc) {
764 _session.set_dirty ();
766 scene_changed (); /* EMIT SIGNAL */
767 SceneChangeChanged (); /* EMIT SIGNAL */
771 /*---------------------------------------------------------------------- */
773 Locations::Locations (Session& s)
774 : SessionHandleRef (s)
776 current_location = 0;
779 Locations::~Locations ()
781 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
782 LocationList::iterator tmp = i;
790 Locations::set_current (Location *loc, bool want_lock)
795 Glib::Threads::Mutex::Lock lm (lock);
796 ret = set_current_unlocked (loc);
798 ret = set_current_unlocked (loc);
802 current_changed (current_location); /* EMIT SIGNAL */
808 Locations::next_available_name(string& result,string base)
810 LocationList::iterator i;
814 std::map<uint32_t,bool> taken;
822 /* find all existing names that match "base", and store
823 the numeric part of them (if any) in the map "taken"
826 for (i = locations.begin(); i != locations.end(); ++i) {
828 const string& temp ((*i)->name());
830 if (!temp.find (base,0)) {
831 /* grab what comes after the "base" as if it was
832 a number, and assuming that works OK,
833 store it in "taken" so that we know it
836 if ((suffix = atoi (temp.substr(l))) != 0) {
837 taken.insert (make_pair (suffix,true));
843 /* Now search for an un-used suffix to add to "base". This
844 will find "holes" in the numbering sequence when a location
847 This must start at 1, both for human-numbering reasons
848 and also because the call to atoi() above would return
849 zero if there is no recognizable numeric suffix, causing
850 "base 0" not to be inserted into the "taken" map.
855 while (n < UINT32_MAX) {
856 if (taken.find (n) == taken.end()) {
857 snprintf (buf, sizeof(buf), "%d", n);
868 Locations::set_current_unlocked (Location *loc)
870 if (find (locations.begin(), locations.end(), loc) == locations.end()) {
871 error << _("Locations: attempt to use unknown location as selected location") << endmsg;
875 current_location = loc;
883 Glib::Threads::Mutex::Lock lm (lock);
885 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
887 LocationList::iterator tmp = i;
890 if (!(*i)->is_session_range()) {
898 current_location = 0;
901 changed (); /* EMIT SIGNAL */
902 current_changed (0); /* EMIT SIGNAL */
906 Locations::clear_markers ()
909 Glib::Threads::Mutex::Lock lm (lock);
910 LocationList::iterator tmp;
912 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
916 if ((*i)->is_mark() && !(*i)->is_session_range()) {
925 changed (); /* EMIT SIGNAL */
929 Locations::clear_ranges ()
932 Glib::Threads::Mutex::Lock lm (lock);
933 LocationList::iterator tmp;
935 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
940 /* We do not remove these ranges as part of this
944 if ((*i)->is_auto_punch() ||
945 (*i)->is_auto_loop() ||
946 (*i)->is_session_range()) {
951 if (!(*i)->is_mark()) {
960 current_location = 0;
964 current_changed (0); /* EMIT SIGNAL */
968 Locations::add (Location *loc, bool make_current)
973 Glib::Threads::Mutex::Lock lm (lock);
974 locations.push_back (loc);
977 current_location = loc;
981 added (loc); /* EMIT SIGNAL */
984 current_changed (current_location); /* EMIT SIGNAL */
987 if (loc->is_session_range()) {
988 Session::StartTimeChanged (0);
989 Session::EndTimeChanged (1);
994 Locations::remove (Location *loc)
996 bool was_removed = false;
997 bool was_current = false;
998 LocationList::iterator i;
1000 if (loc->is_session_range()) {
1005 Glib::Threads::Mutex::Lock lm (lock);
1007 for (i = locations.begin(); i != locations.end(); ++i) {
1010 locations.erase (i);
1012 if (current_location == loc) {
1013 current_location = 0;
1023 removed (loc); /* EMIT SIGNAL */
1026 current_changed (0); /* EMIT SIGNAL */
1032 Locations::get_state ()
1034 XMLNode *node = new XMLNode ("Locations");
1035 LocationList::iterator iter;
1036 Glib::Threads::Mutex::Lock lm (lock);
1038 for (iter = locations.begin(); iter != locations.end(); ++iter) {
1039 node->add_child_nocopy ((*iter)->get_state ());
1046 Locations::set_state (const XMLNode& node, int version)
1048 if (node.name() != "Locations") {
1049 error << _("incorrect XML mode passed to Locations::set_state") << endmsg;
1053 XMLNodeList nlist = node.children();
1055 /* build up a new locations list in here */
1056 LocationList new_locations;
1058 current_location = 0;
1060 Location* session_range_location = 0;
1061 if (version < 3000) {
1062 session_range_location = new Location (_session, 0, 0, _("session"), Location::IsSessionRange);
1063 new_locations.push_back (session_range_location);
1067 Glib::Threads::Mutex::Lock lm (lock);
1069 XMLNodeConstIterator niter;
1070 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1074 XMLProperty const * prop_id = (*niter)->property ("id");
1076 PBD::ID id (prop_id->value ());
1078 LocationList::const_iterator i = locations.begin();
1079 while (i != locations.end () && (*i)->id() != id) {
1084 if (i != locations.end()) {
1085 /* we can re-use an old Location object */
1088 // changed locations will be updated by Locations::changed signal
1089 loc->set_state (**niter, version);
1091 loc = new Location (_session, **niter);
1096 if (version < 3000) {
1097 /* look for old-style IsStart / IsEnd properties in this location;
1098 if they are present, update the session_range_location accordingly
1100 XMLProperty const * prop = (*niter)->property ("flags");
1102 string v = prop->value ();
1104 string::size_type const c = v.find_first_of (',');
1105 string const s = v.substr (0, c);
1106 if (s == X_("IsStart")) {
1107 session_range_location->set_start (loc->start(), true);
1109 } else if (s == X_("IsEnd")) {
1110 session_range_location->set_end (loc->start(), true);
1114 if (c == string::npos) {
1118 v = v.substr (c + 1);
1124 new_locations.push_back (loc);
1128 catch (failed_constructor& err) {
1129 error << _("could not load location from session file - ignored") << endmsg;
1133 /* We may have some unused locations in the old list. */
1134 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
1135 LocationList::iterator tmp = i;
1138 LocationList::iterator n = new_locations.begin();
1141 while (n != new_locations.end ()) {
1142 if ((*i)->id() == (*n)->id()) {
1151 locations.erase (i);
1157 locations = new_locations;
1159 if (locations.size()) {
1160 current_location = locations.front();
1162 current_location = 0;
1166 changed (); /* EMIT SIGNAL */
1172 typedef std::pair<framepos_t,Location*> LocationPair;
1174 struct LocationStartEarlierComparison
1176 bool operator() (LocationPair a, LocationPair b) {
1177 return a.first < b.first;
1181 struct LocationStartLaterComparison
1183 bool operator() (LocationPair a, LocationPair b) {
1184 return a.first > b.first;
1189 Locations::first_mark_before (framepos_t frame, bool include_special_ranges)
1191 Glib::Threads::Mutex::Lock lm (lock);
1192 vector<LocationPair> locs;
1194 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1195 locs.push_back (make_pair ((*i)->start(), (*i)));
1196 if (!(*i)->is_mark()) {
1197 locs.push_back (make_pair ((*i)->end(), (*i)));
1201 LocationStartLaterComparison cmp;
1202 sort (locs.begin(), locs.end(), cmp);
1204 /* locs is sorted in ascending order */
1206 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1207 if ((*i).second->is_hidden()) {
1210 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1213 if ((*i).first < frame) {
1222 Locations::mark_at (framepos_t pos, framecnt_t slop) const
1224 Glib::Threads::Mutex::Lock lm (lock);
1225 Location* closest = 0;
1226 frameoffset_t mindelta = max_framepos;
1227 frameoffset_t delta;
1229 /* locations are not necessarily stored in linear time order so we have
1230 * to iterate across all of them to find the one closest to a give point.
1233 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1235 if ((*i)->is_mark()) {
1236 if (pos > (*i)->start()) {
1237 delta = pos - (*i)->start();
1239 delta = (*i)->start() - pos;
1242 if (slop == 0 && delta == 0) {
1243 /* special case: no slop, and direct hit for position */
1247 if (delta <= slop) {
1248 if (delta < mindelta) {
1260 Locations::first_mark_after (framepos_t frame, bool include_special_ranges)
1262 Glib::Threads::Mutex::Lock lm (lock);
1263 vector<LocationPair> locs;
1265 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1266 locs.push_back (make_pair ((*i)->start(), (*i)));
1267 if (!(*i)->is_mark()) {
1268 locs.push_back (make_pair ((*i)->end(), (*i)));
1272 LocationStartEarlierComparison cmp;
1273 sort (locs.begin(), locs.end(), cmp);
1275 /* locs is sorted in reverse order */
1277 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1278 if ((*i).second->is_hidden()) {
1281 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1284 if ((*i).first > frame) {
1292 /** Look for the `marks' (either locations which are marks, or start/end points of range markers) either
1293 * side of a frame. Note that if frame is exactly on a `mark', that mark will not be considered for returning
1295 * @param frame Frame to look for.
1296 * @param before Filled in with the position of the last `mark' before `frame' (or max_framepos if none exists)
1297 * @param after Filled in with the position of the next `mark' after `frame' (or max_framepos if none exists)
1300 Locations::marks_either_side (framepos_t const frame, framepos_t& before, framepos_t& after) const
1302 before = after = max_framepos;
1307 Glib::Threads::Mutex::Lock lm (lock);
1311 /* Get a list of positions; don't store any that are exactly on our requested position */
1313 std::list<framepos_t> positions;
1315 for (LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
1316 if (((*i)->is_auto_loop() || (*i)->is_auto_punch())) {
1320 if (!(*i)->is_hidden()) {
1321 if ((*i)->is_mark ()) {
1322 if ((*i)->start() != frame) {
1323 positions.push_back ((*i)->start ());
1326 if ((*i)->start() != frame) {
1327 positions.push_back ((*i)->start ());
1329 if ((*i)->end() != frame) {
1330 positions.push_back ((*i)->end ());
1336 if (positions.empty ()) {
1342 std::list<framepos_t>::iterator i = positions.begin ();
1343 while (i != positions.end () && *i < frame) {
1347 if (i == positions.end ()) {
1348 /* run out of marks */
1349 before = positions.back ();
1355 if (i == positions.begin ()) {
1365 Locations::session_range_location () const
1367 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1368 if ((*i)->is_session_range()) {
1369 return const_cast<Location*> (*i);
1376 Locations::auto_loop_location () const
1378 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1379 if ((*i)->is_auto_loop()) {
1380 return const_cast<Location*> (*i);
1387 Locations::auto_punch_location () const
1389 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1390 if ((*i)->is_auto_punch()) {
1391 return const_cast<Location*> (*i);
1398 Locations::num_range_markers () const
1401 Glib::Threads::Mutex::Lock lm (lock);
1402 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1403 if ((*i)->is_range_marker()) {
1411 Locations::get_location_by_id(PBD::ID id)
1413 LocationList::iterator it;
1414 for (it = locations.begin(); it != locations.end(); ++it)
1415 if (id == (*it)->id())
1422 Locations::find_all_between (framepos_t start, framepos_t end, LocationList& ll, Location::Flags flags)
1424 Glib::Threads::Mutex::Lock lm (lock);
1426 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1427 if ((flags == 0 || (*i)->matches (flags)) &&
1428 ((*i)->start() >= start && (*i)->end() < end)) {