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>
32 #include <ardour/location.h>
37 using namespace ARDOUR;
41 Location::Location (const Location& other)
42 : _name (other._name),
43 _start (other._start),
50 Location::operator= (const Location& other)
57 _start = other._start;
59 _flags = other._flags;
61 /* "changed" not emitted on purpose */
67 Location::set_start (jack_nframes_t s)
73 start_changed(this); /* EMIT SIGNAL */
78 if (((is_auto_punch() || is_auto_loop()) && s >= _end) || s > _end) {
84 start_changed(this); /* EMIT SIGNAL */
91 Location::set_end (jack_nframes_t e)
97 end_changed(this); /* EMIT SIGNAL */
102 if (((is_auto_punch() || is_auto_loop()) && e <= _start) || e < _start) {
108 end_changed(this); /* EMIT SIGNAL */
114 Location::set (jack_nframes_t start, jack_nframes_t end)
116 if (is_mark() && start != end) {
118 } else if (((is_auto_punch() || is_auto_loop()) && start >= end) || (start > end)) {
122 if (_start != start) {
124 start_changed(this); /* EMIT SIGNAL */
129 end_changed(this); /* EMIT SIGNAL */
135 Location::set_hidden (bool yn, void *src)
137 if (set_flag_internal (yn, IsHidden)) {
138 FlagsChanged (this, src); /* EMIT SIGNAL */
143 Location::set_cd (bool yn, void *src)
145 if (set_flag_internal (yn, IsCDMarker)) {
146 FlagsChanged (this, src); /* EMIT SIGNAL */
151 Location::set_is_end (bool yn, void *src)
153 if (set_flag_internal (yn, IsEnd)) {
154 FlagsChanged (this, src); /* EMIT SIGNAL */
159 Location::set_is_start (bool yn, void *src)
161 if (set_flag_internal (yn, IsStart)) {
162 FlagsChanged (this, src); /* EMIT SIGNAL */
167 Location::set_auto_punch (bool yn, void *src)
169 if (is_mark() || _start == _end) {
173 if (set_flag_internal (yn, IsAutoPunch)) {
174 FlagsChanged (this, src); /* EMIT SIGNAL */
179 Location::set_auto_loop (bool yn, void *src)
181 if (is_mark() || _start == _end) {
185 if (set_flag_internal (yn, IsAutoLoop)) {
186 FlagsChanged (this, src); /* EMIT SIGNAL */
191 Location::set_flag_internal (bool yn, Flags flag)
194 if (!(_flags & flag)) {
208 Location::set_mark (bool yn)
210 /* This function is private, and so does not emit signals */
212 if (_start != _end) {
216 set_flag_internal (yn, IsMark);
221 Location::cd_info_node(const string & name, const string & value)
223 XMLNode* root = new XMLNode("CD-Info");
225 root->add_property("name", name);
226 root->add_property("value", value);
233 Location::get_state (void)
235 XMLNode *node = new XMLNode ("Location");
238 typedef map<string, string>::const_iterator CI;
239 for(CI m = cd_info.begin(); m != cd_info.end(); ++m){
240 node->add_child_nocopy(cd_info_node(m->first, m->second));
243 node->add_property ("name", name());
244 snprintf (buf, sizeof (buf), "%u", start());
245 node->add_property ("start", buf);
246 snprintf (buf, sizeof (buf), "%u", end());
247 node->add_property ("end", buf);
248 snprintf (buf, sizeof (buf), "%" PRIu32, (uint32_t) _flags);
249 node->add_property ("flags", buf);
255 Location::set_state (const XMLNode& node)
257 XMLPropertyList plist;
258 const XMLProperty *prop;
260 XMLNodeList cd_list = node.children();
261 XMLNodeConstIterator cd_iter;
268 if (node.name() != "Location") {
269 error << _("incorrect XML node passed to Location::set_state") << endmsg;
273 plist = node.properties();
275 if ((prop = node.property ("name")) == 0) {
276 error << _("XML node for Location has no name information") << endmsg;
280 set_name (prop->value());
282 if ((prop = node.property ("start")) == 0) {
283 error << _("XML node for Location has no start information") << endmsg;
287 /* can't use set_start() here, because _end
288 may make the value of _start illegal.
291 _start = atoi (prop->value().c_str());
293 if ((prop = node.property ("end")) == 0) {
294 error << _("XML node for Location has no end information") << endmsg;
298 _end = atoi (prop->value().c_str());
302 if ((prop = node.property ("flags")) == 0) {
303 error << _("XML node for Location has no flags information") << endmsg;
307 _flags = Flags (atoi (prop->value().c_str()));
309 for (cd_iter = cd_list.begin(); cd_iter != cd_list.end(); ++cd_iter) {
313 if (cd_node->name() != "CD-Info") {
317 if ((prop = cd_node->property ("name")) != 0) {
318 cd_name = prop->value();
320 throw failed_constructor ();
323 if ((prop = cd_node->property ("value")) != 0) {
324 cd_value = prop->value();
326 throw failed_constructor ();
330 cd_info[cd_name] = cd_value;
334 changed(this); /* EMIT SIGNAL */
339 /*---------------------------------------------------------------------- */
341 Locations::Locations ()
344 current_location = 0;
345 save_state (_("initial"));
348 Locations::~Locations ()
350 std::set<Location*> all_locations;
352 for (StateMap::iterator siter = states.begin(); siter != states.end(); ++siter) {
354 State* lstate = dynamic_cast<State*> (*siter);
356 for (LocationList::iterator liter = lstate->locations.begin(); liter != lstate->locations.end(); ++liter) {
357 all_locations.insert (*liter);
360 for (LocationList::iterator siter = lstate->states.begin(); siter != lstate->states.end(); ++siter) {
361 all_locations.insert (*siter);
365 set_delete (&all_locations);
369 Locations::set_current (Location *loc, bool want_lock)
375 Glib::Mutex::Lock lm (lock);
376 ret = set_current_unlocked (loc);
378 ret = set_current_unlocked (loc);
382 current_changed (current_location); /* EMIT SIGNAL */
388 Locations::set_current_unlocked (Location *loc)
390 if (find (locations.begin(), locations.end(), loc) == locations.end()) {
391 error << _("Locations: attempt to use unknown location as selected location") << endmsg;
395 current_location = loc;
403 Glib::Mutex::Lock lm (lock);
404 LocationList::iterator tmp;
405 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
408 if (!(*i)->is_end() && !(*i)->is_start()) {
415 current_location = 0;
418 save_state (_("clear"));
420 changed (); /* EMIT SIGNAL */
421 current_changed (0); /* EMIT SIGNAL */
425 Locations::clear_markers ()
428 Glib::Mutex::Lock lm (lock);
429 LocationList::iterator tmp;
431 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
435 if ((*i)->is_mark() && !(*i)->is_end() && !(*i)->is_start()) {
443 save_state (_("clear markers"));
445 changed (); /* EMIT SIGNAL */
449 Locations::clear_ranges ()
452 Glib::Mutex::Lock lm (lock);
453 LocationList::iterator tmp;
455 for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
460 if (!(*i)->is_mark()) {
468 current_location = 0;
471 save_state (_("clear ranges"));
473 changed (); /* EMIT SIGNAL */
474 current_changed (0); /* EMIT SIGNAL */
478 Locations::add (Location *loc, bool make_current)
481 Glib::Mutex::Lock lm (lock);
482 locations.push_back (loc);
485 current_location = loc;
489 save_state (_("add"));
491 added (loc); /* EMIT SIGNAL */
494 current_changed (current_location); /* EMIT SIGNAL */
499 Locations::remove (Location *loc)
502 bool was_removed = false;
503 bool was_current = false;
504 LocationList::iterator i;
506 if (loc->is_end() || loc->is_start()) {
511 Glib::Mutex::Lock lm (lock);
513 for (i = locations.begin(); i != locations.end(); ++i) {
517 if (current_location == loc) {
518 current_location = 0;
527 save_state (_("remove"));
529 removed (loc); /* EMIT SIGNAL */
532 current_changed (0); /* EMIT SIGNAL */
535 changed (); /* EMIT_SIGNAL */
540 Locations::location_changed (Location* loc)
542 save_state (X_("location changed"));
543 changed (); /* EMIT SIGNAL */
547 Locations::get_state ()
549 XMLNode *node = new XMLNode ("Locations");
550 LocationList::iterator iter;
551 Glib::Mutex::Lock lm (lock);
553 for (iter = locations.begin(); iter != locations.end(); ++iter) {
554 node->add_child_nocopy ((*iter)->get_state ());
561 Locations::set_state (const XMLNode& node)
564 XMLNodeConstIterator niter;
566 if (node.name() != "Locations") {
567 error << _("incorrect XML mode passed to Locations::set_state") << endmsg;
571 nlist = node.children();
574 Glib::Mutex::Lock lm (lock);
576 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
577 Location *loc = new Location;
579 if (loc->set_state (**niter)) {
582 locations.push_back (loc);
586 if (locations.size()) {
587 current_location = locations.front();
589 current_location = 0;
593 changed (); /* EMIT SIGNAL */
598 struct LocationStartEarlierComparison
600 bool operator() (Location *a, Location *b) {
601 return a->start() < b->start();
605 struct LocationStartLaterComparison
607 bool operator() (Location *a, Location *b) {
608 return a->start() > b->start();
613 Locations::first_location_before (jack_nframes_t frame)
618 Glib::Mutex::Lock lm (lock);
622 LocationStartLaterComparison cmp;
625 /* locs is now sorted latest..earliest */
627 for (LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
628 if (!(*i)->is_hidden() && (*i)->start() < frame) {
637 Locations::first_location_after (jack_nframes_t frame)
642 Glib::Mutex::Lock lm (lock);
646 LocationStartEarlierComparison cmp;
649 /* locs is now sorted earliest..latest */
651 for (LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
652 if (!(*i)->is_hidden() && (*i)->start() > frame) {
661 Locations::first_mark_before (jack_nframes_t frame)
666 Glib::Mutex::Lock lm (lock);
670 LocationStartLaterComparison cmp;
673 /* locs is now sorted latest..earliest */
675 for (LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
676 if (!(*i)->is_hidden()) {
677 if ((*i)->is_mark()) {
678 /* MARK: start == end */
679 if ((*i)->start() < frame) {
680 return (*i)->start();
683 /* RANGE: start != end, compare start and end */
684 if ((*i)->end() < frame) {
687 if ((*i)->start () < frame) {
688 return (*i)->start();
698 Locations::first_mark_after (jack_nframes_t frame)
703 Glib::Mutex::Lock lm (lock);
707 LocationStartEarlierComparison cmp;
710 /* locs is now sorted earliest..latest */
712 for (LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
713 if (!(*i)->is_hidden()) {
714 if ((*i)->is_mark()) {
715 /* MARK, start == end so just compare start */
716 if ((*i)->start() > frame) {
717 return (*i)->start();
720 /* RANGE, start != end, compare start and end */
721 if ((*i)->start() > frame ) {
722 return (*i)->start ();
724 if ((*i)->end() > frame) {
735 Locations::end_location () const
737 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
738 if ((*i)->is_end()) {
739 return const_cast<Location*> (*i);
746 Locations::start_location () const
748 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
749 if ((*i)->is_start()) {
750 return const_cast<Location*> (*i);
757 Locations::auto_loop_location () const
759 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
760 if ((*i)->is_auto_loop()) {
761 return const_cast<Location*> (*i);
768 Locations::auto_punch_location () const
770 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
771 if ((*i)->is_auto_punch()) {
772 return const_cast<Location*> (*i);
779 Locations::state_factory (std::string why) const
781 State* state = new State (why);
783 state->locations = locations;
785 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
786 state->states.push_back (new Location (**i));
793 Locations::restore_state (StateManager::State& state)
796 Glib::Mutex::Lock lm (lock);
797 State* lstate = dynamic_cast<State*> (&state);
799 locations = lstate->locations;
800 LocationList& states = lstate->states;
801 LocationList::iterator l, s;
803 for (l = locations.begin(), s = states.begin(); s != states.end(); ++s, ++l) {
812 Locations::get_memento () const
814 return sigc::bind (mem_fun (*(const_cast<Locations*> (this)), &StateManager::use_state), _current_state_id);
818 Locations::num_range_markers () const
821 Glib::Mutex::Lock lm (lock);
822 for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
823 if ((*i)->is_range_marker()) {