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)
764 scene_changed (); /* EMIT SIGNAL */
767 /*---------------------------------------------------------------------- */
769 Locations::Locations (Session& s)
770 : SessionHandleRef (s)
772 current_location = 0;
775 Locations::~Locations ()
777 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
778 LocationList::iterator tmp = i;
786 Locations::set_current (Location *loc, bool want_lock)
791 Glib::Threads::Mutex::Lock lm (lock);
792 ret = set_current_unlocked (loc);
794 ret = set_current_unlocked (loc);
798 current_changed (current_location); /* EMIT SIGNAL */
804 Locations::next_available_name(string& result,string base)
806 LocationList::iterator i;
810 std::map<uint32_t,bool> taken;
818 /* find all existing names that match "base", and store
819 the numeric part of them (if any) in the map "taken"
822 for (i = locations.begin(); i != locations.end(); ++i) {
824 const string& temp ((*i)->name());
826 if (!temp.find (base,0)) {
828 if ((suffix = atoi (temp.substr(l,3))) != 0) {
829 taken.insert (make_pair (suffix,true));
835 /* Now search for an un-used suffix to add to "base". This
836 will find "holes" in the numbering sequence when a location
839 This must start at 1, both for human-numbering reasons
840 and also because the call to atoi() above would return
841 zero if there is no recognizable numeric suffix, causing
842 "base 0" not to be inserted into the "taken" map.
847 while (n < UINT32_MAX) {
848 if (taken.find (n) == taken.end()) {
849 snprintf (buf, sizeof(buf), "%d", n);
860 Locations::set_current_unlocked (Location *loc)
862 if (find (locations.begin(), locations.end(), loc) == locations.end()) {
863 error << _("Locations: attempt to use unknown location as selected location") << endmsg;
867 current_location = loc;
875 Glib::Threads::Mutex::Lock lm (lock);
877 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
879 LocationList::iterator tmp = i;
882 if (!(*i)->is_session_range()) {
890 current_location = 0;
893 changed (); /* EMIT SIGNAL */
894 current_changed (0); /* EMIT SIGNAL */
898 Locations::clear_markers ()
901 Glib::Threads::Mutex::Lock lm (lock);
902 LocationList::iterator tmp;
904 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
908 if ((*i)->is_mark() && !(*i)->is_session_range()) {
917 changed (); /* EMIT SIGNAL */
921 Locations::clear_ranges ()
924 Glib::Threads::Mutex::Lock lm (lock);
925 LocationList::iterator tmp;
927 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
932 /* We do not remove these ranges as part of this
936 if ((*i)->is_auto_punch() ||
937 (*i)->is_auto_loop() ||
938 (*i)->is_session_range()) {
943 if (!(*i)->is_mark()) {
952 current_location = 0;
956 current_changed (0); /* EMIT SIGNAL */
960 Locations::add (Location *loc, bool make_current)
965 Glib::Threads::Mutex::Lock lm (lock);
966 locations.push_back (loc);
969 current_location = loc;
973 added (loc); /* EMIT SIGNAL */
976 current_changed (current_location); /* EMIT SIGNAL */
979 if (loc->is_session_range()) {
980 Session::StartTimeChanged (0);
981 Session::EndTimeChanged (1);
986 Locations::remove (Location *loc)
988 bool was_removed = false;
989 bool was_current = false;
990 LocationList::iterator i;
992 if (loc->is_session_range()) {
997 Glib::Threads::Mutex::Lock lm (lock);
999 for (i = locations.begin(); i != locations.end(); ++i) {
1002 locations.erase (i);
1004 if (current_location == loc) {
1005 current_location = 0;
1015 removed (loc); /* EMIT SIGNAL */
1018 current_changed (0); /* EMIT SIGNAL */
1024 Locations::get_state ()
1026 XMLNode *node = new XMLNode ("Locations");
1027 LocationList::iterator iter;
1028 Glib::Threads::Mutex::Lock lm (lock);
1030 for (iter = locations.begin(); iter != locations.end(); ++iter) {
1031 node->add_child_nocopy ((*iter)->get_state ());
1038 Locations::set_state (const XMLNode& node, int version)
1040 if (node.name() != "Locations") {
1041 error << _("incorrect XML mode passed to Locations::set_state") << endmsg;
1045 XMLNodeList nlist = node.children();
1047 /* build up a new locations list in here */
1048 LocationList new_locations;
1050 current_location = 0;
1052 Location* session_range_location = 0;
1053 if (version < 3000) {
1054 session_range_location = new Location (_session, 0, 0, _("session"), Location::IsSessionRange);
1055 new_locations.push_back (session_range_location);
1059 Glib::Threads::Mutex::Lock lm (lock);
1061 XMLNodeConstIterator niter;
1062 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1066 XMLProperty const * prop_id = (*niter)->property ("id");
1068 PBD::ID id (prop_id->value ());
1070 LocationList::const_iterator i = locations.begin();
1071 while (i != locations.end () && (*i)->id() != id) {
1076 if (i != locations.end()) {
1077 /* we can re-use an old Location object */
1080 // changed locations will be updated by Locations::changed signal
1081 loc->set_state (**niter, version);
1083 loc = new Location (_session, **niter);
1088 if (version < 3000) {
1089 /* look for old-style IsStart / IsEnd properties in this location;
1090 if they are present, update the session_range_location accordingly
1092 XMLProperty const * prop = (*niter)->property ("flags");
1094 string v = prop->value ();
1096 string::size_type const c = v.find_first_of (',');
1097 string const s = v.substr (0, c);
1098 if (s == X_("IsStart")) {
1099 session_range_location->set_start (loc->start(), true);
1101 } else if (s == X_("IsEnd")) {
1102 session_range_location->set_end (loc->start(), true);
1106 if (c == string::npos) {
1110 v = v.substr (c + 1);
1116 new_locations.push_back (loc);
1120 catch (failed_constructor& err) {
1121 error << _("could not load location from session file - ignored") << endmsg;
1125 /* We may have some unused locations in the old list. */
1126 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
1127 LocationList::iterator tmp = i;
1130 LocationList::iterator n = new_locations.begin();
1133 while (n != new_locations.end ()) {
1134 if ((*i)->id() == (*n)->id()) {
1143 locations.erase (i);
1149 locations = new_locations;
1151 if (locations.size()) {
1152 current_location = locations.front();
1154 current_location = 0;
1158 changed (); /* EMIT SIGNAL */
1164 typedef std::pair<framepos_t,Location*> LocationPair;
1166 struct LocationStartEarlierComparison
1168 bool operator() (LocationPair a, LocationPair b) {
1169 return a.first < b.first;
1173 struct LocationStartLaterComparison
1175 bool operator() (LocationPair a, LocationPair b) {
1176 return a.first > b.first;
1181 Locations::first_mark_before (framepos_t frame, bool include_special_ranges)
1183 Glib::Threads::Mutex::Lock lm (lock);
1184 vector<LocationPair> locs;
1186 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1187 locs.push_back (make_pair ((*i)->start(), (*i)));
1188 if (!(*i)->is_mark()) {
1189 locs.push_back (make_pair ((*i)->end(), (*i)));
1193 LocationStartLaterComparison cmp;
1194 sort (locs.begin(), locs.end(), cmp);
1196 /* locs is sorted in ascending order */
1198 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1199 if ((*i).second->is_hidden()) {
1202 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1205 if ((*i).first < frame) {
1214 Locations::mark_at (framepos_t pos, framecnt_t slop) const
1216 Glib::Threads::Mutex::Lock lm (lock);
1217 Location* closest = 0;
1218 frameoffset_t mindelta = max_framepos;
1219 frameoffset_t delta;
1221 /* locations are not necessarily stored in linear time order so we have
1222 * to iterate across all of them to find the one closest to a give point.
1225 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1227 if ((*i)->is_mark()) {
1228 if (pos > (*i)->start()) {
1229 delta = pos - (*i)->start();
1231 delta = (*i)->start() - pos;
1234 if (slop == 0 && delta == 0) {
1235 /* special case: no slop, and direct hit for position */
1239 if (delta <= slop) {
1240 if (delta < mindelta) {
1252 Locations::first_mark_after (framepos_t frame, bool include_special_ranges)
1254 Glib::Threads::Mutex::Lock lm (lock);
1255 vector<LocationPair> locs;
1257 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1258 locs.push_back (make_pair ((*i)->start(), (*i)));
1259 if (!(*i)->is_mark()) {
1260 locs.push_back (make_pair ((*i)->end(), (*i)));
1264 LocationStartEarlierComparison cmp;
1265 sort (locs.begin(), locs.end(), cmp);
1267 /* locs is sorted in reverse order */
1269 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1270 if ((*i).second->is_hidden()) {
1273 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1276 if ((*i).first > frame) {
1284 /** Look for the `marks' (either locations which are marks, or start/end points of range markers) either
1285 * side of a frame. Note that if frame is exactly on a `mark', that mark will not be considered for returning
1287 * @param frame Frame to look for.
1288 * @param before Filled in with the position of the last `mark' before `frame' (or max_framepos if none exists)
1289 * @param after Filled in with the position of the next `mark' after `frame' (or max_framepos if none exists)
1292 Locations::marks_either_side (framepos_t const frame, framepos_t& before, framepos_t& after) const
1294 before = after = max_framepos;
1299 Glib::Threads::Mutex::Lock lm (lock);
1303 /* Get a list of positions; don't store any that are exactly on our requested position */
1305 std::list<framepos_t> positions;
1307 for (LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
1308 if (((*i)->is_auto_loop() || (*i)->is_auto_punch())) {
1312 if (!(*i)->is_hidden()) {
1313 if ((*i)->is_mark ()) {
1314 if ((*i)->start() != frame) {
1315 positions.push_back ((*i)->start ());
1318 if ((*i)->start() != frame) {
1319 positions.push_back ((*i)->start ());
1321 if ((*i)->end() != frame) {
1322 positions.push_back ((*i)->end ());
1328 if (positions.empty ()) {
1334 std::list<framepos_t>::iterator i = positions.begin ();
1335 while (i != positions.end () && *i < frame) {
1339 if (i == positions.end ()) {
1340 /* run out of marks */
1341 before = positions.back ();
1347 if (i == positions.begin ()) {
1357 Locations::session_range_location () const
1359 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1360 if ((*i)->is_session_range()) {
1361 return const_cast<Location*> (*i);
1368 Locations::auto_loop_location () const
1370 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1371 if ((*i)->is_auto_loop()) {
1372 return const_cast<Location*> (*i);
1379 Locations::auto_punch_location () const
1381 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1382 if ((*i)->is_auto_punch()) {
1383 return const_cast<Location*> (*i);
1390 Locations::num_range_markers () const
1393 Glib::Threads::Mutex::Lock lm (lock);
1394 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1395 if ((*i)->is_range_marker()) {
1403 Locations::get_location_by_id(PBD::ID id)
1405 LocationList::iterator it;
1406 for (it = locations.begin(); it != locations.end(); ++it)
1407 if (id == (*it)->id())
1414 Locations::find_all_between (framepos_t start, framepos_t end, LocationList& ll, Location::Flags flags)
1416 Glib::Threads::Mutex::Lock lm (lock);
1418 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1419 if ((flags == 0 || (*i)->matches (flags)) &&
1420 ((*i)->start() >= start && (*i)->end() < end)) {