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/types_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"
38 #include "ardour/types_convert.h"
43 DEFINE_ENUM_CONVERT(ARDOUR::Location::Flags);
47 using namespace ARDOUR;
50 PBD::Signal0<void> Location::scene_changed;
51 PBD::Signal1<void,Location*> Location::name_changed;
52 PBD::Signal1<void,Location*> Location::end_changed;
53 PBD::Signal1<void,Location*> Location::start_changed;
54 PBD::Signal1<void,Location*> Location::flags_changed;
55 PBD::Signal1<void,Location*> Location::lock_changed;
56 PBD::Signal1<void,Location*> Location::position_lock_style_changed;
57 PBD::Signal1<void,Location*> Location::changed;
59 Location::Location (Session& s)
60 : SessionHandleRef (s)
67 , _position_lock_style (AudioTime)
73 /** Construct a new Location, giving it the position lock style determined by glue-new-markers-to-bars-and-beats */
74 Location::Location (Session& s, framepos_t sample_start, framepos_t sample_end, const std::string &name, Flags bits, const uint32_t sub_num)
75 : SessionHandleRef (s)
77 , _start (sample_start)
81 , _position_lock_style (s.config.get_glue_new_markers_to_bars_and_beats() ? MusicTime : AudioTime)
84 recompute_beat_from_frames (sub_num);
90 Location::Location (const Location& other)
91 : SessionHandleRef (other._session)
92 , StatefulDestructible()
94 , _start (other._start)
95 , _start_beat (other._start_beat)
97 , _end_beat (other._end_beat)
98 , _flags (other._flags)
99 , _position_lock_style (other._position_lock_style)
102 /* copy is not locked even if original was */
106 assert (_start >= 0);
109 /* scene change is NOT COPIED */
112 Location::Location (Session& s, const XMLNode& node)
113 : SessionHandleRef (s)
115 , _position_lock_style (AudioTime)
117 /* Note: _position_lock_style is initialised above in case set_state doesn't set it
118 (for 2.X session file compatibility).
121 if (set_state (node, Stateful::loading_state_version)) {
122 throw failed_constructor ();
125 assert (_start >= 0);
130 Location::operator== (const Location& other)
132 if (_name != other._name ||
133 _start != other._start ||
134 _end != other._end ||
135 _start_beat != other._start_beat ||
136 _end_beat != other._end_beat ||
137 _flags != other._flags ||
138 _position_lock_style != other._position_lock_style) {
145 Location::operator= (const Location& other)
147 if (this == &other) {
152 _start = other._start;
153 _start_beat = other._start_beat;
155 _end_beat = other._end_beat;
156 _flags = other._flags;
157 _position_lock_style = other._position_lock_style;
159 /* XXX need to copy scene change */
161 /* copy is not locked even if original was */
165 /* "changed" not emitted on purpose */
167 assert (_start >= 0);
173 /** Set location name
177 Location::set_name (const std::string& str)
181 name_changed (this); /* EMIT SIGNAL */
182 NameChanged (); /* EMIT SIGNAL */
185 /** Set start position.
186 * @param s New start.
187 * @param force true to force setting, even if the given new start is after the current end.
188 * @param allow_beat_recompute True to recompute BEAT start time from the new given start time.
191 Location::set_start (framepos_t s, bool force, bool allow_beat_recompute, const uint32_t sub_num)
202 if (((is_auto_punch() || is_auto_loop()) && s >= _end) || (!is_mark() && s > _end)) {
211 if (allow_beat_recompute) {
212 recompute_beat_from_frames (sub_num);
215 start_changed (this); /* EMIT SIGNAL */
216 StartChanged (); /* EMIT SIGNAL */
217 //end_changed (this); /* EMIT SIGNAL */
218 //EndChanged (); /* EMIT SIGNAL */
221 /* moving the start (position) of a marker with a scene change
222 requires an update in the Scene Changer.
226 scene_changed (); /* EMIT SIGNAL */
229 assert (_start >= 0);
234 /* range locations must exceed a minimum duration */
235 if (_end - s < Config->get_range_location_minimum()) {
242 framepos_t const old = _start;
245 if (allow_beat_recompute) {
246 recompute_beat_from_frames (sub_num);
248 start_changed (this); /* EMIT SIGNAL */
249 StartChanged (); /* EMIT SIGNAL */
251 if (is_session_range ()) {
252 Session::StartTimeChanged (old); /* EMIT SIGNAL */
253 AudioFileSource::set_header_position_offset (s);
257 assert (_start >= 0);
262 /** Set end position.
264 * @param force true to force setting, even if the given new end is before the current start.
265 * @param allow_beat_recompute True to recompute BEAT end time from the new given end time.
268 Location::set_end (framepos_t e, bool force, bool allow_beat_recompute, const uint32_t sub_num)
279 if (((is_auto_punch() || is_auto_loop()) && e <= _start) || e < _start) {
288 if (allow_beat_recompute) {
289 recompute_beat_from_frames (sub_num);
291 //start_changed (this); /* EMIT SIGNAL */
292 //StartChanged (); /* EMIT SIGNAL */
293 end_changed (this); /* EMIT SIGNAL */
294 EndChanged (); /* EMIT SIGNAL */
297 assert (_start >= 0);
302 /* range locations must exceed a minimum duration */
303 if (e - _start < Config->get_range_location_minimum()) {
310 framepos_t const old = _end;
313 if (allow_beat_recompute) {
314 recompute_beat_from_frames (sub_num);
317 end_changed(this); /* EMIT SIGNAL */
318 EndChanged(); /* EMIT SIGNAL */
320 if (is_session_range()) {
321 Session::EndTimeChanged (old); /* EMIT SIGNAL */
331 Location::set (framepos_t s, framepos_t e, bool allow_beat_recompute, const uint32_t sub_num)
333 if (s < 0 || e < 0) {
338 if (((is_auto_punch() || is_auto_loop()) && s >= e) || (!is_mark() && s > e)) {
342 bool start_change = false;
343 bool end_change = false;
351 if (allow_beat_recompute) {
352 recompute_beat_from_frames (sub_num);
359 assert (_start >= 0);
364 /* range locations must exceed a minimum duration */
365 if (e - s < Config->get_range_location_minimum()) {
371 framepos_t const old = _start;
374 if (allow_beat_recompute) {
375 recompute_beat_from_frames (sub_num);
380 if (is_session_range ()) {
381 Session::StartTimeChanged (old); /* EMIT SIGNAL */
382 AudioFileSource::set_header_position_offset (s);
389 framepos_t const old = _end;
392 if (allow_beat_recompute) {
393 recompute_beat_from_frames (sub_num);
398 if (is_session_range()) {
399 Session::EndTimeChanged (old); /* EMIT SIGNAL */
406 if (start_change && end_change) {
409 } else if (start_change) {
410 start_changed(this); /* EMIT SIGNAL */
411 StartChanged(); /* EMIT SIGNAL */
412 } else if (end_change) {
413 end_changed(this); /* EMIT SIGNAL */
414 EndChanged(); /* EMIT SIGNAL */
421 Location::move_to (framepos_t pos, const uint32_t sub_num)
433 _end = _start + length();
434 recompute_beat_from_frames (sub_num);
436 changed (this); /* EMIT SIGNAL */
437 Changed (); /* EMIT SIGNAL */
440 assert (_start >= 0);
447 Location::set_hidden (bool yn, void*)
449 if (set_flag_internal (yn, IsHidden)) {
450 flags_changed (this); /* EMIT SIGNAL */
456 Location::set_cd (bool yn, void*)
458 // XXX this really needs to be session start
459 // but its not available here - leave to GUI
461 if (yn && _start == 0) {
462 error << _("You cannot put a CD marker at this position") << endmsg;
466 if (set_flag_internal (yn, IsCDMarker)) {
467 flags_changed (this); /* EMIT SIGNAL */
473 Location::set_is_range_marker (bool yn, void*)
475 if (set_flag_internal (yn, IsRangeMarker)) {
476 flags_changed (this);
477 FlagsChanged (); /* EMIT SIGNAL */
482 Location::set_skip (bool yn)
484 if (is_range_marker() && length() > 0) {
485 if (set_flag_internal (yn, IsSkip)) {
486 flags_changed (this);
493 Location::set_skipping (bool yn)
495 if (is_range_marker() && is_skip() && length() > 0) {
496 if (set_flag_internal (yn, IsSkipping)) {
497 flags_changed (this);
504 Location::set_auto_punch (bool yn, void*)
506 if (is_mark() || _start == _end) {
510 if (set_flag_internal (yn, IsAutoPunch)) {
511 flags_changed (this); /* EMIT SIGNAL */
512 FlagsChanged (); /* EMIT SIGNAL */
517 Location::set_auto_loop (bool yn, void*)
519 if (is_mark() || _start == _end) {
523 if (set_flag_internal (yn, IsAutoLoop)) {
524 flags_changed (this); /* EMIT SIGNAL */
525 FlagsChanged (); /* EMIT SIGNAL */
530 Location::set_flag_internal (bool yn, Flags flag)
533 if (!(_flags & flag)) {
534 _flags = Flags (_flags | flag);
539 _flags = Flags (_flags & ~flag);
547 Location::set_mark (bool yn)
549 /* This function is private, and so does not emit signals */
551 if (_start != _end) {
555 set_flag_internal (yn, IsMark);
560 Location::cd_info_node(const string & name, const string & value)
562 XMLNode* root = new XMLNode("CD-Info");
564 root->set_property("name", name);
565 root->set_property("value", value);
572 Location::get_state ()
574 XMLNode *node = new XMLNode ("Location");
576 typedef map<string, string>::const_iterator CI;
578 for(CI m = cd_info.begin(); m != cd_info.end(); ++m){
579 node->add_child_nocopy(cd_info_node(m->first, m->second));
582 node->set_property ("id", id ());
583 node->set_property ("name", name());
584 node->set_property ("start", start());
585 node->set_property ("end", end());
586 if (position_lock_style() == MusicTime) {
587 node->set_property ("start-beat", _start_beat);
588 node->set_property ("end-beat", _end_beat);
590 node->set_property ("flags", _flags);
591 node->set_property ("locked", _locked);
592 node->set_property ("position-lock-style", _position_lock_style);
595 node->add_child_nocopy (_scene_change->get_state());
602 Location::set_state (const XMLNode& node, int version)
604 XMLNodeList cd_list = node.children();
605 XMLNodeConstIterator cd_iter;
611 if (node.name() != "Location") {
612 error << _("incorrect XML node passed to Location::set_state") << endmsg;
616 if (!set_id (node)) {
617 warning << _("XML node for Location has no ID information") << endmsg;
621 if (!node.get_property ("name", str)) {
622 error << _("XML node for Location has no name information") << endmsg;
628 /* can't use set_start() here, because _end
629 may make the value of _start illegal.
632 if (!node.get_property ("start", _start)) {
633 error << _("XML node for Location has no start information") << endmsg;
637 if (!node.get_property ("end", _end)) {
638 error << _("XML node for Location has no end information") << endmsg;
642 Flags old_flags (_flags);
644 if (!node.get_property ("flags", _flags)) {
645 error << _("XML node for Location has no flags information") << endmsg;
649 if (old_flags != _flags) {
653 if (!node.get_property ("locked", _locked)) {
657 for (cd_iter = cd_list.begin(); cd_iter != cd_list.end(); ++cd_iter) {
661 if (cd_node->name() != "CD-Info") {
665 if (!cd_node->get_property ("name", cd_name)) {
666 throw failed_constructor ();
669 if (!cd_node->get_property ("value", cd_value)) {
670 throw failed_constructor ();
673 cd_info[cd_name] = cd_value;
676 node.get_property ("position-lock-style", _position_lock_style);
678 XMLNode* scene_child = find_named_node (node, SceneChange::xml_node_name);
681 _scene_change = SceneChange::factory (*scene_child, version);
684 if (position_lock_style() == AudioTime) {
685 recompute_beat_from_frames (0);
688 if (!node.get_property ("start-beat", _start_beat) ||
689 !node.get_property ("end-beat", _end_beat)) {
690 recompute_beat_from_frames (0);
695 changed (this); /* EMIT SIGNAL */
696 Changed (); /* EMIT SIGNAL */
698 assert (_start >= 0);
705 Location::set_position_lock_style (PositionLockStyle ps)
707 if (_position_lock_style == ps) {
711 _position_lock_style = ps;
713 if (ps == MusicTime) {
714 recompute_beat_from_frames (0);
717 position_lock_style_changed (this); /* EMIT SIGNAL */
718 PositionLockStyleChanged (); /* EMIT SIGNAL */
722 Location::recompute_beat_from_frames (const uint32_t sub_num)
724 _start_beat = _session.tempo_map().exact_beat_at_frame (_start, sub_num);
725 _end_beat = _session.tempo_map().exact_beat_at_frame (_end, sub_num);
729 Location::recompute_frames_from_beat ()
731 if (_position_lock_style != MusicTime) {
735 TempoMap& map (_session.tempo_map());
736 set (map.frame_at_beat (_start_beat), map.frame_at_beat (_end_beat), false);
756 Location::set_scene_change (boost::shared_ptr<SceneChange> sc)
758 if (_scene_change != sc) {
760 _session.set_dirty ();
762 scene_changed (); /* EMIT SIGNAL */
763 SceneChangeChanged (); /* 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)) {
827 /* grab what comes after the "base" as if it was
828 a number, and assuming that works OK,
829 store it in "taken" so that we know it
832 if ((suffix = atoi (temp.substr(l))) != 0) {
833 taken.insert (make_pair (suffix,true));
839 /* Now search for an un-used suffix to add to "base". This
840 will find "holes" in the numbering sequence when a location
843 This must start at 1, both for human-numbering reasons
844 and also because the call to atoi() above would return
845 zero if there is no recognizable numeric suffix, causing
846 "base 0" not to be inserted into the "taken" map.
851 while (n < UINT32_MAX) {
852 if (taken.find (n) == taken.end()) {
853 snprintf (buf, sizeof(buf), "%d", n);
864 Locations::set_current_unlocked (Location *loc)
866 if (find (locations.begin(), locations.end(), loc) == locations.end()) {
867 error << _("Locations: attempt to use unknown location as selected location") << endmsg;
871 current_location = loc;
879 Glib::Threads::Mutex::Lock lm (lock);
881 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
883 LocationList::iterator tmp = i;
886 if (!(*i)->is_session_range()) {
894 current_location = 0;
897 changed (); /* EMIT SIGNAL */
898 current_changed (0); /* EMIT SIGNAL */
902 Locations::clear_markers ()
905 Glib::Threads::Mutex::Lock lm (lock);
906 LocationList::iterator tmp;
908 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
912 if ((*i)->is_mark() && !(*i)->is_session_range()) {
921 changed (); /* EMIT SIGNAL */
925 Locations::clear_ranges ()
928 Glib::Threads::Mutex::Lock lm (lock);
929 LocationList::iterator tmp;
931 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
936 /* We do not remove these ranges as part of this
940 if ((*i)->is_auto_punch() ||
941 (*i)->is_auto_loop() ||
942 (*i)->is_session_range()) {
947 if (!(*i)->is_mark()) {
956 current_location = 0;
960 current_changed (0); /* EMIT SIGNAL */
964 Locations::add (Location *loc, bool make_current)
969 Glib::Threads::Mutex::Lock lm (lock);
970 locations.push_back (loc);
973 current_location = loc;
977 added (loc); /* EMIT SIGNAL */
980 current_changed (current_location); /* EMIT SIGNAL */
983 if (loc->is_session_range()) {
984 Session::StartTimeChanged (0);
985 Session::EndTimeChanged (1);
990 Locations::remove (Location *loc)
992 bool was_removed = false;
993 bool was_current = false;
994 LocationList::iterator i;
1000 if (loc->is_session_range()) {
1005 Glib::Threads::Mutex::Lock lm (lock);
1007 for (i = locations.begin(); i != locations.end(); ++i) {
1009 bool was_loop = (*i)->is_auto_loop();
1011 locations.erase (i);
1013 if (current_location == loc) {
1014 current_location = 0;
1018 if (_session.get_play_loop()) {
1019 _session.request_play_loop (false, false);
1021 _session.auto_loop_location_changed (0);
1030 removed (loc); /* EMIT SIGNAL */
1033 current_changed (0); /* EMIT SIGNAL */
1039 Locations::get_state ()
1041 XMLNode *node = new XMLNode ("Locations");
1042 LocationList::iterator iter;
1043 Glib::Threads::Mutex::Lock lm (lock);
1045 for (iter = locations.begin(); iter != locations.end(); ++iter) {
1046 node->add_child_nocopy ((*iter)->get_state ());
1053 Locations::set_state (const XMLNode& node, int version)
1055 if (node.name() != "Locations") {
1056 error << _("incorrect XML mode passed to Locations::set_state") << endmsg;
1060 XMLNodeList nlist = node.children();
1062 /* build up a new locations list in here */
1063 LocationList new_locations;
1065 current_location = 0;
1067 Location* session_range_location = 0;
1068 if (version < 3000) {
1069 session_range_location = new Location (_session, 0, 0, _("session"), Location::IsSessionRange, 0);
1070 new_locations.push_back (session_range_location);
1074 Glib::Threads::Mutex::Lock lm (lock);
1076 XMLNodeConstIterator niter;
1077 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1081 XMLProperty const * prop_id = (*niter)->property ("id");
1083 PBD::ID id (prop_id->value ());
1085 LocationList::const_iterator i = locations.begin();
1086 while (i != locations.end () && (*i)->id() != id) {
1091 if (i != locations.end()) {
1092 /* we can re-use an old Location object */
1095 // changed locations will be updated by Locations::changed signal
1096 loc->set_state (**niter, version);
1098 loc = new Location (_session, **niter);
1103 if (version < 3000) {
1104 /* look for old-style IsStart / IsEnd properties in this location;
1105 if they are present, update the session_range_location accordingly
1107 XMLProperty const * prop = (*niter)->property ("flags");
1109 string v = prop->value ();
1111 string::size_type const c = v.find_first_of (',');
1112 string const s = v.substr (0, c);
1113 if (s == X_("IsStart")) {
1114 session_range_location->set_start (loc->start(), true);
1116 } else if (s == X_("IsEnd")) {
1117 session_range_location->set_end (loc->start(), true);
1121 if (c == string::npos) {
1125 v = v.substr (c + 1);
1131 new_locations.push_back (loc);
1135 catch (failed_constructor& err) {
1136 error << _("could not load location from session file - ignored") << endmsg;
1140 /* We may have some unused locations in the old list. */
1141 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
1142 LocationList::iterator tmp = i;
1145 LocationList::iterator n = new_locations.begin();
1148 while (n != new_locations.end ()) {
1149 if ((*i)->id() == (*n)->id()) {
1158 locations.erase (i);
1164 locations = new_locations;
1166 if (locations.size()) {
1167 current_location = locations.front();
1169 current_location = 0;
1173 changed (); /* EMIT SIGNAL */
1179 typedef std::pair<framepos_t,Location*> LocationPair;
1181 struct LocationStartEarlierComparison
1183 bool operator() (LocationPair a, LocationPair b) {
1184 return a.first < b.first;
1188 struct LocationStartLaterComparison
1190 bool operator() (LocationPair a, LocationPair b) {
1191 return a.first > b.first;
1196 Locations::first_mark_before (framepos_t frame, bool include_special_ranges)
1198 Glib::Threads::Mutex::Lock lm (lock);
1199 vector<LocationPair> locs;
1201 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1202 locs.push_back (make_pair ((*i)->start(), (*i)));
1203 if (!(*i)->is_mark()) {
1204 locs.push_back (make_pair ((*i)->end(), (*i)));
1208 LocationStartLaterComparison cmp;
1209 sort (locs.begin(), locs.end(), cmp);
1211 /* locs is sorted in ascending order */
1213 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1214 if ((*i).second->is_hidden()) {
1217 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1220 if ((*i).first < frame) {
1229 Locations::mark_at (framepos_t pos, framecnt_t slop) const
1231 Glib::Threads::Mutex::Lock lm (lock);
1232 Location* closest = 0;
1233 frameoffset_t mindelta = max_framepos;
1234 frameoffset_t delta;
1236 /* locations are not necessarily stored in linear time order so we have
1237 * to iterate across all of them to find the one closest to a give point.
1240 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1242 if ((*i)->is_mark()) {
1243 if (pos > (*i)->start()) {
1244 delta = pos - (*i)->start();
1246 delta = (*i)->start() - pos;
1249 if (slop == 0 && delta == 0) {
1250 /* special case: no slop, and direct hit for position */
1254 if (delta <= slop) {
1255 if (delta < mindelta) {
1267 Locations::first_mark_after (framepos_t frame, bool include_special_ranges)
1269 Glib::Threads::Mutex::Lock lm (lock);
1270 vector<LocationPair> locs;
1272 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1273 locs.push_back (make_pair ((*i)->start(), (*i)));
1274 if (!(*i)->is_mark()) {
1275 locs.push_back (make_pair ((*i)->end(), (*i)));
1279 LocationStartEarlierComparison cmp;
1280 sort (locs.begin(), locs.end(), cmp);
1282 /* locs is sorted in reverse order */
1284 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1285 if ((*i).second->is_hidden()) {
1288 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1291 if ((*i).first > frame) {
1299 /** Look for the `marks' (either locations which are marks, or start/end points of range markers) either
1300 * side of a frame. Note that if frame is exactly on a `mark', that mark will not be considered for returning
1302 * @param frame Frame to look for.
1303 * @param before Filled in with the position of the last `mark' before `frame' (or max_framepos if none exists)
1304 * @param after Filled in with the position of the next `mark' after `frame' (or max_framepos if none exists)
1307 Locations::marks_either_side (framepos_t const frame, framepos_t& before, framepos_t& after) const
1309 before = after = max_framepos;
1314 Glib::Threads::Mutex::Lock lm (lock);
1318 /* Get a list of positions; don't store any that are exactly on our requested position */
1320 std::list<framepos_t> positions;
1322 for (LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
1323 if (((*i)->is_auto_loop() || (*i)->is_auto_punch())) {
1327 if (!(*i)->is_hidden()) {
1328 if ((*i)->is_mark ()) {
1329 if ((*i)->start() != frame) {
1330 positions.push_back ((*i)->start ());
1333 if ((*i)->start() != frame) {
1334 positions.push_back ((*i)->start ());
1336 if ((*i)->end() != frame) {
1337 positions.push_back ((*i)->end ());
1343 if (positions.empty ()) {
1349 std::list<framepos_t>::iterator i = positions.begin ();
1350 while (i != positions.end () && *i < frame) {
1354 if (i == positions.end ()) {
1355 /* run out of marks */
1356 before = positions.back ();
1362 if (i == positions.begin ()) {
1372 Locations::session_range_location () const
1374 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1375 if ((*i)->is_session_range()) {
1376 return const_cast<Location*> (*i);
1383 Locations::auto_loop_location () const
1385 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1386 if ((*i)->is_auto_loop()) {
1387 return const_cast<Location*> (*i);
1394 Locations::auto_punch_location () const
1396 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1397 if ((*i)->is_auto_punch()) {
1398 return const_cast<Location*> (*i);
1405 Locations::num_range_markers () const
1408 Glib::Threads::Mutex::Lock lm (lock);
1409 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1410 if ((*i)->is_range_marker()) {
1418 Locations::get_location_by_id(PBD::ID id)
1420 LocationList::iterator it;
1421 for (it = locations.begin(); it != locations.end(); ++it)
1422 if (id == (*it)->id())
1429 Locations::find_all_between (framepos_t start, framepos_t end, LocationList& ll, Location::Flags flags)
1431 Glib::Threads::Mutex::Lock lm (lock);
1433 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1434 if ((flags == 0 || (*i)->matches (flags)) &&
1435 ((*i)->start() >= start && (*i)->end() < end)) {