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)) {
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;
996 if (loc->is_session_range()) {
1001 Glib::Threads::Mutex::Lock lm (lock);
1003 for (i = locations.begin(); i != locations.end(); ++i) {
1006 locations.erase (i);
1008 if (current_location == loc) {
1009 current_location = 0;
1019 removed (loc); /* EMIT SIGNAL */
1022 current_changed (0); /* EMIT SIGNAL */
1028 Locations::get_state ()
1030 XMLNode *node = new XMLNode ("Locations");
1031 LocationList::iterator iter;
1032 Glib::Threads::Mutex::Lock lm (lock);
1034 for (iter = locations.begin(); iter != locations.end(); ++iter) {
1035 node->add_child_nocopy ((*iter)->get_state ());
1042 Locations::set_state (const XMLNode& node, int version)
1044 if (node.name() != "Locations") {
1045 error << _("incorrect XML mode passed to Locations::set_state") << endmsg;
1049 XMLNodeList nlist = node.children();
1051 /* build up a new locations list in here */
1052 LocationList new_locations;
1054 current_location = 0;
1056 Location* session_range_location = 0;
1057 if (version < 3000) {
1058 session_range_location = new Location (_session, 0, 0, _("session"), Location::IsSessionRange);
1059 new_locations.push_back (session_range_location);
1063 Glib::Threads::Mutex::Lock lm (lock);
1065 XMLNodeConstIterator niter;
1066 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1070 XMLProperty const * prop_id = (*niter)->property ("id");
1072 PBD::ID id (prop_id->value ());
1074 LocationList::const_iterator i = locations.begin();
1075 while (i != locations.end () && (*i)->id() != id) {
1080 if (i != locations.end()) {
1081 /* we can re-use an old Location object */
1084 // changed locations will be updated by Locations::changed signal
1085 loc->set_state (**niter, version);
1087 loc = new Location (_session, **niter);
1092 if (version < 3000) {
1093 /* look for old-style IsStart / IsEnd properties in this location;
1094 if they are present, update the session_range_location accordingly
1096 XMLProperty const * prop = (*niter)->property ("flags");
1098 string v = prop->value ();
1100 string::size_type const c = v.find_first_of (',');
1101 string const s = v.substr (0, c);
1102 if (s == X_("IsStart")) {
1103 session_range_location->set_start (loc->start(), true);
1105 } else if (s == X_("IsEnd")) {
1106 session_range_location->set_end (loc->start(), true);
1110 if (c == string::npos) {
1114 v = v.substr (c + 1);
1120 new_locations.push_back (loc);
1124 catch (failed_constructor& err) {
1125 error << _("could not load location from session file - ignored") << endmsg;
1129 /* We may have some unused locations in the old list. */
1130 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
1131 LocationList::iterator tmp = i;
1134 LocationList::iterator n = new_locations.begin();
1137 while (n != new_locations.end ()) {
1138 if ((*i)->id() == (*n)->id()) {
1147 locations.erase (i);
1153 locations = new_locations;
1155 if (locations.size()) {
1156 current_location = locations.front();
1158 current_location = 0;
1162 changed (); /* EMIT SIGNAL */
1168 typedef std::pair<framepos_t,Location*> LocationPair;
1170 struct LocationStartEarlierComparison
1172 bool operator() (LocationPair a, LocationPair b) {
1173 return a.first < b.first;
1177 struct LocationStartLaterComparison
1179 bool operator() (LocationPair a, LocationPair b) {
1180 return a.first > b.first;
1185 Locations::first_mark_before (framepos_t frame, bool include_special_ranges)
1187 Glib::Threads::Mutex::Lock lm (lock);
1188 vector<LocationPair> locs;
1190 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1191 locs.push_back (make_pair ((*i)->start(), (*i)));
1192 if (!(*i)->is_mark()) {
1193 locs.push_back (make_pair ((*i)->end(), (*i)));
1197 LocationStartLaterComparison cmp;
1198 sort (locs.begin(), locs.end(), cmp);
1200 /* locs is sorted in ascending order */
1202 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1203 if ((*i).second->is_hidden()) {
1206 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1209 if ((*i).first < frame) {
1218 Locations::mark_at (framepos_t pos, framecnt_t slop) const
1220 Glib::Threads::Mutex::Lock lm (lock);
1221 Location* closest = 0;
1222 frameoffset_t mindelta = max_framepos;
1223 frameoffset_t delta;
1225 /* locations are not necessarily stored in linear time order so we have
1226 * to iterate across all of them to find the one closest to a give point.
1229 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1231 if ((*i)->is_mark()) {
1232 if (pos > (*i)->start()) {
1233 delta = pos - (*i)->start();
1235 delta = (*i)->start() - pos;
1238 if (slop == 0 && delta == 0) {
1239 /* special case: no slop, and direct hit for position */
1243 if (delta <= slop) {
1244 if (delta < mindelta) {
1256 Locations::first_mark_after (framepos_t frame, bool include_special_ranges)
1258 Glib::Threads::Mutex::Lock lm (lock);
1259 vector<LocationPair> locs;
1261 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1262 locs.push_back (make_pair ((*i)->start(), (*i)));
1263 if (!(*i)->is_mark()) {
1264 locs.push_back (make_pair ((*i)->end(), (*i)));
1268 LocationStartEarlierComparison cmp;
1269 sort (locs.begin(), locs.end(), cmp);
1271 /* locs is sorted in reverse order */
1273 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1274 if ((*i).second->is_hidden()) {
1277 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1280 if ((*i).first > frame) {
1288 /** Look for the `marks' (either locations which are marks, or start/end points of range markers) either
1289 * side of a frame. Note that if frame is exactly on a `mark', that mark will not be considered for returning
1291 * @param frame Frame to look for.
1292 * @param before Filled in with the position of the last `mark' before `frame' (or max_framepos if none exists)
1293 * @param after Filled in with the position of the next `mark' after `frame' (or max_framepos if none exists)
1296 Locations::marks_either_side (framepos_t const frame, framepos_t& before, framepos_t& after) const
1298 before = after = max_framepos;
1303 Glib::Threads::Mutex::Lock lm (lock);
1307 /* Get a list of positions; don't store any that are exactly on our requested position */
1309 std::list<framepos_t> positions;
1311 for (LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
1312 if (((*i)->is_auto_loop() || (*i)->is_auto_punch())) {
1316 if (!(*i)->is_hidden()) {
1317 if ((*i)->is_mark ()) {
1318 if ((*i)->start() != frame) {
1319 positions.push_back ((*i)->start ());
1322 if ((*i)->start() != frame) {
1323 positions.push_back ((*i)->start ());
1325 if ((*i)->end() != frame) {
1326 positions.push_back ((*i)->end ());
1332 if (positions.empty ()) {
1338 std::list<framepos_t>::iterator i = positions.begin ();
1339 while (i != positions.end () && *i < frame) {
1343 if (i == positions.end ()) {
1344 /* run out of marks */
1345 before = positions.back ();
1351 if (i == positions.begin ()) {
1361 Locations::session_range_location () const
1363 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1364 if ((*i)->is_session_range()) {
1365 return const_cast<Location*> (*i);
1372 Locations::auto_loop_location () const
1374 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1375 if ((*i)->is_auto_loop()) {
1376 return const_cast<Location*> (*i);
1383 Locations::auto_punch_location () const
1385 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1386 if ((*i)->is_auto_punch()) {
1387 return const_cast<Location*> (*i);
1394 Locations::num_range_markers () const
1397 Glib::Threads::Mutex::Lock lm (lock);
1398 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1399 if ((*i)->is_range_marker()) {
1407 Locations::get_location_by_id(PBD::ID id)
1409 LocationList::iterator it;
1410 for (it = locations.begin(); it != locations.end(); ++it)
1411 if (id == (*it)->id())
1418 Locations::find_all_between (framepos_t start, framepos_t end, LocationList& ll, Location::Flags flags)
1420 Glib::Threads::Mutex::Lock lm (lock);
1422 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1423 if ((flags == 0 || (*i)->matches (flags)) &&
1424 ((*i)->start() >= start && (*i)->end() < end)) {