support for old-school automation loading
authorPaul Davis <paul@linuxaudiosystems.com>
Tue, 31 Oct 2006 18:08:16 +0000 (18:08 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 31 Oct 2006 18:08:16 +0000 (18:08 +0000)
git-svn-id: svn://localhost/ardour2/trunk@1039 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/ardour/ardour/automation_event.h
libs/ardour/ardour/io.h
libs/ardour/ardour/panner.h
libs/ardour/ardour/redirect.h
libs/ardour/io.cc
libs/ardour/panner.cc
libs/ardour/redirect.cc
libs/ardour/route.cc
libs/ardour/sndfilesource.cc

index 24d73faaa4ac8d9b09248c39b0334d4e598d6b3c..459ec2b6cf881da727f1eabcbbcdfacc8bc06cac 100644 (file)
@@ -86,6 +86,8 @@ class AutomationList : public PBD::StatefulDestructible
        void reposition_for_rt_add (double when);
        void rt_add (double when, double value);
        void add (double when, double value);
+       /* this should be private but old-school automation loading needs it in IO/Redirect */
+       void fast_simple_add (double when, double value);
 
        void reset_range (double start, double end);
        void erase_range (double start, double end);
@@ -211,7 +213,6 @@ class AutomationList : public PBD::StatefulDestructible
        iterator rt_insertion_point;
        double   rt_pos;
 
-       void fast_simple_add (double when, double value);
        void maybe_signal_changed ();
        void mark_dirty ();
        void _x_scale (double factor);
index 2783ee414044bf4fad18e8846ba40dabce14854c..3090e213105bd6ce14e2de59f153108182fb80fd 100644 (file)
@@ -313,6 +313,7 @@ public:
 
        virtual int set_automation_state (const XMLNode&);
        virtual XMLNode& get_automation_state ();
+       virtual int load_automation (std::string path);
 
        /* AudioTrack::deprecated_use_diskstream_connections() needs these */
 
index 47e30e43d7046143c6975b64606c170ce0e195bd..32d512c2534e2c3c350d37019c2aeab52c6d1a8b 100644 (file)
@@ -91,6 +91,10 @@ class StreamPanner : public sigc::trackable, public Stateful
        
        Panner & get_parent() { return parent; }
        
+       /* old school automation loading */
+
+       virtual int load (istream&, string path, uint32_t&) = 0;
+
   protected:
        friend class Panner;
        Panner& parent;
@@ -146,6 +150,10 @@ class BaseStereoPanner : public StreamPanner
 
        Curve& automation() { return _automation; }
 
+       /* old school automation loading */
+
+       int load (istream&, string path, uint32_t&);
+
   protected:
        float left;
        float right;
@@ -208,6 +216,10 @@ class Multi2dPanner : public StreamPanner
        XMLNode& get_state (void);
        int set_state (const XMLNode&);
 
+       /* old school automation loading */
+
+       int load (istream&, string path, uint32_t&);
+
   private:
        Curve _automation;
        void update ();
@@ -285,7 +297,11 @@ class Panner : public std::vector<StreamPanner*>, public Stateful, public sigc::
        void set_position (float x, StreamPanner& orig);
        void set_position (float x, float y, StreamPanner& orig);
        void set_position (float x, float y, float z, StreamPanner& orig);
-       
+
+       /* old school automation */
+
+       int load ();
+
   private:
 
        Session&         _session;
@@ -295,6 +311,11 @@ class Panner : public std::vector<StreamPanner*>, public Stateful, public sigc::
        LinkDirection    _link_direction;
 
        static float current_automation_version_number;
+
+       /* old school automation handling */
+
+       std::string automation_path;
+       void set_name (std::string);
 };
 
 } // namespace ARDOUR
index ccfd8590b2105737e4426fbf2dcf08fd904dfae1..847b9b8c13f32bb343a6340c10dcb35ae3c45c86 100644 (file)
@@ -127,12 +127,15 @@ class Redirect : public IO
 
        int set_automation_state (const XMLNode&);
        XMLNode& get_automation_state ();
-
+       
   private:
        bool _active;
        Placement _placement;
        uint32_t _sort_key;
        void* _gui;  /* generic, we don't know or care what this is */
+
+       int old_set_automation_state (const XMLNode&);
+       int load_automation (std::string path);
 };
 
 } // namespace ARDOUR
index 02adc3d53d5b569a28c7fb3828dd54b70359d257..0804369b94e2fcc218330a4089b7e249f56e3d18 100644 (file)
@@ -1425,6 +1425,7 @@ int
 IO::panners_became_legal ()
 {
        _panner->reset (_noutputs, pans_required());
+       _panner->load (); // automation
        panner_legal_c.disconnect ();
        return 0;
 }
@@ -1611,6 +1612,10 @@ IO::set_state (const XMLNode& node)
                _gain = _desired_gain;
        }
 
+       if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
+               /* old school automation handling */
+       }
+
        for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
 
                if ((*iter)->name() == "Panner") {
@@ -1679,6 +1684,84 @@ IO::get_automation_state ()
        return (_gain_automation_curve.get_state ());
 }
 
+int
+IO::load_automation (string path)
+{
+       string fullpath;
+       ifstream in;
+       char line[128];
+       uint32_t linecnt = 0;
+       float version;
+       LocaleGuard lg (X_("POSIX"));
+
+       fullpath = _session.automation_dir();
+       fullpath += path;
+
+       in.open (fullpath.c_str());
+
+       if (!in) {
+               fullpath = _session.automation_dir();
+               fullpath += _session.snap_name();
+               fullpath += '-';
+               fullpath += path;
+
+               in.open (fullpath.c_str());
+
+               if (!in) {
+                       error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
+                       return -1;
+               }
+       }
+
+       clear_automation ();
+
+       while (in.getline (line, sizeof(line), '\n')) {
+               char type;
+               jack_nframes_t when;
+               double value;
+
+               if (++linecnt == 1) {
+                       if (memcmp (line, "version", 7) == 0) {
+                               if (sscanf (line, "version %f", &version) != 1) {
+                                       error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
+                                       return -1;
+                               }
+                       } else {
+                               error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
+                               return -1;
+                       }
+
+                       continue;
+               }
+
+               if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
+                       warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
+                       continue;
+               }
+
+               switch (type) {
+               case 'g':
+                       _gain_automation_curve.fast_simple_add (when, value);
+                       break;
+
+               case 's':
+                       break;
+
+               case 'm':
+                       break;
+
+               case 'p':
+                       /* older (pre-1.0) versions of ardour used this */
+                       break;
+
+               default:
+                       warning << _("dubious automation event found (and ignored)") << endmsg;
+               }
+       }
+
+       return 0;
+}
+
 int
 IO::connecting_became_legal ()
 {
index 306757297df72d1c7a5e05509fc7b6acc332a04f..00b31f314d36f78ef0a373b8e585dfc912c547e5 100644 (file)
@@ -231,6 +231,39 @@ BaseStereoPanner::set_automation_state (AutoState state)
        }
 }
 
+int
+BaseStereoPanner::load (istream& in, string path, uint32_t& linecnt)
+{
+       char line[128];
+       LocaleGuard lg (X_("POSIX"));
+       
+       _automation.clear ();
+
+       while (in.getline (line, sizeof (line), '\n')) {
+               jack_nframes_t when;
+               double value;
+
+               ++linecnt;
+
+               if (strcmp (line, "end") == 0) {
+                       break;
+               }
+
+               if (sscanf (line, "%" PRIu32 " %lf", &when, &value) != 2) {
+                       warning << string_compose(_("badly formatted pan automation event record at line %1 of %2 (ignored) [%3]"), linecnt, path, line) << endmsg;
+                       continue;
+               }
+
+               _automation.fast_simple_add (when, value);
+       }
+
+       /* now that we are done loading */
+
+       _automation.StateChanged (Change (0));
+
+       return 0;
+}
+
 void
 BaseStereoPanner::distribute (Sample* src, Sample** obufs, gain_t gain_coeff, nframes_t nframes)
 {
@@ -676,6 +709,12 @@ Multi2dPanner::factory (Panner& p)
        return new Multi2dPanner (p);
 }
 
+int
+Multi2dPanner::load (istream& in, string path, uint32_t& linecnt)
+{
+       return 0;
+}
+
 XMLNode&
 Multi2dPanner::get_state (void)
 {
@@ -733,6 +772,8 @@ Multi2dPanner::set_state (const XMLNode& node)
 Panner::Panner (string name, Session& s)
        : _session (s)
 {
+       set_name (name);
+
        _linked = false;
        _link_direction = SameDirection;
        _bypassed = false;
@@ -1121,6 +1162,16 @@ Panner::set_state (const XMLNode& node)
                }       
        }
 
+       /* don't try to do old-school automation loading if it wasn't marked as existing */
+
+       if ((prop = node.property (X_("automation")))) {
+
+               /* automation path is relative */
+               
+               automation_path = _session.automation_dir();
+               automation_path += prop->value ();
+       } 
+
        return 0;
 }
 
@@ -1280,3 +1331,84 @@ Panner::set_position (float xpos, float ypos, float zpos, StreamPanner& orig)
                }
        }
 }
+
+/* old school automation handling */
+
+void
+Panner::set_name (string str)
+{
+       automation_path = _session.automation_dir();
+       automation_path += _session.snap_name();
+       automation_path += "-pan-";
+       automation_path += legalize_for_path (str);
+       automation_path += ".automation";
+}
+
+int
+Panner::load ()
+{
+       char line[128];
+       uint32_t linecnt = 0;
+       float version;
+       iterator sp;
+       LocaleGuard lg (X_("POSIX"));
+
+       if (automation_path.length() == 0) {
+               return 0;
+       }
+       
+       if (access (automation_path.c_str(), F_OK)) {
+               return 0;
+       }
+
+       ifstream in (automation_path.c_str());
+
+       if (!in) {
+               error << string_compose (_("cannot open pan automation file %1 (%2)"),
+                                 automation_path, strerror (errno))
+                     << endmsg;
+               return -1;
+       }
+
+       sp = begin();
+
+       while (in.getline (line, sizeof(line), '\n')) {
+
+               if (++linecnt == 1) {
+                       if (memcmp (line, X_("version"), 7) == 0) {
+                               if (sscanf (line, "version %f", &version) != 1) {
+                                       error << string_compose(_("badly formed version number in pan automation event file \"%1\""), automation_path) << endmsg;
+                                       return -1;
+                               }
+                       } else {
+                               error << string_compose(_("no version information in pan automation event file \"%1\" (first line = %2)"), 
+                                                automation_path, line) << endmsg;
+                               return -1;
+                       }
+
+                       continue;
+               }
+
+               if (strlen (line) == 0 || line[0] == '#') {
+                       continue;
+               }
+
+               if (strcmp (line, "begin") == 0) {
+                       
+                       if (sp == end()) {
+                               error << string_compose (_("too many panner states found in pan automation file %1"),
+                                                 automation_path)
+                                     << endmsg;
+                               return -1;
+                       }
+
+                       if ((*sp)->load (in, automation_path, linecnt)) {
+                               return -1;
+                       }
+                       
+                       ++sp;
+               }
+       }
+
+       return 0;
+}
index 5623e5d5103800d5cc2a6882c7f41c60a6abae81..0f3e9adce31e4c069642185e31297109217d64fe 100644 (file)
@@ -244,10 +244,11 @@ Redirect::set_state (const XMLNode& node)
 
                } else if ((*niter)->name() == X_("Automation")) {
 
+
                        XMLProperty *prop;
                        
                        if ((prop = (*niter)->property ("path")) != 0) {
-                               warning << string_compose (_("old automation data found for %1, ignored"), _name) << endmsg;
+                               old_set_automation_state (*(*niter));
                        } else {
                                set_automation_state (*(*niter));
                        }
@@ -298,6 +299,81 @@ Redirect::set_state (const XMLNode& node)
        return 0;
 }
 
+int
+Redirect::old_set_automation_state (const XMLNode& node)
+{
+       const XMLProperty *prop;
+                       
+       if ((prop = node.property ("path")) != 0) {
+               load_automation (prop->value());
+       } else {
+               warning << string_compose(_("%1: Automation node has no path property"), _name) << endmsg;
+       }
+       
+       if ((prop = node.property ("visible")) != 0) {
+               uint32_t what;
+               stringstream sstr;
+               
+               visible_parameter_automation.clear ();
+               
+               sstr << prop->value();
+               while (1) {
+                       sstr >> what;
+                       if (sstr.fail()) {
+                               break;
+                       }
+                       mark_automation_visible (what, true);
+               }
+       }
+
+       return 0;
+}
+
+int
+Redirect::load_automation (string path)
+{
+       string fullpath;
+
+       if (path[0] == '/') { // legacy
+               fullpath = path;
+       } else {
+               fullpath = _session.automation_dir();
+               fullpath += path;
+       }
+       ifstream in (fullpath.c_str());
+
+       if (!in) {
+               warning << string_compose(_("%1: cannot open %2 to load automation data (%3)"), _name, fullpath, strerror (errno)) << endmsg;
+               return 1;
+       }
+
+       Glib::Mutex::Lock lm (_automation_lock);
+       set<uint32_t> tosave;
+       parameter_automation.clear ();
+
+       while (in) {
+               double when;
+               double value;
+               uint32_t port;
+
+               in >> port;     if (!in) break;
+               in >> when;  if (!in) goto bad;
+               in >> value; if (!in) goto bad;
+               
+               AutomationList& al = automation_list (port);
+               al.add (when, value);
+               tosave.insert (port);
+       }
+       
+       return 0;
+
+  bad:
+       error << string_compose(_("%1: cannot load automation data from %2"), _name, fullpath) << endmsg;
+       parameter_automation.clear ();
+       return -1;
+}
+
+
 void
 Redirect::what_has_automation (set<uint32_t>& s) const
 {
index b204ad76dc5d51df46623b260e72822e193d0d01..10505053f997ada7ef76fd6d3766a890f33a7226 100644 (file)
@@ -1499,7 +1499,7 @@ Route::_set_state (const XMLNode& node, bool call_base)
                return -1;
        }
 
-       if ((prop = node.property ("flags")) != 0) {
+       if ((prop = node.property (X_("flags"))) != 0) {
                int x;
                sscanf (prop->value().c_str(), "0x%x", &x);
                _flags = Flag (x);
@@ -1507,20 +1507,20 @@ Route::_set_state (const XMLNode& node, bool call_base)
                _flags = Flag (0);
        }
        
-       if ((prop = node.property ("default-type")) != 0) {
+       if ((prop = node.property (X_("default-type"))) != 0) {
                _default_type = DataType(prop->value());
                assert(_default_type != DataType::NIL);
        }
 
-       if ((prop = node.property ("phase-invert")) != 0) {
+       if ((prop = node.property (X_("phase-invert"))) != 0) {
                set_phase_invert(prop->value()=="yes"?true:false, this);
        }
 
-       if ((prop = node.property ("active")) != 0) {
+       if ((prop = node.property (X_("active"))) != 0) {
                set_active (prop->value() == "yes");
        }
 
-       if ((prop = node.property ("muted")) != 0) {
+       if ((prop = node.property (X_("muted"))) != 0) {
                bool yn = prop->value()=="yes"?true:false; 
 
                /* force reset of mute status */
@@ -1530,7 +1530,7 @@ Route::_set_state (const XMLNode& node, bool call_base)
                mute_gain = desired_mute_gain;
        }
 
-       if ((prop = node.property ("soloed")) != 0) {
+       if ((prop = node.property (X_("soloed"))) != 0) {
                bool yn = prop->value()=="yes"?true:false; 
 
                /* force reset of solo status */
@@ -1540,23 +1540,23 @@ Route::_set_state (const XMLNode& node, bool call_base)
                solo_gain = desired_solo_gain;
        }
 
-       if ((prop = node.property ("mute-affects-pre-fader")) != 0) {
+       if ((prop = node.property (X_("mute-affects-pre-fader"))) != 0) {
                _mute_affects_pre_fader = (prop->value()=="yes")?true:false;
        }
 
-       if ((prop = node.property ("mute-affects-post-fader")) != 0) {
+       if ((prop = node.property (X_("mute-affects-post-fader"))) != 0) {
                _mute_affects_post_fader = (prop->value()=="yes")?true:false;
        }
 
-       if ((prop = node.property ("mute-affects-control-outs")) != 0) {
+       if ((prop = node.property (X_("mute-affects-control-outs"))) != 0) {
                _mute_affects_control_outs = (prop->value()=="yes")?true:false;
        }
 
-       if ((prop = node.property ("mute-affects-main-outs")) != 0) {
+       if ((prop = node.property (X_("mute-affects-main-outs"))) != 0) {
                _mute_affects_main_outs = (prop->value()=="yes")?true:false;
        }
 
-       if ((prop = node.property ("edit-group")) != 0) {
+       if ((prop = node.property (X_("edit-group"))) != 0) {
                RouteGroup* edit_group = _session.edit_group_by_name(prop->value());
                if(edit_group == 0) {
                        error << string_compose(_("Route %1: unknown edit group \"%2 in saved state (ignored)"), _name, prop->value()) << endmsg;
@@ -1565,7 +1565,7 @@ Route::_set_state (const XMLNode& node, bool call_base)
                }
        }
 
-       if ((prop = node.property ("order-keys")) != 0) {
+       if ((prop = node.property (X_("order-keys"))) != 0) {
 
                long n;
 
@@ -1602,7 +1602,7 @@ Route::_set_state (const XMLNode& node, bool call_base)
                delete deferred_state;
        }
 
-       deferred_state = new XMLNode("deferred state");
+       deferred_state = new XMLNode(X_("deferred state"));
 
        /* set parent class properties before anything else */
 
@@ -1621,7 +1621,7 @@ Route::_set_state (const XMLNode& node, bool call_base)
 
                child = *niter;
                        
-               if (child->name() == "Send") {
+               if (child->name() == X_("Send")) {
 
 
                        if (!IO::ports_legal) {
@@ -1632,7 +1632,7 @@ Route::_set_state (const XMLNode& node, bool call_base)
                                add_redirect_from_xml (*child);
                        }
 
-               } else if (child->name() == "Insert") {
+               } else if (child->name() == X_("Insert")) {
                        
                        if (!IO::ports_legal) {
                                
@@ -1643,7 +1643,13 @@ Route::_set_state (const XMLNode& node, bool call_base)
                                add_redirect_from_xml (*child);
                        }
 
-               } else if (child->name() == "ControlOuts") {
+               } else if (child->name() == X_("Automation")) {
+                       
+                       if ((prop = child->property (X_("path"))) != 0)  {
+                               load_automation (prop->value());
+                       }
+
+               } else if (child->name() == X_("ControlOuts")) {
                        
                        string coutname = _name;
                        coutname += _("[control]");
@@ -1651,25 +1657,25 @@ Route::_set_state (const XMLNode& node, bool call_base)
                        _control_outs = new IO (_session, coutname);
                        _control_outs->set_state (**(child->children().begin()));
 
-               } else if (child->name() == "Comment") {
+               } else if (child->name() == X_("Comment")) {
 
                        /* XXX this is a terrible API design in libxml++ */
 
                        XMLNode *cmt = *(child->children().begin());
                        _comment = cmt->content();
 
-               } else if (child->name() == "extra") {
+               } else if (child->name() == X_("extra")) {
                        _extra_xml = new XMLNode (*child);
-               } else if (child->name() == "solo") {
+               } else if (child->name() == X_("solo")) {
                        _solo_control.set_state (*child);
                        _session.add_controllable (&_solo_control);
-               } else if (child->name() == "mute") {
+               } else if (child->name() == X_("mute")) {
                        _mute_control.set_state (*child);
                        _session.add_controllable (&_mute_control);
                }
        }
 
-       if ((prop = node.property ("mix-group")) != 0) {
+       if ((prop = node.property (X_("mix-group"))) != 0) {
                RouteGroup* mix_group = _session.mix_group_by_name(prop->value());
                if (mix_group == 0) {
                        error << string_compose(_("Route %1: unknown mix group \"%2 in saved state (ignored)"), _name, prop->value()) << endmsg;
index 5e6f512e531c4e342b1f788793632b7914a003bb..cb4334c7cbbf13c4aa14d490d957e5221d2bf072 100644 (file)
@@ -507,14 +507,10 @@ SndFileSource::set_header_timeline_position ()
 nframes_t
 SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
 {
-       nframes_t where;
-       
-       where = sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE);
-
-       if (where != frame_pos) {
+       if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
                char errbuf[256];
                sf_error_str (0, errbuf, sizeof (errbuf) - 1);
-               error << string_compose (_("%1: cannot seek to %2, now at %3 (libsndfile error: %4"), _path, frame_pos, where, errbuf) << endmsg;
+               error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
                return 0;
        }