Transfer Fn: skip phase calculation for silence and small signal levels
[ardour.git] / gtk2_ardour / luainstance.cc
index 8d1644276df555517e0de26e1858e7033dab3a3a..0756d803be498092eac59fc7ca695dd929022455 100644 (file)
@@ -20,6 +20,7 @@
 #include <cairomm/surface.h>
 #include <pango/pangocairo.h>
 
+#include "pbd/file_utils.h"
 #include "pbd/strsplit.h"
 
 #include "gtkmm2ext/bindings.h"
@@ -28,6 +29,7 @@
 #include "ardour/audioengine.h"
 #include "ardour/disk_reader.h"
 #include "ardour/disk_writer.h"
+#include "ardour/filesystem_paths.h"
 #include "ardour/plugin_manager.h"
 #include "ardour/route.h"
 #include "ardour/session.h"
@@ -54,6 +56,8 @@
 
 #include "pbd/i18n.h"
 
+static const char* ui_scripts_file_name = "ui_scripts";
+
 namespace LuaCairo {
 /** wrap RefPtr< Cairo::ImageSurface >
  *
@@ -69,9 +73,9 @@ class ImageSurface {
                 * color or alpha channel belonging to format will be 0. The contents of bits
                 * within a pixel, but not belonging to the given format are undefined).
                 *
-                * @param format        format of pixels in the surface to create
-                * @param width         width of the surface, in pixels
-                * @param height        height of the surface, in pixels
+                * @param format  format of pixels in the surface to create
+                * @param width   width of the surface, in pixels
+                * @param height  height of the surface, in pixels
                 */
                ImageSurface (Cairo::Format format, int width, int height)
                        : _surface (Cairo::ImageSurface::create (format, width, height))
@@ -143,10 +147,10 @@ class ImageSurface {
 
                /** Marks a rectangular area of the given surface dirty.
                 *
-                * @param x      X coordinate of dirty rectangle
-                * @param y     Y coordinate of dirty rectangle
-                * @param width         width of dirty rectangle
-                * @param height        height of dirty rectangle
+                * @param x X coordinate of dirty rectangle
+                * @param y Y coordinate of dirty rectangle
+                * @param width width of dirty rectangle
+                * @param height height of dirty rectangle
                 */
                void mark_dirty (int x, int y, int width, int height) {
                        _surface->mark_dirty (x, y, width, height);
@@ -363,6 +367,8 @@ const char *luasignalstr[] = {
 }; // namespace
 
 
+static std::string http_get_unlogged (const std::string& url) { return ArdourCurl::http_get (url, false); }
+
 /** special cases for Ardour's Mixer UI */
 namespace LuaMixer {
 
@@ -440,7 +446,7 @@ lua_actionlist (lua_State *L)
        vector<string> tooltips;
        vector<string> keys;
        vector<Glib::RefPtr<Gtk::Action> > actions;
-       Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
+       ActionManager::get_all_actions (paths, labels, tooltips, keys, actions);
 
        vector<string>::iterator p;
        vector<string>::iterator l;
@@ -466,24 +472,18 @@ lua_actionlist (lua_State *L)
                        continue;
                if (parts[1] == _("redirectmenu"))
                        continue;
-               if (parts[1] == _("Editor_menus"))
-                       continue;
                if (parts[1] == _("RegionList"))
                        continue;
                if (parts[1] == _("ProcessorMenu"))
                        continue;
 
-               /* strip <Actions>/ from the start */
-               string path = (*p);
-               path = path.substr (strlen ("<Actions>/"));
-
                if (!action_tbl[parts[1]].isTable()) {
                        action_tbl[parts[1]] = luabridge::newTable (L);
                }
                assert (action_tbl[parts[1]].isTable());
                luabridge::LuaRef tbl (action_tbl[parts[1]]);
                assert (tbl.isTable());
-               tbl[*l] = path;
+               tbl[*l] = *p;
        }
 
        luabridge::push (L, action_tbl);
@@ -506,6 +506,7 @@ lua_translate_order (RouteDialogs::InsertAt place)
 
 using namespace ARDOUR;
 
+PBD::Signal0<void> LuaInstance::LuaTimerS;
 PBD::Signal0<void> LuaInstance::LuaTimerDS;
 PBD::Signal0<void> LuaInstance::SetSession;
 
@@ -744,11 +745,11 @@ LuaInstance::register_classes (lua_State* L)
        luabridge::getGlobalNamespace (L)
                .beginNamespace ("ArdourUI")
 
-               .addFunction ("http_get", (std::string (*)(const std::string&))&ArdourCurl::http_get_unlogged)
+               .addFunction ("http_get", &http_get_unlogged)
 
                .addFunction ("processor_selection", &LuaMixer::processor_selection)
 
-               .beginStdList <ArdourMarker*> ("ArdourMarkerList")
+               .beginStdCPtrList <ArdourMarker> ("ArdourMarkerList")
                .endClass ()
 
                .beginClass <ArdourMarker> ("ArdourMarker")
@@ -1089,8 +1090,6 @@ LuaInstance::LuaInstance ()
 {
        lua.Print.connect (&_lua_print);
        init ();
-
-       LuaScriptParamList args;
 }
 
 LuaInstance::~LuaInstance ()
@@ -1264,6 +1263,64 @@ LuaInstance::init ()
        lua_setglobal (L, "Editor");
 }
 
+int
+LuaInstance::load_state ()
+{
+       std::string uiscripts;
+       if (!find_file (ardour_config_search_path(), ui_scripts_file_name, uiscripts)) {
+               return -1;
+       }
+       XMLTree tree;
+
+       info << string_compose (_("Loading user ui scripts file %1"), uiscripts) << endmsg;
+
+       if (!tree.read (uiscripts)) {
+               error << string_compose(_("cannot read ui scripts file \"%1\""), uiscripts) << endmsg;
+               return -1;
+       }
+
+       if (set_state (*tree.root())) {
+               error << string_compose(_("user ui scripts file \"%1\" not loaded successfully."), uiscripts) << endmsg;
+               return -1;
+       }
+
+       return 0;
+}
+
+int
+LuaInstance::save_state ()
+{
+       if (!_session) {
+               /* action scripts are un-registered with the session */
+               return -1;
+       }
+
+       std::string uiscripts = Glib::build_filename (user_config_directory(), ui_scripts_file_name);
+
+       XMLNode* node = new XMLNode (X_("UIScripts"));
+       node->add_child_nocopy (get_action_state ());
+       node->add_child_nocopy (get_hook_state ());
+
+       XMLTree tree;
+       tree.set_root (node);
+
+       if (!tree.write (uiscripts.c_str())){
+               error << string_compose (_("UI script file %1 not saved"), uiscripts) << endmsg;
+               return -1;
+       }
+       return 0;
+}
+
+void
+LuaInstance::set_dirty ()
+{
+       if (!_session || _session->deletion_in_progress()) {
+               return;
+       }
+       save_state ();
+       _session->set_dirty (); // XXX is this reasonable?
+}
+
 void LuaInstance::set_session (Session* s)
 {
        SessionHandlePtr::set_session (s);
@@ -1271,12 +1328,15 @@ void LuaInstance::set_session (Session* s)
                return;
        }
 
+       load_state ();
+
        lua_State* L = lua.getState();
        LuaBindings::set_session (L, _session);
 
        for (LuaCallbackMap::iterator i = _callbacks.begin(); i != _callbacks.end(); ++i) {
                i->second->set_session (s);
        }
+       second_connection = Timers::rapid_connect (sigc::mem_fun(*this, & LuaInstance::every_second));
        point_one_second_connection = Timers::rapid_connect (sigc::mem_fun(*this, & LuaInstance::every_point_one_seconds));
        SetSession (); /* EMIT SIGNAL */
 }
@@ -1285,10 +1345,11 @@ void
 LuaInstance::session_going_away ()
 {
        ENSURE_GUI_THREAD (*this, &LuaInstance::session_going_away);
+       second_connection.disconnect ();
        point_one_second_connection.disconnect ();
 
        (*_lua_clear)();
-       for (int i = 0; i < 9; ++i) {
+       for (int i = 0; i < MAX_LUA_ACTION_SCRIPTS; ++i) {
                ActionChanged (i, ""); /* EMIT SIGNAL */
        }
        SessionHandlePtr::session_going_away ();
@@ -1299,6 +1360,12 @@ LuaInstance::session_going_away ()
        lua.do_command ("collectgarbage();");
 }
 
+void
+LuaInstance::every_second ()
+{
+       LuaTimerS (); // emit signal
+}
+
 void
 LuaInstance::every_point_one_seconds ()
 {
@@ -1320,7 +1387,7 @@ LuaInstance::set_state (const XMLNode& node)
                        } catch (luabridge::LuaException const& e) {
                                cerr << "LuaException:" << e.what () << endl;
                        } catch (...) { }
-                       for (int i = 0; i < 9; ++i) {
+                       for (int i = 0; i < MAX_LUA_ACTION_SCRIPTS; ++i) {
                                std::string name;
                                if (lua_action_name (i, name)) {
                                        ActionChanged (i, name); /* EMIT SIGNAL */
@@ -1330,6 +1397,7 @@ LuaInstance::set_state (const XMLNode& node)
                }
        }
 
+       assert (_callbacks.empty());
        if ((child = find_named_node (node, "ActionHooks"))) {
                for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
                        try {
@@ -1535,7 +1603,7 @@ LuaInstance::set_lua_action (
        } catch (...) {
                return false;
        }
-       _session->set_dirty ();
+       set_dirty ();
        return true;
 }
 
@@ -1551,7 +1619,7 @@ LuaInstance::remove_lua_action (const int id)
                return false;
        }
        ActionChanged (id, ""); /* EMIT SIGNAL */
-       _session->set_dirty ();
+       set_dirty ();
        return true;
 }
 
@@ -1578,7 +1646,7 @@ std::vector<std::string>
 LuaInstance::lua_action_names ()
 {
        std::vector<std::string> rv;
-       for (int i = 0; i < 9; ++i) {
+       for (int i = 0; i < MAX_LUA_ACTION_SCRIPTS; ++i) {
                std::string name;
                if (lua_action_name (i, name)) {
                        rv.push_back (name);
@@ -1672,11 +1740,11 @@ LuaInstance::register_lua_slot (const std::string& name, const std::string& scri
                _callbacks.insert (std::make_pair(p->id(), p));
                p->drop_callback.connect (_slotcon, MISSING_INVALIDATOR, boost::bind (&LuaInstance::unregister_lua_slot, this, p->id()), gui_context());
                SlotChanged (p->id(), p->name(), p->signals()); /* EMIT SIGNAL */
+               set_dirty ();
                return true;
        } catch (luabridge::LuaException const& e) {
                cerr << "LuaException:" << e.what () << endl;
        } catch (...) { }
-       _session->set_dirty ();
        return false;
 }
 
@@ -1687,9 +1755,9 @@ LuaInstance::unregister_lua_slot (const PBD::ID& id)
        if (i != _callbacks.end()) {
                SlotChanged (id, "", ActionHook()); /* EMIT SIGNAL */
                _callbacks.erase (i);
+               set_dirty ();
                return true;
        }
-       _session->set_dirty ();
        return false;
 }