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.
23 #include <cstdio> /* for sprintf */
27 #include <sigc++/bind.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/session.h>
35 #include <ardour/audiofilesource.h>
40 using namespace ARDOUR;
44 Location::Location (const Location& other)
45 : _name (other._name),
46 _start (other._start),
50 /* start and end flags can never be copied, because there can only ever be one of each */
52 _flags = Flags (_flags & ~IsStart);
53 _flags = Flags (_flags & ~IsEnd);
56 Location::Location (const XMLNode& node)
58 if (set_state (node)) {
59 throw failed_constructor ();
64 Location::operator= (const Location& other)
71 _start = other._start;
73 _flags = other._flags;
75 /* "changed" not emitted on purpose */
81 Location::set_start (nframes_t s)
89 start_changed(this); /* EMIT SIGNAL */
93 Session::StartTimeChanged (); /* EMIT SIGNAL */
94 AudioFileSource::set_header_position_offset ( s );
98 Session::EndTimeChanged (); /* EMIT SIGNAL */
104 if (((is_auto_punch() || is_auto_loop()) && s >= _end) || s > _end) {
110 start_changed(this); /* EMIT SIGNAL */
117 Location::set_end (nframes_t e)
123 end_changed(this); /* EMIT SIGNAL */
128 if (((is_auto_punch() || is_auto_loop()) && e <= _start) || e < _start) {
134 end_changed(this); /* EMIT SIGNAL */
140 Location::set (nframes_t start, nframes_t end)
142 if (is_mark() && start != end) {
144 } else if (((is_auto_punch() || is_auto_loop()) && start >= end) || (start > end)) {
148 if (_start != start) {
150 start_changed(this); /* EMIT SIGNAL */
155 end_changed(this); /* EMIT SIGNAL */
161 Location::set_hidden (bool yn, void *src)
163 if (set_flag_internal (yn, IsHidden)) {
164 FlagsChanged (this, src); /* EMIT SIGNAL */
169 Location::set_cd (bool yn, void *src)
171 if (set_flag_internal (yn, IsCDMarker)) {
172 FlagsChanged (this, src); /* EMIT SIGNAL */
177 Location::set_is_end (bool yn, void *src)
179 if (set_flag_internal (yn, IsEnd)) {
180 FlagsChanged (this, src); /* EMIT SIGNAL */
185 Location::set_is_start (bool yn, void *src)
187 if (set_flag_internal (yn, IsStart)) {
188 FlagsChanged (this, src); /* EMIT SIGNAL */
193 Location::set_auto_punch (bool yn, void *src)
195 if (is_mark() || _start == _end) {
199 if (set_flag_internal (yn, IsAutoPunch)) {
200 FlagsChanged (this, src); /* EMIT SIGNAL */
205 Location::set_auto_loop (bool yn, void *src)
207 if (is_mark() || _start == _end) {
211 if (set_flag_internal (yn, IsAutoLoop)) {
212 FlagsChanged (this, src); /* EMIT SIGNAL */
217 Location::set_flag_internal (bool yn, Flags flag)
220 if (!(_flags & flag)) {
221 _flags = Flags (_flags | flag);
226 _flags = Flags (_flags & ~flag);
234 Location::set_mark (bool yn)
236 /* This function is private, and so does not emit signals */
238 if (_start != _end) {
242 set_flag_internal (yn, IsMark);
247 Location::cd_info_node(const string & name, const string & value)
249 XMLNode* root = new XMLNode("CD-Info");
251 root->add_property("name", name);
252 root->add_property("value", value);
259 Location::get_state (void)
261 XMLNode *node = new XMLNode ("Location");
264 typedef map<string, string>::const_iterator CI;
266 for(CI m = cd_info.begin(); m != cd_info.end(); ++m){
267 node->add_child_nocopy(cd_info_node(m->first, m->second));
270 id().print (buf, sizeof (buf));
271 node->add_property("id", buf);
272 node->add_property ("name", name());
273 snprintf (buf, sizeof (buf), "%u", start());
274 node->add_property ("start", buf);
275 snprintf (buf, sizeof (buf), "%u", end());
276 node->add_property ("end", buf);
277 node->add_property ("flags", enum_2_string (_flags));
283 Location::set_state (const XMLNode& node)
285 const XMLProperty *prop;
287 XMLNodeList cd_list = node.children();
288 XMLNodeConstIterator cd_iter;
294 if (node.name() != "Location") {
295 error << _("incorrect XML node passed to Location::set_state") << endmsg;
299 if ((prop = node.property ("id")) == 0) {
300 warning << _("XML node for Location has no ID information") << endmsg;
302 _id = prop->value ();
305 if ((prop = node.property ("name")) == 0) {
306 error << _("XML node for Location has no name information") << endmsg;
310 set_name (prop->value());
312 if ((prop = node.property ("start")) == 0) {
313 error << _("XML node for Location has no start information") << endmsg;
317 /* can't use set_start() here, because _end
318 may make the value of _start illegal.
321 _start = atoi (prop->value().c_str());
323 if ((prop = node.property ("end")) == 0) {
324 error << _("XML node for Location has no end information") << endmsg;
328 _end = atoi (prop->value().c_str());
330 if ((prop = node.property ("flags")) == 0) {
331 error << _("XML node for Location has no flags information") << endmsg;
335 _flags = Flags (string_2_enum (prop->value(), _flags));
337 for (cd_iter = cd_list.begin(); cd_iter != cd_list.end(); ++cd_iter) {
341 if (cd_node->name() != "CD-Info") {
345 if ((prop = cd_node->property ("name")) != 0) {
346 cd_name = prop->value();
348 throw failed_constructor ();
351 if ((prop = cd_node->property ("value")) != 0) {
352 cd_value = prop->value();
354 throw failed_constructor ();
358 cd_info[cd_name] = cd_value;
362 changed(this); /* EMIT SIGNAL */
367 /*---------------------------------------------------------------------- */
369 Locations::Locations ()
372 current_location = 0;
375 Locations::~Locations ()
377 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
378 LocationList::iterator tmp = i;
386 Locations::set_current (Location *loc, bool want_lock)
392 Glib::Mutex::Lock lm (lock);
393 ret = set_current_unlocked (loc);
395 ret = set_current_unlocked (loc);
399 current_changed (current_location); /* EMIT SIGNAL */
405 Locations::set_current_unlocked (Location *loc)
407 if (find (locations.begin(), locations.end(), loc) == locations.end()) {
408 error << _("Locations: attempt to use unknown location as selected location") << endmsg;
412 current_location = loc;
420 Glib::Mutex::Lock lm (lock);
422 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
424 LocationList::iterator tmp = i;
427 if (!(*i)->is_end() && !(*i)->is_start()) {
434 current_location = 0;
437 changed (); /* EMIT SIGNAL */
438 current_changed (0); /* EMIT SIGNAL */
442 Locations::clear_markers ()
445 Glib::Mutex::Lock lm (lock);
446 LocationList::iterator tmp;
448 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
452 if ((*i)->is_mark() && !(*i)->is_end() && !(*i)->is_start()) {
460 changed (); /* EMIT SIGNAL */
464 Locations::clear_ranges ()
467 Glib::Mutex::Lock lm (lock);
468 LocationList::iterator tmp;
470 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
475 if (!(*i)->is_mark()) {
483 current_location = 0;
486 changed (); /* EMIT SIGNAL */
487 current_changed (0); /* EMIT SIGNAL */
491 Locations::add (Location *loc, bool make_current)
494 Glib::Mutex::Lock lm (lock);
495 locations.push_back (loc);
498 current_location = loc;
502 added (loc); /* EMIT SIGNAL */
505 current_changed (current_location); /* EMIT SIGNAL */
510 Locations::remove (Location *loc)
513 bool was_removed = false;
514 bool was_current = false;
515 LocationList::iterator i;
517 if (loc->is_end() || loc->is_start()) {
522 Glib::Mutex::Lock lm (lock);
524 for (i = locations.begin(); i != locations.end(); ++i) {
528 if (current_location == loc) {
529 current_location = 0;
539 removed (loc); /* EMIT SIGNAL */
542 current_changed (0); /* EMIT SIGNAL */
545 changed (); /* EMIT_SIGNAL */
550 Locations::location_changed (Location* loc)
552 changed (); /* EMIT SIGNAL */
556 Locations::get_state ()
558 XMLNode *node = new XMLNode ("Locations");
559 LocationList::iterator iter;
560 Glib::Mutex::Lock lm (lock);
562 for (iter = locations.begin(); iter != locations.end(); ++iter) {
563 node->add_child_nocopy ((*iter)->get_state ());
570 Locations::set_state (const XMLNode& node)
573 XMLNodeConstIterator niter;
575 if (node.name() != "Locations") {
576 error << _("incorrect XML mode passed to Locations::set_state") << endmsg;
580 nlist = node.children();
583 current_location = 0;
586 Glib::Mutex::Lock lm (lock);
588 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
592 Location *loc = new Location (**niter);
593 locations.push_back (loc);
596 catch (failed_constructor& err) {
597 error << _("could not load location from session file - ignored") << endmsg;
601 if (locations.size()) {
603 current_location = locations.front();
605 current_location = 0;
609 changed (); /* EMIT SIGNAL */
614 struct LocationStartEarlierComparison
616 bool operator() (Location *a, Location *b) {
617 return a->start() < b->start();
621 struct LocationStartLaterComparison
623 bool operator() (Location *a, Location *b) {
624 return a->start() > b->start();
629 Locations::first_location_before (nframes_t frame)
634 Glib::Mutex::Lock lm (lock);
638 LocationStartLaterComparison cmp;
641 /* locs is now sorted latest..earliest */
643 for (LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
644 if (!(*i)->is_hidden() && (*i)->start() < frame) {
653 Locations::first_location_after (nframes_t frame)
658 Glib::Mutex::Lock lm (lock);
662 LocationStartEarlierComparison cmp;
665 /* locs is now sorted earliest..latest */
667 for (LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
668 if (!(*i)->is_hidden() && (*i)->start() > frame) {
677 Locations::first_mark_before (nframes_t frame)
682 Glib::Mutex::Lock lm (lock);
686 LocationStartLaterComparison cmp;
689 /* locs is now sorted latest..earliest */
691 for (LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
692 if (!(*i)->is_hidden()) {
693 if ((*i)->is_mark()) {
694 /* MARK: start == end */
695 if ((*i)->start() < frame) {
696 return (*i)->start();
699 /* RANGE: start != end, compare start and end */
700 if ((*i)->end() < frame) {
703 if ((*i)->start () < frame) {
704 return (*i)->start();
714 Locations::first_mark_after (nframes_t frame)
719 Glib::Mutex::Lock lm (lock);
723 LocationStartEarlierComparison cmp;
726 /* locs is now sorted earliest..latest */
728 for (LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
729 if (!(*i)->is_hidden()) {
730 if ((*i)->is_mark()) {
731 /* MARK, start == end so just compare start */
732 if ((*i)->start() > frame) {
733 return (*i)->start();
736 /* RANGE, start != end, compare start and end */
737 if ((*i)->start() > frame ) {
738 return (*i)->start ();
740 if ((*i)->end() > frame) {
751 Locations::end_location () const
753 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
754 if ((*i)->is_end()) {
755 return const_cast<Location*> (*i);
762 Locations::start_location () const
764 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
765 if ((*i)->is_start()) {
766 return const_cast<Location*> (*i);
773 Locations::auto_loop_location () const
775 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
776 if ((*i)->is_auto_loop()) {
777 return const_cast<Location*> (*i);
784 Locations::auto_punch_location () const
786 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
787 if ((*i)->is_auto_punch()) {
788 return const_cast<Location*> (*i);
795 Locations::num_range_markers () const
798 Glib::Mutex::Lock lm (lock);
799 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
800 if ((*i)->is_range_marker()) {
808 Locations::get_location_by_id(PBD::ID id)
810 LocationList::iterator it;
811 for (it = locations.begin(); it != locations.end(); it++)
812 if (id == (*it)->id())