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)
108 , _position_lock_style (AudioTime)
110 /* Note: _position_lock_style is initialised above in case set_state doesn't set it
111 (for 2.X session file compatibility).
114 if (set_state (node, Stateful::loading_state_version)) {
115 throw failed_constructor ();
118 assert (_start >= 0);
123 Location::operator== (const Location& other)
125 if (_name != other._name ||
126 _start != other._start ||
127 _end != other._end ||
128 _bbt_start != other._bbt_start ||
129 _bbt_end != other._bbt_end ||
130 _flags != other._flags ||
131 _position_lock_style != other._position_lock_style) {
138 Location::operator= (const Location& other)
140 if (this == &other) {
145 _start = other._start;
146 _bbt_start = other._bbt_start;
148 _bbt_end = other._bbt_end;
149 _flags = other._flags;
150 _position_lock_style = other._position_lock_style;
152 /* XXX need to copy scene change */
154 /* copy is not locked even if original was */
158 /* "changed" not emitted on purpose */
160 assert (_start >= 0);
166 /** Set location name
170 Location::set_name (const std::string& str)
174 name_changed (this); /* EMIT SIGNAL */
175 NameChanged (); /* EMIT SIGNAL */
178 /** Set start position.
179 * @param s New start.
180 * @param force true to force setting, even if the given new start is after the current end.
181 * @param allow_bbt_recompute True to recompute BBT start time from the new given start time.
184 Location::set_start (framepos_t s, bool force, bool allow_bbt_recompute)
195 if (((is_auto_punch() || is_auto_loop()) && s >= _end) || (!is_mark() && s > _end)) {
204 if (allow_bbt_recompute) {
205 recompute_bbt_from_frames ();
208 start_changed (this); /* EMIT SIGNAL */
209 StartChanged (); /* EMIT SIGNAL */
210 end_changed (this); /* EMIT SIGNAL */
211 EndChanged (); /* EMIT SIGNAL */
214 /* moving the start (position) of a marker with a scene change
215 requires an update in the Scene Changer.
219 scene_changed (); /* EMIT SIGNAL */
222 assert (_start >= 0);
227 /* range locations must exceed a minimum duration */
228 if (_end - s < Config->get_range_location_minimum()) {
235 framepos_t const old = _start;
238 if (allow_bbt_recompute) {
239 recompute_bbt_from_frames ();
241 start_changed (this); /* EMIT SIGNAL */
242 StartChanged (); /* EMIT SIGNAL */
244 if (is_session_range ()) {
245 Session::StartTimeChanged (old); /* EMIT SIGNAL */
246 AudioFileSource::set_header_position_offset (s);
250 assert (_start >= 0);
255 /** Set end position.
257 * @param force true to force setting, even if the given new end is before the current start.
258 * @param allow_bbt_recompute True to recompute BBT end time from the new given end time.
261 Location::set_end (framepos_t e, bool force, bool allow_bbt_recompute)
272 if (((is_auto_punch() || is_auto_loop()) && e <= _start) || e < _start) {
281 if (allow_bbt_recompute) {
282 recompute_bbt_from_frames ();
284 start_changed (this); /* EMIT SIGNAL */
285 StartChanged (); /* EMIT SIGNAL */
286 end_changed (this); /* EMIT SIGNAL */
287 EndChanged (); /* EMIT SIGNAL */
290 assert (_start >= 0);
295 /* range locations must exceed a minimum duration */
296 if (e - _start < Config->get_range_location_minimum()) {
303 framepos_t const old = _end;
306 if (allow_bbt_recompute) {
307 recompute_bbt_from_frames ();
310 end_changed(this); /* EMIT SIGNAL */
311 EndChanged(); /* EMIT SIGNAL */
313 if (is_session_range()) {
314 Session::EndTimeChanged (old); /* EMIT SIGNAL */
324 Location::set (framepos_t s, framepos_t e, bool allow_bbt_recompute)
326 if (s < 0 || e < 0) {
331 if (((is_auto_punch() || is_auto_loop()) && s >= e) || (!is_mark() && s > e)) {
335 bool start_change = false;
336 bool end_change = false;
344 if (allow_bbt_recompute) {
345 recompute_bbt_from_frames ();
352 assert (_start >= 0);
357 /* range locations must exceed a minimum duration */
358 if (e - s < Config->get_range_location_minimum()) {
364 framepos_t const old = _start;
367 if (allow_bbt_recompute) {
368 recompute_bbt_from_frames ();
373 if (is_session_range ()) {
374 Session::StartTimeChanged (old); /* EMIT SIGNAL */
375 AudioFileSource::set_header_position_offset (s);
382 framepos_t const old = _end;
385 if (allow_bbt_recompute) {
386 recompute_bbt_from_frames ();
391 if (is_session_range()) {
392 Session::EndTimeChanged (old); /* EMIT SIGNAL */
400 start_changed(this); /* EMIT SIGNAL */
401 StartChanged(); /* EMIT SIGNAL */
405 end_changed(this); /* EMIT SIGNAL */
406 EndChanged(); /* EMIT SIGNAL */
409 if (start_change && end_change) {
418 Location::move_to (framepos_t pos)
430 _end = _start + length();
431 recompute_bbt_from_frames ();
433 changed (this); /* EMIT SIGNAL */
434 Changed (); /* EMIT SIGNAL */
437 assert (_start >= 0);
444 Location::set_hidden (bool yn, void*)
446 if (set_flag_internal (yn, IsHidden)) {
447 flags_changed (this); /* EMIT SIGNAL */
453 Location::set_cd (bool yn, void*)
455 // XXX this really needs to be session start
456 // but its not available here - leave to GUI
458 if (yn && _start == 0) {
459 error << _("You cannot put a CD marker at this position") << endmsg;
463 if (set_flag_internal (yn, IsCDMarker)) {
464 flags_changed (this); /* EMIT SIGNAL */
470 Location::set_is_range_marker (bool yn, void*)
472 if (set_flag_internal (yn, IsRangeMarker)) {
473 flags_changed (this);
474 FlagsChanged (); /* EMIT SIGNAL */
479 Location::set_skip (bool yn)
481 if (is_range_marker() && length() > 0) {
482 if (set_flag_internal (yn, IsSkip)) {
483 flags_changed (this);
490 Location::set_skipping (bool yn)
492 if (is_range_marker() && is_skip() && length() > 0) {
493 if (set_flag_internal (yn, IsSkipping)) {
494 flags_changed (this);
501 Location::set_auto_punch (bool yn, void*)
503 if (is_mark() || _start == _end) {
507 if (set_flag_internal (yn, IsAutoPunch)) {
508 flags_changed (this); /* EMIT SIGNAL */
509 FlagsChanged (); /* EMIT SIGNAL */
514 Location::set_auto_loop (bool yn, void*)
516 if (is_mark() || _start == _end) {
520 if (set_flag_internal (yn, IsAutoLoop)) {
521 flags_changed (this); /* EMIT SIGNAL */
522 FlagsChanged (); /* EMIT SIGNAL */
527 Location::set_flag_internal (bool yn, Flags flag)
530 if (!(_flags & flag)) {
531 _flags = Flags (_flags | flag);
536 _flags = Flags (_flags & ~flag);
544 Location::set_mark (bool yn)
546 /* This function is private, and so does not emit signals */
548 if (_start != _end) {
552 set_flag_internal (yn, IsMark);
557 Location::cd_info_node(const string & name, const string & value)
559 XMLNode* root = new XMLNode("CD-Info");
561 root->add_property("name", name);
562 root->add_property("value", value);
569 Location::get_state ()
571 XMLNode *node = new XMLNode ("Location");
574 typedef map<string, string>::const_iterator CI;
576 for(CI m = cd_info.begin(); m != cd_info.end(); ++m){
577 node->add_child_nocopy(cd_info_node(m->first, m->second));
580 id().print (buf, sizeof (buf));
581 node->add_property("id", buf);
582 node->add_property ("name", name());
583 snprintf (buf, sizeof (buf), "%" PRId64, start());
584 node->add_property ("start", buf);
585 snprintf (buf, sizeof (buf), "%" PRId64, end());
586 node->add_property ("end", buf);
587 node->add_property ("flags", enum_2_string (_flags));
588 node->add_property ("locked", (_locked ? "yes" : "no"));
589 node->add_property ("position-lock-style", enum_2_string (_position_lock_style));
592 node->add_child_nocopy (_scene_change->get_state());
599 Location::set_state (const XMLNode& node, int version)
601 const XMLProperty *prop;
603 XMLNodeList cd_list = node.children();
604 XMLNodeConstIterator cd_iter;
610 if (node.name() != "Location") {
611 error << _("incorrect XML node passed to Location::set_state") << endmsg;
615 if (!set_id (node)) {
616 warning << _("XML node for Location has no ID information") << endmsg;
619 if ((prop = node.property ("name")) == 0) {
620 error << _("XML node for Location has no name information") << endmsg;
624 set_name (prop->value());
626 if ((prop = node.property ("start")) == 0) {
627 error << _("XML node for Location has no start information") << endmsg;
631 /* can't use set_start() here, because _end
632 may make the value of _start illegal.
635 sscanf (prop->value().c_str(), "%" PRId64, &_start);
637 if ((prop = node.property ("end")) == 0) {
638 error << _("XML node for Location has no end information") << endmsg;
642 sscanf (prop->value().c_str(), "%" PRId64, &_end);
644 if ((prop = node.property ("flags")) == 0) {
645 error << _("XML node for Location has no flags information") << endmsg;
649 Flags old_flags (_flags);
650 _flags = Flags (string_2_enum (prop->value(), _flags));
652 if (old_flags != _flags) {
656 if ((prop = node.property ("locked")) != 0) {
657 _locked = string_is_affirmative (prop->value());
662 for (cd_iter = cd_list.begin(); cd_iter != cd_list.end(); ++cd_iter) {
666 if (cd_node->name() != "CD-Info") {
670 if ((prop = cd_node->property ("name")) != 0) {
671 cd_name = prop->value();
673 throw failed_constructor ();
676 if ((prop = cd_node->property ("value")) != 0) {
677 cd_value = prop->value();
679 throw failed_constructor ();
683 cd_info[cd_name] = cd_value;
686 if ((prop = node.property ("position-lock-style")) != 0) {
687 _position_lock_style = PositionLockStyle (string_2_enum (prop->value(), _position_lock_style));
690 XMLNode* scene_child = find_named_node (node, SceneChange::xml_node_name);
693 _scene_change = SceneChange::factory (*scene_child, version);
696 recompute_bbt_from_frames ();
698 changed (this); /* EMIT SIGNAL */
699 Changed (); /* EMIT SIGNAL */
701 assert (_start >= 0);
708 Location::set_position_lock_style (PositionLockStyle ps)
710 if (_position_lock_style == ps) {
714 _position_lock_style = ps;
716 recompute_bbt_from_frames ();
718 position_lock_style_changed (this); /* EMIT SIGNAL */
719 PositionLockStyleChanged (); /* EMIT SIGNAL */
723 Location::recompute_bbt_from_frames ()
725 if (_position_lock_style != MusicTime) {
729 _session.bbt_time (_start, _bbt_start);
730 _session.bbt_time (_end, _bbt_end);
734 Location::recompute_frames_from_bbt ()
736 if (_position_lock_style != MusicTime) {
740 TempoMap& map (_session.tempo_map());
741 set (map.frame_time (_bbt_start), map.frame_time (_bbt_end), false);
761 Location::set_scene_change (boost::shared_ptr<SceneChange> sc)
763 if (_scene_change != sc) {
765 _session.set_dirty ();
767 scene_changed (); /* EMIT SIGNAL */
768 SceneChangeChanged (); /* EMIT SIGNAL */
772 /*---------------------------------------------------------------------- */
774 Locations::Locations (Session& s)
775 : SessionHandleRef (s)
777 current_location = 0;
780 Locations::~Locations ()
782 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
783 LocationList::iterator tmp = i;
791 Locations::set_current (Location *loc, bool want_lock)
796 Glib::Threads::Mutex::Lock lm (lock);
797 ret = set_current_unlocked (loc);
799 ret = set_current_unlocked (loc);
803 current_changed (current_location); /* EMIT SIGNAL */
809 Locations::next_available_name(string& result,string base)
811 LocationList::iterator i;
815 std::map<uint32_t,bool> taken;
823 /* find all existing names that match "base", and store
824 the numeric part of them (if any) in the map "taken"
827 for (i = locations.begin(); i != locations.end(); ++i) {
829 const string& temp ((*i)->name());
831 if (!temp.find (base,0)) {
832 /* grab what comes after the "base" as if it was
833 a number, and assuming that works OK,
834 store it in "taken" so that we know it
837 if ((suffix = atoi (temp.substr(l))) != 0) {
838 taken.insert (make_pair (suffix,true));
844 /* Now search for an un-used suffix to add to "base". This
845 will find "holes" in the numbering sequence when a location
848 This must start at 1, both for human-numbering reasons
849 and also because the call to atoi() above would return
850 zero if there is no recognizable numeric suffix, causing
851 "base 0" not to be inserted into the "taken" map.
856 while (n < UINT32_MAX) {
857 if (taken.find (n) == taken.end()) {
858 snprintf (buf, sizeof(buf), "%d", n);
869 Locations::set_current_unlocked (Location *loc)
871 if (find (locations.begin(), locations.end(), loc) == locations.end()) {
872 error << _("Locations: attempt to use unknown location as selected location") << endmsg;
876 current_location = loc;
884 Glib::Threads::Mutex::Lock lm (lock);
886 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
888 LocationList::iterator tmp = i;
891 if (!(*i)->is_session_range()) {
899 current_location = 0;
902 changed (); /* EMIT SIGNAL */
903 current_changed (0); /* EMIT SIGNAL */
907 Locations::clear_markers ()
910 Glib::Threads::Mutex::Lock lm (lock);
911 LocationList::iterator tmp;
913 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
917 if ((*i)->is_mark() && !(*i)->is_session_range()) {
926 changed (); /* EMIT SIGNAL */
930 Locations::clear_ranges ()
933 Glib::Threads::Mutex::Lock lm (lock);
934 LocationList::iterator tmp;
936 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
941 /* We do not remove these ranges as part of this
945 if ((*i)->is_auto_punch() ||
946 (*i)->is_auto_loop() ||
947 (*i)->is_session_range()) {
952 if (!(*i)->is_mark()) {
961 current_location = 0;
965 current_changed (0); /* EMIT SIGNAL */
969 Locations::add (Location *loc, bool make_current)
974 Glib::Threads::Mutex::Lock lm (lock);
975 locations.push_back (loc);
978 current_location = loc;
982 added (loc); /* EMIT SIGNAL */
985 current_changed (current_location); /* EMIT SIGNAL */
988 if (loc->is_session_range()) {
989 Session::StartTimeChanged (0);
990 Session::EndTimeChanged (1);
995 Locations::remove (Location *loc)
997 bool was_removed = false;
998 bool was_current = false;
999 LocationList::iterator i;
1001 if (loc->is_session_range()) {
1006 Glib::Threads::Mutex::Lock lm (lock);
1008 for (i = locations.begin(); i != locations.end(); ++i) {
1011 locations.erase (i);
1013 if (current_location == loc) {
1014 current_location = 0;
1024 removed (loc); /* EMIT SIGNAL */
1027 current_changed (0); /* EMIT SIGNAL */
1033 Locations::get_state ()
1035 XMLNode *node = new XMLNode ("Locations");
1036 LocationList::iterator iter;
1037 Glib::Threads::Mutex::Lock lm (lock);
1039 for (iter = locations.begin(); iter != locations.end(); ++iter) {
1040 node->add_child_nocopy ((*iter)->get_state ());
1047 Locations::set_state (const XMLNode& node, int version)
1049 if (node.name() != "Locations") {
1050 error << _("incorrect XML mode passed to Locations::set_state") << endmsg;
1054 XMLNodeList nlist = node.children();
1056 /* build up a new locations list in here */
1057 LocationList new_locations;
1059 current_location = 0;
1061 Location* session_range_location = 0;
1062 if (version < 3000) {
1063 session_range_location = new Location (_session, 0, 0, _("session"), Location::IsSessionRange);
1064 new_locations.push_back (session_range_location);
1068 Glib::Threads::Mutex::Lock lm (lock);
1070 XMLNodeConstIterator niter;
1071 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1075 XMLProperty const * prop_id = (*niter)->property ("id");
1077 PBD::ID id (prop_id->value ());
1079 LocationList::const_iterator i = locations.begin();
1080 while (i != locations.end () && (*i)->id() != id) {
1085 if (i != locations.end()) {
1086 /* we can re-use an old Location object */
1089 // changed locations will be updated by Locations::changed signal
1090 loc->set_state (**niter, version);
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 /* We may have some unused locations in the old list. */
1135 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
1136 LocationList::iterator tmp = i;
1139 LocationList::iterator n = new_locations.begin();
1142 while (n != new_locations.end ()) {
1143 if ((*i)->id() == (*n)->id()) {
1152 locations.erase (i);
1158 locations = new_locations;
1160 if (locations.size()) {
1161 current_location = locations.front();
1163 current_location = 0;
1167 changed (); /* EMIT SIGNAL */
1173 typedef std::pair<framepos_t,Location*> LocationPair;
1175 struct LocationStartEarlierComparison
1177 bool operator() (LocationPair a, LocationPair b) {
1178 return a.first < b.first;
1182 struct LocationStartLaterComparison
1184 bool operator() (LocationPair a, LocationPair b) {
1185 return a.first > b.first;
1190 Locations::first_mark_before (framepos_t frame, bool include_special_ranges)
1192 Glib::Threads::Mutex::Lock lm (lock);
1193 vector<LocationPair> locs;
1195 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1196 locs.push_back (make_pair ((*i)->start(), (*i)));
1197 if (!(*i)->is_mark()) {
1198 locs.push_back (make_pair ((*i)->end(), (*i)));
1202 LocationStartLaterComparison cmp;
1203 sort (locs.begin(), locs.end(), cmp);
1205 /* locs is sorted in ascending order */
1207 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1208 if ((*i).second->is_hidden()) {
1211 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1214 if ((*i).first < frame) {
1223 Locations::mark_at (framepos_t pos, framecnt_t slop) const
1225 Glib::Threads::Mutex::Lock lm (lock);
1226 Location* closest = 0;
1227 frameoffset_t mindelta = max_framepos;
1228 frameoffset_t delta;
1230 /* locations are not necessarily stored in linear time order so we have
1231 * to iterate across all of them to find the one closest to a give point.
1234 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1236 if ((*i)->is_mark()) {
1237 if (pos > (*i)->start()) {
1238 delta = pos - (*i)->start();
1240 delta = (*i)->start() - pos;
1243 if (slop == 0 && delta == 0) {
1244 /* special case: no slop, and direct hit for position */
1248 if (delta <= slop) {
1249 if (delta < mindelta) {
1261 Locations::first_mark_after (framepos_t frame, bool include_special_ranges)
1263 Glib::Threads::Mutex::Lock lm (lock);
1264 vector<LocationPair> locs;
1266 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1267 locs.push_back (make_pair ((*i)->start(), (*i)));
1268 if (!(*i)->is_mark()) {
1269 locs.push_back (make_pair ((*i)->end(), (*i)));
1273 LocationStartEarlierComparison cmp;
1274 sort (locs.begin(), locs.end(), cmp);
1276 /* locs is sorted in reverse order */
1278 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1279 if ((*i).second->is_hidden()) {
1282 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1285 if ((*i).first > frame) {
1293 /** Look for the `marks' (either locations which are marks, or start/end points of range markers) either
1294 * side of a frame. Note that if frame is exactly on a `mark', that mark will not be considered for returning
1296 * @param frame Frame to look for.
1297 * @param before Filled in with the position of the last `mark' before `frame' (or max_framepos if none exists)
1298 * @param after Filled in with the position of the next `mark' after `frame' (or max_framepos if none exists)
1301 Locations::marks_either_side (framepos_t const frame, framepos_t& before, framepos_t& after) const
1303 before = after = max_framepos;
1308 Glib::Threads::Mutex::Lock lm (lock);
1312 /* Get a list of positions; don't store any that are exactly on our requested position */
1314 std::list<framepos_t> positions;
1316 for (LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
1317 if (((*i)->is_auto_loop() || (*i)->is_auto_punch())) {
1321 if (!(*i)->is_hidden()) {
1322 if ((*i)->is_mark ()) {
1323 if ((*i)->start() != frame) {
1324 positions.push_back ((*i)->start ());
1327 if ((*i)->start() != frame) {
1328 positions.push_back ((*i)->start ());
1330 if ((*i)->end() != frame) {
1331 positions.push_back ((*i)->end ());
1337 if (positions.empty ()) {
1343 std::list<framepos_t>::iterator i = positions.begin ();
1344 while (i != positions.end () && *i < frame) {
1348 if (i == positions.end ()) {
1349 /* run out of marks */
1350 before = positions.back ();
1356 if (i == positions.begin ()) {
1366 Locations::session_range_location () const
1368 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1369 if ((*i)->is_session_range()) {
1370 return const_cast<Location*> (*i);
1377 Locations::auto_loop_location () const
1379 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1380 if ((*i)->is_auto_loop()) {
1381 return const_cast<Location*> (*i);
1388 Locations::auto_punch_location () const
1390 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1391 if ((*i)->is_auto_punch()) {
1392 return const_cast<Location*> (*i);
1399 Locations::num_range_markers () const
1402 Glib::Threads::Mutex::Lock lm (lock);
1403 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1404 if ((*i)->is_range_marker()) {
1412 Locations::get_location_by_id(PBD::ID id)
1414 LocationList::iterator it;
1415 for (it = locations.begin(); it != locations.end(); ++it)
1416 if (id == (*it)->id())
1423 Locations::find_all_between (framepos_t start, framepos_t end, LocationList& ll, Location::Flags flags)
1425 Glib::Threads::Mutex::Lock lm (lock);
1427 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1428 if ((flags == 0 || (*i)->matches (flags)) &&
1429 ((*i)->start() >= start && (*i)->end() < end)) {