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 */
399 if (start_change && end_change) {
402 } else if (start_change) {
403 start_changed(this); /* EMIT SIGNAL */
404 StartChanged(); /* EMIT SIGNAL */
405 } else if (end_change) {
406 end_changed(this); /* EMIT SIGNAL */
407 EndChanged(); /* EMIT SIGNAL */
414 Location::move_to (framepos_t pos)
426 _end = _start + length();
427 recompute_bbt_from_frames ();
429 changed (this); /* EMIT SIGNAL */
430 Changed (); /* EMIT SIGNAL */
433 assert (_start >= 0);
440 Location::set_hidden (bool yn, void*)
442 if (set_flag_internal (yn, IsHidden)) {
443 flags_changed (this); /* EMIT SIGNAL */
449 Location::set_cd (bool yn, void*)
451 // XXX this really needs to be session start
452 // but its not available here - leave to GUI
454 if (yn && _start == 0) {
455 error << _("You cannot put a CD marker at this position") << endmsg;
459 if (set_flag_internal (yn, IsCDMarker)) {
460 flags_changed (this); /* EMIT SIGNAL */
466 Location::set_is_range_marker (bool yn, void*)
468 if (set_flag_internal (yn, IsRangeMarker)) {
469 flags_changed (this);
470 FlagsChanged (); /* EMIT SIGNAL */
475 Location::set_skip (bool yn)
477 if (is_range_marker() && length() > 0) {
478 if (set_flag_internal (yn, IsSkip)) {
479 flags_changed (this);
486 Location::set_skipping (bool yn)
488 if (is_range_marker() && is_skip() && length() > 0) {
489 if (set_flag_internal (yn, IsSkipping)) {
490 flags_changed (this);
497 Location::set_auto_punch (bool yn, void*)
499 if (is_mark() || _start == _end) {
503 if (set_flag_internal (yn, IsAutoPunch)) {
504 flags_changed (this); /* EMIT SIGNAL */
505 FlagsChanged (); /* EMIT SIGNAL */
510 Location::set_auto_loop (bool yn, void*)
512 if (is_mark() || _start == _end) {
516 if (set_flag_internal (yn, IsAutoLoop)) {
517 flags_changed (this); /* EMIT SIGNAL */
518 FlagsChanged (); /* EMIT SIGNAL */
523 Location::set_flag_internal (bool yn, Flags flag)
526 if (!(_flags & flag)) {
527 _flags = Flags (_flags | flag);
532 _flags = Flags (_flags & ~flag);
540 Location::set_mark (bool yn)
542 /* This function is private, and so does not emit signals */
544 if (_start != _end) {
548 set_flag_internal (yn, IsMark);
553 Location::cd_info_node(const string & name, const string & value)
555 XMLNode* root = new XMLNode("CD-Info");
557 root->add_property("name", name);
558 root->add_property("value", value);
565 Location::get_state ()
567 XMLNode *node = new XMLNode ("Location");
570 typedef map<string, string>::const_iterator CI;
572 for(CI m = cd_info.begin(); m != cd_info.end(); ++m){
573 node->add_child_nocopy(cd_info_node(m->first, m->second));
576 id().print (buf, sizeof (buf));
577 node->add_property("id", buf);
578 node->add_property ("name", name());
579 snprintf (buf, sizeof (buf), "%" PRId64, start());
580 node->add_property ("start", buf);
581 snprintf (buf, sizeof (buf), "%" PRId64, end());
582 node->add_property ("end", buf);
583 node->add_property ("flags", enum_2_string (_flags));
584 node->add_property ("locked", (_locked ? "yes" : "no"));
585 node->add_property ("position-lock-style", enum_2_string (_position_lock_style));
588 node->add_child_nocopy (_scene_change->get_state());
595 Location::set_state (const XMLNode& node, int version)
597 XMLProperty const * prop;
599 XMLNodeList cd_list = node.children();
600 XMLNodeConstIterator cd_iter;
606 if (node.name() != "Location") {
607 error << _("incorrect XML node passed to Location::set_state") << endmsg;
611 if (!set_id (node)) {
612 warning << _("XML node for Location has no ID information") << endmsg;
615 if ((prop = node.property ("name")) == 0) {
616 error << _("XML node for Location has no name information") << endmsg;
620 set_name (prop->value());
622 if ((prop = node.property ("start")) == 0) {
623 error << _("XML node for Location has no start information") << endmsg;
627 /* can't use set_start() here, because _end
628 may make the value of _start illegal.
631 sscanf (prop->value().c_str(), "%" PRId64, &_start);
633 if ((prop = node.property ("end")) == 0) {
634 error << _("XML node for Location has no end information") << endmsg;
638 sscanf (prop->value().c_str(), "%" PRId64, &_end);
640 if ((prop = node.property ("flags")) == 0) {
641 error << _("XML node for Location has no flags information") << endmsg;
645 Flags old_flags (_flags);
646 _flags = Flags (string_2_enum (prop->value(), _flags));
648 if (old_flags != _flags) {
652 if ((prop = node.property ("locked")) != 0) {
653 _locked = string_is_affirmative (prop->value());
658 for (cd_iter = cd_list.begin(); cd_iter != cd_list.end(); ++cd_iter) {
662 if (cd_node->name() != "CD-Info") {
666 if ((prop = cd_node->property ("name")) != 0) {
667 cd_name = prop->value();
669 throw failed_constructor ();
672 if ((prop = cd_node->property ("value")) != 0) {
673 cd_value = prop->value();
675 throw failed_constructor ();
679 cd_info[cd_name] = cd_value;
682 if ((prop = node.property ("position-lock-style")) != 0) {
683 _position_lock_style = PositionLockStyle (string_2_enum (prop->value(), _position_lock_style));
686 XMLNode* scene_child = find_named_node (node, SceneChange::xml_node_name);
689 _scene_change = SceneChange::factory (*scene_child, version);
692 recompute_bbt_from_frames ();
694 changed (this); /* EMIT SIGNAL */
695 Changed (); /* EMIT SIGNAL */
697 assert (_start >= 0);
704 Location::set_position_lock_style (PositionLockStyle ps)
706 if (_position_lock_style == ps) {
710 _position_lock_style = ps;
712 recompute_bbt_from_frames ();
714 position_lock_style_changed (this); /* EMIT SIGNAL */
715 PositionLockStyleChanged (); /* EMIT SIGNAL */
719 Location::recompute_bbt_from_frames ()
721 if (_position_lock_style != MusicTime) {
725 _bbt_start = _session.tempo_map().beat_at_frame (_start);
726 _bbt_end = _session.tempo_map().beat_at_frame (_end);
730 Location::recompute_frames_from_bbt ()
732 if (_position_lock_style != MusicTime) {
736 TempoMap& map (_session.tempo_map());
737 set (map.frame_at_beat (_bbt_start), map.frame_at_beat (_bbt_end), false);
757 Location::set_scene_change (boost::shared_ptr<SceneChange> sc)
759 if (_scene_change != sc) {
761 _session.set_dirty ();
763 scene_changed (); /* EMIT SIGNAL */
764 SceneChangeChanged (); /* EMIT SIGNAL */
768 /*---------------------------------------------------------------------- */
770 Locations::Locations (Session& s)
771 : SessionHandleRef (s)
773 current_location = 0;
776 Locations::~Locations ()
778 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
779 LocationList::iterator tmp = i;
787 Locations::set_current (Location *loc, bool want_lock)
792 Glib::Threads::Mutex::Lock lm (lock);
793 ret = set_current_unlocked (loc);
795 ret = set_current_unlocked (loc);
799 current_changed (current_location); /* EMIT SIGNAL */
805 Locations::next_available_name(string& result,string base)
807 LocationList::iterator i;
811 std::map<uint32_t,bool> taken;
819 /* find all existing names that match "base", and store
820 the numeric part of them (if any) in the map "taken"
823 for (i = locations.begin(); i != locations.end(); ++i) {
825 const string& temp ((*i)->name());
827 if (!temp.find (base,0)) {
828 /* grab what comes after the "base" as if it was
829 a number, and assuming that works OK,
830 store it in "taken" so that we know it
833 if ((suffix = atoi (temp.substr(l))) != 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;
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)) {