Generic MIDI control now saves+restores its state; PBD::ID now requires a buffer...
authorPaul Davis <paul@linuxaudiosystems.com>
Thu, 5 Oct 2006 01:49:32 +0000 (01:49 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Thu, 5 Oct 2006 01:49:32 +0000 (01:49 +0000)
git-svn-id: svn://localhost/ardour2/trunk@949 d708f5d6-7413-0410-9779-e7cbd77b26cf

31 files changed:
gtk2_ardour/editor.cc
gtk2_ardour/main.cc
libs/ardour/ardour/control_protocol_manager.h
libs/ardour/ardour/io.h
libs/ardour/ardour/panner.h
libs/ardour/ardour/plugin.h
libs/ardour/ardour/route.h
libs/ardour/ardour/session.h
libs/ardour/audio_diskstream.cc
libs/ardour/audio_track.cc
libs/ardour/audioregion.cc
libs/ardour/control_protocol_manager.cc
libs/ardour/crossfade.cc
libs/ardour/io.cc
libs/ardour/location.cc
libs/ardour/panner.cc
libs/ardour/playlist.cc
libs/ardour/plugin.cc
libs/ardour/redirect.cc
libs/ardour/region.cc
libs/ardour/route.cc
libs/ardour/session_state.cc
libs/ardour/source.cc
libs/ardour/track.cc
libs/pbd/controllable.cc
libs/pbd/id.cc
libs/pbd/pbd/controllable.h
libs/pbd/pbd/id.h
libs/surfaces/generic_midi/generic_midi_control_protocol.cc
libs/surfaces/generic_midi/midicontrollable.cc
libs/surfaces/tranzport/tranzport_control_protocol.cc

index 9ab8efb742ba7cb45f2ad634f430c54b4a5221db..f1fe88cd7afde87310ea50971bec793d1087d147 100644 (file)
@@ -2162,7 +2162,7 @@ Editor::get_state ()
        XMLNode* node = new XMLNode ("Editor");
        char buf[32];
 
-       _id.print (buf);
+       _id.print (buf, sizeof (buf));
        node->add_property ("id", buf);
        
        if (is_realized()) {
index ce7a129d081dbf28a0cc8a8d30df6d20bafd7086..049ef29ead0dae3f2bd4e3d938a7f5f45afb84a2 100644 (file)
@@ -383,13 +383,7 @@ int main (int argc, char *argv[])
        cout << _("Ardour/GTK ") 
             << VERSIONSTRING
             << _("\n   (built using ")
-            << gtk_ardour_major_version << '.'
-            << gtk_ardour_minor_version << '.'
-            << gtk_ardour_micro_version
-            << _(" with libardour ")
-            << libardour_major_version << '.'
-            << libardour_minor_version << '.' 
-            << libardour_micro_version 
+            << ARDOUR::get_ardour_revision ()
 #ifdef __GNUC__
             << _(" and GCC version ") << __VERSION__ 
 #endif
index 8eda7a4555b83a648faa3b1aa3f68f3f40dada50..99de5479fb0ad6eb32417e9cca3cb8538c25ef22 100644 (file)
@@ -24,6 +24,9 @@ struct ControlProtocolInfo {
     bool requested;
     bool mandatory;
     XMLNode* state;
+
+    ControlProtocolInfo() : descriptor (0), protocol (0), state (0) {}
+    ~ControlProtocolInfo() { if (state) { delete state; } }
 };
 
  class ControlProtocolManager : public sigc::trackable, public Stateful
@@ -46,6 +49,8 @@ struct ControlProtocolInfo {
 
        static const std::string state_node_name;
 
+       void set_protocol_states (const XMLNode&);
+
        int set_state (const XMLNode&);
        XMLNode& get_state (void);
 
index 163ae462f3b5c7c281ccd81e6e085c855a976903..c32ef31de86785b17b3b020524d9e7f1bf04208b 100644 (file)
@@ -295,7 +295,7 @@ public:
                                   gain_t initial, gain_t target, bool invert_polarity);
 
        struct GainControllable : public PBD::Controllable {
-           GainControllable (IO& i) : io (i) {}
+           GainControllable (std::string name, IO& i) : Controllable (name), io (i) {}
         
            void set_value (float val);
            float get_value (void) const;
index 3091527e59b78b93884809405a7f6734b0f8b01f..0cb0c3dfaad79a6e1ce1bb4483a4368bcd31b2b7 100644 (file)
@@ -114,7 +114,7 @@ class StreamPanner : public sigc::trackable, public Stateful
        bool             _muted;
 
        struct PanControllable : public PBD::Controllable {
-           PanControllable (StreamPanner& p) : panner (p) {}
+           PanControllable (std::string name, StreamPanner& p) : Controllable (name), panner (p) {}
            
            StreamPanner& panner;
            
index dcc657018ad037dff65e47c6b324084972824c5a..bc71da84aee4177f945fb372285bcfef63955822 100644 (file)
@@ -98,9 +98,8 @@ class Plugin : public PBD::StatefulDestructible, public sigc::trackable
            float step;
            float smallstep;
            float largestep;
-
-               bool min_unbound;
-               bool max_unbound;
+           bool min_unbound;
+           bool max_unbound;
        };
 
        virtual uint32_t unique_id() const = 0;
@@ -162,7 +161,7 @@ class Plugin : public PBD::StatefulDestructible, public sigc::trackable
        void setup_controls ();
 
        struct PortControllable : public PBD::Controllable {
-           PortControllable (Plugin&, uint32_t abs_port_id,
+           PortControllable (std::string name, Plugin&, uint32_t abs_port_id,
                              float lower, float upper, bool toggled, bool logarithmic);
 
            void set_value (float);
index 8ebc598e95cf7692f80c74887f142b93843bda53..b3ac609880eca695c4426295d2883bd3a436326b 100644 (file)
@@ -222,7 +222,7 @@ class Route : public IO
                    SoloControl
            };
            
-           ToggleControllable (Route&, ToggleType);
+           ToggleControllable (std::string name, Route&, ToggleType);
            void set_value (float);
            float get_value (void) const;
 
index 79fd4429958cb1f13f8b269e00d32d5de98227da..ca7c38b2814e2b91905dc909e08e30e2bee0c121 100644 (file)
@@ -93,7 +93,7 @@ class AudioRegion;
 class Region;
 class Playlist;
 class VSTPlugin;
-class ControlProtocolManager;
+class ControlProtocolInfo;
 
 struct AudioExportSpecification;
 struct RouteGroup;
@@ -415,7 +415,7 @@ class Session : public sigc::trackable, public PBD::StatefulDestructible
        XMLNode& get_state();
        int      set_state(const XMLNode& node); // not idempotent
        XMLNode& get_template();
-
+       
        void add_instant_xml (XMLNode&, const std::string& dir);
 
        enum StateOfTheState {
@@ -904,6 +904,9 @@ class Session : public sigc::trackable, public PBD::StatefulDestructible
 
        PBD::Controllable* controllable_by_id (const PBD::ID&);
 
+       void add_controllable (PBD::Controllable*);
+       void remove_controllable (PBD::Controllable*);
+
   protected:
        friend class AudioEngine;
        void set_block_size (nframes_t nframes);
@@ -1667,19 +1670,19 @@ class Session : public sigc::trackable, public PBD::StatefulDestructible
        LayerModel layer_model;
        CrossfadeModel xfade_model;
 
-       typedef std::list<PBD::Controllable*> Controllables;
+       typedef std::set<PBD::Controllable*> Controllables;
        Glib::Mutex controllables_lock;
        Controllables controllables;
 
-       void add_controllable (PBD::Controllable*);
-       void remove_controllable (PBD::Controllable*);
-
-
        void reset_native_file_format();
        bool first_file_data_format_reset;
        bool first_file_header_format_reset;
 
        void config_changed (const char*);
+
+       void add_control_protocol (const ControlProtocolInfo* const, XMLNode*);
+       XMLNode& get_control_protocol_state ();
+       
 };
 
 } // namespace ARDOUR
index efe4e89cd164bf48e4fd54c772a0d4351352d2c3..137458960807d41975955874eff456244b2bda07 100644 (file)
@@ -1759,7 +1759,7 @@ AudioDiskstream::get_state ()
        node->add_property ("speed", buf);
 
        node->add_property("name", _name);
-       id().print (buf);
+       id().print (buf, sizeof (buf));
        node->add_property("id", buf);
 
        if (!capturing_sources.empty() && _session.get_record_enabled()) {
index 2860470abd6182a09479b20d3da66205d20221a4..171f2d7c6b39483bb5e6385bd715225d9af86980 100644 (file)
@@ -246,6 +246,10 @@ AudioTrack::set_state (const XMLNode& node)
                                sscanf (prop->value().c_str(), "%d", &x);
                                set_remote_control_id (x);
                        }
+
+               } else if (child->name() == X_("recenable")) {
+                       _rec_enable_control.set_state (*child);
+                       _session.add_controllable (&_rec_enable_control);
                }
        }
 
@@ -273,7 +277,7 @@ AudioTrack::state(bool full_state)
 
                for (vector<FreezeRecordInsertInfo*>::iterator i = _freeze_record.insert_info.begin(); i != _freeze_record.insert_info.end(); ++i) {
                        inode = new XMLNode (X_("insert"));
-                       (*i)->id.print (buf);
+                       (*i)->id.print (buf, sizeof (buf));
                        inode->add_property (X_("id"), buf);
                        inode->add_child_copy ((*i)->state);
                
@@ -317,9 +321,11 @@ AudioTrack::state(bool full_state)
           diskstream.
        */
 
-       _diskstream->id().print (buf);
+       _diskstream->id().print (buf, sizeof (buf));
        root.add_property ("diskstream-id", buf);
 
+       root.add_child_nocopy (_rec_enable_control.get_state());
+
        return root;
 }
 
index ee3840063d35762a67f0cccc591136c12ef3b55e..855ff074ca2d6db7aa2bf5f368d04366538d90c8 100644 (file)
@@ -688,7 +688,7 @@ AudioRegion::state (bool full)
 
        for (uint32_t n=0; n < sources.size(); ++n) {
                snprintf (buf2, sizeof(buf2), "source-%d", n);
-               sources[n]->id().print (buf);
+               sources[n]->id().print (buf, sizeof (buf));
                node.add_property (buf2, buf);
        }
 
index 5c02936ba03acebb72e30c5599ff0092dd3d2519..7170b456562746b5a86c3c9853e94aca9ccc0034 100644 (file)
@@ -50,7 +50,7 @@ ControlProtocolManager::set_session (Session& s)
                        instantiate (**i);
                        (*i)->requested = false;
 
-                       if ((*i)->state) {
+                       if ((*i)->protocol && (*i)->state) {
                                (*i)->protocol->set_state (*(*i)->state);
                        }
                }
@@ -93,6 +93,10 @@ ControlProtocolManager::instantiate (ControlProtocolInfo& cpi)
        Glib::Mutex::Lock lm (protocols_lock);
        control_protocols.push_back (cpi.protocol);
 
+       if (cpi.state) {
+               cpi.protocol->set_state (*cpi.state);
+       }
+
        return cpi.protocol;
 }
 
@@ -154,7 +158,7 @@ ControlProtocolManager::discover_control_protocols (string path)
        vector<string *> *found;
        PathScanner scanner;
 
-       cerr << "looking for control protocols in " << path << endl;
+       info << string_compose (_("looking for control protocols in %1"), path) << endmsg;
 
        found = scanner (path, protocol_filter, 0, false, true);
 
@@ -261,11 +265,20 @@ ControlProtocolManager::set_state (const XMLNode& node)
 
        for (citer = clist.begin(); citer != clist.end(); ++citer) {
                if ((*citer)->name() == X_("Protocol")) {
+
                        prop = (*citer)->property (X_("active"));
+
                        if (prop && prop->value() == X_("yes")) {
                                if ((prop = (*citer)->property (X_("name"))) != 0) {
                                        ControlProtocolInfo* cpi = cpi_by_name (prop->value());
                                        if (cpi) {
+
+                                               if (!(*citer)->children().empty()) {
+                                                       cpi->state = (*citer)->children().front ();
+                                               } else {
+                                                       cpi->state = 0;
+                                               }
+                                               
                                                if (_session) {
                                                        instantiate (*cpi);
                                                } else {
@@ -294,3 +307,34 @@ ControlProtocolManager::get_state (void)
 
        return *root;
 }
+
+void
+ControlProtocolManager::set_protocol_states (const XMLNode& node)
+{
+       XMLNodeList nlist;
+       XMLNodeConstIterator niter;
+       XMLProperty* prop;
+
+       nlist = node.children();
+
+       for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+
+               XMLNode* child = (*niter);
+
+               if ((prop = child->property ("name")) == 0) {
+                       error << _("control protocol XML node has no name property. Ignored.") << endmsg;
+                       continue;
+               }
+
+               ControlProtocolInfo* cpi = cpi_by_name (prop->value());
+
+               if (!cpi) {
+                       warning << string_compose (_("control protocol \"%1\" is not known. Ignored"), prop->value()) << endmsg;
+                       continue;
+               }
+
+               /* copy the node so that ownership is clear */
+
+               cpi->state = new XMLNode (*child);
+       }
+}
index acf254e73a474ae5f7219d60576b38cb5df46616..32a9e2b533d832c1ef8b960ceb8521f756a1a8e0 100644 (file)
@@ -679,9 +679,9 @@ Crossfade::get_state ()
        char buf[64];
        LocaleGuard lg (X_("POSIX"));
 
-       _out->id().print (buf);
+       _out->id().print (buf, sizeof (buf));
        node->add_property ("out", buf);
-       _in->id().print (buf);
+       _in->id().print (buf, sizeof (buf));
        node->add_property ("in", buf);
        node->add_property ("active", (_active ? "yes" : "no"));
        node->add_property ("follow-overlap", (_follow_overlap ? "yes" : "no"));
index f38f93867502e5861a9805a704652b0105d0d2d2..34070f3dff1c88ee41f2b69be2acb606602c3d17 100644 (file)
@@ -107,7 +107,7 @@ IO::IO (Session& s, string name,
        : _session (s),
          _name (name),
          _default_type(default_type),
-         _gain_control (*this),
+         _gain_control (X_("gaincontrol"), *this),
          _gain_automation_curve (0.0, 2.0, 1.0),
          _input_minimum (input_min),
          _input_maximum (input_max),
@@ -1431,7 +1431,7 @@ IO::state (bool full_state)
        Glib::Mutex::Lock lm (io_lock);
 
        node->add_property("name", _name);
-       id().print (buf);
+       id().print (buf, sizeof (buf));
        node->add_property("id", buf);
 
        str = "";
@@ -1513,6 +1513,7 @@ IO::state (bool full_state)
        }
 
        node->add_child_nocopy (_panner->state (full_state));
+       node->add_child_nocopy (_gain_control.get_state ());
 
        snprintf (buf, sizeof(buf), "%2.12f", gain());
        node->add_property ("gain", buf);
@@ -1627,9 +1628,15 @@ IO::set_state (const XMLNode& node)
        }
 
        for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
+
                if ((*iter)->name() == "Panner") {
                        _panner->set_state (**iter);
                }
+
+               if ((*iter)->name() == X_("gaincontrol")) {
+                       _gain_control.set_state (**iter);
+                       _session.add_controllable (&_gain_control);
+               }
        }
 
        if ((prop = node.property ("automation-state")) != 0) {
index 5716d9fad55c9886310e5c3f2062a4603057e8dd..39331cfda644284474e453a165b6ac8cc049004a 100644 (file)
@@ -266,7 +266,7 @@ Location::get_state (void)
                node->add_child_nocopy(cd_info_node(m->first, m->second));
        }
 
-       id().print (buf);
+       id().print (buf, sizeof (buf));
        node->add_property("id", buf);
        node->add_property ("name", name());
        snprintf (buf, sizeof (buf), "%u", start());
index 257a21fe585dbdf401faf57cd8b736d19dd725d7..22053ce56b717f1656c834141ef45f462e4e1965 100644 (file)
@@ -67,7 +67,7 @@ static double direct_pan_to_control (pan_t val) {
 
 StreamPanner::StreamPanner (Panner& p)
        : parent (p),
-         _control (*this)
+         _control (X_("panner"), *this)
 {
        _muted = false;
 
@@ -543,6 +543,7 @@ EqualPowerStereoPanner::state (bool full_state)
        root->add_property (X_("automation-style"), buf);
 
        StreamPanner::add_state (*root);
+       root->add_child_nocopy (_control.get_state ());
 
        return *root;
 }
@@ -575,6 +576,13 @@ EqualPowerStereoPanner::set_state (const XMLNode& node)
        }
 
        StreamPanner::set_state (node);
+
+       for (XMLNodeConstIterator iter = node.children().begin(); iter != node.children().end(); ++iter) {
+               if ((*iter)->name() == X_("panner")) {
+                       _control.set_state (**iter);
+                       parent.session().add_controllable (&_control);
+               }
+       }
        
        return 0;
 }
index 7a87033a56351e7f880914e557e489ac74683a28..6d6a07da95f085bfe983877cb2700f8efdd684fd 100644 (file)
@@ -1420,7 +1420,7 @@ Playlist::state (bool full_state)
        
        node->add_property (X_("name"), _name);
 
-       _orig_diskstream_id.print (buf);
+       _orig_diskstream_id.print (buf, sizeof (buf));
        node->add_property (X_("orig_diskstream_id"), buf);
        node->add_property (X_("frozen"), _frozen ? "yes" : "no");
 
index 9a82c3bbabef3e22ca07fc4edb545a7c22a14ebf..3b471014eb503199216d69200fb4f7d405c224c7 100644 (file)
@@ -95,15 +95,17 @@ Plugin::get_nth_control (uint32_t n)
                Plugin::ParameterDescriptor desc;
 
                get_parameter_descriptor (n, desc);
-               
-               controls[n] = new PortControllable (*this, n, desc.lower, desc.upper, desc.toggled, desc.logarithmic);
+       
+               controls[n] = new PortControllable (describe_parameter (n), *this, n, 
+                                                   desc.lower, desc.upper, desc.toggled, desc.logarithmic);
        } 
 
        return controls[n];
 }
 
-Plugin::PortControllable::PortControllable (Plugin& p, uint32_t port_id, float low, float up, bool t, bool loga)
-       : plugin (p), absolute_port (port_id)
+Plugin::PortControllable::PortControllable (string name, Plugin& p, uint32_t port_id, 
+                                           float low, float up, bool t, bool loga)
+       : Controllable (name), plugin (p), absolute_port (port_id)
 {
        toggled = t;
        logarithmic = loga;
index 41d6e59246c7ecd22ebd7185cbaf4d1f6b477de2..9323966f96f4879270b50ed5df33dff3f97cd3e5 100644 (file)
@@ -233,7 +233,7 @@ Redirect::state (bool full_state)
                
                path = _session.snap_name();
                path += "-redirect-";
-               id().print (buf);
+               id().print (buf, sizeof (buf));
                path += buf;
                path += ".automation";
                
index 6c7e72be4643c20e9296202b332af32b962ede45..a13ddd77cdd85589d89438c408d43757f1fcf8b3 100644 (file)
@@ -860,7 +860,7 @@ Region::state (bool full_state)
        XMLNode *node = new XMLNode ("Region");
        char buf[64];
        
-       _id.print (buf);
+       _id.print (buf, sizeof (buf));
        node->add_property ("id", buf);
        node->add_property ("name", _name);
        snprintf (buf, sizeof (buf), "%u", _start);
index 9c752eefebf9fd646981ffa1b02dfe874201ba3e..70a5d586a0b6bf1d958b1da1746c4e3138a54707 100644 (file)
@@ -55,16 +55,16 @@ uint32_t Route::order_key_cnt = 0;
 Route::Route (Session& sess, string name, int input_min, int input_max, int output_min, int output_max, Flag flg, DataType default_type)
        : IO (sess, name, input_min, input_max, output_min, output_max, default_type),
          _flags (flg),
-         _solo_control (*this, ToggleControllable::SoloControl),
-         _mute_control (*this, ToggleControllable::MuteControl)
+         _solo_control (X_("solo"), *this, ToggleControllable::SoloControl),
+         _mute_control (X_("mute"), *this, ToggleControllable::MuteControl)
 {
        init ();
 }
 
 Route::Route (Session& sess, const XMLNode& node)
        : IO (sess, "route"),
-         _solo_control (*this, ToggleControllable::SoloControl),
-         _mute_control (*this, ToggleControllable::MuteControl)
+         _solo_control (X_("solo"), *this, ToggleControllable::SoloControl),
+         _mute_control (X_("mute"), *this, ToggleControllable::MuteControl)
 {
        init ();
        set_state (node);
@@ -1379,6 +1379,8 @@ Route::state(bool full_state)
        node->add_property ("order-keys", order_string);
 
        node->add_child_nocopy (IO::state (full_state));
+       node->add_child_nocopy (_solo_control.get_state ());
+       node->add_child_nocopy (_mute_control.get_state ());
 
        if (_control_outs) {
                XMLNode* cnode = new XMLNode (X_("ControlOuts"));
@@ -1684,6 +1686,12 @@ Route::set_state (const XMLNode& node)
 
                } else if (child->name() == "extra") {
                        _extra_xml = new XMLNode (*child);
+               } else if (child->name() == "solo") {
+                       _solo_control.set_state (*child);
+                       _session.add_controllable (&_solo_control);
+               } else if (child->name() == "mute") {
+                       _mute_control.set_state (*child);
+                       _session.add_controllable (&_mute_control);
                }
        }
 
@@ -2220,8 +2228,8 @@ Route::automation_snapshot (nframes_t now)
        }
 }
 
-Route::ToggleControllable::ToggleControllable (Route& s, ToggleType tp)
-       : route (s), type(tp)
+Route::ToggleControllable::ToggleControllable (std::string name, Route& s, ToggleType tp)
+       : Controllable (name), route (s), type(tp)
 {
        
 }
index cb52b9c4e4c943626fe5c74a409c9112059d30a4..159f8a8473535947c0ccbb4916c1f1d49a0e7ff4 100644 (file)
@@ -84,6 +84,8 @@
 #include <ardour/region_factory.h>
 #include <ardour/source_factory.h>
 
+#include <control_protocol/control_protocol.h>
+
 #include "i18n.h"
 #include <locale.h>
 
@@ -242,7 +244,6 @@ Session::first_stage_init (string fullpath, string snapshot_name)
         Curve::CurveCreated.connect (mem_fun (*this, &Session::add_curve));
         AutomationList::AutomationListCreated.connect (mem_fun (*this, &Session::add_automation_list));
 
-       Controllable::Created.connect (mem_fun (*this, &Session::add_controllable));
        Controllable::GoingAway.connect (mem_fun (*this, &Session::remove_controllable));
 
        IO::MoreOutputs.connect (mem_fun (*this, &Session::ensure_passthru_buffers));
@@ -967,6 +968,8 @@ Session::state(bool full_state)
 
        node->add_child_nocopy (_tempo_map->get_state());
 
+       node->add_child_nocopy (get_control_protocol_state());
+
        if (_extra_xml) {
                node->add_child_copy (*_extra_xml);
        }
@@ -974,6 +977,25 @@ Session::state(bool full_state)
        return *node;
 }
 
+XMLNode&
+Session::get_control_protocol_state ()
+{
+       ControlProtocolManager& cpm (ControlProtocolManager::instance());
+       XMLNode* node = new XMLNode (X_("ControlProtocols"));
+
+       cpm.foreach_known_protocol (bind (mem_fun (*this, &Session::add_control_protocol), node));
+       
+       return *node;
+}
+
+void
+Session::add_control_protocol (const ControlProtocolInfo* const cpi, XMLNode* node)
+{
+       if (cpi->protocol) {
+               node->add_child_nocopy (cpi->protocol->get_state());
+       }
+}
+
 int
 Session::set_state (const XMLNode& node)
 {
@@ -1030,6 +1052,7 @@ Session::set_state (const XMLNode& node)
        EditGroups
        MixGroups
        Click
+       ControlProtocols
        */
 
        if (use_config_midi_ports ()) {
@@ -1161,6 +1184,10 @@ Session::set_state (const XMLNode& node)
                _click_io->set_state (*child);
        }
        
+       if ((child = find_named_node (node, "ControlProtocols")) != 0) {
+               ControlProtocolManager::instance().set_protocol_states (*child);
+       }
+
        /* here beginneth the second phase ... */
 
        StateReady (); /* EMIT SIGNAL */
@@ -2719,7 +2746,7 @@ void
 Session::add_controllable (Controllable* c)
 {
        Glib::Mutex::Lock lm (controllables_lock);
-       controllables.push_back (c);
+       controllables.insert (c);
 }
 
 void
@@ -2730,7 +2757,12 @@ Session::remove_controllable (Controllable* c)
        }
 
        Glib::Mutex::Lock lm (controllables_lock);
-       controllables.remove (c);
+
+       Controllables::iterator x = controllables.find (c);
+
+       if (x != controllables.end()) {
+               controllables.erase (x);
+       }
 }      
 
 Controllable*
index e4e036584c508441ce906c04bac82b53cd7282f4..7ade8a8573fdd7db1187520cd62cd6b3c0057dfc 100644 (file)
@@ -71,7 +71,7 @@ Source::get_state ()
        char buf[64];
 
        node->add_property ("name", _name);
-       _id.print (buf);
+       _id.print (buf, sizeof (buf));
        node->add_property ("id", buf);
 
        if (_timestamp != 0) {
index cfa7d71a239420654e213fd96a96b76516bd9ebc..6d959ed88d227e20ba36b8a6b81aea59f2864737 100644 (file)
@@ -119,7 +119,7 @@ Track::freeze_state() const
 }
 
 Track::RecEnableControllable::RecEnableControllable (Track& s)
-       : track (s)
+       : Controllable (X_("recenable")), track (s)
 {
 }
 
index b1176c64a52a59dac2c6544940ce35572c2712b4..80c6811e6aed84be96ec20fb8c1f1c375fda648b 100644 (file)
@@ -1,26 +1,40 @@
 #include <pbd/controllable.h>
 #include <pbd/xml++.h>
+#include <pbd/error.h>
 
 #include "i18n.h"
 
 using namespace PBD;
 
-sigc::signal<void,Controllable*> Controllable::Created;
 sigc::signal<void,Controllable*> Controllable::GoingAway;
 sigc::signal<bool,Controllable*> Controllable::StartLearning;
 sigc::signal<void,Controllable*> Controllable::StopLearning;
 
-Controllable::Controllable ()
+Controllable::Controllable (std::string name)
+       : _name (name)
 {
-       Created (this);
 }
 
 XMLNode&
 Controllable::get_state ()
 {
-       XMLNode* node = new XMLNode (X_("Controllable"));
+       XMLNode* node = new XMLNode (_name);
        char buf[64];
-       _id.print (buf);
+       _id.print (buf, sizeof (buf));
        node->add_property (X_("id"), buf);
        return *node;
 }
+
+int
+Controllable::set_state (const XMLNode& node)
+{
+       const XMLProperty* prop = node.property (X_("id"));
+
+       if (prop) {
+               _id = prop->value();
+               return 0;
+       } else {
+               error << _("Controllable state node has no ID property") << endmsg;
+               return -1;
+       }
+}
index c99e242beecbeab81db0be8472236373576b6240..353776de9f5c585acc89be5ef59cf2a420dcc25e 100644 (file)
@@ -40,16 +40,15 @@ ID::string_assign (string str)
 }
 
 void
-ID::print (char* buf) const
+ID::print (char* buf, uint32_t bufsize) const
 {
-       /* XXX sizeof buf is unknown. bad API design */
-       snprintf (buf, 32, "%" PRIu64, _id);
+       snprintf (buf, bufsize, "%" PRIu64, _id);
 }
 
 string ID::to_s() const
 {
     char buf[32]; // see print()
-    print(buf);
+    print(buf, sizeof (buf));
     return string(buf);
 }
 
@@ -64,7 +63,7 @@ ostream&
 operator<< (ostream& ostr, const ID& _id)
 {
        char buf[32];
-       _id.print (buf);
+       _id.print (buf, sizeof (buf));
        ostr << buf;
        return ostr;
 }
index c46e477b6ecd1fda518a3a879b59c5684fcc3c56..ff8f8a9b52004a1b8342bdf67fed3d526a28da19 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __pbd_controllable_h__
 #define __pbd_controllable_h__
 
+#include <string>
+
 #include <sigc++/trackable.h>
 #include <sigc++/signal.h>
 
@@ -13,7 +15,7 @@ namespace PBD {
 
 class Controllable : public virtual sigc::trackable, public Stateful {
   public:
-       Controllable ();
+       Controllable (std::string name);
        virtual ~Controllable() { GoingAway (this); }
 
        virtual void set_value (float) = 0;
@@ -23,22 +25,20 @@ class Controllable : public virtual sigc::trackable, public Stateful {
 
        sigc::signal<void> LearningFinished;
 
-       static sigc::signal<void,Controllable*> Created;
        static sigc::signal<void,Controllable*> GoingAway;
 
-
        static sigc::signal<bool,PBD::Controllable*> StartLearning;
        static sigc::signal<void,PBD::Controllable*> StopLearning;
 
        sigc::signal<void> Changed;
 
-       const PBD::ID& id() const { return _id; }
-
-       int set_state (const XMLNode&) { return 0; }
+       int set_state (const XMLNode&);
        XMLNode& get_state ();
 
+       std::string name() const { return _name; }
+
   private:
-       PBD::ID _id;
+       std::string _name;
 };
 
 }
index c1103627342ba4d313052baa62cc03acb39de70e..eb3691d99ec7e98167cb7b692847207d29c5f999 100644 (file)
@@ -27,7 +27,7 @@ class ID {
                return _id < other._id;
        }
 
-       void print (char* buf) const;
+       void print (char* buf, uint32_t bufsize) const;
         std::string to_s() const;
        
        static uint64_t counter() { return _counter; }
index d905c0bc41bcf1299007f3dedc57973811cd2a01..a8a5b6eacec4f88967e150890870fafe2e351f59 100644 (file)
@@ -39,7 +39,7 @@ using namespace PBD;
 #include "i18n.h"
 
 GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
-       : ControlProtocol  (s, _("GenericMIDI"))
+       : ControlProtocol  (s, _("Generic MIDI"))
 {
        MIDI::Manager* mm = MIDI::Manager::instance();
 
@@ -173,7 +173,10 @@ GenericMidiControlProtocol::stop_learning (Controllable* c)
 XMLNode&
 GenericMidiControlProtocol::get_state () 
 {
-       XMLNode* node = new XMLNode (_name); /* node name must match protocol name */
+       XMLNode* node = new XMLNode ("Protocol"); 
+
+       node->add_property (X_("name"), _name);
+
        XMLNode* children = new XMLNode (X_("controls"));
 
        node->add_child_nocopy (*children);
@@ -215,19 +218,24 @@ GenericMidiControlProtocol::set_state (const XMLNode& node)
                XMLProperty* prop;
 
                if ((prop = (*niter)->property ("id")) != 0) {
-
+                       
                        ID id = prop->value ();
-
+                       
                        c = session->controllable_by_id (id);
-
+                       
                        if (c) {
                                MIDIControllable* mc = new MIDIControllable (*_port, *c);
                                if (mc->set_state (**niter) == 0) {
                                        controllables.insert (mc);
                                }
+                               
+                       } else {
+                               warning << string_compose (_("Generic MIDI control: controllable %1 not found in session (ignored)"),
+                                                          id)
+                                       << endmsg;
                        }
                }
        }
-       
+
        return 0;
 }
index d6135fd2a86f426b6685a0cac8393297cc129177..1cf32f11f60d6a6fce5c1c16fc715902987393a2 100644 (file)
@@ -345,6 +345,8 @@ MIDIControllable::set_state (const XMLNode& node)
                return -1;
        }
 
+       bind_midi (control_channel, control_type, control_additional);
+       
        return 0;
 }
 
index 04d56c575c38d370e262a6bf89bb53a57e2cff98..2e2d9432443965ac84ba8b512ff3d43b35c69c7d 100644 (file)
@@ -1577,7 +1577,8 @@ TranzportControlProtocol::print (int row, int col, const char *text)
 XMLNode&
 TranzportControlProtocol::get_state () 
 {
-       XMLNode* node = new XMLNode (_name); /* node name must match protocol name */
+       XMLNode* node = new XMLNode (X_("Protocol"));
+       node->add_property (X_("name"), _name);
        return *node;
 }