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)
61 , _block_change_notifications (false)
67 /** Construct a new Location, giving it the position lock style determined by glue-new-markers-to-bars-and-beats */
68 Location::Location (Session& s, framepos_t sample_start, framepos_t sample_end, const std::string &name, Flags bits)
69 : SessionHandleRef (s)
71 , _start (sample_start)
75 , _position_lock_style (s.config.get_glue_new_markers_to_bars_and_beats() ? MusicTime : AudioTime)
76 , _block_change_notifications (false)
79 recompute_bbt_from_frames ();
85 Location::Location (const Location& other)
86 : SessionHandleRef (other._session)
87 , StatefulDestructible()
89 , _start (other._start)
90 , _bbt_start (other._bbt_start)
92 , _bbt_end (other._bbt_end)
93 , _flags (other._flags)
94 , _position_lock_style (other._position_lock_style)
95 , _block_change_notifications (false)
98 /* copy is not locked even if original was */
102 assert (_start >= 0);
105 /* scene change is NOT COPIED */
108 Location::Location (Session& s, const XMLNode& node)
109 : SessionHandleRef (s)
110 , _position_lock_style (AudioTime)
112 /* Note: _position_lock_style is initialised above in case set_state doesn't set it
113 (for 2.X session file compatibility).
116 if (set_state (node, Stateful::loading_state_version)) {
117 throw failed_constructor ();
120 assert (_start >= 0);
125 Location::operator== (const Location& other)
127 if (_name != other._name ||
128 _start != other._start ||
129 _end != other._end ||
130 _bbt_start != other._bbt_start ||
131 _bbt_end != other._bbt_end ||
132 _flags != other._flags ||
133 _position_lock_style != other._position_lock_style) {
140 Location::operator= (const Location& other)
142 if (this == &other) {
147 _start = other._start;
148 _bbt_start = other._bbt_start;
150 _bbt_end = other._bbt_end;
151 _flags = other._flags;
152 _position_lock_style = other._position_lock_style;
154 /* XXX need to copy scene change */
156 /* copy is not locked even if original was */
160 /* "changed" not emitted on purpose */
162 assert (_start >= 0);
168 /** Set location name
172 Location::set_name (const std::string& str)
176 name_changed (this); /* EMIT SIGNAL */
177 NameChanged (); /* EMIT SIGNAL */
180 /** Set start position.
181 * @param s New start.
182 * @param force true to force setting, even if the given new start is after the current end.
183 * @param allow_bbt_recompute True to recompute BBT start time from the new given start time.
186 Location::set_start (framepos_t s, bool force, bool allow_bbt_recompute)
197 if (((is_auto_punch() || is_auto_loop()) && s >= _end) || (!is_mark() && s > _end)) {
206 if (allow_bbt_recompute) {
207 recompute_bbt_from_frames ();
210 start_changed (this); /* EMIT SIGNAL */
211 StartChanged (); /* EMIT SIGNAL */
212 end_changed (this); /* EMIT SIGNAL */
213 EndChanged (); /* EMIT SIGNAL */
216 /* moving the start (position) of a marker with a scene change
217 requires an update in the Scene Changer.
221 scene_changed (); /* EMIT SIGNAL */
224 assert (_start >= 0);
229 /* range locations must exceed a minimum duration */
230 if (_end - s < Config->get_range_location_minimum()) {
237 framepos_t const old = _start;
240 if (allow_bbt_recompute) {
241 recompute_bbt_from_frames ();
243 start_changed (this); /* EMIT SIGNAL */
244 StartChanged (); /* EMIT SIGNAL */
246 if (is_session_range ()) {
247 Session::StartTimeChanged (old); /* EMIT SIGNAL */
248 AudioFileSource::set_header_position_offset (s);
252 assert (_start >= 0);
257 /** Set end position.
259 * @param force true to force setting, even if the given new end is before the current start.
260 * @param allow_bbt_recompute True to recompute BBT end time from the new given end time.
263 Location::set_end (framepos_t e, bool force, bool allow_bbt_recompute)
274 if (((is_auto_punch() || is_auto_loop()) && e <= _start) || e < _start) {
283 if (allow_bbt_recompute) {
284 recompute_bbt_from_frames ();
286 start_changed (this); /* EMIT SIGNAL */
287 StartChanged (); /* EMIT SIGNAL */
288 end_changed (this); /* EMIT SIGNAL */
289 EndChanged (); /* EMIT SIGNAL */
292 assert (_start >= 0);
297 /* range locations must exceed a minimum duration */
298 if (e - _start < Config->get_range_location_minimum()) {
305 framepos_t const old = _end;
308 if (allow_bbt_recompute) {
309 recompute_bbt_from_frames ();
312 end_changed(this); /* EMIT SIGNAL */
313 EndChanged(); /* EMIT SIGNAL */
315 if (is_session_range()) {
316 Session::EndTimeChanged (old); /* EMIT SIGNAL */
326 Location::set (framepos_t s, framepos_t e, bool allow_bbt_recompute)
328 if (s < 0 || e < 0) {
333 if (((is_auto_punch() || is_auto_loop()) && s >= e) || (!is_mark() && s > e)) {
337 bool start_change = false;
338 bool end_change = false;
346 if (allow_bbt_recompute) {
347 recompute_bbt_from_frames ();
354 assert (_start >= 0);
359 /* range locations must exceed a minimum duration */
360 if (e - s < Config->get_range_location_minimum()) {
366 framepos_t const old = _start;
369 if (allow_bbt_recompute) {
370 recompute_bbt_from_frames ();
375 if (is_session_range ()) {
376 Session::StartTimeChanged (old); /* EMIT SIGNAL */
377 AudioFileSource::set_header_position_offset (s);
384 framepos_t const old = _end;
387 if (allow_bbt_recompute) {
388 recompute_bbt_from_frames ();
393 if (is_session_range()) {
394 Session::EndTimeChanged (old); /* EMIT SIGNAL */
402 start_changed(this); /* EMIT SIGNAL */
403 StartChanged(); /* EMIT SIGNAL */
407 end_changed(this); /* EMIT SIGNAL */
408 EndChanged(); /* EMIT SIGNAL */
411 if (start_change && end_change) {
414 if (!_block_change_notifications) {
423 Location::move_to (framepos_t pos)
435 _end = _start + length();
436 recompute_bbt_from_frames ();
438 changed (this); /* EMIT SIGNAL */
440 if (!_block_change_notifications) {
441 Changed (); /* EMIT SIGNAL */
445 assert (_start >= 0);
452 Location::set_hidden (bool yn, void*)
454 if (set_flag_internal (yn, IsHidden)) {
455 flags_changed (this); /* EMIT SIGNAL */
461 Location::set_cd (bool yn, void*)
463 // XXX this really needs to be session start
464 // but its not available here - leave to GUI
466 if (yn && _start == 0) {
467 error << _("You cannot put a CD marker at this position") << endmsg;
471 if (set_flag_internal (yn, IsCDMarker)) {
472 flags_changed (this); /* EMIT SIGNAL */
478 Location::set_is_range_marker (bool yn, void*)
480 if (set_flag_internal (yn, IsRangeMarker)) {
481 flags_changed (this);
482 FlagsChanged (); /* EMIT SIGNAL */
487 Location::set_skip (bool yn)
489 if (is_range_marker() && length() > 0) {
490 if (set_flag_internal (yn, IsSkip)) {
491 flags_changed (this);
498 Location::set_skipping (bool yn)
500 if (is_range_marker() && is_skip() && length() > 0) {
501 if (set_flag_internal (yn, IsSkipping)) {
502 flags_changed (this);
509 Location::set_auto_punch (bool yn, void*)
511 if (is_mark() || _start == _end) {
515 if (set_flag_internal (yn, IsAutoPunch)) {
516 flags_changed (this); /* EMIT SIGNAL */
517 FlagsChanged (); /* EMIT SIGNAL */
522 Location::set_auto_loop (bool yn, void*)
524 if (is_mark() || _start == _end) {
528 if (set_flag_internal (yn, IsAutoLoop)) {
529 flags_changed (this); /* EMIT SIGNAL */
530 FlagsChanged (); /* EMIT SIGNAL */
535 Location::set_flag_internal (bool yn, Flags flag)
538 if (!(_flags & flag)) {
539 _flags = Flags (_flags | flag);
544 _flags = Flags (_flags & ~flag);
552 Location::set_mark (bool yn)
554 /* This function is private, and so does not emit signals */
556 if (_start != _end) {
560 set_flag_internal (yn, IsMark);
565 Location::cd_info_node(const string & name, const string & value)
567 XMLNode* root = new XMLNode("CD-Info");
569 root->add_property("name", name);
570 root->add_property("value", value);
577 Location::get_state ()
579 XMLNode *node = new XMLNode ("Location");
582 typedef map<string, string>::const_iterator CI;
584 for(CI m = cd_info.begin(); m != cd_info.end(); ++m){
585 node->add_child_nocopy(cd_info_node(m->first, m->second));
588 id().print (buf, sizeof (buf));
589 node->add_property("id", buf);
590 node->add_property ("name", name());
591 snprintf (buf, sizeof (buf), "%" PRId64, start());
592 node->add_property ("start", buf);
593 snprintf (buf, sizeof (buf), "%" PRId64, end());
594 node->add_property ("end", buf);
595 node->add_property ("flags", enum_2_string (_flags));
596 node->add_property ("locked", (_locked ? "yes" : "no"));
597 node->add_property ("position-lock-style", enum_2_string (_position_lock_style));
600 node->add_child_nocopy (_scene_change->get_state());
607 Location::set_state (const XMLNode& node, int version)
609 const XMLProperty *prop;
611 XMLNodeList cd_list = node.children();
612 XMLNodeConstIterator cd_iter;
618 if (node.name() != "Location") {
619 error << _("incorrect XML node passed to Location::set_state") << endmsg;
623 if (!set_id (node)) {
624 warning << _("XML node for Location has no ID information") << endmsg;
627 if ((prop = node.property ("name")) == 0) {
628 error << _("XML node for Location has no name information") << endmsg;
632 set_name (prop->value());
634 if ((prop = node.property ("start")) == 0) {
635 error << _("XML node for Location has no start information") << endmsg;
639 /* can't use set_start() here, because _end
640 may make the value of _start illegal.
643 sscanf (prop->value().c_str(), "%" PRId64, &_start);
645 if ((prop = node.property ("end")) == 0) {
646 error << _("XML node for Location has no end information") << endmsg;
650 sscanf (prop->value().c_str(), "%" PRId64, &_end);
652 if ((prop = node.property ("flags")) == 0) {
653 error << _("XML node for Location has no flags information") << endmsg;
657 _flags = Flags (string_2_enum (prop->value(), _flags));
659 if ((prop = node.property ("locked")) != 0) {
660 _locked = string_is_affirmative (prop->value());
665 for (cd_iter = cd_list.begin(); cd_iter != cd_list.end(); ++cd_iter) {
669 if (cd_node->name() != "CD-Info") {
673 if ((prop = cd_node->property ("name")) != 0) {
674 cd_name = prop->value();
676 throw failed_constructor ();
679 if ((prop = cd_node->property ("value")) != 0) {
680 cd_value = prop->value();
682 throw failed_constructor ();
686 cd_info[cd_name] = cd_value;
689 if ((prop = node.property ("position-lock-style")) != 0) {
690 _position_lock_style = PositionLockStyle (string_2_enum (prop->value(), _position_lock_style));
693 XMLNode* scene_child = find_named_node (node, SceneChange::xml_node_name);
696 _scene_change = SceneChange::factory (*scene_child, version);
699 recompute_bbt_from_frames ();
701 changed (this); /* EMIT SIGNAL */
703 if (!_block_change_notifications) {
704 Changed (); /* EMIT SIGNAL */
707 assert (_start >= 0);
714 Location::set_position_lock_style (PositionLockStyle ps)
716 if (_position_lock_style == ps) {
720 _position_lock_style = ps;
722 recompute_bbt_from_frames ();
724 position_lock_style_changed (this); /* EMIT SIGNAL */
725 PositionLockStyleChanged (); /* EMIT SIGNAL */
729 Location::recompute_bbt_from_frames ()
731 if (_position_lock_style != MusicTime) {
735 _session.bbt_time (_start, _bbt_start);
736 _session.bbt_time (_end, _bbt_end);
740 Location::recompute_frames_from_bbt ()
742 if (_position_lock_style != MusicTime) {
746 TempoMap& map (_session.tempo_map());
747 set (map.frame_time (_bbt_start), map.frame_time (_bbt_end), false);
767 Location::set_scene_change (boost::shared_ptr<SceneChange> sc)
771 scene_changed (); /* EMIT SIGNAL */
774 /*---------------------------------------------------------------------- */
776 Locations::Locations (Session& s)
777 : SessionHandleRef (s)
779 current_location = 0;
782 Locations::~Locations ()
784 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
785 LocationList::iterator tmp = i;
793 Locations::set_current (Location *loc, bool want_lock)
798 Glib::Threads::Mutex::Lock lm (lock);
799 ret = set_current_unlocked (loc);
801 ret = set_current_unlocked (loc);
805 current_changed (current_location); /* EMIT SIGNAL */
811 Locations::next_available_name(string& result,string base)
813 LocationList::iterator i;
817 std::map<uint32_t,bool> taken;
825 /* find all existing names that match "base", and store
826 the numeric part of them (if any) in the map "taken"
829 for (i = locations.begin(); i != locations.end(); ++i) {
831 const string& temp ((*i)->name());
833 if (!temp.find (base,0)) {
835 if ((suffix = atoi (temp.substr(l,3))) != 0) {
836 taken.insert (make_pair (suffix,true));
842 /* Now search for an un-used suffix to add to "base". This
843 will find "holes" in the numbering sequence when a location
846 This must start at 1, both for human-numbering reasons
847 and also because the call to atoi() above would return
848 zero if there is no recognizable numeric suffix, causing
849 "base 0" not to be inserted into the "taken" map.
854 while (n < UINT32_MAX) {
855 if (taken.find (n) == taken.end()) {
856 snprintf (buf, sizeof(buf), "%d", n);
867 Locations::set_current_unlocked (Location *loc)
869 if (find (locations.begin(), locations.end(), loc) == locations.end()) {
870 error << _("Locations: attempt to use unknown location as selected location") << endmsg;
874 current_location = loc;
882 Glib::Threads::Mutex::Lock lm (lock);
884 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
886 LocationList::iterator tmp = i;
889 if (!(*i)->is_session_range()) {
897 current_location = 0;
900 changed (); /* EMIT SIGNAL */
901 current_changed (0); /* EMIT SIGNAL */
905 Locations::clear_markers ()
908 Glib::Threads::Mutex::Lock lm (lock);
909 LocationList::iterator tmp;
911 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
915 if ((*i)->is_mark() && !(*i)->is_session_range()) {
924 changed (); /* EMIT SIGNAL */
928 Locations::clear_ranges ()
931 Glib::Threads::Mutex::Lock lm (lock);
932 LocationList::iterator tmp;
934 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
939 /* We do not remove these ranges as part of this
943 if ((*i)->is_auto_punch() ||
944 (*i)->is_auto_loop() ||
945 (*i)->is_session_range()) {
950 if (!(*i)->is_mark()) {
959 current_location = 0;
963 current_changed (0); /* EMIT SIGNAL */
967 Locations::add (Location *loc, bool make_current)
972 Glib::Threads::Mutex::Lock lm (lock);
973 locations.push_back (loc);
976 current_location = loc;
980 added (loc); /* EMIT SIGNAL */
983 current_changed (current_location); /* EMIT SIGNAL */
986 if (loc->is_session_range()) {
987 Session::StartTimeChanged (0);
988 Session::EndTimeChanged (1);
993 Locations::remove (Location *loc)
995 bool was_removed = false;
996 bool was_current = false;
997 LocationList::iterator i;
999 if (loc->is_session_range()) {
1004 Glib::Threads::Mutex::Lock lm (lock);
1006 for (i = locations.begin(); i != locations.end(); ++i) {
1009 locations.erase (i);
1011 if (current_location == loc) {
1012 current_location = 0;
1022 removed (loc); /* EMIT SIGNAL */
1025 current_changed (0); /* EMIT SIGNAL */
1031 Locations::get_state ()
1033 XMLNode *node = new XMLNode ("Locations");
1034 LocationList::iterator iter;
1035 Glib::Threads::Mutex::Lock lm (lock);
1037 for (iter = locations.begin(); iter != locations.end(); ++iter) {
1038 node->add_child_nocopy ((*iter)->get_state ());
1045 Locations::set_state (const XMLNode& node, int version)
1047 if (node.name() != "Locations") {
1048 error << _("incorrect XML mode passed to Locations::set_state") << endmsg;
1052 XMLNodeList nlist = node.children();
1054 /* build up a new locations list in here */
1055 LocationList new_locations;
1057 current_location = 0;
1059 Location* session_range_location = 0;
1060 if (version < 3000) {
1061 session_range_location = new Location (_session, 0, 0, _("session"), Location::IsSessionRange);
1062 new_locations.push_back (session_range_location);
1066 Glib::Threads::Mutex::Lock lm (lock);
1068 XMLNodeConstIterator niter;
1069 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1073 XMLProperty const * prop_id = (*niter)->property ("id");
1075 PBD::ID id (prop_id->value ());
1077 LocationList::const_iterator i = locations.begin();
1078 while (i != locations.end () && (*i)->id() != id) {
1083 if (i != locations.end()) {
1084 /* we can re-use an old Location object */
1087 // changed locations will be updated by Locations::changed signal
1088 loc->set_block_change_notifications (true);
1089 loc->set_state (**niter, version);
1090 loc->set_block_change_notifications (false);
1092 loc = new Location (_session, **niter);
1097 if (version < 3000) {
1098 /* look for old-style IsStart / IsEnd properties in this location;
1099 if they are present, update the session_range_location accordingly
1101 XMLProperty const * prop = (*niter)->property ("flags");
1103 string v = prop->value ();
1105 string::size_type const c = v.find_first_of (',');
1106 string const s = v.substr (0, c);
1107 if (s == X_("IsStart")) {
1108 session_range_location->set_start (loc->start(), true);
1110 } else if (s == X_("IsEnd")) {
1111 session_range_location->set_end (loc->start(), true);
1115 if (c == string::npos) {
1119 v = v.substr (c + 1);
1125 new_locations.push_back (loc);
1129 catch (failed_constructor& err) {
1130 error << _("could not load location from session file - ignored") << endmsg;
1134 locations = new_locations;
1136 if (locations.size()) {
1137 current_location = locations.front();
1139 current_location = 0;
1143 changed (); /* EMIT SIGNAL */
1149 typedef std::pair<framepos_t,Location*> LocationPair;
1151 struct LocationStartEarlierComparison
1153 bool operator() (LocationPair a, LocationPair b) {
1154 return a.first < b.first;
1158 struct LocationStartLaterComparison
1160 bool operator() (LocationPair a, LocationPair b) {
1161 return a.first > b.first;
1166 Locations::first_mark_before (framepos_t frame, bool include_special_ranges)
1168 Glib::Threads::Mutex::Lock lm (lock);
1169 vector<LocationPair> locs;
1171 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1172 locs.push_back (make_pair ((*i)->start(), (*i)));
1173 if (!(*i)->is_mark()) {
1174 locs.push_back (make_pair ((*i)->end(), (*i)));
1178 LocationStartLaterComparison cmp;
1179 sort (locs.begin(), locs.end(), cmp);
1181 /* locs is sorted in ascending order */
1183 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1184 if ((*i).second->is_hidden()) {
1187 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1190 if ((*i).first < frame) {
1199 Locations::mark_at (framepos_t pos, framecnt_t slop) const
1201 Glib::Threads::Mutex::Lock lm (lock);
1202 Location* closest = 0;
1203 frameoffset_t mindelta = max_framepos;
1204 frameoffset_t delta;
1206 /* locations are not necessarily stored in linear time order so we have
1207 * to iterate across all of them to find the one closest to a give point.
1210 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1212 if ((*i)->is_mark()) {
1213 if (pos > (*i)->start()) {
1214 delta = pos - (*i)->start();
1216 delta = (*i)->start() - pos;
1219 if (slop == 0 && delta == 0) {
1220 /* special case: no slop, and direct hit for position */
1224 if (delta <= slop) {
1225 if (delta < mindelta) {
1237 Locations::first_mark_after (framepos_t frame, bool include_special_ranges)
1239 Glib::Threads::Mutex::Lock lm (lock);
1240 vector<LocationPair> locs;
1242 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1243 locs.push_back (make_pair ((*i)->start(), (*i)));
1244 if (!(*i)->is_mark()) {
1245 locs.push_back (make_pair ((*i)->end(), (*i)));
1249 LocationStartEarlierComparison cmp;
1250 sort (locs.begin(), locs.end(), cmp);
1252 /* locs is sorted in reverse order */
1254 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1255 if ((*i).second->is_hidden()) {
1258 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1261 if ((*i).first > frame) {
1269 /** Look for the `marks' (either locations which are marks, or start/end points of range markers) either
1270 * side of a frame. Note that if frame is exactly on a `mark', that mark will not be considered for returning
1272 * @param frame Frame to look for.
1273 * @param before Filled in with the position of the last `mark' before `frame' (or max_framepos if none exists)
1274 * @param after Filled in with the position of the next `mark' after `frame' (or max_framepos if none exists)
1277 Locations::marks_either_side (framepos_t const frame, framepos_t& before, framepos_t& after) const
1279 before = after = max_framepos;
1284 Glib::Threads::Mutex::Lock lm (lock);
1288 /* Get a list of positions; don't store any that are exactly on our requested position */
1290 std::list<framepos_t> positions;
1292 for (LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
1293 if (((*i)->is_auto_loop() || (*i)->is_auto_punch())) {
1297 if (!(*i)->is_hidden()) {
1298 if ((*i)->is_mark ()) {
1299 if ((*i)->start() != frame) {
1300 positions.push_back ((*i)->start ());
1303 if ((*i)->start() != frame) {
1304 positions.push_back ((*i)->start ());
1306 if ((*i)->end() != frame) {
1307 positions.push_back ((*i)->end ());
1313 if (positions.empty ()) {
1319 std::list<framepos_t>::iterator i = positions.begin ();
1320 while (i != positions.end () && *i < frame) {
1324 if (i == positions.end ()) {
1325 /* run out of marks */
1326 before = positions.back ();
1332 if (i == positions.begin ()) {
1342 Locations::session_range_location () const
1344 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1345 if ((*i)->is_session_range()) {
1346 return const_cast<Location*> (*i);
1353 Locations::auto_loop_location () const
1355 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1356 if ((*i)->is_auto_loop()) {
1357 return const_cast<Location*> (*i);
1364 Locations::auto_punch_location () const
1366 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1367 if ((*i)->is_auto_punch()) {
1368 return const_cast<Location*> (*i);
1375 Locations::num_range_markers () const
1378 Glib::Threads::Mutex::Lock lm (lock);
1379 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1380 if ((*i)->is_range_marker()) {
1388 Locations::get_location_by_id(PBD::ID id)
1390 LocationList::iterator it;
1391 for (it = locations.begin(); it != locations.end(); ++it)
1392 if (id == (*it)->id())
1399 Locations::find_all_between (framepos_t start, framepos_t end, LocationList& ll, Location::Flags flags)
1401 Glib::Threads::Mutex::Lock lm (lock);
1403 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1404 if ((flags == 0 || (*i)->matches (flags)) &&
1405 ((*i)->start() >= start && (*i)->end() < end)) {