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;
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_state (**niter, version);
1088 loc = new Location (_session, **niter);
1093 if (version < 3000) {
1094 /* look for old-style IsStart / IsEnd properties in this location;
1095 if they are present, update the session_range_location accordingly
1097 XMLProperty const * prop = (*niter)->property ("flags");
1099 string v = prop->value ();
1101 string::size_type const c = v.find_first_of (',');
1102 string const s = v.substr (0, c);
1103 if (s == X_("IsStart")) {
1104 session_range_location->set_start (loc->start(), true);
1106 } else if (s == X_("IsEnd")) {
1107 session_range_location->set_end (loc->start(), true);
1111 if (c == string::npos) {
1115 v = v.substr (c + 1);
1121 new_locations.push_back (loc);
1125 catch (failed_constructor& err) {
1126 error << _("could not load location from session file - ignored") << endmsg;
1130 /* We may have some unused locations in the old list. */
1131 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
1132 LocationList::iterator tmp = i;
1135 LocationList::iterator n = new_locations.begin();
1138 while (n != new_locations.end ()) {
1139 if ((*i)->id() == (*n)->id()) {
1148 locations.erase (i);
1154 locations = new_locations;
1156 if (locations.size()) {
1157 current_location = locations.front();
1159 current_location = 0;
1163 changed (); /* EMIT SIGNAL */
1169 typedef std::pair<framepos_t,Location*> LocationPair;
1171 struct LocationStartEarlierComparison
1173 bool operator() (LocationPair a, LocationPair b) {
1174 return a.first < b.first;
1178 struct LocationStartLaterComparison
1180 bool operator() (LocationPair a, LocationPair b) {
1181 return a.first > b.first;
1186 Locations::first_mark_before (framepos_t frame, bool include_special_ranges)
1188 Glib::Threads::Mutex::Lock lm (lock);
1189 vector<LocationPair> locs;
1191 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1192 locs.push_back (make_pair ((*i)->start(), (*i)));
1193 if (!(*i)->is_mark()) {
1194 locs.push_back (make_pair ((*i)->end(), (*i)));
1198 LocationStartLaterComparison cmp;
1199 sort (locs.begin(), locs.end(), cmp);
1201 /* locs is sorted in ascending order */
1203 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1204 if ((*i).second->is_hidden()) {
1207 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1210 if ((*i).first < frame) {
1219 Locations::mark_at (framepos_t pos, framecnt_t slop) const
1221 Glib::Threads::Mutex::Lock lm (lock);
1222 Location* closest = 0;
1223 frameoffset_t mindelta = max_framepos;
1224 frameoffset_t delta;
1226 /* locations are not necessarily stored in linear time order so we have
1227 * to iterate across all of them to find the one closest to a give point.
1230 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1232 if ((*i)->is_mark()) {
1233 if (pos > (*i)->start()) {
1234 delta = pos - (*i)->start();
1236 delta = (*i)->start() - pos;
1239 if (slop == 0 && delta == 0) {
1240 /* special case: no slop, and direct hit for position */
1244 if (delta <= slop) {
1245 if (delta < mindelta) {
1257 Locations::first_mark_after (framepos_t frame, bool include_special_ranges)
1259 Glib::Threads::Mutex::Lock lm (lock);
1260 vector<LocationPair> locs;
1262 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1263 locs.push_back (make_pair ((*i)->start(), (*i)));
1264 if (!(*i)->is_mark()) {
1265 locs.push_back (make_pair ((*i)->end(), (*i)));
1269 LocationStartEarlierComparison cmp;
1270 sort (locs.begin(), locs.end(), cmp);
1272 /* locs is sorted in reverse order */
1274 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1275 if ((*i).second->is_hidden()) {
1278 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1281 if ((*i).first > frame) {
1289 /** Look for the `marks' (either locations which are marks, or start/end points of range markers) either
1290 * side of a frame. Note that if frame is exactly on a `mark', that mark will not be considered for returning
1292 * @param frame Frame to look for.
1293 * @param before Filled in with the position of the last `mark' before `frame' (or max_framepos if none exists)
1294 * @param after Filled in with the position of the next `mark' after `frame' (or max_framepos if none exists)
1297 Locations::marks_either_side (framepos_t const frame, framepos_t& before, framepos_t& after) const
1299 before = after = max_framepos;
1304 Glib::Threads::Mutex::Lock lm (lock);
1308 /* Get a list of positions; don't store any that are exactly on our requested position */
1310 std::list<framepos_t> positions;
1312 for (LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
1313 if (((*i)->is_auto_loop() || (*i)->is_auto_punch())) {
1317 if (!(*i)->is_hidden()) {
1318 if ((*i)->is_mark ()) {
1319 if ((*i)->start() != frame) {
1320 positions.push_back ((*i)->start ());
1323 if ((*i)->start() != frame) {
1324 positions.push_back ((*i)->start ());
1326 if ((*i)->end() != frame) {
1327 positions.push_back ((*i)->end ());
1333 if (positions.empty ()) {
1339 std::list<framepos_t>::iterator i = positions.begin ();
1340 while (i != positions.end () && *i < frame) {
1344 if (i == positions.end ()) {
1345 /* run out of marks */
1346 before = positions.back ();
1352 if (i == positions.begin ()) {
1362 Locations::session_range_location () const
1364 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1365 if ((*i)->is_session_range()) {
1366 return const_cast<Location*> (*i);
1373 Locations::auto_loop_location () const
1375 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1376 if ((*i)->is_auto_loop()) {
1377 return const_cast<Location*> (*i);
1384 Locations::auto_punch_location () const
1386 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1387 if ((*i)->is_auto_punch()) {
1388 return const_cast<Location*> (*i);
1395 Locations::num_range_markers () const
1398 Glib::Threads::Mutex::Lock lm (lock);
1399 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1400 if ((*i)->is_range_marker()) {
1408 Locations::get_location_by_id(PBD::ID id)
1410 LocationList::iterator it;
1411 for (it = locations.begin(); it != locations.end(); ++it)
1412 if (id == (*it)->id())
1419 Locations::find_all_between (framepos_t start, framepos_t end, LocationList& ll, Location::Flags flags)
1421 Glib::Threads::Mutex::Lock lm (lock);
1423 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1424 if ((flags == 0 || (*i)->matches (flags)) &&
1425 ((*i)->start() >= start && (*i)->end() < end)) {