new automation state model, sort of working, but not really
[ardour.git] / libs / ardour / location.cc
index ce726fb453f62d017539d65c30d2c2ddd28f7eff..579a0e2820d2eb9faf31ae4662fd8e33134457f1 100644 (file)
 #include <pbd/xml++.h>
 
 #include <ardour/location.h>
+#include <ardour/session.h>
+#include <ardour/audiofilesource.h>
 
 #include "i18n.h"
 
 using namespace std;
 using namespace ARDOUR;
 using namespace sigc;
+using namespace PBD;
 
 Location::Location (const Location& other)
        : _name (other._name),
@@ -43,6 +46,17 @@ Location::Location (const Location& other)
          _end (other._end),
          _flags (other._flags)
 {
+       /* start and end flags can never be copied, because there can only ever be one of each */
+
+       _flags = Flags (_flags & ~IsStart);
+       _flags = Flags (_flags & ~IsEnd);
+}
+
+Location::Location (const XMLNode& node)
+{
+       if (set_state (node)) {
+               throw failed_constructor ();
+       }
 }
 
 Location*
@@ -63,13 +77,25 @@ Location::operator= (const Location& other)
 }
 
 int
-Location::set_start (jack_nframes_t s)
+Location::set_start (nframes_t s)
 {
        if (is_mark()) {
                if (_start != s) {
+
                        _start = s;
                        _end = s;
-                        changed(this); /* EMIT SIGNAL */
+
+                       start_changed(this); /* EMIT SIGNAL */
+
+                       if ( is_start() ) {
+
+                               Session::StartTimeChanged (); /* EMIT SIGNAL */
+                               AudioFileSource::set_header_position_offset ( s );
+                       }
+
+                       if ( is_end() ) {
+                               Session::EndTimeChanged (); /* EMIT SIGNAL */
+                       }
                }
                return 0;
        }
@@ -80,19 +106,20 @@ Location::set_start (jack_nframes_t s)
 
        if (s != _start) {
                _start = s; 
-                start_changed(this); /* EMIT SIGNAL */
+               start_changed(this); /* EMIT SIGNAL */
        }
-               return 0;
+
+       return 0;
 }
 
 int
-Location::set_end (jack_nframes_t e)
+Location::set_end (nframes_t e)
 {
        if (is_mark()) {
                if (_start != e) {
                        _start = e;
                        _end = e;
-                        changed(this); /* EMIT SIGNAL */
+                       end_changed(this); /* EMIT SIGNAL */
                }
                return 0;
        }
@@ -109,7 +136,7 @@ Location::set_end (jack_nframes_t e)
 }
 
 int
-Location::set (jack_nframes_t start, jack_nframes_t end)
+Location::set (nframes_t start, nframes_t end)
 {
        if (is_mark() && start != end) {
                return -1;
@@ -117,10 +144,14 @@ Location::set (jack_nframes_t start, jack_nframes_t end)
                return -1;
        }
        
-       if (_start != start || _end != end) {
+       if (_start != start) {
                _start = start;
+               start_changed(this); /* EMIT SIGNAL */
+       }
+
+       if (_end != end) {
                _end = end;
-                changed(this); /* EMIT SIGNAL */
+               end_changed(this); /* EMIT SIGNAL */
        }
        return 0;
 }
@@ -149,6 +180,14 @@ Location::set_is_end (bool yn, void *src)
        }
 }
 
+void
+Location::set_is_start (bool yn, void *src)
+{
+       if (set_flag_internal (yn, IsStart)) {
+                FlagsChanged (this, src); /* EMIT SIGNAL */
+       }
+}
+
 void
 Location::set_auto_punch (bool yn, void *src) 
 {
@@ -219,13 +258,16 @@ XMLNode&
 Location::get_state (void)
 {
        XMLNode *node = new XMLNode ("Location");
-       char buf[32];
+       char buf[64];
 
        typedef map<string, string>::const_iterator CI;
+
        for(CI m = cd_info.begin(); m != cd_info.end(); ++m){
                node->add_child_nocopy(cd_info_node(m->first, m->second));
        }
 
+       id().print (buf, sizeof (buf));
+       node->add_property("id", buf);
        node->add_property ("name", name());
        snprintf (buf, sizeof (buf), "%u", start());
        node->add_property ("start", buf);
@@ -240,7 +282,6 @@ Location::get_state (void)
 int
 Location::set_state (const XMLNode& node)
 {
-       XMLPropertyList plist;
        const XMLProperty *prop;
 
        XMLNodeList cd_list = node.children();
@@ -250,14 +291,17 @@ Location::set_state (const XMLNode& node)
        string cd_name;
        string cd_value;
 
-
        if (node.name() != "Location") {
                error << _("incorrect XML node passed to Location::set_state") << endmsg;
                return -1;
        }
 
-       plist = node.properties();
-               
+       if ((prop = node.property ("id")) == 0) {
+               warning << _("XML node for Location has no ID information") << endmsg;
+       } else {
+               _id = prop->value ();
+       }
+
        if ((prop = node.property ("name")) == 0) {
                error << _("XML node for Location has no name information") << endmsg;
                return -1;
@@ -328,27 +372,16 @@ Locations::Locations ()
 
 {
        current_location = 0;
-       save_state (_("initial"));
 }
 
 Locations::~Locations () 
 {
-       std::set<Location*> all_locations;
-       
-       for (StateMap::iterator siter = states.begin(); siter != states.end(); ++siter) {
-
-               State* lstate = dynamic_cast<State*> (*siter);
-
-               for (LocationList::iterator liter = lstate->locations.begin(); liter != lstate->locations.end(); ++liter) {
-                       all_locations.insert (*liter);
-               }
-
-               for (LocationList::iterator siter = lstate->states.begin(); siter != lstate->states.end(); ++siter) {
-                       all_locations.insert (*siter);
-               }
+       for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
+               LocationList::iterator tmp = i;
+               ++tmp;
+               delete *i;
+               i = tmp;
        }
-
-       set_delete (&all_locations);
 }
 
 int
@@ -358,7 +391,7 @@ Locations::set_current (Location *loc, bool want_lock)
        int ret;
 
        if (want_lock) {
-               LockMonitor lm (lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock lm (lock);
                ret = set_current_unlocked (loc);
        } else {
                ret = set_current_unlocked (loc);
@@ -386,12 +419,12 @@ void
 Locations::clear ()
 {
        {
-               LockMonitor lm (lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock lm (lock);
                LocationList::iterator tmp;
                for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
                        tmp = i;
                        ++tmp;
-                       if (!(*i)->is_end()) {
+                       if (!(*i)->is_end() && !(*i)->is_start()) {
                                locations.erase (i);
                        }
                        i = tmp;
@@ -401,8 +434,6 @@ Locations::clear ()
                current_location = 0;
        }
 
-       save_state (_("clear"));
-       
        changed (); /* EMIT SIGNAL */
        current_changed (0); /* EMIT SIGNAL */
 }      
@@ -411,14 +442,14 @@ void
 Locations::clear_markers ()
 {
        {
-               LockMonitor lm (lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock lm (lock);
                LocationList::iterator tmp;
 
                for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
                        tmp = i;
                        ++tmp;
 
-                       if ((*i)->is_mark() && !(*i)->is_end()) {
+                       if ((*i)->is_mark() && !(*i)->is_end() && !(*i)->is_start()) {
                                locations.erase (i);
                        }
 
@@ -426,8 +457,6 @@ Locations::clear_markers ()
                }
        }
 
-       save_state (_("clear markers"));
-       
        changed (); /* EMIT SIGNAL */
 }      
 
@@ -435,7 +464,7 @@ void
 Locations::clear_ranges ()
 {
        {
-               LockMonitor lm (lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock lm (lock);
                LocationList::iterator tmp;
                
                for (LocationList::iterator i = locations.begin(); i != locations.end(); ) {
@@ -454,8 +483,6 @@ Locations::clear_ranges ()
                current_location = 0;
        }
 
-       save_state (_("clear ranges"));
-
        changed (); /* EMIT SIGNAL */
        current_changed (0); /* EMIT SIGNAL */
 }      
@@ -464,18 +491,14 @@ void
 Locations::add (Location *loc, bool make_current)
 {
        {
-               LockMonitor lm (lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock lm (lock);
                locations.push_back (loc);
 
-               loc->changed.connect (mem_fun (*this, &Locations::location_changed));
-
                if (make_current) {
                        current_location = loc;
                }
        }
        
-       save_state (_("add"));
-
        added (loc); /* EMIT SIGNAL */
 
        if (make_current) {
@@ -491,12 +514,12 @@ Locations::remove (Location *loc)
        bool was_current = false;
        LocationList::iterator i;
 
-       if (loc->is_end()) {
+       if (loc->is_end() || loc->is_start()) {
                return;
        }
 
        {
-               LockMonitor lm (lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock lm (lock);
 
                for (i = locations.begin(); i != locations.end(); ++i) {
                        if ((*i) == loc) {
@@ -512,9 +535,8 @@ Locations::remove (Location *loc)
        }
        
        if (was_removed) {
-               save_state (_("remove"));
-
-                removed (loc); /* EMIT SIGNAL */
+               
+               removed (loc); /* EMIT SIGNAL */
 
                if (was_current) {
                         current_changed (0); /* EMIT SIGNAL */
@@ -525,9 +547,8 @@ Locations::remove (Location *loc)
 }
 
 void
-Locations::location_changed (Location* ignored)
+Locations::location_changed (Location* loc)
 {
-       save_state (X_("location changed"));
        changed (); /* EMIT SIGNAL */
 }
 
@@ -536,7 +557,7 @@ Locations::get_state ()
 {
        XMLNode *node = new XMLNode ("Locations");
        LocationList::iterator iter;
-       LockMonitor lm (lock, __LINE__, __FILE__);
+       Glib::Mutex::Lock lm (lock);
        
        for (iter  = locations.begin(); iter != locations.end(); ++iter) {
                node->add_child_nocopy ((*iter)->get_state ());
@@ -559,19 +580,23 @@ Locations::set_state (const XMLNode& node)
        nlist = node.children();
        
        {
-               LockMonitor lm (lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock lm (lock);
 
                for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
-                       Location *loc = new Location;
                        
-                       if (loc->set_state (**niter)) {
-                               delete loc;
-                       } else {
+                       try {
+
+                               Location *loc = new Location (**niter);
                                locations.push_back (loc);
                        }
+
+                       catch (failed_constructor& err) {
+                               error << _("could not load location from session file - ignored") << endmsg;
+                       }
                }
                
                if (locations.size()) {
+
                        current_location = locations.front();
                } else {
                        current_location = 0;
@@ -598,12 +623,12 @@ struct LocationStartLaterComparison
 };
 
 Location *
-Locations::first_location_before (jack_nframes_t frame)
+Locations::first_location_before (nframes_t frame)
 {
        LocationList locs;
 
        {
-               LockMonitor lm (lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock lm (lock);
                locs = locations;
        }
 
@@ -622,12 +647,12 @@ Locations::first_location_before (jack_nframes_t frame)
 }
 
 Location *
-Locations::first_location_after (jack_nframes_t frame)
+Locations::first_location_after (nframes_t frame)
 {
        LocationList locs;
 
        {
-               LockMonitor lm (lock, __LINE__, __FILE__);
+               Glib::Mutex::Lock lm (lock);
                locs = locations;
        }
 
@@ -645,6 +670,80 @@ Locations::first_location_after (jack_nframes_t frame)
        return 0;
 }
 
+nframes_t
+Locations::first_mark_before (nframes_t frame)
+{
+       LocationList locs;
+
+       {
+        Glib::Mutex::Lock lm (lock);
+               locs = locations;
+       }
+
+       LocationStartLaterComparison cmp;
+       locs.sort (cmp);
+
+       /* locs is now sorted latest..earliest */
+       
+       for (LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
+               if (!(*i)->is_hidden()) {
+                       if ((*i)->is_mark()) {
+                               /* MARK: start == end */
+                               if ((*i)->start() < frame) {
+                                       return (*i)->start();
+                               }
+                       } else {
+                               /* RANGE: start != end, compare start and end */
+                               if ((*i)->end() < frame) {
+                                       return (*i)->end();
+                               }
+                               if ((*i)->start () < frame) {
+                                       return (*i)->start();
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+
+nframes_t
+Locations::first_mark_after (nframes_t frame)
+{
+       LocationList locs;
+
+       {
+        Glib::Mutex::Lock lm (lock);
+               locs = locations;
+       }
+
+       LocationStartEarlierComparison cmp;
+       locs.sort (cmp);
+
+       /* locs is now sorted earliest..latest */
+       
+       for (LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
+               if (!(*i)->is_hidden()) {
+                       if ((*i)->is_mark()) {
+                               /* MARK, start == end so just compare start */
+                               if ((*i)->start() > frame) {
+                                       return (*i)->start();
+                               }
+                       } else {
+                               /* RANGE, start != end, compare start and end */
+                               if ((*i)->start() > frame ) {
+                                       return (*i)->start ();
+                               }
+                               if ((*i)->end() > frame) {
+                                       return (*i)->end ();
+                               }
+                       }
+               }
+       }
+
+       return max_frames;
+}
+
 Location*
 Locations::end_location () const
 {
@@ -656,6 +755,17 @@ Locations::end_location () const
        return 0;
 }      
 
+Location*
+Locations::start_location () const
+{
+       for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
+               if ((*i)->is_start()) {
+                       return const_cast<Location*> (*i);
+               }
+       }
+       return 0;
+}      
+
 Location*
 Locations::auto_loop_location () const
 {
@@ -678,41 +788,26 @@ Locations::auto_punch_location () const
        return 0;
 }      
 
-StateManager::State*
-Locations::state_factory (std::string why) const
+uint32_t
+Locations::num_range_markers () const
 {
-       State* state = new State (why);
-
-       state->locations = locations;
-       
+       uint32_t cnt = 0;
+       Glib::Mutex::Lock lm (lock);
        for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
-               state->states.push_back (new Location (**i));
-       }
-
-       return state;
-}
-
-Change
-Locations::restore_state (StateManager::State& state) 
-{
-       {
-               LockMonitor lm (lock, __LINE__, __FILE__);
-               State* lstate = dynamic_cast<State*> (&state);
-
-               locations = lstate->locations;
-               LocationList& states = lstate->states;
-               LocationList::iterator l, s;
-
-               for (l = locations.begin(), s = states.begin(); s != states.end(); ++s, ++l) {
-                       (*l) = (*s);
+               if ((*i)->is_range_marker()) {
+                       ++cnt;
                }
        }
-
-       return Change (0);
+       return cnt;
 }
 
-UndoAction
-Locations::get_memento () const
+Location *
+Locations::get_location_by_id(PBD::ID id)
 {
-  return sigc::bind (mem_fun (*(const_cast<Locations*> (this)), &StateManager::use_state), _current_state_id);
+    LocationList::iterator it;
+    for (it  = locations.begin(); it != locations.end(); it++)
+        if (id == (*it)->id())
+            return *it;
+
+    return 0;
 }