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)
61 , _block_change_notifications (false)
67 /** Construct a new Location, giving it the position lock style determined by glue-new-markers-to-bars-and-beats */
68 Location::Location (Session& s, framepos_t sample_start, framepos_t sample_end, const std::string &name, Flags bits)
69 : SessionHandleRef (s)
71 , _start (sample_start)
75 , _position_lock_style (s.config.get_glue_new_markers_to_bars_and_beats() ? MusicTime : AudioTime)
76 , _block_change_notifications (false)
78 recompute_bbt_from_frames ();
84 Location::Location (const Location& other)
85 : SessionHandleRef (other._session)
86 , StatefulDestructible()
88 , _start (other._start)
89 , _bbt_start (other._bbt_start)
91 , _bbt_end (other._bbt_end)
92 , _flags (other._flags)
93 , _position_lock_style (other._position_lock_style)
94 , _block_change_notifications (false)
96 /* copy is not locked even if original was */
100 assert (_start >= 0);
103 /* scene change is NOT COPIED */
106 Location::Location (Session& s, const XMLNode& node)
107 : 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) {
412 if (!_block_change_notifications) {
421 Location::move_to (framepos_t pos)
433 _end = _start + length();
434 recompute_bbt_from_frames ();
436 changed (this); /* EMIT SIGNAL */
438 if (!_block_change_notifications) {
439 Changed (); /* EMIT SIGNAL */
443 assert (_start >= 0);
450 Location::set_hidden (bool yn, void*)
452 if (set_flag_internal (yn, IsHidden)) {
453 flags_changed (this); /* EMIT SIGNAL */
459 Location::set_cd (bool yn, void*)
461 // XXX this really needs to be session start
462 // but its not available here - leave to GUI
464 if (yn && _start == 0) {
465 error << _("You cannot put a CD marker at this position") << endmsg;
469 if (set_flag_internal (yn, IsCDMarker)) {
470 flags_changed (this); /* EMIT SIGNAL */
476 Location::set_is_range_marker (bool yn, void*)
478 if (set_flag_internal (yn, IsRangeMarker)) {
479 flags_changed (this);
480 FlagsChanged (); /* EMIT SIGNAL */
485 Location::set_skip (bool yn)
487 if (is_range_marker() && length() > 0) {
488 if (set_flag_internal (yn, IsSkip)) {
489 flags_changed (this);
496 Location::set_skipping (bool yn)
498 if (is_range_marker() && is_skip() && length() > 0) {
499 if (set_flag_internal (yn, IsSkipping)) {
500 flags_changed (this);
507 Location::set_auto_punch (bool yn, void*)
509 if (is_mark() || _start == _end) {
513 if (set_flag_internal (yn, IsAutoPunch)) {
514 flags_changed (this); /* EMIT SIGNAL */
515 FlagsChanged (); /* EMIT SIGNAL */
520 Location::set_auto_loop (bool yn, void*)
522 if (is_mark() || _start == _end) {
526 if (set_flag_internal (yn, IsAutoLoop)) {
527 flags_changed (this); /* EMIT SIGNAL */
528 FlagsChanged (); /* EMIT SIGNAL */
533 Location::set_flag_internal (bool yn, Flags flag)
536 if (!(_flags & flag)) {
537 _flags = Flags (_flags | flag);
542 _flags = Flags (_flags & ~flag);
550 Location::set_mark (bool yn)
552 /* This function is private, and so does not emit signals */
554 if (_start != _end) {
558 set_flag_internal (yn, IsMark);
563 Location::cd_info_node(const string & name, const string & value)
565 XMLNode* root = new XMLNode("CD-Info");
567 root->add_property("name", name);
568 root->add_property("value", value);
575 Location::get_state ()
577 XMLNode *node = new XMLNode ("Location");
580 typedef map<string, string>::const_iterator CI;
582 for(CI m = cd_info.begin(); m != cd_info.end(); ++m){
583 node->add_child_nocopy(cd_info_node(m->first, m->second));
586 id().print (buf, sizeof (buf));
587 node->add_property("id", buf);
588 node->add_property ("name", name());
589 snprintf (buf, sizeof (buf), "%" PRId64, start());
590 node->add_property ("start", buf);
591 snprintf (buf, sizeof (buf), "%" PRId64, end());
592 node->add_property ("end", buf);
593 node->add_property ("flags", enum_2_string (_flags));
594 node->add_property ("locked", (_locked ? "yes" : "no"));
595 node->add_property ("position-lock-style", enum_2_string (_position_lock_style));
598 node->add_child_nocopy (_scene_change->get_state());
605 Location::set_state (const XMLNode& node, int version)
607 const XMLProperty *prop;
609 XMLNodeList cd_list = node.children();
610 XMLNodeConstIterator cd_iter;
616 if (node.name() != "Location") {
617 error << _("incorrect XML node passed to Location::set_state") << endmsg;
621 if (!set_id (node)) {
622 warning << _("XML node for Location has no ID information") << endmsg;
625 if ((prop = node.property ("name")) == 0) {
626 error << _("XML node for Location has no name information") << endmsg;
630 set_name (prop->value());
632 if ((prop = node.property ("start")) == 0) {
633 error << _("XML node for Location has no start information") << endmsg;
637 /* can't use set_start() here, because _end
638 may make the value of _start illegal.
641 sscanf (prop->value().c_str(), "%" PRId64, &_start);
643 if ((prop = node.property ("end")) == 0) {
644 error << _("XML node for Location has no end information") << endmsg;
648 sscanf (prop->value().c_str(), "%" PRId64, &_end);
650 if ((prop = node.property ("flags")) == 0) {
651 error << _("XML node for Location has no flags information") << endmsg;
655 _flags = Flags (string_2_enum (prop->value(), _flags));
657 if ((prop = node.property ("locked")) != 0) {
658 _locked = string_is_affirmative (prop->value());
663 for (cd_iter = cd_list.begin(); cd_iter != cd_list.end(); ++cd_iter) {
667 if (cd_node->name() != "CD-Info") {
671 if ((prop = cd_node->property ("name")) != 0) {
672 cd_name = prop->value();
674 throw failed_constructor ();
677 if ((prop = cd_node->property ("value")) != 0) {
678 cd_value = prop->value();
680 throw failed_constructor ();
684 cd_info[cd_name] = cd_value;
687 if ((prop = node.property ("position-lock-style")) != 0) {
688 _position_lock_style = PositionLockStyle (string_2_enum (prop->value(), _position_lock_style));
691 XMLNode* scene_child = find_named_node (node, SceneChange::xml_node_name);
694 _scene_change = SceneChange::factory (*scene_child, version);
697 recompute_bbt_from_frames ();
699 changed (this); /* EMIT SIGNAL */
701 if (!_block_change_notifications) {
702 Changed (); /* EMIT SIGNAL */
705 assert (_start >= 0);
712 Location::set_position_lock_style (PositionLockStyle ps)
714 if (_position_lock_style == ps) {
718 _position_lock_style = ps;
720 recompute_bbt_from_frames ();
722 position_lock_style_changed (this); /* EMIT SIGNAL */
723 PositionLockStyleChanged (); /* EMIT SIGNAL */
727 Location::recompute_bbt_from_frames ()
729 if (_position_lock_style != MusicTime) {
733 _session.bbt_time (_start, _bbt_start);
734 _session.bbt_time (_end, _bbt_end);
738 Location::recompute_frames_from_bbt ()
740 if (_position_lock_style != MusicTime) {
744 TempoMap& map (_session.tempo_map());
745 set (map.frame_time (_bbt_start), map.frame_time (_bbt_end), false);
765 Location::set_scene_change (boost::shared_ptr<SceneChange> sc)
769 scene_changed (); /* 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)) {
833 if ((suffix = atoi (temp.substr(l,3))) != 0) {
834 taken.insert (make_pair (suffix,true));
840 /* Now search for an un-used suffix to add to "base". This
841 will find "holes" in the numbering sequence when a location
844 This must start at 1, both for human-numbering reasons
845 and also because the call to atoi() above would return
846 zero if there is no recognizable numeric suffix, causing
847 "base 0" not to be inserted into the "taken" map.
852 while (n < UINT32_MAX) {
853 if (taken.find (n) == taken.end()) {
854 snprintf (buf, sizeof(buf), "%d", n);
865 Locations::set_current_unlocked (Location *loc)
867 if (find (locations.begin(), locations.end(), loc) == locations.end()) {
868 error << _("Locations: attempt to use unknown location as selected location") << endmsg;
872 current_location = loc;
880 Glib::Threads::Mutex::Lock lm (lock);
882 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
884 LocationList::iterator tmp = i;
887 if (!(*i)->is_session_range()) {
895 current_location = 0;
898 changed (); /* EMIT SIGNAL */
899 current_changed (0); /* EMIT SIGNAL */
903 Locations::clear_markers ()
906 Glib::Threads::Mutex::Lock lm (lock);
907 LocationList::iterator tmp;
909 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
913 if ((*i)->is_mark() && !(*i)->is_session_range()) {
922 changed (); /* EMIT SIGNAL */
926 Locations::clear_ranges ()
929 Glib::Threads::Mutex::Lock lm (lock);
930 LocationList::iterator tmp;
932 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
937 /* We do not remove these ranges as part of this
941 if ((*i)->is_auto_punch() ||
942 (*i)->is_auto_loop() ||
943 (*i)->is_session_range()) {
948 if (!(*i)->is_mark()) {
957 current_location = 0;
961 current_changed (0); /* EMIT SIGNAL */
965 Locations::add (Location *loc, bool make_current)
970 Glib::Threads::Mutex::Lock lm (lock);
971 locations.push_back (loc);
974 current_location = loc;
978 added (loc); /* EMIT SIGNAL */
981 current_changed (current_location); /* EMIT SIGNAL */
984 if (loc->is_session_range()) {
985 Session::StartTimeChanged (0);
986 Session::EndTimeChanged (1);
991 Locations::remove (Location *loc)
993 bool was_removed = false;
994 bool was_current = false;
995 LocationList::iterator i;
997 if (loc->is_session_range()) {
1002 Glib::Threads::Mutex::Lock lm (lock);
1004 for (i = locations.begin(); i != locations.end(); ++i) {
1007 locations.erase (i);
1009 if (current_location == loc) {
1010 current_location = 0;
1020 removed (loc); /* EMIT SIGNAL */
1023 current_changed (0); /* EMIT SIGNAL */
1029 Locations::get_state ()
1031 XMLNode *node = new XMLNode ("Locations");
1032 LocationList::iterator iter;
1033 Glib::Threads::Mutex::Lock lm (lock);
1035 for (iter = locations.begin(); iter != locations.end(); ++iter) {
1036 node->add_child_nocopy ((*iter)->get_state ());
1043 Locations::set_state (const XMLNode& node, int version)
1045 if (node.name() != "Locations") {
1046 error << _("incorrect XML mode passed to Locations::set_state") << endmsg;
1050 XMLNodeList nlist = node.children();
1052 /* build up a new locations list in here */
1053 LocationList new_locations;
1055 current_location = 0;
1057 Location* session_range_location = 0;
1058 if (version < 3000) {
1059 session_range_location = new Location (_session, 0, 0, _("session"), Location::IsSessionRange);
1060 new_locations.push_back (session_range_location);
1064 Glib::Threads::Mutex::Lock lm (lock);
1066 XMLNodeConstIterator niter;
1067 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1071 XMLProperty const * prop_id = (*niter)->property ("id");
1073 PBD::ID id (prop_id->value ());
1075 LocationList::const_iterator i = locations.begin();
1076 while (i != locations.end () && (*i)->id() != id) {
1081 if (i != locations.end()) {
1082 /* we can re-use an old Location object */
1085 // changed locations will be updated by Locations::changed signal
1086 loc->set_block_change_notifications (true);
1087 loc->set_state (**niter, version);
1088 loc->set_block_change_notifications (false);
1090 loc = new Location (_session, **niter);
1095 if (version < 3000) {
1096 /* look for old-style IsStart / IsEnd properties in this location;
1097 if they are present, update the session_range_location accordingly
1099 XMLProperty const * prop = (*niter)->property ("flags");
1101 string v = prop->value ();
1103 string::size_type const c = v.find_first_of (',');
1104 string const s = v.substr (0, c);
1105 if (s == X_("IsStart")) {
1106 session_range_location->set_start (loc->start(), true);
1108 } else if (s == X_("IsEnd")) {
1109 session_range_location->set_end (loc->start(), true);
1113 if (c == string::npos) {
1117 v = v.substr (c + 1);
1123 new_locations.push_back (loc);
1127 catch (failed_constructor& err) {
1128 error << _("could not load location from session file - ignored") << endmsg;
1132 locations = new_locations;
1134 if (locations.size()) {
1135 current_location = locations.front();
1137 current_location = 0;
1141 changed (); /* EMIT SIGNAL */
1147 typedef std::pair<framepos_t,Location*> LocationPair;
1149 struct LocationStartEarlierComparison
1151 bool operator() (LocationPair a, LocationPair b) {
1152 return a.first < b.first;
1156 struct LocationStartLaterComparison
1158 bool operator() (LocationPair a, LocationPair b) {
1159 return a.first > b.first;
1164 Locations::first_mark_before (framepos_t frame, bool include_special_ranges)
1166 Glib::Threads::Mutex::Lock lm (lock);
1167 vector<LocationPair> locs;
1169 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1170 locs.push_back (make_pair ((*i)->start(), (*i)));
1171 if (!(*i)->is_mark()) {
1172 locs.push_back (make_pair ((*i)->end(), (*i)));
1176 LocationStartLaterComparison cmp;
1177 sort (locs.begin(), locs.end(), cmp);
1179 /* locs is sorted in ascending order */
1181 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1182 if ((*i).second->is_hidden()) {
1185 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1188 if ((*i).first < frame) {
1197 Locations::mark_at (framepos_t pos, framecnt_t slop) const
1199 Glib::Threads::Mutex::Lock lm (lock);
1200 Location* closest = 0;
1201 frameoffset_t mindelta = max_framepos;
1202 frameoffset_t delta;
1204 /* locations are not necessarily stored in linear time order so we have
1205 * to iterate across all of them to find the one closest to a give point.
1208 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1210 if ((*i)->is_mark()) {
1211 if (pos > (*i)->start()) {
1212 delta = pos - (*i)->start();
1214 delta = (*i)->start() - pos;
1217 if (slop == 0 && delta == 0) {
1218 /* special case: no slop, and direct hit for position */
1222 if (delta <= slop) {
1223 if (delta < mindelta) {
1235 Locations::first_mark_after (framepos_t frame, bool include_special_ranges)
1237 Glib::Threads::Mutex::Lock lm (lock);
1238 vector<LocationPair> locs;
1240 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1241 locs.push_back (make_pair ((*i)->start(), (*i)));
1242 if (!(*i)->is_mark()) {
1243 locs.push_back (make_pair ((*i)->end(), (*i)));
1247 LocationStartEarlierComparison cmp;
1248 sort (locs.begin(), locs.end(), cmp);
1250 /* locs is sorted in reverse order */
1252 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1253 if ((*i).second->is_hidden()) {
1256 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1259 if ((*i).first > frame) {
1267 /** Look for the `marks' (either locations which are marks, or start/end points of range markers) either
1268 * side of a frame. Note that if frame is exactly on a `mark', that mark will not be considered for returning
1270 * @param frame Frame to look for.
1271 * @param before Filled in with the position of the last `mark' before `frame' (or max_framepos if none exists)
1272 * @param after Filled in with the position of the next `mark' after `frame' (or max_framepos if none exists)
1275 Locations::marks_either_side (framepos_t const frame, framepos_t& before, framepos_t& after) const
1277 before = after = max_framepos;
1282 Glib::Threads::Mutex::Lock lm (lock);
1286 /* Get a list of positions; don't store any that are exactly on our requested position */
1288 std::list<framepos_t> positions;
1290 for (LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
1291 if (((*i)->is_auto_loop() || (*i)->is_auto_punch())) {
1295 if (!(*i)->is_hidden()) {
1296 if ((*i)->is_mark ()) {
1297 if ((*i)->start() != frame) {
1298 positions.push_back ((*i)->start ());
1301 if ((*i)->start() != frame) {
1302 positions.push_back ((*i)->start ());
1304 if ((*i)->end() != frame) {
1305 positions.push_back ((*i)->end ());
1311 if (positions.empty ()) {
1317 std::list<framepos_t>::iterator i = positions.begin ();
1318 while (i != positions.end () && *i < frame) {
1322 if (i == positions.end ()) {
1323 /* run out of marks */
1324 before = positions.back ();
1330 if (i == positions.begin ()) {
1340 Locations::session_range_location () const
1342 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1343 if ((*i)->is_session_range()) {
1344 return const_cast<Location*> (*i);
1351 Locations::auto_loop_location () const
1353 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1354 if ((*i)->is_auto_loop()) {
1355 return const_cast<Location*> (*i);
1362 Locations::auto_punch_location () const
1364 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1365 if ((*i)->is_auto_punch()) {
1366 return const_cast<Location*> (*i);
1373 Locations::num_range_markers () const
1376 Glib::Threads::Mutex::Lock lm (lock);
1377 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1378 if ((*i)->is_range_marker()) {
1386 Locations::get_location_by_id(PBD::ID id)
1388 LocationList::iterator it;
1389 for (it = locations.begin(); it != locations.end(); ++it)
1390 if (id == (*it)->id())
1397 Locations::find_all_between (framepos_t start, framepos_t end, LocationList& ll, Location::Flags flags)
1399 Glib::Threads::Mutex::Lock lm (lock);
1401 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1402 if ((flags == 0 || (*i)->matches (flags)) &&
1403 ((*i)->start() >= start && (*i)->end() < end)) {