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)
76 recompute_bbt_from_frames ();
82 Location::Location (const Location& other)
83 : SessionHandleRef (other._session)
84 , StatefulDestructible()
86 , _start (other._start)
87 , _bbt_start (other._bbt_start)
89 , _bbt_end (other._bbt_end)
90 , _flags (other._flags)
91 , _position_lock_style (other._position_lock_style)
93 /* copy is not locked even if original was */
100 /* scene change is NOT COPIED */
103 Location::Location (Session& s, const XMLNode& node)
104 : SessionHandleRef (s)
105 , _position_lock_style (AudioTime)
107 /* Note: _position_lock_style is initialised above in case set_state doesn't set it
108 (for 2.X session file compatibility).
111 if (set_state (node, Stateful::loading_state_version)) {
112 throw failed_constructor ();
115 assert (_start >= 0);
120 Location::operator== (const Location& other)
122 if (_name != other._name ||
123 _start != other._start ||
124 _end != other._end ||
125 _bbt_start != other._bbt_start ||
126 _bbt_end != other._bbt_end ||
127 _flags != other._flags ||
128 _position_lock_style != other._position_lock_style) {
135 Location::operator= (const Location& other)
137 if (this == &other) {
142 _start = other._start;
143 _bbt_start = other._bbt_start;
145 _bbt_end = other._bbt_end;
146 _flags = other._flags;
147 _position_lock_style = other._position_lock_style;
149 /* XXX need to copy scene change */
151 /* copy is not locked even if original was */
155 /* "changed" not emitted on purpose */
157 assert (_start >= 0);
163 /** Set location name
167 Location::set_name (const std::string& str)
171 name_changed (this); /* EMIT SIGNAL */
172 NameChanged (); /* EMIT SIGNAL */
175 /** Set start position.
176 * @param s New start.
177 * @param force true to force setting, even if the given new start is after the current end.
178 * @param allow_bbt_recompute True to recompute BBT start time from the new given start time.
181 Location::set_start (framepos_t s, bool force, bool allow_bbt_recompute)
192 if (((is_auto_punch() || is_auto_loop()) && s >= _end) || (!is_mark() && s > _end)) {
201 if (allow_bbt_recompute) {
202 recompute_bbt_from_frames ();
205 start_changed (this); /* EMIT SIGNAL */
206 StartChanged (); /* EMIT SIGNAL */
207 end_changed (this); /* EMIT SIGNAL */
208 EndChanged (); /* EMIT SIGNAL */
211 /* moving the start (position) of a marker with a scene change
212 requires an update in the Scene Changer.
216 scene_changed (); /* EMIT SIGNAL */
219 assert (_start >= 0);
227 framepos_t const old = _start;
230 if (allow_bbt_recompute) {
231 recompute_bbt_from_frames ();
233 start_changed (this); /* EMIT SIGNAL */
234 StartChanged (); /* EMIT SIGNAL */
236 if (is_session_range ()) {
237 Session::StartTimeChanged (old); /* EMIT SIGNAL */
238 AudioFileSource::set_header_position_offset (s);
242 assert (_start >= 0);
247 /** Set end position.
249 * @param force true to force setting, even if the given new start is after the current end.
250 * @param allow_bbt_recompute True to recompute BBT end time from the new given end time.
253 Location::set_end (framepos_t e, bool force, bool allow_bbt_recompute)
264 if (((is_auto_punch() || is_auto_loop()) && e <= _start) || e < _start) {
273 if (allow_bbt_recompute) {
274 recompute_bbt_from_frames ();
276 start_changed (this); /* EMIT SIGNAL */
277 StartChanged (); /* EMIT SIGNAL */
278 end_changed (this); /* EMIT SIGNAL */
279 EndChanged (); /* EMIT SIGNAL */
282 assert (_start >= 0);
290 framepos_t const old = _end;
293 if (allow_bbt_recompute) {
294 recompute_bbt_from_frames ();
297 end_changed(this); /* EMIT SIGNAL */
298 EndChanged(); /* EMIT SIGNAL */
300 if (is_session_range()) {
301 Session::EndTimeChanged (old); /* EMIT SIGNAL */
311 Location::set (framepos_t s, framepos_t e, bool allow_bbt_recompute)
313 if (s < 0 || e < 0) {
318 if (((is_auto_punch() || is_auto_loop()) && s >= e) || (!is_mark() && s > e)) {
322 bool start_change = false;
323 bool end_change = false;
331 if (allow_bbt_recompute) {
332 recompute_bbt_from_frames ();
339 assert (_start >= 0);
346 framepos_t const old = _start;
349 if (allow_bbt_recompute) {
350 recompute_bbt_from_frames ();
355 if (is_session_range ()) {
356 Session::StartTimeChanged (old); /* EMIT SIGNAL */
357 AudioFileSource::set_header_position_offset (s);
364 framepos_t const old = _end;
367 if (allow_bbt_recompute) {
368 recompute_bbt_from_frames ();
373 if (is_session_range()) {
374 Session::EndTimeChanged (old); /* EMIT SIGNAL */
382 start_changed(this); /* EMIT SIGNAL */
383 StartChanged(); /* EMIT SIGNAL */
387 end_changed(this); /* EMIT SIGNAL */
388 EndChanged(); /* EMIT SIGNAL */
391 if (start_change && end_change) {
400 Location::move_to (framepos_t pos)
412 _end = _start + length();
413 recompute_bbt_from_frames ();
415 changed (this); /* EMIT SIGNAL */
416 Changed (); /* EMIT SIGNAL */
419 assert (_start >= 0);
426 Location::set_hidden (bool yn, void*)
428 if (set_flag_internal (yn, IsHidden)) {
429 flags_changed (this); /* EMIT SIGNAL */
435 Location::set_cd (bool yn, void*)
437 // XXX this really needs to be session start
438 // but its not available here - leave to GUI
440 if (yn && _start == 0) {
441 error << _("You cannot put a CD marker at this position") << endmsg;
445 if (set_flag_internal (yn, IsCDMarker)) {
446 flags_changed (this); /* EMIT SIGNAL */
452 Location::set_is_range_marker (bool yn, void*)
454 if (set_flag_internal (yn, IsRangeMarker)) {
455 flags_changed (this);
456 FlagsChanged (); /* EMIT SIGNAL */
461 Location::set_skip (bool yn)
463 if (is_range_marker() && length() > 0) {
464 if (set_flag_internal (yn, IsSkip)) {
465 flags_changed (this);
472 Location::set_skipping (bool yn)
474 if (is_range_marker() && is_skip() && length() > 0) {
475 if (set_flag_internal (yn, IsSkipping)) {
476 flags_changed (this);
483 Location::set_auto_punch (bool yn, void*)
485 if (is_mark() || _start == _end) {
489 if (set_flag_internal (yn, IsAutoPunch)) {
490 flags_changed (this); /* EMIT SIGNAL */
491 FlagsChanged (); /* EMIT SIGNAL */
496 Location::set_auto_loop (bool yn, void*)
498 if (is_mark() || _start == _end) {
502 if (set_flag_internal (yn, IsAutoLoop)) {
503 flags_changed (this); /* EMIT SIGNAL */
504 FlagsChanged (); /* EMIT SIGNAL */
509 Location::set_flag_internal (bool yn, Flags flag)
512 if (!(_flags & flag)) {
513 _flags = Flags (_flags | flag);
518 _flags = Flags (_flags & ~flag);
526 Location::set_mark (bool yn)
528 /* This function is private, and so does not emit signals */
530 if (_start != _end) {
534 set_flag_internal (yn, IsMark);
539 Location::cd_info_node(const string & name, const string & value)
541 XMLNode* root = new XMLNode("CD-Info");
543 root->add_property("name", name);
544 root->add_property("value", value);
551 Location::get_state ()
553 XMLNode *node = new XMLNode ("Location");
556 typedef map<string, string>::const_iterator CI;
558 for(CI m = cd_info.begin(); m != cd_info.end(); ++m){
559 node->add_child_nocopy(cd_info_node(m->first, m->second));
562 id().print (buf, sizeof (buf));
563 node->add_property("id", buf);
564 node->add_property ("name", name());
565 snprintf (buf, sizeof (buf), "%" PRId64, start());
566 node->add_property ("start", buf);
567 snprintf (buf, sizeof (buf), "%" PRId64, end());
568 node->add_property ("end", buf);
569 node->add_property ("flags", enum_2_string (_flags));
570 node->add_property ("locked", (_locked ? "yes" : "no"));
571 node->add_property ("position-lock-style", enum_2_string (_position_lock_style));
574 node->add_child_nocopy (_scene_change->get_state());
581 Location::set_state (const XMLNode& node, int version)
583 const XMLProperty *prop;
585 XMLNodeList cd_list = node.children();
586 XMLNodeConstIterator cd_iter;
592 if (node.name() != "Location") {
593 error << _("incorrect XML node passed to Location::set_state") << endmsg;
597 if (!set_id (node)) {
598 warning << _("XML node for Location has no ID information") << endmsg;
601 if ((prop = node.property ("name")) == 0) {
602 error << _("XML node for Location has no name information") << endmsg;
606 set_name (prop->value());
608 if ((prop = node.property ("start")) == 0) {
609 error << _("XML node for Location has no start information") << endmsg;
613 /* can't use set_start() here, because _end
614 may make the value of _start illegal.
617 sscanf (prop->value().c_str(), "%" PRId64, &_start);
619 if ((prop = node.property ("end")) == 0) {
620 error << _("XML node for Location has no end information") << endmsg;
624 sscanf (prop->value().c_str(), "%" PRId64, &_end);
626 if ((prop = node.property ("flags")) == 0) {
627 error << _("XML node for Location has no flags information") << endmsg;
631 _flags = Flags (string_2_enum (prop->value(), _flags));
633 if ((prop = node.property ("locked")) != 0) {
634 _locked = string_is_affirmative (prop->value());
639 for (cd_iter = cd_list.begin(); cd_iter != cd_list.end(); ++cd_iter) {
643 if (cd_node->name() != "CD-Info") {
647 if ((prop = cd_node->property ("name")) != 0) {
648 cd_name = prop->value();
650 throw failed_constructor ();
653 if ((prop = cd_node->property ("value")) != 0) {
654 cd_value = prop->value();
656 throw failed_constructor ();
660 cd_info[cd_name] = cd_value;
663 if ((prop = node.property ("position-lock-style")) != 0) {
664 _position_lock_style = PositionLockStyle (string_2_enum (prop->value(), _position_lock_style));
667 XMLNode* scene_child = find_named_node (node, SceneChange::xml_node_name);
670 _scene_change = SceneChange::factory (*scene_child, version);
673 recompute_bbt_from_frames ();
675 changed (this); /* EMIT SIGNAL */
676 Changed (); /* EMIT SIGNAL */
678 assert (_start >= 0);
685 Location::set_position_lock_style (PositionLockStyle ps)
687 if (_position_lock_style == ps) {
691 _position_lock_style = ps;
693 recompute_bbt_from_frames ();
695 position_lock_style_changed (this); /* EMIT SIGNAL */
696 PositionLockStyleChanged (); /* EMIT SIGNAL */
700 Location::recompute_bbt_from_frames ()
702 if (_position_lock_style != MusicTime) {
706 _session.bbt_time (_start, _bbt_start);
707 _session.bbt_time (_end, _bbt_end);
711 Location::recompute_frames_from_bbt ()
713 if (_position_lock_style != MusicTime) {
717 TempoMap& map (_session.tempo_map());
718 set (map.frame_time (_bbt_start), map.frame_time (_bbt_end), false);
738 Location::set_scene_change (boost::shared_ptr<SceneChange> sc)
742 scene_changed (); /* EMIT SIGNAL */
745 /*---------------------------------------------------------------------- */
747 Locations::Locations (Session& s)
748 : SessionHandleRef (s)
750 current_location = 0;
753 Locations::~Locations ()
755 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
756 LocationList::iterator tmp = i;
764 Locations::set_current (Location *loc, bool want_lock)
769 Glib::Threads::Mutex::Lock lm (lock);
770 ret = set_current_unlocked (loc);
772 ret = set_current_unlocked (loc);
776 current_changed (current_location); /* EMIT SIGNAL */
782 Locations::next_available_name(string& result,string base)
784 LocationList::iterator i;
788 std::map<uint32_t,bool> taken;
796 /* find all existing names that match "base", and store
797 the numeric part of them (if any) in the map "taken"
800 for (i = locations.begin(); i != locations.end(); ++i) {
802 const string& temp ((*i)->name());
804 if (!temp.find (base,0)) {
806 if ((suffix = atoi (temp.substr(l,3))) != 0) {
807 taken.insert (make_pair (suffix,true));
813 /* Now search for an un-used suffix to add to "base". This
814 will find "holes" in the numbering sequence when a location
817 This must start at 1, both for human-numbering reasons
818 and also because the call to atoi() above would return
819 zero if there is no recognizable numeric suffix, causing
820 "base 0" not to be inserted into the "taken" map.
825 while (n < UINT32_MAX) {
826 if (taken.find (n) == taken.end()) {
827 snprintf (buf, sizeof(buf), "%d", n);
838 Locations::set_current_unlocked (Location *loc)
840 if (find (locations.begin(), locations.end(), loc) == locations.end()) {
841 error << _("Locations: attempt to use unknown location as selected location") << endmsg;
845 current_location = loc;
853 Glib::Threads::Mutex::Lock lm (lock);
855 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
857 LocationList::iterator tmp = i;
860 if (!(*i)->is_session_range()) {
868 current_location = 0;
871 changed (); /* EMIT SIGNAL */
872 current_changed (0); /* EMIT SIGNAL */
876 Locations::clear_markers ()
879 Glib::Threads::Mutex::Lock lm (lock);
880 LocationList::iterator tmp;
882 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
886 if ((*i)->is_mark() && !(*i)->is_session_range()) {
895 changed (); /* EMIT SIGNAL */
899 Locations::clear_ranges ()
902 Glib::Threads::Mutex::Lock lm (lock);
903 LocationList::iterator tmp;
905 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
910 /* We do not remove these ranges as part of this
914 if ((*i)->is_auto_punch() ||
915 (*i)->is_auto_loop() ||
916 (*i)->is_session_range()) {
921 if (!(*i)->is_mark()) {
930 current_location = 0;
934 current_changed (0); /* EMIT SIGNAL */
938 Locations::add (Location *loc, bool make_current)
943 Glib::Threads::Mutex::Lock lm (lock);
944 locations.push_back (loc);
947 current_location = loc;
951 added (loc); /* EMIT SIGNAL */
954 current_changed (current_location); /* EMIT SIGNAL */
957 if (loc->is_session_range()) {
958 Session::StartTimeChanged (0);
959 Session::EndTimeChanged (1);
964 Locations::remove (Location *loc)
966 bool was_removed = false;
967 bool was_current = false;
968 LocationList::iterator i;
970 if (loc->is_session_range()) {
975 Glib::Threads::Mutex::Lock lm (lock);
977 for (i = locations.begin(); i != locations.end(); ++i) {
982 if (current_location == loc) {
983 current_location = 0;
993 removed (loc); /* EMIT SIGNAL */
996 current_changed (0); /* EMIT SIGNAL */
1002 Locations::get_state ()
1004 XMLNode *node = new XMLNode ("Locations");
1005 LocationList::iterator iter;
1006 Glib::Threads::Mutex::Lock lm (lock);
1008 for (iter = locations.begin(); iter != locations.end(); ++iter) {
1009 node->add_child_nocopy ((*iter)->get_state ());
1016 Locations::set_state (const XMLNode& node, int version)
1018 if (node.name() != "Locations") {
1019 error << _("incorrect XML mode passed to Locations::set_state") << endmsg;
1023 XMLNodeList nlist = node.children();
1025 /* build up a new locations list in here */
1026 LocationList new_locations;
1028 current_location = 0;
1030 Location* session_range_location = 0;
1031 if (version < 3000) {
1032 session_range_location = new Location (_session, 0, 0, _("session"), Location::IsSessionRange);
1033 new_locations.push_back (session_range_location);
1037 Glib::Threads::Mutex::Lock lm (lock);
1039 XMLNodeConstIterator niter;
1040 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1044 XMLProperty const * prop_id = (*niter)->property ("id");
1046 PBD::ID id (prop_id->value ());
1048 LocationList::const_iterator i = locations.begin();
1049 while (i != locations.end () && (*i)->id() != id) {
1054 if (i != locations.end()) {
1055 /* we can re-use an old Location object */
1057 loc->set_state (**niter, version);
1059 loc = new Location (_session, **niter);
1064 if (version < 3000) {
1065 /* look for old-style IsStart / IsEnd properties in this location;
1066 if they are present, update the session_range_location accordingly
1068 XMLProperty const * prop = (*niter)->property ("flags");
1070 string v = prop->value ();
1072 string::size_type const c = v.find_first_of (',');
1073 string const s = v.substr (0, c);
1074 if (s == X_("IsStart")) {
1075 session_range_location->set_start (loc->start(), true);
1077 } else if (s == X_("IsEnd")) {
1078 session_range_location->set_end (loc->start(), true);
1082 if (c == string::npos) {
1086 v = v.substr (c + 1);
1092 new_locations.push_back (loc);
1096 catch (failed_constructor& err) {
1097 error << _("could not load location from session file - ignored") << endmsg;
1101 locations = new_locations;
1103 if (locations.size()) {
1104 current_location = locations.front();
1106 current_location = 0;
1110 changed (); /* EMIT SIGNAL */
1116 typedef std::pair<framepos_t,Location*> LocationPair;
1118 struct LocationStartEarlierComparison
1120 bool operator() (LocationPair a, LocationPair b) {
1121 return a.first < b.first;
1125 struct LocationStartLaterComparison
1127 bool operator() (LocationPair a, LocationPair b) {
1128 return a.first > b.first;
1133 Locations::first_mark_before (framepos_t frame, bool include_special_ranges)
1135 Glib::Threads::Mutex::Lock lm (lock);
1136 vector<LocationPair> locs;
1138 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1139 locs.push_back (make_pair ((*i)->start(), (*i)));
1140 if (!(*i)->is_mark()) {
1141 locs.push_back (make_pair ((*i)->end(), (*i)));
1145 LocationStartLaterComparison cmp;
1146 sort (locs.begin(), locs.end(), cmp);
1148 /* locs is sorted in ascending order */
1150 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1151 if ((*i).second->is_hidden()) {
1154 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1157 if ((*i).first < frame) {
1166 Locations::mark_at (framepos_t pos, framecnt_t slop) const
1168 Glib::Threads::Mutex::Lock lm (lock);
1169 Location* closest = 0;
1170 frameoffset_t mindelta = max_framepos;
1171 frameoffset_t delta;
1173 /* locations are not necessarily stored in linear time order so we have
1174 * to iterate across all of them to find the one closest to a give point.
1177 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1179 if ((*i)->is_mark()) {
1180 if (pos > (*i)->start()) {
1181 delta = pos - (*i)->start();
1183 delta = (*i)->start() - pos;
1186 if (slop == 0 && delta == 0) {
1187 /* special case: no slop, and direct hit for position */
1191 if (delta <= slop) {
1192 if (delta < mindelta) {
1204 Locations::first_mark_after (framepos_t frame, bool include_special_ranges)
1206 Glib::Threads::Mutex::Lock lm (lock);
1207 vector<LocationPair> locs;
1209 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1210 locs.push_back (make_pair ((*i)->start(), (*i)));
1211 if (!(*i)->is_mark()) {
1212 locs.push_back (make_pair ((*i)->end(), (*i)));
1216 LocationStartEarlierComparison cmp;
1217 sort (locs.begin(), locs.end(), cmp);
1219 /* locs is sorted in reverse order */
1221 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1222 if ((*i).second->is_hidden()) {
1225 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1228 if ((*i).first > frame) {
1236 /** Look for the `marks' (either locations which are marks, or start/end points of range markers) either
1237 * side of a frame. Note that if frame is exactly on a `mark', that mark will not be considered for returning
1239 * @param frame Frame to look for.
1240 * @param before Filled in with the position of the last `mark' before `frame' (or max_framepos if none exists)
1241 * @param after Filled in with the position of the next `mark' after `frame' (or max_framepos if none exists)
1244 Locations::marks_either_side (framepos_t const frame, framepos_t& before, framepos_t& after) const
1246 before = after = max_framepos;
1251 Glib::Threads::Mutex::Lock lm (lock);
1255 /* Get a list of positions; don't store any that are exactly on our requested position */
1257 std::list<framepos_t> positions;
1259 for (LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
1260 if (((*i)->is_auto_loop() || (*i)->is_auto_punch())) {
1264 if (!(*i)->is_hidden()) {
1265 if ((*i)->is_mark ()) {
1266 if ((*i)->start() != frame) {
1267 positions.push_back ((*i)->start ());
1270 if ((*i)->start() != frame) {
1271 positions.push_back ((*i)->start ());
1273 if ((*i)->end() != frame) {
1274 positions.push_back ((*i)->end ());
1280 if (positions.empty ()) {
1286 std::list<framepos_t>::iterator i = positions.begin ();
1287 while (i != positions.end () && *i < frame) {
1291 if (i == positions.end ()) {
1292 /* run out of marks */
1293 before = positions.back ();
1299 if (i == positions.begin ()) {
1309 Locations::session_range_location () const
1311 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1312 if ((*i)->is_session_range()) {
1313 return const_cast<Location*> (*i);
1320 Locations::auto_loop_location () const
1322 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1323 if ((*i)->is_auto_loop()) {
1324 return const_cast<Location*> (*i);
1331 Locations::auto_punch_location () const
1333 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1334 if ((*i)->is_auto_punch()) {
1335 return const_cast<Location*> (*i);
1342 Locations::num_range_markers () const
1345 Glib::Threads::Mutex::Lock lm (lock);
1346 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1347 if ((*i)->is_range_marker()) {
1355 Locations::get_location_by_id(PBD::ID id)
1357 LocationList::iterator it;
1358 for (it = locations.begin(); it != locations.end(); ++it)
1359 if (id == (*it)->id())
1366 Locations::find_all_between (framepos_t start, framepos_t end, LocationList& ll, Location::Flags flags)
1368 Glib::Threads::Mutex::Lock lm (lock);
1370 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1371 if ((flags == 0 || (*i)->matches (flags)) &&
1372 ((*i)->start() >= start && (*i)->end() < end)) {