ardour
location.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2000 Paul Davis
3 
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.
8 
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.
13 
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.
17 
18 */
19 
20 #include <algorithm>
21 #include <set>
22 #include <cstdio> /* for sprintf */
23 #include <unistd.h>
24 #include <cerrno>
25 #include <ctime>
26 #include <list>
27 
28 #include "pbd/convert.h"
29 #include "pbd/stl_delete.h"
30 #include "pbd/xml++.h"
31 #include "pbd/enumwriter.h"
32 
33 #include "ardour/location.h"
35 #include "ardour/session.h"
36 #include "ardour/audiofilesource.h"
37 #include "ardour/tempo.h"
38 
39 #include "i18n.h"
40 
41 using namespace std;
42 using namespace ARDOUR;
43 using namespace PBD;
44 
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;
53 
54 Location::Location (Session& s)
55  : SessionHandleRef (s)
56  , _start (0)
57  , _end (0)
58  , _flags (Flags (0))
59  , _locked (false)
60  , _position_lock_style (AudioTime)
61 {
62  assert (_start >= 0);
63  assert (_end >= 0);
64 }
65 
67 Location::Location (Session& s, framepos_t sample_start, framepos_t sample_end, const std::string &name, Flags bits)
68  : SessionHandleRef (s)
69  , _name (name)
70  , _start (sample_start)
71  , _end (sample_end)
72  , _flags (bits)
73  , _locked (false)
74  , _position_lock_style (s.config.get_glue_new_markers_to_bars_and_beats() ? MusicTime : AudioTime)
75 {
77 
78  assert (_start >= 0);
79  assert (_end >= 0);
80 }
81 
83  : SessionHandleRef (other._session)
85  , _name (other._name)
86  , _start (other._start)
87  , _bbt_start (other._bbt_start)
88  , _end (other._end)
89  , _bbt_end (other._bbt_end)
90  , _flags (other._flags)
91  , _position_lock_style (other._position_lock_style)
92 {
93  /* copy is not locked even if original was */
94 
95  _locked = false;
96 
97  assert (_start >= 0);
98  assert (_end >= 0);
99 
100  /* scene change is NOT COPIED */
101 }
102 
104  : SessionHandleRef (s)
105  , _position_lock_style (AudioTime)
106 {
107  /* Note: _position_lock_style is initialised above in case set_state doesn't set it
108  (for 2.X session file compatibility).
109  */
110 
112  throw failed_constructor ();
113  }
114 
115  assert (_start >= 0);
116  assert (_end >= 0);
117 }
118 
119 bool
121 {
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 ||
129  return false;
130  }
131  return true;
132 }
133 
134 Location*
136 {
137  if (this == &other) {
138  return this;
139  }
140 
141  _name = other._name;
142  _start = other._start;
143  _bbt_start = other._bbt_start;
144  _end = other._end;
145  _bbt_end = other._bbt_end;
146  _flags = other._flags;
148 
149  /* XXX need to copy scene change */
150 
151  /* copy is not locked even if original was */
152 
153  _locked = false;
154 
155  /* "changed" not emitted on purpose */
156 
157  assert (_start >= 0);
158  assert (_end >= 0);
159 
160  return this;
161 }
162 
166 void
167 Location::set_name (const std::string& str)
168 {
169  _name = str;
170 
171  name_changed (this); /* EMIT SIGNAL */
172  NameChanged (); /* EMIT SIGNAL */
173 }
174 
180 int
181 Location::set_start (framepos_t s, bool force, bool allow_bbt_recompute)
182 {
183  if (s < 0) {
184  return -1;
185  }
186 
187  if (_locked) {
188  return -1;
189  }
190 
191  if (!force) {
192  if (((is_auto_punch() || is_auto_loop()) && s >= _end) || (!is_mark() && s > _end)) {
193  return -1;
194  }
195  }
196 
197  if (is_mark()) {
198  if (_start != s) {
199  _start = s;
200  _end = s;
201  if (allow_bbt_recompute) {
203  }
204 
205  start_changed (this); /* EMIT SIGNAL */
206  StartChanged (); /* EMIT SIGNAL */
207  end_changed (this); /* EMIT SIGNAL */
208  EndChanged (); /* EMIT SIGNAL */
209  }
210 
211  /* moving the start (position) of a marker with a scene change
212  requires an update in the Scene Changer.
213  */
214 
215  if (_scene_change) {
216  scene_changed (); /* EMIT SIGNAL */
217  }
218 
219  assert (_start >= 0);
220  assert (_end >= 0);
221 
222  return 0;
223  } else if (!force) {
224  /* range locations must exceed a minimum duration */
225  if (_end - s < Config->get_range_location_minimum()) {
226  return -1;
227  }
228  }
229 
230  if (s != _start) {
231 
232  framepos_t const old = _start;
233 
234  _start = s;
235  if (allow_bbt_recompute) {
237  }
238  start_changed (this); /* EMIT SIGNAL */
239  StartChanged (); /* EMIT SIGNAL */
240 
241  if (is_session_range ()) {
242  Session::StartTimeChanged (old); /* EMIT SIGNAL */
244  }
245  }
246 
247  assert (_start >= 0);
248 
249  return 0;
250 }
251 
257 int
258 Location::set_end (framepos_t e, bool force, bool allow_bbt_recompute)
259 {
260  if (e < 0) {
261  return -1;
262  }
263 
264  if (_locked) {
265  return -1;
266  }
267 
268  if (!force) {
269  if (((is_auto_punch() || is_auto_loop()) && e <= _start) || e < _start) {
270  return -1;
271  }
272  }
273 
274  if (is_mark()) {
275  if (_start != e) {
276  _start = e;
277  _end = e;
278  if (allow_bbt_recompute) {
280  }
281  start_changed (this); /* EMIT SIGNAL */
282  StartChanged (); /* EMIT SIGNAL */
283  end_changed (this); /* EMIT SIGNAL */
284  EndChanged (); /* EMIT SIGNAL */
285  }
286 
287  assert (_start >= 0);
288  assert (_end >= 0);
289 
290  return 0;
291  } else if (!force) {
292  /* range locations must exceed a minimum duration */
293  if (e - _start < Config->get_range_location_minimum()) {
294  return -1;
295  }
296  }
297 
298  if (e != _end) {
299 
300  framepos_t const old = _end;
301 
302  _end = e;
303  if (allow_bbt_recompute) {
305  }
306 
307  end_changed(this); /* EMIT SIGNAL */
308  EndChanged(); /* EMIT SIGNAL */
309 
310  if (is_session_range()) {
311  Session::EndTimeChanged (old); /* EMIT SIGNAL */
312  }
313  }
314 
315  assert (_end >= 0);
316 
317  return 0;
318 }
319 
320 int
321 Location::set (framepos_t s, framepos_t e, bool allow_bbt_recompute)
322 {
323  if (s < 0 || e < 0) {
324  return -1;
325  }
326 
327  /* check validity */
328  if (((is_auto_punch() || is_auto_loop()) && s >= e) || (!is_mark() && s > e)) {
329  return -1;
330  }
331 
332  bool start_change = false;
333  bool end_change = false;
334 
335  if (is_mark()) {
336 
337  if (_start != s) {
338  _start = s;
339  _end = s;
340 
341  if (allow_bbt_recompute) {
343  }
344 
345  start_change = true;
346  end_change = true;
347  }
348 
349  assert (_start >= 0);
350  assert (_end >= 0);
351 
352  } else {
353 
354  /* range locations must exceed a minimum duration */
355  if (e - s < Config->get_range_location_minimum()) {
356  return -1;
357  }
358 
359  if (s != _start) {
360 
361  framepos_t const old = _start;
362  _start = s;
363 
364  if (allow_bbt_recompute) {
366  }
367 
368  start_change = true;
369 
370  if (is_session_range ()) {
371  Session::StartTimeChanged (old); /* EMIT SIGNAL */
373  }
374  }
375 
376 
377  if (e != _end) {
378 
379  framepos_t const old = _end;
380  _end = e;
381 
382  if (allow_bbt_recompute) {
384  }
385 
386  end_change = true;
387 
388  if (is_session_range()) {
389  Session::EndTimeChanged (old); /* EMIT SIGNAL */
390  }
391  }
392 
393  assert (_end >= 0);
394  }
395 
396  if (start_change) {
397  start_changed(this); /* EMIT SIGNAL */
398  StartChanged(); /* EMIT SIGNAL */
399  }
400 
401  if (end_change) {
402  end_changed(this); /* EMIT SIGNAL */
403  EndChanged(); /* EMIT SIGNAL */
404  }
405 
406  if (start_change && end_change) {
407  changed (this);
408  Changed ();
409  }
410 
411  return 0;
412 }
413 
414 int
416 {
417  if (pos < 0) {
418  return -1;
419  }
420 
421  if (_locked) {
422  return -1;
423  }
424 
425  if (_start != pos) {
426  _start = pos;
427  _end = _start + length();
429 
430  changed (this); /* EMIT SIGNAL */
431  Changed (); /* EMIT SIGNAL */
432  }
433 
434  assert (_start >= 0);
435  assert (_end >= 0);
436 
437  return 0;
438 }
439 
440 void
441 Location::set_hidden (bool yn, void*)
442 {
443  if (set_flag_internal (yn, IsHidden)) {
444  flags_changed (this); /* EMIT SIGNAL */
445  FlagsChanged ();
446  }
447 }
448 
449 void
450 Location::set_cd (bool yn, void*)
451 {
452  // XXX this really needs to be session start
453  // but its not available here - leave to GUI
454 
455  if (yn && _start == 0) {
456  error << _("You cannot put a CD marker at this position") << endmsg;
457  return;
458  }
459 
460  if (set_flag_internal (yn, IsCDMarker)) {
461  flags_changed (this); /* EMIT SIGNAL */
462  FlagsChanged ();
463  }
464 }
465 
466 void
468 {
469  if (set_flag_internal (yn, IsRangeMarker)) {
470  flags_changed (this);
471  FlagsChanged (); /* EMIT SIGNAL */
472  }
473 }
474 
475 void
477 {
478  if (is_range_marker() && length() > 0) {
479  if (set_flag_internal (yn, IsSkip)) {
480  flags_changed (this);
481  FlagsChanged ();
482  }
483  }
484 }
485 
486 void
488 {
489  if (is_range_marker() && is_skip() && length() > 0) {
490  if (set_flag_internal (yn, IsSkipping)) {
491  flags_changed (this);
492  FlagsChanged ();
493  }
494  }
495 }
496 
497 void
498 Location::set_auto_punch (bool yn, void*)
499 {
500  if (is_mark() || _start == _end) {
501  return;
502  }
503 
504  if (set_flag_internal (yn, IsAutoPunch)) {
505  flags_changed (this); /* EMIT SIGNAL */
506  FlagsChanged (); /* EMIT SIGNAL */
507  }
508 }
509 
510 void
511 Location::set_auto_loop (bool yn, void*)
512 {
513  if (is_mark() || _start == _end) {
514  return;
515  }
516 
517  if (set_flag_internal (yn, IsAutoLoop)) {
518  flags_changed (this); /* EMIT SIGNAL */
519  FlagsChanged (); /* EMIT SIGNAL */
520  }
521 }
522 
523 bool
525 {
526  if (yn) {
527  if (!(_flags & flag)) {
528  _flags = Flags (_flags | flag);
529  return true;
530  }
531  } else {
532  if (_flags & flag) {
533  _flags = Flags (_flags & ~flag);
534  return true;
535  }
536  }
537  return false;
538 }
539 
540 void
542 {
543  /* This function is private, and so does not emit signals */
544 
545  if (_start != _end) {
546  return;
547  }
548 
550 }
551 
552 
553 XMLNode&
554 Location::cd_info_node(const string & name, const string & value)
555 {
556  XMLNode* root = new XMLNode("CD-Info");
557 
558  root->add_property("name", name);
559  root->add_property("value", value);
560 
561  return *root;
562 }
563 
564 
565 XMLNode&
567 {
568  XMLNode *node = new XMLNode ("Location");
569  char buf[64];
570 
571  typedef map<string, string>::const_iterator CI;
572 
573  for(CI m = cd_info.begin(); m != cd_info.end(); ++m){
574  node->add_child_nocopy(cd_info_node(m->first, m->second));
575  }
576 
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));
587 
588  if (_scene_change) {
589  node->add_child_nocopy (_scene_change->get_state());
590  }
591 
592  return *node;
593 }
594 
595 int
596 Location::set_state (const XMLNode& node, int version)
597 {
598  const XMLProperty *prop;
599 
600  XMLNodeList cd_list = node.children();
601  XMLNodeConstIterator cd_iter;
602  XMLNode *cd_node;
603 
604  string cd_name;
605  string cd_value;
606 
607  if (node.name() != "Location") {
608  error << _("incorrect XML node passed to Location::set_state") << endmsg;
609  return -1;
610  }
611 
612  if (!set_id (node)) {
613  warning << _("XML node for Location has no ID information") << endmsg;
614  }
615 
616  if ((prop = node.property ("name")) == 0) {
617  error << _("XML node for Location has no name information") << endmsg;
618  return -1;
619  }
620 
621  set_name (prop->value());
622 
623  if ((prop = node.property ("start")) == 0) {
624  error << _("XML node for Location has no start information") << endmsg;
625  return -1;
626  }
627 
628  /* can't use set_start() here, because _end
629  may make the value of _start illegal.
630  */
631 
632  sscanf (prop->value().c_str(), "%" PRId64, &_start);
633 
634  if ((prop = node.property ("end")) == 0) {
635  error << _("XML node for Location has no end information") << endmsg;
636  return -1;
637  }
638 
639  sscanf (prop->value().c_str(), "%" PRId64, &_end);
640 
641  if ((prop = node.property ("flags")) == 0) {
642  error << _("XML node for Location has no flags information") << endmsg;
643  return -1;
644  }
645 
646  _flags = Flags (string_2_enum (prop->value(), _flags));
647 
648  if ((prop = node.property ("locked")) != 0) {
649  _locked = string_is_affirmative (prop->value());
650  } else {
651  _locked = false;
652  }
653 
654  for (cd_iter = cd_list.begin(); cd_iter != cd_list.end(); ++cd_iter) {
655 
656  cd_node = *cd_iter;
657 
658  if (cd_node->name() != "CD-Info") {
659  continue;
660  }
661 
662  if ((prop = cd_node->property ("name")) != 0) {
663  cd_name = prop->value();
664  } else {
665  throw failed_constructor ();
666  }
667 
668  if ((prop = cd_node->property ("value")) != 0) {
669  cd_value = prop->value();
670  } else {
671  throw failed_constructor ();
672  }
673 
674 
675  cd_info[cd_name] = cd_value;
676  }
677 
678  if ((prop = node.property ("position-lock-style")) != 0) {
680  }
681 
682  XMLNode* scene_child = find_named_node (node, SceneChange::xml_node_name);
683 
684  if (scene_child) {
685  _scene_change = SceneChange::factory (*scene_child, version);
686  }
687 
689 
690  changed (this); /* EMIT SIGNAL */
691  Changed (); /* EMIT SIGNAL */
692 
693  assert (_start >= 0);
694  assert (_end >= 0);
695 
696  return 0;
697 }
698 
699 void
701 {
702  if (_position_lock_style == ps) {
703  return;
704  }
705 
707 
709 
710  position_lock_style_changed (this); /* EMIT SIGNAL */
711  PositionLockStyleChanged (); /* EMIT SIGNAL */
712 }
713 
714 void
716 {
718  return;
719  }
720 
723 }
724 
725 void
727 {
729  return;
730  }
731 
732  TempoMap& map (_session.tempo_map());
733  set (map.frame_time (_bbt_start), map.frame_time (_bbt_end), false);
734 }
735 
736 void
738 {
739  _locked = true;
740  lock_changed (this);
741  LockChanged ();
742 }
743 
744 void
746 {
747  _locked = false;
748  lock_changed (this);
749  LockChanged ();
750 }
751 
752 void
754 {
755  _scene_change = sc;
756 
757  scene_changed (); /* EMIT SIGNAL */
758 }
759 
760 /*---------------------------------------------------------------------- */
761 
763  : SessionHandleRef (s)
764 {
765  current_location = 0;
766 }
767 
769 {
770  for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
771  LocationList::iterator tmp = i;
772  ++tmp;
773  delete *i;
774  i = tmp;
775  }
776 }
777 
778 int
779 Locations::set_current (Location *loc, bool want_lock)
780 {
781  int ret;
782 
783  if (want_lock) {
785  ret = set_current_unlocked (loc);
786  } else {
787  ret = set_current_unlocked (loc);
788  }
789 
790  if (ret == 0) {
791  current_changed (current_location); /* EMIT SIGNAL */
792  }
793  return ret;
794 }
795 
796 int
797 Locations::next_available_name(string& result,string base)
798 {
799  LocationList::iterator i;
800  string::size_type l;
801  int suffix;
802  char buf[32];
803  std::map<uint32_t,bool> taken;
804  uint32_t n;
805 
806  result = base;
807  l = base.length();
808 
809  if (!base.empty()) {
810 
811  /* find all existing names that match "base", and store
812  the numeric part of them (if any) in the map "taken"
813  */
814 
815  for (i = locations.begin(); i != locations.end(); ++i) {
816 
817  const string& temp ((*i)->name());
818 
819  if (!temp.find (base,0)) {
820 
821  if ((suffix = atoi (temp.substr(l,3))) != 0) {
822  taken.insert (make_pair (suffix,true));
823  }
824  }
825  }
826  }
827 
828  /* Now search for an un-used suffix to add to "base". This
829  will find "holes" in the numbering sequence when a location
830  was deleted.
831 
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.
836  */
837 
838  n = 1;
839 
840  while (n < UINT32_MAX) {
841  if (taken.find (n) == taken.end()) {
842  snprintf (buf, sizeof(buf), "%d", n);
843  result += buf;
844  return 1;
845  }
846  ++n;
847  }
848 
849  return 0;
850 }
851 
852 int
854 {
855  if (find (locations.begin(), locations.end(), loc) == locations.end()) {
856  error << _("Locations: attempt to use unknown location as selected location") << endmsg;
857  return -1;
858  }
859 
860  current_location = loc;
861  return 0;
862 }
863 
864 void
866 {
867  {
869 
870  for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
871 
872  LocationList::iterator tmp = i;
873  ++tmp;
874 
875  if (!(*i)->is_session_range()) {
876  delete *i;
877  locations.erase (i);
878  }
879 
880  i = tmp;
881  }
882 
883  current_location = 0;
884  }
885 
886  changed (); /* EMIT SIGNAL */
887  current_changed (0); /* EMIT SIGNAL */
888 }
889 
890 void
892 {
893  {
895  LocationList::iterator tmp;
896 
897  for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
898  tmp = i;
899  ++tmp;
900 
901  if ((*i)->is_mark() && !(*i)->is_session_range()) {
902  delete *i;
903  locations.erase (i);
904  }
905 
906  i = tmp;
907  }
908  }
909 
910  changed (); /* EMIT SIGNAL */
911 }
912 
913 void
915 {
916  {
918  LocationList::iterator tmp;
919 
920  for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
921 
922  tmp = i;
923  ++tmp;
924 
925  /* We do not remove these ranges as part of this
926  * operation
927  */
928 
929  if ((*i)->is_auto_punch() ||
930  (*i)->is_auto_loop() ||
931  (*i)->is_session_range()) {
932  i = tmp;
933  continue;
934  }
935 
936  if (!(*i)->is_mark()) {
937  delete *i;
938  locations.erase (i);
939 
940  }
941 
942  i = tmp;
943  }
944 
945  current_location = 0;
946  }
947 
948  changed ();
949  current_changed (0); /* EMIT SIGNAL */
950 }
951 
952 void
953 Locations::add (Location *loc, bool make_current)
954 {
955  assert (loc);
956 
957  {
959  locations.push_back (loc);
960 
961  if (make_current) {
962  current_location = loc;
963  }
964  }
965 
966  added (loc); /* EMIT SIGNAL */
967 
968  if (make_current) {
969  current_changed (current_location); /* EMIT SIGNAL */
970  }
971 
972  if (loc->is_session_range()) {
975  }
976 }
977 
978 void
980 {
981  bool was_removed = false;
982  bool was_current = false;
983  LocationList::iterator i;
984 
985  if (loc->is_session_range()) {
986  return;
987  }
988 
989  {
991 
992  for (i = locations.begin(); i != locations.end(); ++i) {
993  if ((*i) == loc) {
994  delete *i;
995  locations.erase (i);
996  was_removed = true;
997  if (current_location == loc) {
998  current_location = 0;
999  was_current = true;
1000  }
1001  break;
1002  }
1003  }
1004  }
1005 
1006  if (was_removed) {
1007 
1008  removed (loc); /* EMIT SIGNAL */
1009 
1010  if (was_current) {
1011  current_changed (0); /* EMIT SIGNAL */
1012  }
1013  }
1014 }
1015 
1016 XMLNode&
1018 {
1019  XMLNode *node = new XMLNode ("Locations");
1020  LocationList::iterator iter;
1022 
1023  for (iter = locations.begin(); iter != locations.end(); ++iter) {
1024  node->add_child_nocopy ((*iter)->get_state ());
1025  }
1026 
1027  return *node;
1028 }
1029 
1030 int
1031 Locations::set_state (const XMLNode& node, int version)
1032 {
1033  if (node.name() != "Locations") {
1034  error << _("incorrect XML mode passed to Locations::set_state") << endmsg;
1035  return -1;
1036  }
1037 
1038  XMLNodeList nlist = node.children();
1039 
1040  /* build up a new locations list in here */
1041  LocationList new_locations;
1042 
1043  current_location = 0;
1044 
1046  if (version < 3000) {
1047  session_range_location = new Location (_session, 0, 0, _("session"), Location::IsSessionRange);
1048  new_locations.push_back (session_range_location);
1049  }
1050 
1051  {
1053 
1054  XMLNodeConstIterator niter;
1055  for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1056 
1057  try {
1058 
1059  XMLProperty const * prop_id = (*niter)->property ("id");
1060  assert (prop_id);
1061  PBD::ID id (prop_id->value ());
1062 
1063  LocationList::const_iterator i = locations.begin();
1064  while (i != locations.end () && (*i)->id() != id) {
1065  ++i;
1066  }
1067 
1068  Location* loc;
1069  if (i != locations.end()) {
1070  /* we can re-use an old Location object */
1071  loc = *i;
1072  loc->set_state (**niter, version);
1073  } else {
1074  loc = new Location (_session, **niter);
1075  }
1076 
1077  bool add = true;
1078 
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
1082  */
1083  XMLProperty const * prop = (*niter)->property ("flags");
1084  if (prop) {
1085  string v = prop->value ();
1086  while (1) {
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);
1091  add = false;
1092  } else if (s == X_("IsEnd")) {
1093  session_range_location->set_end (loc->start(), true);
1094  add = false;
1095  }
1096 
1097  if (c == string::npos) {
1098  break;
1099  }
1100 
1101  v = v.substr (c + 1);
1102  }
1103  }
1104  }
1105 
1106  if (add) {
1107  new_locations.push_back (loc);
1108  }
1109  }
1110 
1111  catch (failed_constructor& err) {
1112  error << _("could not load location from session file - ignored") << endmsg;
1113  }
1114  }
1115 
1116  /* We may have some unused locations in the old list. */
1117  for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
1118  LocationList::iterator tmp = i;
1119  ++tmp;
1120 
1121  LocationList::iterator n = new_locations.begin();
1122  bool found = false;
1123 
1124  while (n != new_locations.end ()) {
1125  if ((*i)->id() == (*n)->id()) {
1126  found = true;
1127  break;
1128  }
1129  ++n;
1130  }
1131 
1132  if (!found) {
1133  delete *i;
1134  locations.erase (i);
1135  }
1136 
1137  i = tmp;
1138  }
1139 
1140  locations = new_locations;
1141 
1142  if (locations.size()) {
1143  current_location = locations.front();
1144  } else {
1145  current_location = 0;
1146  }
1147  }
1148 
1149  changed (); /* EMIT SIGNAL */
1150 
1151  return 0;
1152 }
1153 
1154 
1155 typedef std::pair<framepos_t,Location*> LocationPair;
1156 
1158 {
1159  bool operator() (LocationPair a, LocationPair b) {
1160  return a.first < b.first;
1161  }
1162 };
1163 
1165 {
1166  bool operator() (LocationPair a, LocationPair b) {
1167  return a.first > b.first;
1168  }
1169 };
1170 
1171 framepos_t
1172 Locations::first_mark_before (framepos_t frame, bool include_special_ranges)
1173 {
1175  vector<LocationPair> locs;
1176 
1177  for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1178  locs.push_back (make_pair ((*i)->start(), (*i)));
1179  if (!(*i)->is_mark()) {
1180  locs.push_back (make_pair ((*i)->end(), (*i)));
1181  }
1182  }
1183 
1185  sort (locs.begin(), locs.end(), cmp);
1186 
1187  /* locs is sorted in ascending order */
1188 
1189  for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1190  if ((*i).second->is_hidden()) {
1191  continue;
1192  }
1193  if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1194  continue;
1195  }
1196  if ((*i).first < frame) {
1197  return (*i).first;
1198  }
1199  }
1200 
1201  return -1;
1202 }
1203 
1204 Location*
1206 {
1208  Location* closest = 0;
1209  frameoffset_t mindelta = max_framepos;
1210  frameoffset_t delta;
1211 
1212  /* locations are not necessarily stored in linear time order so we have
1213  * to iterate across all of them to find the one closest to a give point.
1214  */
1215 
1216  for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1217 
1218  if ((*i)->is_mark()) {
1219  if (pos > (*i)->start()) {
1220  delta = pos - (*i)->start();
1221  } else {
1222  delta = (*i)->start() - pos;
1223  }
1224 
1225  if (slop == 0 && delta == 0) {
1226  /* special case: no slop, and direct hit for position */
1227  return *i;
1228  }
1229 
1230  if (delta <= slop) {
1231  if (delta < mindelta) {
1232  closest = *i;
1233  mindelta = delta;
1234  }
1235  }
1236  }
1237  }
1238 
1239  return closest;
1240 }
1241 
1242 framepos_t
1243 Locations::first_mark_after (framepos_t frame, bool include_special_ranges)
1244 {
1246  vector<LocationPair> locs;
1247 
1248  for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
1249  locs.push_back (make_pair ((*i)->start(), (*i)));
1250  if (!(*i)->is_mark()) {
1251  locs.push_back (make_pair ((*i)->end(), (*i)));
1252  }
1253  }
1254 
1256  sort (locs.begin(), locs.end(), cmp);
1257 
1258  /* locs is sorted in reverse order */
1259 
1260  for (vector<LocationPair>::iterator i = locs.begin(); i != locs.end(); ++i) {
1261  if ((*i).second->is_hidden()) {
1262  continue;
1263  }
1264  if (!include_special_ranges && ((*i).second->is_auto_loop() || (*i).second->is_auto_punch())) {
1265  continue;
1266  }
1267  if ((*i).first > frame) {
1268  return (*i).first;
1269  }
1270  }
1271 
1272  return -1;
1273 }
1274 
1282 void
1283 Locations::marks_either_side (framepos_t const frame, framepos_t& before, framepos_t& after) const
1284 {
1285  before = after = max_framepos;
1286 
1287  LocationList locs;
1288 
1289  {
1291  locs = locations;
1292  }
1293 
1294  /* Get a list of positions; don't store any that are exactly on our requested position */
1295 
1296  std::list<framepos_t> positions;
1297 
1298  for (LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
1299  if (((*i)->is_auto_loop() || (*i)->is_auto_punch())) {
1300  continue;
1301  }
1302 
1303  if (!(*i)->is_hidden()) {
1304  if ((*i)->is_mark ()) {
1305  if ((*i)->start() != frame) {
1306  positions.push_back ((*i)->start ());
1307  }
1308  } else {
1309  if ((*i)->start() != frame) {
1310  positions.push_back ((*i)->start ());
1311  }
1312  if ((*i)->end() != frame) {
1313  positions.push_back ((*i)->end ());
1314  }
1315  }
1316  }
1317  }
1318 
1319  if (positions.empty ()) {
1320  return;
1321  }
1322 
1323  positions.sort ();
1324 
1325  std::list<framepos_t>::iterator i = positions.begin ();
1326  while (i != positions.end () && *i < frame) {
1327  ++i;
1328  }
1329 
1330  if (i == positions.end ()) {
1331  /* run out of marks */
1332  before = positions.back ();
1333  return;
1334  }
1335 
1336  after = *i;
1337 
1338  if (i == positions.begin ()) {
1339  /* none before */
1340  return;
1341  }
1342 
1343  --i;
1344  before = *i;
1345 }
1346 
1347 Location*
1349 {
1350  for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1351  if ((*i)->is_session_range()) {
1352  return const_cast<Location*> (*i);
1353  }
1354  }
1355  return 0;
1356 }
1357 
1358 Location*
1360 {
1361  for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1362  if ((*i)->is_auto_loop()) {
1363  return const_cast<Location*> (*i);
1364  }
1365  }
1366  return 0;
1367 }
1368 
1369 Location*
1371 {
1372  for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1373  if ((*i)->is_auto_punch()) {
1374  return const_cast<Location*> (*i);
1375  }
1376  }
1377  return 0;
1378 }
1379 
1380 uint32_t
1382 {
1383  uint32_t cnt = 0;
1385  for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1386  if ((*i)->is_range_marker()) {
1387  ++cnt;
1388  }
1389  }
1390  return cnt;
1391 }
1392 
1393 Location *
1395 {
1396  LocationList::iterator it;
1397  for (it = locations.begin(); it != locations.end(); ++it)
1398  if (id == (*it)->id())
1399  return *it;
1400 
1401  return 0;
1402 }
1403 
1404 void
1406 {
1408 
1409  for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
1410  if ((flags == 0 || (*i)->matches (flags)) &&
1411  ((*i)->start() >= start && (*i)->end() < end)) {
1412  ll.push_back (*i);
1413  }
1414  }
1415 }
1416 
static PBD::Signal1< void, Location * > start_changed
Definition: location.h:114
int next_available_name(std::string &result, std::string base)
Definition: location.cc:797
framepos_t first_mark_after(framepos_t, bool include_special_ranges=false)
Definition: location.cc:1243
Location * current_location
Definition: location.h:228
std::pair< framepos_t, Location * > LocationPair
Definition: location.cc:1155
ARDOUR::Session & _session
bool operator==(const Location &other)
Definition: location.cc:120
Location * mark_at(framepos_t, framecnt_t slop=0) const
Definition: location.cc:1205
static PBD::Signal0< void > scene_changed
Definition: location.h:146
int atoi(const string &s)
Definition: convert.cc:140
PBD::Signal1< void, Location * > current_changed
Definition: location.h:203
static PBD::Signal1< void, Location * > end_changed
Definition: location.h:113
void set_mark(bool yn)
Definition: location.cc:541
Location * auto_loop_location() const
Definition: location.cc:1359
const std::string & value() const
Definition: xml++.h:159
bool is_skip() const
Definition: location.h:99
std::list< Location * > LocationList
Definition: location.h:167
PBD::Signal1< void, Location * > added
Definition: location.h:209
boost::shared_ptr< SceneChange > _scene_change
Definition: location.h:157
#define enum_2_string(e)
Definition: enumwriter.h:97
void clear_ranges()
Definition: location.cc:914
static PBD::Signal1< void, framepos_t > EndTimeChanged
Definition: session.h:585
void set_name(const std::string &str)
Definition: location.cc:167
void recompute_bbt_from_frames()
Definition: location.cc:715
const std::string & name() const
Definition: xml++.h:104
PBD::Signal0< void > LockChanged
Definition: location.h:131
TempoMap & tempo_map()
Definition: session.h:596
void set_auto_punch(bool yn, void *src)
Definition: location.cc:498
PositionLockStyle _position_lock_style
Definition: location.h:156
static std::string xml_node_name
Definition: scene_change.h:37
framepos_t first_mark_before(framepos_t, bool include_special_ranges=false)
Definition: location.cc:1172
Timecode::BBT_Time _bbt_end
Definition: location.h:153
framepos_t end() const
Definition: location.h:72
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
LIBPBD_API Transmitter warning
const XMLNodeList & children(const std::string &str=std::string()) const
Definition: xml++.cc:329
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
static PBD::Signal1< void, Location * > position_lock_style_changed
Definition: location.h:117
int set_state(const XMLNode &, int version)
Definition: location.cc:1031
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
Definition: region.cc:63
void marks_either_side(framepos_t const, framepos_t &, framepos_t &) const
Definition: location.cc:1283
void set_skipping(bool yn)
Definition: location.cc:487
int move_to(framepos_t pos)
Definition: location.cc:415
bool is_session_range() const
Definition: location.h:97
Definition: id.h:32
Location * session_range_location() const
Definition: location.cc:1348
std::list< XMLNode * > XMLNodeList
Definition: xml++.h:44
#define _(Text)
Definition: i18n.h:11
Locations(Session &)
Definition: location.cc:762
static PBD::Signal1< void, framepos_t > StartTimeChanged
Definition: session.h:584
Timecode::BBT_Time _bbt_start
Definition: location.h:151
#define X_(Text)
Definition: i18n.h:13
int64_t framecnt_t
Definition: types.h:76
XMLProperty * property(const char *)
Definition: xml++.cc:413
PBD::Signal0< void > PositionLockStyleChanged
Definition: location.h:132
int set(framepos_t start, framepos_t end, bool allow_bbt_recompute=true)
Definition: location.cc:321
#define string_2_enum(str, e)
Definition: enumwriter.h:98
int set_current_unlocked(Location *)
Definition: location.cc:853
Location * get_location_by_id(PBD::ID)
Definition: location.cc:1394
std::map< std::string, std::string > cd_info
Definition: location.h:136
bool is_auto_punch() const
Definition: location.h:92
PBD::Signal1< void, Location * > removed
Definition: location.h:210
void set_is_range_marker(bool yn, void *src)
Definition: location.cc:467
bool string_is_affirmative(const std::string &str)
Definition: convert.cc:282
PBD::Signal0< void > FlagsChanged
Definition: location.h:130
Definition: amp.h:29
const PBD::ID & id() const
Definition: stateful.h:68
static boost::shared_ptr< SceneChange > factory(const XMLNode &, int version)
Definition: scene_change.cc:31
XMLNode & cd_info_node(const std::string &, const std::string &)
Definition: location.cc:554
void print(char *buf, uint32_t bufsize) const
Definition: id.cc:73
framepos_t _start
Definition: location.h:150
bool set_id(const XMLNode &)
Definition: stateful.cc:381
void set_auto_loop(bool yn, void *src)
Definition: location.cc:511
XMLNode & get_state(void)
Definition: location.cc:566
Location * operator=(const Location &other)
Definition: location.cc:135
int64_t framepos_t
Definition: types.h:66
LIBARDOUR_API XMLNode * find_named_node(const XMLNode &node, std::string name)
PBD::Signal0< void > NameChanged
Definition: location.h:126
int64_t frameoffset_t
Definition: types.h:71
static int loading_state_version
Definition: stateful.h:90
uint32_t num_range_markers() const
Definition: location.cc:1381
void find_all_between(framepos_t start, framepos_t, LocationList &, Location::Flags)
Definition: location.cc:1405
bool changed() const
Definition: stateful.cc:325
bool is_mark() const
Definition: location.h:94
bool set_flag_internal(bool yn, Flags flag)
Definition: location.cc:524
int set_start(framepos_t s, bool force=false, bool allow_bbt_recompute=true)
Definition: location.cc:181
XMLProperty * add_property(const char *name, const std::string &value)
void add(Location *, bool make_current=false)
Definition: location.cc:953
const char * name
void add_child_nocopy(XMLNode &)
Definition: xml++.cc:357
XMLNode & get_state(void)
Definition: location.cc:1017
static void set_header_position_offset(framecnt_t offset)
const std::string & name() const
Definition: location.h:81
void set_cd(bool yn, void *src)
Definition: location.cc:450
Definition: xml++.h:95
static PBD::Signal1< void, Location * > flags_changed
Definition: location.h:115
void set_scene_change(boost::shared_ptr< SceneChange >)
Definition: location.cc:753
std::string _name
Definition: location.h:149
int set_state(const XMLNode &, int version)
Definition: location.cc:596
Definition: debug.h:30
framecnt_t length() const
Definition: location.h:73
void clear_markers()
Definition: location.cc:891
PBD::Signal0< void > EndChanged
Definition: location.h:127
framepos_t _end
Definition: location.h:152
static PBD::Signal1< void, Location * > lock_changed
Definition: location.h:116
PBD::Signal0< void > StartChanged
Definition: location.h:128
framepos_t start() const
Definition: location.h:71
static const framepos_t max_framepos
Definition: types.h:78
PositionLockStyle
Definition: types.h:553
void remove(Location *)
Definition: location.cc:979
bool is_range_marker() const
Definition: location.h:98
static PBD::Signal1< void, Location * > name_changed
Definition: location.h:112
void set_skip(bool yn)
Definition: location.cc:476
Location(Session &)
Definition: location.cc:54
LocationList locations
Definition: location.h:227
bool is_auto_loop() const
Definition: location.h:93
Glib::Threads::Mutex lock
Definition: location.h:229
XMLNodeList::const_iterator XMLNodeConstIterator
Definition: xml++.h:49
void recompute_frames_from_bbt()
Definition: location.cc:726
void bbt_time(framepos_t when, Timecode::BBT_Time &)
Definition: session_time.cc:47
void set_hidden(bool yn, void *src)
Definition: location.cc:441
int set_end(framepos_t e, bool force=false, bool allow_bbt_recompute=true)
Definition: location.cc:258
PBD::Signal0< void > Changed
Definition: location.h:129
int set_current(Location *, bool want_lock=true)
Definition: location.cc:779
void set_position_lock_style(PositionLockStyle ps)
Definition: location.cc:700
Location * auto_punch_location() const
Definition: location.cc:1370