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)
762 if (_scene_change != sc) {
765 scene_changed (); /* EMIT SIGNAL */
766 SceneChangeChanged (); /* EMIT SIGNAL */
770 /*---------------------------------------------------------------------- */
772 Locations::Locations (Session& s)
773 : SessionHandleRef (s)
775 current_location = 0;
778 Locations::~Locations ()
780 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
781 LocationList::iterator tmp = i;
789 Locations::set_current (Location *loc, bool want_lock)
794 Glib::Threads::Mutex::Lock lm (lock);
795 ret = set_current_unlocked (loc);
797 ret = set_current_unlocked (loc);
801 current_changed (current_location); /* EMIT SIGNAL */
807 Locations::next_available_name(string& result,string base)
809 LocationList::iterator i;
813 std::map<uint32_t,bool> taken;
821 /* find all existing names that match "base", and store
822 the numeric part of them (if any) in the map "taken"
825 for (i = locations.begin(); i != locations.end(); ++i) {
827 const string& temp ((*i)->name());
829 if (!temp.find (base,0)) {
830 /* grab what comes after the "base" as if it was
831 a number, and assuming that works OK,
832 store it in "taken" so that we know it
835 if ((suffix = atoi (temp.substr(l))) != 0) {
836 taken.insert (make_pair (suffix,true));
842 /* Now search for an un-used suffix to add to "base". This
843 will find "holes" in the numbering sequence when a location
846 This must start at 1, both for human-numbering reasons
847 and also because the call to atoi() above would return
848 zero if there is no recognizable numeric suffix, causing
849 "base 0" not to be inserted into the "taken" map.
854 while (n < UINT32_MAX) {
855 if (taken.find (n) == taken.end()) {
856 snprintf (buf, sizeof(buf), "%d", n);
867 Locations::set_current_unlocked (Location *loc)
869 if (find (locations.begin(), locations.end(), loc) == locations.end()) {
870 error << _("Locations: attempt to use unknown location as selected location") << endmsg;
874 current_location = loc;
882 Glib::Threads::Mutex::Lock lm (lock);
884 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
886 LocationList::iterator tmp = i;
889 if (!(*i)->is_session_range()) {
897 current_location = 0;
900 changed (); /* EMIT SIGNAL */
901 current_changed (0); /* EMIT SIGNAL */
905 Locations::clear_markers ()
908 Glib::Threads::Mutex::Lock lm (lock);
909 LocationList::iterator tmp;
911 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
915 if ((*i)->is_mark() && !(*i)->is_session_range()) {
924 changed (); /* EMIT SIGNAL */
928 Locations::clear_ranges ()
931 Glib::Threads::Mutex::Lock lm (lock);
932 LocationList::iterator tmp;
934 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
939 /* We do not remove these ranges as part of this
943 if ((*i)->is_auto_punch() ||
944 (*i)->is_auto_loop() ||
945 (*i)->is_session_range()) {
950 if (!(*i)->is_mark()) {
959 current_location = 0;
963 current_changed (0); /* EMIT SIGNAL */
967 Locations::add (Location *loc, bool make_current)
972 Glib::Threads::Mutex::Lock lm (lock);
973 locations.push_back (loc);
976 current_location = loc;
980 added (loc); /* EMIT SIGNAL */
983 current_changed (current_location); /* EMIT SIGNAL */
986 if (loc->is_session_range()) {
987 Session::StartTimeChanged (0);
988 Session::EndTimeChanged (1);
993 Locations::remove (Location *loc)
995 bool was_removed = false;
996 bool was_current = false;
997 LocationList::iterator i;
999 if (loc->is_session_range()) {
1004 Glib::Threads::Mutex::Lock lm (lock);
1006 for (i = locations.begin(); i != locations.end(); ++i) {
1009 locations.erase (i);
1011 if (current_location == loc) {
1012 current_location = 0;
1022 removed (loc); /* EMIT SIGNAL */
1025 current_changed (0); /* EMIT SIGNAL */
1031 Locations::get_state ()
1033 XMLNode *node = new XMLNode ("Locations");
1034 LocationList::iterator iter;
1035 Glib::Threads::Mutex::Lock lm (lock);
1037 for (iter = locations.begin(); iter != locations.end(); ++iter) {
1038 node->add_child_nocopy ((*iter)->get_state ());
1045 Locations::set_state (const XMLNode& node, int version)
1047 if (node.name() != "Locations") {
1048 error << _("incorrect XML mode passed to Locations::set_state") << endmsg;
1052 XMLNodeList nlist = node.children();
1054 /* build up a new locations list in here */
1055 LocationList new_locations;
1057 current_location = 0;
1059 Location* session_range_location = 0;
1060 if (version < 3000) {
1061 session_range_location = new Location (_session, 0, 0, _("session"), Location::IsSessionRange);
1062 new_locations.push_back (session_range_location);
1066 Glib::Threads::Mutex::Lock lm (lock);
1068 XMLNodeConstIterator niter;
1069 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1073 XMLProperty const * prop_id = (*niter)->property ("id");
1075 PBD::ID id (prop_id->value ());
1077 LocationList::const_iterator i = locations.begin();
1078 while (i != locations.end () && (*i)->id() != id) {
1083 if (i != locations.end()) {
1084 /* we can re-use an old Location object */
1087 // changed locations will be updated by Locations::changed signal
1088 loc->set_state (**niter, version);
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 /* We may have some unused locations in the old list. */
1133 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
1134 LocationList::iterator tmp = i;
1137 LocationList::iterator n = new_locations.begin();
1140 while (n != new_locations.end ()) {
1141 if ((*i)->id() == (*n)->id()) {
1150 locations.erase (i);
1156 locations = new_locations;
1158 if (locations.size()) {
1159 current_location = locations.front();
1161 current_location = 0;
1165 changed (); /* EMIT SIGNAL */
1171 typedef std::pair<framepos_t,Location*> LocationPair;
1173 struct LocationStartEarlierComparison
1175 bool operator() (LocationPair a, LocationPair b) {
1176 return a.first < b.first;
1180 struct LocationStartLaterComparison
1182 bool operator() (LocationPair a, LocationPair b) {
1183 return a.first > b.first;
1188 Locations::first_mark_before (framepos_t frame, bool include_special_ranges)
1190 Glib::Threads::Mutex::Lock lm (lock);
1191 vector<LocationPair> locs;
1193 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1194 locs.push_back (make_pair ((*i)->start(), (*i)));
1195 if (!(*i)->is_mark()) {
1196 locs.push_back (make_pair ((*i)->end(), (*i)));
1200 LocationStartLaterComparison cmp;
1201 sort (locs.begin(), locs.end(), cmp);
1203 /* locs is sorted in ascending order */
1205 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1206 if ((*i).second->is_hidden()) {
1209 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1212 if ((*i).first < frame) {
1221 Locations::mark_at (framepos_t pos, framecnt_t slop) const
1223 Glib::Threads::Mutex::Lock lm (lock);
1224 Location* closest = 0;
1225 frameoffset_t mindelta = max_framepos;
1226 frameoffset_t delta;
1228 /* locations are not necessarily stored in linear time order so we have
1229 * to iterate across all of them to find the one closest to a give point.
1232 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1234 if ((*i)->is_mark()) {
1235 if (pos > (*i)->start()) {
1236 delta = pos - (*i)->start();
1238 delta = (*i)->start() - pos;
1241 if (slop == 0 && delta == 0) {
1242 /* special case: no slop, and direct hit for position */
1246 if (delta <= slop) {
1247 if (delta < mindelta) {
1259 Locations::first_mark_after (framepos_t frame, bool include_special_ranges)
1261 Glib::Threads::Mutex::Lock lm (lock);
1262 vector<LocationPair> locs;
1264 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1265 locs.push_back (make_pair ((*i)->start(), (*i)));
1266 if (!(*i)->is_mark()) {
1267 locs.push_back (make_pair ((*i)->end(), (*i)));
1271 LocationStartEarlierComparison cmp;
1272 sort (locs.begin(), locs.end(), cmp);
1274 /* locs is sorted in reverse order */
1276 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1277 if ((*i).second->is_hidden()) {
1280 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1283 if ((*i).first > frame) {
1291 /** Look for the `marks' (either locations which are marks, or start/end points of range markers) either
1292 * side of a frame. Note that if frame is exactly on a `mark', that mark will not be considered for returning
1294 * @param frame Frame to look for.
1295 * @param before Filled in with the position of the last `mark' before `frame' (or max_framepos if none exists)
1296 * @param after Filled in with the position of the next `mark' after `frame' (or max_framepos if none exists)
1299 Locations::marks_either_side (framepos_t const frame, framepos_t& before, framepos_t& after) const
1301 before = after = max_framepos;
1306 Glib::Threads::Mutex::Lock lm (lock);
1310 /* Get a list of positions; don't store any that are exactly on our requested position */
1312 std::list<framepos_t> positions;
1314 for (LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
1315 if (((*i)->is_auto_loop() || (*i)->is_auto_punch())) {
1319 if (!(*i)->is_hidden()) {
1320 if ((*i)->is_mark ()) {
1321 if ((*i)->start() != frame) {
1322 positions.push_back ((*i)->start ());
1325 if ((*i)->start() != frame) {
1326 positions.push_back ((*i)->start ());
1328 if ((*i)->end() != frame) {
1329 positions.push_back ((*i)->end ());
1335 if (positions.empty ()) {
1341 std::list<framepos_t>::iterator i = positions.begin ();
1342 while (i != positions.end () && *i < frame) {
1346 if (i == positions.end ()) {
1347 /* run out of marks */
1348 before = positions.back ();
1354 if (i == positions.begin ()) {
1364 Locations::session_range_location () const
1366 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1367 if ((*i)->is_session_range()) {
1368 return const_cast<Location*> (*i);
1375 Locations::auto_loop_location () const
1377 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1378 if ((*i)->is_auto_loop()) {
1379 return const_cast<Location*> (*i);
1386 Locations::auto_punch_location () const
1388 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1389 if ((*i)->is_auto_punch()) {
1390 return const_cast<Location*> (*i);
1397 Locations::num_range_markers () const
1400 Glib::Threads::Mutex::Lock lm (lock);
1401 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1402 if ((*i)->is_range_marker()) {
1410 Locations::get_location_by_id(PBD::ID id)
1412 LocationList::iterator it;
1413 for (it = locations.begin(); it != locations.end(); ++it)
1414 if (id == (*it)->id())
1421 Locations::find_all_between (framepos_t start, framepos_t end, LocationList& ll, Location::Flags flags)
1423 Glib::Threads::Mutex::Lock lm (lock);
1425 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1426 if ((flags == 0 || (*i)->matches (flags)) &&
1427 ((*i)->start() >= start && (*i)->end() < end)) {