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)
76 recompute_bbt_from_frames ();
82 Location::Location (const Location& other)
83 : SessionHandleRef (other._session)
84 , StatefulDestructible()
86 , _start (other._start)
87 , _bbt_start (other._bbt_start)
89 , _bbt_end (other._bbt_end)
90 , _flags (other._flags)
91 , _position_lock_style (other._position_lock_style)
93 /* copy is not locked even if original was */
100 /* scene change is NOT COPIED */
103 Location::Location (Session& s, const XMLNode& node)
104 : SessionHandleRef (s)
105 , _position_lock_style (AudioTime)
107 /* Note: _position_lock_style is initialised above in case set_state doesn't set it
108 (for 2.X session file compatibility).
111 if (set_state (node, Stateful::loading_state_version)) {
112 throw failed_constructor ();
115 assert (_start >= 0);
120 Location::operator== (const Location& other)
122 if (_name != other._name ||
123 _start != other._start ||
124 _end != other._end ||
125 _bbt_start != other._bbt_start ||
126 _bbt_end != other._bbt_end ||
127 _flags != other._flags ||
128 _position_lock_style != other._position_lock_style) {
135 Location::operator= (const Location& other)
137 if (this == &other) {
142 _start = other._start;
143 _bbt_start = other._bbt_start;
145 _bbt_end = other._bbt_end;
146 _flags = other._flags;
147 _position_lock_style = other._position_lock_style;
149 /* XXX need to copy scene change */
151 /* copy is not locked even if original was */
155 /* "changed" not emitted on purpose */
157 assert (_start >= 0);
163 /** Set location name
167 Location::set_name (const std::string& str)
171 name_changed (this); /* EMIT SIGNAL */
172 NameChanged (); /* EMIT SIGNAL */
175 /** Set start position.
176 * @param s New start.
177 * @param force true to force setting, even if the given new start is after the current end.
178 * @param allow_bbt_recompute True to recompute BBT start time from the new given start time.
181 Location::set_start (framepos_t s, bool force, bool allow_bbt_recompute)
192 if (((is_auto_punch() || is_auto_loop()) && s >= _end) || (!is_mark() && s > _end)) {
201 if (allow_bbt_recompute) {
202 recompute_bbt_from_frames ();
205 start_changed (this); /* EMIT SIGNAL */
206 StartChanged (); /* EMIT SIGNAL */
207 end_changed (this); /* EMIT SIGNAL */
208 EndChanged (); /* EMIT SIGNAL */
211 /* moving the start (position) of a marker with a scene change
212 requires an update in the Scene Changer.
216 scene_changed (); /* EMIT SIGNAL */
219 assert (_start >= 0);
224 /* range locations must exceed a minimum duration */
225 if (_end - s < Config->get_range_location_minimum()) {
232 framepos_t const old = _start;
235 if (allow_bbt_recompute) {
236 recompute_bbt_from_frames ();
238 start_changed (this); /* EMIT SIGNAL */
239 StartChanged (); /* EMIT SIGNAL */
241 if (is_session_range ()) {
242 Session::StartTimeChanged (old); /* EMIT SIGNAL */
243 AudioFileSource::set_header_position_offset (s);
247 assert (_start >= 0);
252 /** Set end position.
254 * @param force true to force setting, even if the given new end is before the current start.
255 * @param allow_bbt_recompute True to recompute BBT end time from the new given end time.
258 Location::set_end (framepos_t e, bool force, bool allow_bbt_recompute)
269 if (((is_auto_punch() || is_auto_loop()) && e <= _start) || e < _start) {
278 if (allow_bbt_recompute) {
279 recompute_bbt_from_frames ();
281 start_changed (this); /* EMIT SIGNAL */
282 StartChanged (); /* EMIT SIGNAL */
283 end_changed (this); /* EMIT SIGNAL */
284 EndChanged (); /* EMIT SIGNAL */
287 assert (_start >= 0);
292 /* range locations must exceed a minimum duration */
293 if (e - _start < Config->get_range_location_minimum()) {
300 framepos_t const old = _end;
303 if (allow_bbt_recompute) {
304 recompute_bbt_from_frames ();
307 end_changed(this); /* EMIT SIGNAL */
308 EndChanged(); /* EMIT SIGNAL */
310 if (is_session_range()) {
311 Session::EndTimeChanged (old); /* EMIT SIGNAL */
321 Location::set (framepos_t s, framepos_t e, bool allow_bbt_recompute)
323 if (s < 0 || e < 0) {
328 if (((is_auto_punch() || is_auto_loop()) && s >= e) || (!is_mark() && s > e)) {
332 bool start_change = false;
333 bool end_change = false;
341 if (allow_bbt_recompute) {
342 recompute_bbt_from_frames ();
349 assert (_start >= 0);
354 /* range locations must exceed a minimum duration */
355 if (e - s < Config->get_range_location_minimum()) {
361 framepos_t const old = _start;
364 if (allow_bbt_recompute) {
365 recompute_bbt_from_frames ();
370 if (is_session_range ()) {
371 Session::StartTimeChanged (old); /* EMIT SIGNAL */
372 AudioFileSource::set_header_position_offset (s);
379 framepos_t const old = _end;
382 if (allow_bbt_recompute) {
383 recompute_bbt_from_frames ();
388 if (is_session_range()) {
389 Session::EndTimeChanged (old); /* EMIT SIGNAL */
397 start_changed(this); /* EMIT SIGNAL */
398 StartChanged(); /* EMIT SIGNAL */
402 end_changed(this); /* EMIT SIGNAL */
403 EndChanged(); /* EMIT SIGNAL */
406 if (start_change && end_change) {
415 Location::move_to (framepos_t pos)
427 _end = _start + length();
428 recompute_bbt_from_frames ();
430 changed (this); /* EMIT SIGNAL */
431 Changed (); /* EMIT SIGNAL */
434 assert (_start >= 0);
441 Location::set_hidden (bool yn, void*)
443 if (set_flag_internal (yn, IsHidden)) {
444 flags_changed (this); /* EMIT SIGNAL */
450 Location::set_cd (bool yn, void*)
452 // XXX this really needs to be session start
453 // but its not available here - leave to GUI
455 if (yn && _start == 0) {
456 error << _("You cannot put a CD marker at this position") << endmsg;
460 if (set_flag_internal (yn, IsCDMarker)) {
461 flags_changed (this); /* EMIT SIGNAL */
467 Location::set_is_range_marker (bool yn, void*)
469 if (set_flag_internal (yn, IsRangeMarker)) {
470 flags_changed (this);
471 FlagsChanged (); /* EMIT SIGNAL */
476 Location::set_skip (bool yn)
478 if (is_range_marker() && length() > 0) {
479 if (set_flag_internal (yn, IsSkip)) {
480 flags_changed (this);
487 Location::set_skipping (bool yn)
489 if (is_range_marker() && is_skip() && length() > 0) {
490 if (set_flag_internal (yn, IsSkipping)) {
491 flags_changed (this);
498 Location::set_auto_punch (bool yn, void*)
500 if (is_mark() || _start == _end) {
504 if (set_flag_internal (yn, IsAutoPunch)) {
505 flags_changed (this); /* EMIT SIGNAL */
506 FlagsChanged (); /* EMIT SIGNAL */
511 Location::set_auto_loop (bool yn, void*)
513 if (is_mark() || _start == _end) {
517 if (set_flag_internal (yn, IsAutoLoop)) {
518 flags_changed (this); /* EMIT SIGNAL */
519 FlagsChanged (); /* EMIT SIGNAL */
524 Location::set_flag_internal (bool yn, Flags flag)
527 if (!(_flags & flag)) {
528 _flags = Flags (_flags | flag);
533 _flags = Flags (_flags & ~flag);
541 Location::set_mark (bool yn)
543 /* This function is private, and so does not emit signals */
545 if (_start != _end) {
549 set_flag_internal (yn, IsMark);
554 Location::cd_info_node(const string & name, const string & value)
556 XMLNode* root = new XMLNode("CD-Info");
558 root->add_property("name", name);
559 root->add_property("value", value);
566 Location::get_state ()
568 XMLNode *node = new XMLNode ("Location");
571 typedef map<string, string>::const_iterator CI;
573 for(CI m = cd_info.begin(); m != cd_info.end(); ++m){
574 node->add_child_nocopy(cd_info_node(m->first, m->second));
577 id().print (buf, sizeof (buf));
578 node->add_property("id", buf);
579 node->add_property ("name", name());
580 snprintf (buf, sizeof (buf), "%" PRId64, start());
581 node->add_property ("start", buf);
582 snprintf (buf, sizeof (buf), "%" PRId64, end());
583 node->add_property ("end", buf);
584 node->add_property ("flags", enum_2_string (_flags));
585 node->add_property ("locked", (_locked ? "yes" : "no"));
586 node->add_property ("position-lock-style", enum_2_string (_position_lock_style));
589 node->add_child_nocopy (_scene_change->get_state());
596 Location::set_state (const XMLNode& node, int version)
598 const XMLProperty *prop;
600 XMLNodeList cd_list = node.children();
601 XMLNodeConstIterator cd_iter;
607 if (node.name() != "Location") {
608 error << _("incorrect XML node passed to Location::set_state") << endmsg;
612 if (!set_id (node)) {
613 warning << _("XML node for Location has no ID information") << endmsg;
616 if ((prop = node.property ("name")) == 0) {
617 error << _("XML node for Location has no name information") << endmsg;
621 set_name (prop->value());
623 if ((prop = node.property ("start")) == 0) {
624 error << _("XML node for Location has no start information") << endmsg;
628 /* can't use set_start() here, because _end
629 may make the value of _start illegal.
632 sscanf (prop->value().c_str(), "%" PRId64, &_start);
634 if ((prop = node.property ("end")) == 0) {
635 error << _("XML node for Location has no end information") << endmsg;
639 sscanf (prop->value().c_str(), "%" PRId64, &_end);
641 if ((prop = node.property ("flags")) == 0) {
642 error << _("XML node for Location has no flags information") << endmsg;
646 _flags = Flags (string_2_enum (prop->value(), _flags));
648 if ((prop = node.property ("locked")) != 0) {
649 _locked = string_is_affirmative (prop->value());
654 for (cd_iter = cd_list.begin(); cd_iter != cd_list.end(); ++cd_iter) {
658 if (cd_node->name() != "CD-Info") {
662 if ((prop = cd_node->property ("name")) != 0) {
663 cd_name = prop->value();
665 throw failed_constructor ();
668 if ((prop = cd_node->property ("value")) != 0) {
669 cd_value = prop->value();
671 throw failed_constructor ();
675 cd_info[cd_name] = cd_value;
678 if ((prop = node.property ("position-lock-style")) != 0) {
679 _position_lock_style = PositionLockStyle (string_2_enum (prop->value(), _position_lock_style));
682 XMLNode* scene_child = find_named_node (node, SceneChange::xml_node_name);
685 _scene_change = SceneChange::factory (*scene_child, version);
688 recompute_bbt_from_frames ();
690 changed (this); /* EMIT SIGNAL */
691 Changed (); /* EMIT SIGNAL */
693 assert (_start >= 0);
700 Location::set_position_lock_style (PositionLockStyle ps)
702 if (_position_lock_style == ps) {
706 _position_lock_style = ps;
708 recompute_bbt_from_frames ();
710 position_lock_style_changed (this); /* EMIT SIGNAL */
711 PositionLockStyleChanged (); /* EMIT SIGNAL */
715 Location::recompute_bbt_from_frames ()
717 if (_position_lock_style != MusicTime) {
721 _session.bbt_time (_start, _bbt_start);
722 _session.bbt_time (_end, _bbt_end);
726 Location::recompute_frames_from_bbt ()
728 if (_position_lock_style != MusicTime) {
732 TempoMap& map (_session.tempo_map());
733 set (map.frame_time (_bbt_start), map.frame_time (_bbt_end), false);
753 Location::set_scene_change (boost::shared_ptr<SceneChange> sc)
757 scene_changed (); /* EMIT SIGNAL */
760 /*---------------------------------------------------------------------- */
762 Locations::Locations (Session& s)
763 : SessionHandleRef (s)
765 current_location = 0;
768 Locations::~Locations ()
770 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
771 LocationList::iterator tmp = i;
779 Locations::set_current (Location *loc, bool want_lock)
784 Glib::Threads::Mutex::Lock lm (lock);
785 ret = set_current_unlocked (loc);
787 ret = set_current_unlocked (loc);
791 current_changed (current_location); /* EMIT SIGNAL */
797 Locations::next_available_name(string& result,string base)
799 LocationList::iterator i;
803 std::map<uint32_t,bool> taken;
811 /* find all existing names that match "base", and store
812 the numeric part of them (if any) in the map "taken"
815 for (i = locations.begin(); i != locations.end(); ++i) {
817 const string& temp ((*i)->name());
819 if (!temp.find (base,0)) {
821 if ((suffix = atoi (temp.substr(l,3))) != 0) {
822 taken.insert (make_pair (suffix,true));
828 /* Now search for an un-used suffix to add to "base". This
829 will find "holes" in the numbering sequence when a location
832 This must start at 1, both for human-numbering reasons
833 and also because the call to atoi() above would return
834 zero if there is no recognizable numeric suffix, causing
835 "base 0" not to be inserted into the "taken" map.
840 while (n < UINT32_MAX) {
841 if (taken.find (n) == taken.end()) {
842 snprintf (buf, sizeof(buf), "%d", n);
853 Locations::set_current_unlocked (Location *loc)
855 if (find (locations.begin(), locations.end(), loc) == locations.end()) {
856 error << _("Locations: attempt to use unknown location as selected location") << endmsg;
860 current_location = loc;
868 Glib::Threads::Mutex::Lock lm (lock);
870 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
872 LocationList::iterator tmp = i;
875 if (!(*i)->is_session_range()) {
883 current_location = 0;
886 changed (); /* EMIT SIGNAL */
887 current_changed (0); /* EMIT SIGNAL */
891 Locations::clear_markers ()
894 Glib::Threads::Mutex::Lock lm (lock);
895 LocationList::iterator tmp;
897 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
901 if ((*i)->is_mark() && !(*i)->is_session_range()) {
910 changed (); /* EMIT SIGNAL */
914 Locations::clear_ranges ()
917 Glib::Threads::Mutex::Lock lm (lock);
918 LocationList::iterator tmp;
920 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
925 /* We do not remove these ranges as part of this
929 if ((*i)->is_auto_punch() ||
930 (*i)->is_auto_loop() ||
931 (*i)->is_session_range()) {
936 if (!(*i)->is_mark()) {
945 current_location = 0;
949 current_changed (0); /* EMIT SIGNAL */
953 Locations::add (Location *loc, bool make_current)
958 Glib::Threads::Mutex::Lock lm (lock);
959 locations.push_back (loc);
962 current_location = loc;
966 added (loc); /* EMIT SIGNAL */
969 current_changed (current_location); /* EMIT SIGNAL */
972 if (loc->is_session_range()) {
973 Session::StartTimeChanged (0);
974 Session::EndTimeChanged (1);
979 Locations::remove (Location *loc)
981 bool was_removed = false;
982 bool was_current = false;
983 LocationList::iterator i;
985 if (loc->is_session_range()) {
990 Glib::Threads::Mutex::Lock lm (lock);
992 for (i = locations.begin(); i != locations.end(); ++i) {
997 if (current_location == loc) {
998 current_location = 0;
1008 removed (loc); /* EMIT SIGNAL */
1011 current_changed (0); /* EMIT SIGNAL */
1017 Locations::get_state ()
1019 XMLNode *node = new XMLNode ("Locations");
1020 LocationList::iterator iter;
1021 Glib::Threads::Mutex::Lock lm (lock);
1023 for (iter = locations.begin(); iter != locations.end(); ++iter) {
1024 node->add_child_nocopy ((*iter)->get_state ());
1031 Locations::set_state (const XMLNode& node, int version)
1033 if (node.name() != "Locations") {
1034 error << _("incorrect XML mode passed to Locations::set_state") << endmsg;
1038 XMLNodeList nlist = node.children();
1040 /* build up a new locations list in here */
1041 LocationList new_locations;
1043 current_location = 0;
1045 Location* session_range_location = 0;
1046 if (version < 3000) {
1047 session_range_location = new Location (_session, 0, 0, _("session"), Location::IsSessionRange);
1048 new_locations.push_back (session_range_location);
1052 Glib::Threads::Mutex::Lock lm (lock);
1054 XMLNodeConstIterator niter;
1055 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1059 XMLProperty const * prop_id = (*niter)->property ("id");
1061 PBD::ID id (prop_id->value ());
1063 LocationList::const_iterator i = locations.begin();
1064 while (i != locations.end () && (*i)->id() != id) {
1069 if (i != locations.end()) {
1070 /* we can re-use an old Location object */
1072 loc->set_state (**niter, version);
1074 loc = new Location (_session, **niter);
1079 if (version < 3000) {
1080 /* look for old-style IsStart / IsEnd properties in this location;
1081 if they are present, update the session_range_location accordingly
1083 XMLProperty const * prop = (*niter)->property ("flags");
1085 string v = prop->value ();
1087 string::size_type const c = v.find_first_of (',');
1088 string const s = v.substr (0, c);
1089 if (s == X_("IsStart")) {
1090 session_range_location->set_start (loc->start(), true);
1092 } else if (s == X_("IsEnd")) {
1093 session_range_location->set_end (loc->start(), true);
1097 if (c == string::npos) {
1101 v = v.substr (c + 1);
1107 new_locations.push_back (loc);
1111 catch (failed_constructor& err) {
1112 error << _("could not load location from session file - ignored") << endmsg;
1116 locations = new_locations;
1118 if (locations.size()) {
1119 current_location = locations.front();
1121 current_location = 0;
1125 changed (); /* EMIT SIGNAL */
1131 typedef std::pair<framepos_t,Location*> LocationPair;
1133 struct LocationStartEarlierComparison
1135 bool operator() (LocationPair a, LocationPair b) {
1136 return a.first < b.first;
1140 struct LocationStartLaterComparison
1142 bool operator() (LocationPair a, LocationPair b) {
1143 return a.first > b.first;
1148 Locations::first_mark_before (framepos_t frame, bool include_special_ranges)
1150 Glib::Threads::Mutex::Lock lm (lock);
1151 vector<LocationPair> locs;
1153 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1154 locs.push_back (make_pair ((*i)->start(), (*i)));
1155 if (!(*i)->is_mark()) {
1156 locs.push_back (make_pair ((*i)->end(), (*i)));
1160 LocationStartLaterComparison cmp;
1161 sort (locs.begin(), locs.end(), cmp);
1163 /* locs is sorted in ascending order */
1165 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1166 if ((*i).second->is_hidden()) {
1169 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1172 if ((*i).first < frame) {
1181 Locations::mark_at (framepos_t pos, framecnt_t slop) const
1183 Glib::Threads::Mutex::Lock lm (lock);
1184 Location* closest = 0;
1185 frameoffset_t mindelta = max_framepos;
1186 frameoffset_t delta;
1188 /* locations are not necessarily stored in linear time order so we have
1189 * to iterate across all of them to find the one closest to a give point.
1192 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1194 if ((*i)->is_mark()) {
1195 if (pos > (*i)->start()) {
1196 delta = pos - (*i)->start();
1198 delta = (*i)->start() - pos;
1201 if (slop == 0 && delta == 0) {
1202 /* special case: no slop, and direct hit for position */
1206 if (delta <= slop) {
1207 if (delta < mindelta) {
1219 Locations::first_mark_after (framepos_t frame, bool include_special_ranges)
1221 Glib::Threads::Mutex::Lock lm (lock);
1222 vector<LocationPair> locs;
1224 for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1225 locs.push_back (make_pair ((*i)->start(), (*i)));
1226 if (!(*i)->is_mark()) {
1227 locs.push_back (make_pair ((*i)->end(), (*i)));
1231 LocationStartEarlierComparison cmp;
1232 sort (locs.begin(), locs.end(), cmp);
1234 /* locs is sorted in reverse order */
1236 for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1237 if ((*i).second->is_hidden()) {
1240 if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1243 if ((*i).first > frame) {
1251 /** Look for the `marks' (either locations which are marks, or start/end points of range markers) either
1252 * side of a frame. Note that if frame is exactly on a `mark', that mark will not be considered for returning
1254 * @param frame Frame to look for.
1255 * @param before Filled in with the position of the last `mark' before `frame' (or max_framepos if none exists)
1256 * @param after Filled in with the position of the next `mark' after `frame' (or max_framepos if none exists)
1259 Locations::marks_either_side (framepos_t const frame, framepos_t& before, framepos_t& after) const
1261 before = after = max_framepos;
1266 Glib::Threads::Mutex::Lock lm (lock);
1270 /* Get a list of positions; don't store any that are exactly on our requested position */
1272 std::list<framepos_t> positions;
1274 for (LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
1275 if (((*i)->is_auto_loop() || (*i)->is_auto_punch())) {
1279 if (!(*i)->is_hidden()) {
1280 if ((*i)->is_mark ()) {
1281 if ((*i)->start() != frame) {
1282 positions.push_back ((*i)->start ());
1285 if ((*i)->start() != frame) {
1286 positions.push_back ((*i)->start ());
1288 if ((*i)->end() != frame) {
1289 positions.push_back ((*i)->end ());
1295 if (positions.empty ()) {
1301 std::list<framepos_t>::iterator i = positions.begin ();
1302 while (i != positions.end () && *i < frame) {
1306 if (i == positions.end ()) {
1307 /* run out of marks */
1308 before = positions.back ();
1314 if (i == positions.begin ()) {
1324 Locations::session_range_location () const
1326 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1327 if ((*i)->is_session_range()) {
1328 return const_cast<Location*> (*i);
1335 Locations::auto_loop_location () const
1337 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1338 if ((*i)->is_auto_loop()) {
1339 return const_cast<Location*> (*i);
1346 Locations::auto_punch_location () const
1348 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1349 if ((*i)->is_auto_punch()) {
1350 return const_cast<Location*> (*i);
1357 Locations::num_range_markers () const
1360 Glib::Threads::Mutex::Lock lm (lock);
1361 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1362 if ((*i)->is_range_marker()) {
1370 Locations::get_location_by_id(PBD::ID id)
1372 LocationList::iterator it;
1373 for (it = locations.begin(); it != locations.end(); ++it)
1374 if (id == (*it)->id())
1381 Locations::find_all_between (framepos_t start, framepos_t end, LocationList& ll, Location::Flags flags)
1383 Glib::Threads::Mutex::Lock lm (lock);
1385 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1386 if ((flags == 0 || (*i)->matches (flags)) &&
1387 ((*i)->start() >= start && (*i)->end() < end)) {