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 = Flags (string_2_enum (prop->value(), _flags));
650 if ((prop = node.property ("locked")) != 0) {
651 _locked = string_is_affirmative (prop->value());
656 for (cd_iter = cd_list.begin(); cd_iter != cd_list.end(); ++cd_iter) {
660 if (cd_node->name() != "CD-Info") {
664 if ((prop = cd_node->property ("name")) != 0) {
665 cd_name = prop->value();
667 throw failed_constructor ();
670 if ((prop = cd_node->property ("value")) != 0) {
671 cd_value = prop->value();
673 throw failed_constructor ();
677 cd_info[cd_name] = cd_value;
680 if ((prop = node.property ("position-lock-style")) != 0) {
681 _position_lock_style = PositionLockStyle (string_2_enum (prop->value(), _position_lock_style));
684 XMLNode* scene_child = find_named_node (node, SceneChange::xml_node_name);
687 _scene_change = SceneChange::factory (*scene_child, version);
690 recompute_bbt_from_frames ();
692 changed (this); /* EMIT SIGNAL */
693 Changed (); /* EMIT SIGNAL */
695 assert (_start >= 0);
702 Location::set_position_lock_style (PositionLockStyle ps)
704 if (_position_lock_style == ps) {
708 _position_lock_style = ps;
710 recompute_bbt_from_frames ();
712 position_lock_style_changed (this); /* EMIT SIGNAL */
713 PositionLockStyleChanged (); /* EMIT SIGNAL */
717 Location::recompute_bbt_from_frames ()
719 if (_position_lock_style != MusicTime) {
723 _session.bbt_time (_start, _bbt_start);
724 _session.bbt_time (_end, _bbt_end);
728 Location::recompute_frames_from_bbt ()
730 if (_position_lock_style != MusicTime) {
734 TempoMap& map (_session.tempo_map());
735 set (map.frame_time (_bbt_start), map.frame_time (_bbt_end), false);
755 Location::set_scene_change (boost::shared_ptr<SceneChange> sc)
759 scene_changed (); /* EMIT SIGNAL */
762 /*---------------------------------------------------------------------- */
764 Locations::Locations (Session& s)
765 : SessionHandleRef (s)
767 current_location = 0;
770 Locations::~Locations ()
772 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
773 LocationList::iterator tmp = i;
781 Locations::set_current (Location *loc, bool want_lock)
786 Glib::Threads::Mutex::Lock lm (lock);
787 ret = set_current_unlocked (loc);
789 ret = set_current_unlocked (loc);
793 current_changed (current_location); /* EMIT SIGNAL */
799 Locations::next_available_name(string& result,string base)
801 LocationList::iterator i;
805 std::map<uint32_t,bool> taken;
813 /* find all existing names that match "base", and store
814 the numeric part of them (if any) in the map "taken"
817 for (i = locations.begin(); i != locations.end(); ++i) {
819 const string& temp ((*i)->name());
821 if (!temp.find (base,0)) {
823 if ((suffix = atoi (temp.substr(l,3))) != 0) {
824 taken.insert (make_pair (suffix,true));
830 /* Now search for an un-used suffix to add to "base". This
831 will find "holes" in the numbering sequence when a location
834 This must start at 1, both for human-numbering reasons
835 and also because the call to atoi() above would return
836 zero if there is no recognizable numeric suffix, causing
837 "base 0" not to be inserted into the "taken" map.
842 while (n < UINT32_MAX) {
843 if (taken.find (n) == taken.end()) {
844 snprintf (buf, sizeof(buf), "%d", n);
855 Locations::set_current_unlocked (Location *loc)
857 if (find (locations.begin(), locations.end(), loc) == locations.end()) {
858 error << _("Locations: attempt to use unknown location as selected location") << endmsg;
862 current_location = loc;
870 Glib::Threads::Mutex::Lock lm (lock);
872 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
874 LocationList::iterator tmp = i;
877 if (!(*i)->is_session_range()) {
885 current_location = 0;
888 changed (); /* EMIT SIGNAL */
889 current_changed (0); /* EMIT SIGNAL */
893 Locations::clear_markers ()
896 Glib::Threads::Mutex::Lock lm (lock);
897 LocationList::iterator tmp;
899 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
903 if ((*i)->is_mark() && !(*i)->is_session_range()) {
912 changed (); /* EMIT SIGNAL */
916 Locations::clear_ranges ()
919 Glib::Threads::Mutex::Lock lm (lock);
920 LocationList::iterator tmp;
922 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
927 /* We do not remove these ranges as part of this
931 if ((*i)->is_auto_punch() ||
932 (*i)->is_auto_loop() ||
933 (*i)->is_session_range()) {
938 if (!(*i)->is_mark()) {
947 current_location = 0;
951 current_changed (0); /* EMIT SIGNAL */
955 Locations::add (Location *loc, bool make_current)
960 Glib::Threads::Mutex::Lock lm (lock);
961 locations.push_back (loc);
964 current_location = loc;
968 added (loc); /* EMIT SIGNAL */
971 current_changed (current_location); /* EMIT SIGNAL */
974 if (loc->is_session_range()) {
975 Session::StartTimeChanged (0);
976 Session::EndTimeChanged (1);
981 Locations::remove (Location *loc)
983 bool was_removed = false;
984 bool was_current = false;
985 LocationList::iterator i;
987 if (loc->is_session_range()) {
992 Glib::Threads::Mutex::Lock lm (lock);
994 for (i = locations.begin(); i != locations.end(); ++i) {
999 if (current_location == loc) {
1000 current_location = 0;
1010 removed (loc); /* EMIT SIGNAL */
1013 current_changed (0); /* EMIT SIGNAL */
1019 Locations::get_state ()
1021 XMLNode *node = new XMLNode ("Locations");
1022 LocationList::iterator iter;
1023 Glib::Threads::Mutex::Lock lm (lock);
1025 for (iter = locations.begin(); iter != locations.end(); ++iter) {
1026 node->add_child_nocopy ((*iter)->get_state ());
1033 Locations::set_state (const XMLNode& node, int version)
1035 if (node.name() != "Locations") {
1036 error << _("incorrect XML mode passed to Locations::set_state") << endmsg;
1040 XMLNodeList nlist = node.children();
1042 /* build up a new locations list in here */
1043 LocationList new_locations;
1045 current_location = 0;
1047 Location* session_range_location = 0;
1048 if (version < 3000) {
1049 session_range_location = new Location (_session, 0, 0, _("session"), Location::IsSessionRange);
1050 new_locations.push_back (session_range_location);
1054 Glib::Threads::Mutex::Lock lm (lock);
1056 XMLNodeConstIterator niter;
1057 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1061 XMLProperty const * prop_id = (*niter)->property ("id");
1063 PBD::ID id (prop_id->value ());
1065 LocationList::const_iterator i = locations.begin();
1066 while (i != locations.end () && (*i)->id() != id) {
1071 if (i != locations.end()) {
1072 /* we can re-use an old Location object */
1075 // changed locations will be updated by Locations::changed signal
1076 loc->set_state (**niter, version);
1078 loc = new Location (_session, **niter);
1083 if (version < 3000) {
1084 /* look for old-style IsStart / IsEnd properties in this location;
1085 if they are present, update the session_range_location accordingly
1087 XMLProperty const * prop = (*niter)->property ("flags");
1089 string v = prop->value ();
1091 string::size_type const c = v.find_first_of (',');
1092 string const s = v.substr (0, c);
1093 if (s == X_("IsStart")) {
1094 session_range_location->set_start (loc->start(), true);
1096 } else if (s == X_("IsEnd")) {
1097 session_range_location->set_end (loc->start(), true);
1101 if (c == string::npos) {
1105 v = v.substr (c + 1);
1111 new_locations.push_back (loc);
1115 catch (failed_constructor& err) {
1116 error << _("could not load location from session file - ignored") << endmsg;
1120 /* We may have some unused locations in the old list. */
1121 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
1122 LocationList::iterator tmp = i;
1125 LocationList::iterator n = new_locations.begin();
1128 while (n != new_locations.end ()) {
1129 if ((*i)->id() == (*n)->id()) {
1138 locations.erase (i);
1144 locations = new_locations;
1146 if (locations.size()) {
1147 current_location = locations.front();
1149 current_location = 0;
1153 changed (); /* EMIT SIGNAL */
1159 typedef std::pair<framepos_t,Location*> LocationPair;
1161 struct LocationStartEarlierComparison
1163 bool operator() (LocationPair a, LocationPair b) {
1164 return a.first < b.first;
1168 struct LocationStartLaterComparison
1170 bool operator() (LocationPair a, LocationPair b) {
1171 return a.first > b.first;
1176 Locations::first_mark_before (framepos_t frame, bool include_special_ranges)
1178 Glib::Threads::Mutex::Lock lm (lock);
1179 vector<LocationPair> locs;
1181 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1182 locs.push_back (make_pair ((*i)->start(), (*i)));
1183 if (!(*i)->is_mark()) {
1184 locs.push_back (make_pair ((*i)->end(), (*i)));
1188 LocationStartLaterComparison cmp;
1189 sort (locs.begin(), locs.end(), cmp);
1191 /* locs is sorted in ascending order */
1193 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1194 if ((*i).second->is_hidden()) {
1197 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1200 if ((*i).first < frame) {
1209 Locations::mark_at (framepos_t pos, framecnt_t slop) const
1211 Glib::Threads::Mutex::Lock lm (lock);
1212 Location* closest = 0;
1213 frameoffset_t mindelta = max_framepos;
1214 frameoffset_t delta;
1216 /* locations are not necessarily stored in linear time order so we have
1217 * to iterate across all of them to find the one closest to a give point.
1220 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1222 if ((*i)->is_mark()) {
1223 if (pos > (*i)->start()) {
1224 delta = pos - (*i)->start();
1226 delta = (*i)->start() - pos;
1229 if (slop == 0 && delta == 0) {
1230 /* special case: no slop, and direct hit for position */
1234 if (delta <= slop) {
1235 if (delta < mindelta) {
1247 Locations::first_mark_after (framepos_t frame, bool include_special_ranges)
1249 Glib::Threads::Mutex::Lock lm (lock);
1250 vector<LocationPair> locs;
1252 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1253 locs.push_back (make_pair ((*i)->start(), (*i)));
1254 if (!(*i)->is_mark()) {
1255 locs.push_back (make_pair ((*i)->end(), (*i)));
1259 LocationStartEarlierComparison cmp;
1260 sort (locs.begin(), locs.end(), cmp);
1262 /* locs is sorted in reverse order */
1264 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1265 if ((*i).second->is_hidden()) {
1268 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1271 if ((*i).first > frame) {
1279 /** Look for the `marks' (either locations which are marks, or start/end points of range markers) either
1280 * side of a frame. Note that if frame is exactly on a `mark', that mark will not be considered for returning
1282 * @param frame Frame to look for.
1283 * @param before Filled in with the position of the last `mark' before `frame' (or max_framepos if none exists)
1284 * @param after Filled in with the position of the next `mark' after `frame' (or max_framepos if none exists)
1287 Locations::marks_either_side (framepos_t const frame, framepos_t& before, framepos_t& after) const
1289 before = after = max_framepos;
1294 Glib::Threads::Mutex::Lock lm (lock);
1298 /* Get a list of positions; don't store any that are exactly on our requested position */
1300 std::list<framepos_t> positions;
1302 for (LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
1303 if (((*i)->is_auto_loop() || (*i)->is_auto_punch())) {
1307 if (!(*i)->is_hidden()) {
1308 if ((*i)->is_mark ()) {
1309 if ((*i)->start() != frame) {
1310 positions.push_back ((*i)->start ());
1313 if ((*i)->start() != frame) {
1314 positions.push_back ((*i)->start ());
1316 if ((*i)->end() != frame) {
1317 positions.push_back ((*i)->end ());
1323 if (positions.empty ()) {
1329 std::list<framepos_t>::iterator i = positions.begin ();
1330 while (i != positions.end () && *i < frame) {
1334 if (i == positions.end ()) {
1335 /* run out of marks */
1336 before = positions.back ();
1342 if (i == positions.begin ()) {
1352 Locations::session_range_location () const
1354 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1355 if ((*i)->is_session_range()) {
1356 return const_cast<Location*> (*i);
1363 Locations::auto_loop_location () const
1365 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1366 if ((*i)->is_auto_loop()) {
1367 return const_cast<Location*> (*i);
1374 Locations::auto_punch_location () const
1376 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1377 if ((*i)->is_auto_punch()) {
1378 return const_cast<Location*> (*i);
1385 Locations::num_range_markers () const
1388 Glib::Threads::Mutex::Lock lm (lock);
1389 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1390 if ((*i)->is_range_marker()) {
1398 Locations::get_location_by_id(PBD::ID id)
1400 LocationList::iterator it;
1401 for (it = locations.begin(); it != locations.end(); ++it)
1402 if (id == (*it)->id())
1409 Locations::find_all_between (framepos_t start, framepos_t end, LocationList& ll, Location::Flags flags)
1411 Glib::Threads::Mutex::Lock lm (lock);
1413 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1414 if ((flags == 0 || (*i)->matches (flags)) &&
1415 ((*i)->start() >= start && (*i)->end() < end)) {