cue monitoring for MIDI
[ardour.git] / libs / ardour / luaproc.cc
index f2db7848c8946857131dd10158264c97b734b0d8..c1fd455cdff50f1eca0a7691d0138fef5149dafd 100644 (file)
@@ -22,7 +22,6 @@
 #include <glibmm/fileutils.h>
 
 #include "pbd/gstdio_compat.h"
-#include "pbd/locale_guard.h"
 #include "pbd/pthread_utils.h"
 
 #include "ardour/audio_buffer.h"
@@ -46,7 +45,7 @@ LuaProc::LuaProc (AudioEngine& engine,
                   Session& session,
                   const std::string &script)
        : Plugin (engine, session)
-       , _mempool ("LuaProc", 2097152)
+       , _mempool ("LuaProc", 3145728)
 #ifdef USE_TLSF
        , lua (lua_newstate (&PBD::TLSF::lalloc, &_mempool))
 #elif defined USE_MALLOC
@@ -61,6 +60,7 @@ LuaProc::LuaProc (AudioEngine& engine,
        , _designated_bypass_port (UINT32_MAX)
        , _control_data (0)
        , _shadow_data (0)
+       , _configured (false)
        , _has_midi_input (false)
        , _has_midi_output (false)
 {
@@ -76,7 +76,7 @@ LuaProc::LuaProc (AudioEngine& engine,
 
 LuaProc::LuaProc (const LuaProc &other)
        : Plugin (other)
-       , _mempool ("LuaProc", 2097152)
+       , _mempool ("LuaProc", 3145728)
 #ifdef USE_TLSF
        , lua (lua_newstate (&PBD::TLSF::lalloc, &_mempool))
 #elif defined USE_MALLOC
@@ -86,11 +86,13 @@ LuaProc::LuaProc (const LuaProc &other)
 #endif
        , _lua_dsp (0)
        , _script (other.script ())
+       , _origin (other._origin)
        , _lua_does_channelmapping (false)
        , _lua_has_inline_display (false)
        , _designated_bypass_port (UINT32_MAX)
        , _control_data (0)
        , _shadow_data (0)
+       , _configured (false)
        , _has_midi_input (false)
        , _has_midi_output (false)
 {
@@ -142,10 +144,13 @@ LuaProc::init ()
 
        luabridge::getGlobalNamespace (L)
                .beginNamespace ("Ardour")
-               .beginClass <LuaProc> ("LuaProc")
+               .deriveClass <LuaProc, PBD::StatefulDestructible> ("LuaProc")
                .addFunction ("queue_draw", &LuaProc::queue_draw)
                .addFunction ("shmem", &LuaProc::instance_shm)
                .addFunction ("table", &LuaProc::instance_ref)
+               .addFunction ("route", &LuaProc::route)
+               .addFunction ("unique_id", &LuaProc::unique_id)
+               .addFunction ("name", &LuaProc::name)
                .endClass ()
                .endNamespace ();
 
@@ -158,13 +163,22 @@ LuaProc::init ()
        lua_setglobal (L, "self");
 
        // sandbox
-       lua.do_command ("io = nil os = nil loadfile = nil require = nil dofile = nil package = nil debug = nil");
+       lua.sandbox (true);
 #if 0
        lua.do_command ("for n in pairs(_G) do print(n) end print ('----')"); // print global env
 #endif
        lua.do_command ("function ardour () end");
 }
 
+boost::weak_ptr<Route>
+LuaProc::route () const
+{
+       if (!_owner) {
+               return boost::weak_ptr<Route>();
+       }
+       return static_cast<Route*>(_owner)->weakroute ();
+}
+
 void
 LuaProc::lua_print (std::string s) {
        std::cout <<"LuaProc: " << s << "\n";
@@ -224,27 +238,7 @@ LuaProc::load_script ()
                try {
                        lua_dsp_init (_session.nominal_frame_rate ());
                } catch (luabridge::LuaException const& e) {
-                       ;
-               }
-       }
-
-       // query midi i/o
-       luabridge::LuaRef lua_dsp_has_midi_in = luabridge::getGlobal (L, "dsp_has_midi_input");
-       if (lua_dsp_has_midi_in.type () == LUA_TFUNCTION) {
-               try {
-                       _has_midi_input = lua_dsp_has_midi_in ();
-               } catch (luabridge::LuaException const& e) {
-                       ;
-               }
-       }
-
-       luabridge::LuaRef lua_dsp_has_midi_out = luabridge::getGlobal (L, "dsp_has_midi_output");
-       if (lua_dsp_has_midi_out.type () == LUA_TFUNCTION) {
-               try {
-                       _has_midi_output = lua_dsp_has_midi_out ();
-               } catch (luabridge::LuaException const& e) {
-                       ;
-               }
+               } catch (...) { }
        }
 
        _ctrl_params.clear ();
@@ -348,22 +342,26 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan
 
        lua_State* L = lua.getState ();
        luabridge::LuaRef ioconfig = luabridge::getGlobal (L, "dsp_ioconfig");
-       if (!ioconfig.isFunction ()) {
-               return false;
-       }
 
        luabridge::LuaRef *_iotable = NULL; // can't use reference :(
-       try {
-               luabridge::LuaRef iotable = ioconfig ();
-               if (iotable.isTable ()) {
-                       _iotable = new luabridge::LuaRef (iotable);
+
+       if (ioconfig.isFunction ()) {
+               try {
+                       luabridge::LuaRef iotable = ioconfig ();
+                       if (iotable.isTable ()) {
+                               _iotable = new luabridge::LuaRef (iotable);
+                       }
+               } catch (luabridge::LuaException const& e) {
+                       _iotable = NULL;
+               } catch (...) {
+                       _iotable = NULL;
                }
-       } catch (luabridge::LuaException const& e) {
-               return false;
        }
 
        if (!_iotable) {
-               return false;
+               /* empty table as default */
+               luabridge::LuaRef iotable = luabridge::newTable(L);
+               _iotable = new luabridge::LuaRef (iotable);
        }
 
        // now we can reference it.
@@ -371,7 +369,9 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan
        delete _iotable;
 
        if ((iotable).length () < 1) {
-               return false;
+               /* empty table as only config, to get default values */
+               luabridge::LuaRef ioconf = luabridge::newTable(L);
+               iotable[1] = ioconf;
        }
 
        const int audio_in = in.n_audio ();
@@ -379,6 +379,7 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan
 
        // preferred setting (provided by plugin_insert)
        const int preferred_out = out.n_audio ();
+       const int preferred_midiout = out.n_midi ();
 
        int midi_out = -1;
        int audio_out = -1;
@@ -394,17 +395,22 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan
       imprecise->set (DataType::AUDIO, (in));                       \
       imprecise->set (DataType::MIDI, possible_midiin);             \
     }                                                               \
+    _has_midi_input = (possible_midiin > 0);                        \
+    _has_midi_output = (possible_midiout > 0);                      \
     penalty = p;                                                    \
     found = true;                                                   \
   }                                                                 \
 }
 
 #define FOUNDCFG_IMPRECISE(in, out) {                               \
-  float p = fabsf ((float)(out) - preferred_out) ;                  \
-  if (in != audio_in) {                                             \
-    p += 1000;                                                      \
-  }                                                                 \
-  if ((out) > preferred_out) { p *= 1.1; }                          \
+  const float p = fabsf ((float)(out) - preferred_out) *            \
+                      (((out) > preferred_out) ? 1.1 : 1)           \
+                + fabsf ((float)possible_midiout - preferred_midiout) *    \
+                      ((possible_midiout - preferred_midiout) ? 0.6 : 0.5) \
+                + fabsf ((float)(in) - audio_in) *                  \
+                      (((in) > audio_in) ? 275 : 250)               \
+                + fabsf ((float)possible_midiin - midi_in) *        \
+                      ((possible_midiin - midi_in) ? 100 : 110);    \
   FOUNDCFG_PENALTY(in, out, p);                                     \
 }
 
@@ -432,10 +438,10 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan
 
                int possible_in = io["audio_in"].isNumber() ? io["audio_in"] : -1;
                int possible_out = io["audio_out"].isNumber() ? io["audio_out"] : -1;
-               int possible_midiin = _has_midi_input ? 1 : 0;
-               int possible_midiout = _has_midi_output ? 1 : 0;
+               int possible_midiin = io["midi_in"].isNumber() ? io["midi_in"] : 0;
+               int possible_midiout = io["midi_out"].isNumber() ? io["midi_out"] : 0;
 
-               if (midi_in > 0 && possible_midiin == 0 && !imprecise) {
+               if (midi_in != possible_midiin && !imprecise) {
                        continue;
                }
 
@@ -446,39 +452,11 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan
                        FOUNDCFG_PENALTY(audio_in, preferred_out, -1);
                }
 
-               // "imprecise" matches
-               if (possible_out == 0) {
-                       /* skip configurations with no audio output, unless
-                        * the plugin is a midi filter or generator */
-                       if (possible_in == 0 && _has_midi_output) {
-                               if (audio_in == 0) {
-                                       FOUNDCFG(possible_out);
-                                       break;
-                               } else if (imprecise) {
-                                       // TODO hide audio input from plugin
-                                       FOUNDCFG_IMPRECISE (possible_in, possible_out);
-                               }
-                       }
+               if (possible_out == 0 && possible_midiout == 0) {
+                       /* skip configurations with no output at all */
                        continue;
                }
 
-               if (possible_in == 0) {
-                       /* no inputs, generators & instruments */
-                       if (possible_out == -1 || possible_out == -2) {
-                               /* any output configuration possible
-                                * out == -2 is invalid, interpreted as out == -1 */
-                               FOUNDCFG (preferred_out);
-                               ANYTHINGGOES;
-                       } else if (possible_out < -2) {
-                               /* variable number of outputs up to -N, */
-                               FOUNDCFG (min (-possible_out, preferred_out));
-                               UPTO (-possible_out);
-                       } else {
-                               /* exact number of outputs */
-                               FOUNDCFG (possible_out);
-                       }
-               }
-
                if (possible_in == -1 || possible_in == -2) {
                        /* wildcard for input */
                        if (possible_out == possible_in) {
@@ -501,10 +479,10 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan
                        }
                }
 
-               if (possible_in < -2 || possible_in > 0) {
+               if (possible_in < -2 || possible_in >= 0) {
                        /* specified number, exact or up to */
                        int desired_in;
-                       if (possible_in > 0) {
+                       if (possible_in >= 0) {
                                /* configuration can only match possible_in */
                                desired_in = possible_in;
                        } else {
@@ -532,8 +510,6 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, Chan
                                 * Really imprecise only if desired_in != audio_in */
                                FOUNDCFG_IMPRECISE (desired_in, possible_out);
                        }
-                       // ideally we'll also find the closest, best matching
-                       // input configuration with minimal output penalty...
                }
 
        }
@@ -565,7 +541,7 @@ LuaProc::configure_io (ChanCount in, ChanCount out)
        _info->n_outputs = _selected_out;
 
        // configure the DSP if needed
-       if (in != _configured_in || out != _configured_out) {
+       if (in != _configured_in || out != _configured_out || !_configured) {
                lua_State* L = lua.getState ();
                luabridge::LuaRef lua_dsp_configure = luabridge::getGlobal (L, "dsp_configure");
                if (lua_dsp_configure.type () == LUA_TFUNCTION) {
@@ -602,12 +578,15 @@ LuaProc::configure_io (ChanCount in, ChanCount out)
                                        _info->n_inputs = lin;
                                        _info->n_outputs = lout;
                                }
+                               _configured = true;
                        } catch (luabridge::LuaException const& e) {
                                PBD::error << "LuaException: " << e.what () << "\n";
 #ifndef NDEBUG
                                std::cerr << "LuaException: " << e.what () << "\n";
 #endif
                                return false;
+                       } catch (...) {
+                               return false;
                        }
                }
        }
@@ -694,7 +673,7 @@ LuaProc::connect_and_run (BufferSet& bufs,
                                if (valid) {
                                        for (MidiBuffer::iterator m = bufs.get_midi(idx).begin();
                                                        m != bufs.get_midi(idx).end(); ++m, ++e) {
-                                               const Evoral::MIDIEvent<framepos_t> ev(*m, false);
+                                               const Evoral::Event<framepos_t> ev(*m, false);
                                                luabridge::LuaRef lua_midi_data (luabridge::newTable (L));
                                                const uint8_t* data = ev.buffer();
                                                for (uint32_t i = 0; i < ev.size(); ++i) {
@@ -703,6 +682,8 @@ LuaProc::connect_and_run (BufferSet& bufs,
                                                luabridge::LuaRef lua_midi_event (luabridge::newTable (L));
                                                lua_midi_event["time"] = 1 + (*m).time();
                                                lua_midi_event["data"] = lua_midi_data;
+                                               lua_midi_event["bytes"] = data;
+                                               lua_midi_event["size"] = ev.size();
                                                lua_midi_src_tbl[e] = lua_midi_event;
                                        }
                                }
@@ -756,6 +737,8 @@ LuaProc::connect_and_run (BufferSet& bufs,
                std::cerr << "LuaException: " << e.what () << "\n";
 #endif
                return -1;
+       } catch (...) {
+               return -1;
        }
 #ifdef WITH_LUAPROC_STATS
        int64_t t1 = g_get_monotonic_time ();
@@ -780,24 +763,21 @@ void
 LuaProc::add_state (XMLNode* root) const
 {
        XMLNode*    child;
-       char        buf[32];
-       LocaleGuard lg;
 
        gchar* b64 = g_base64_encode ((const guchar*)_script.c_str (), _script.size ());
        std::string b64s (b64);
        g_free (b64);
        XMLNode* script_node = new XMLNode (X_("script"));
-       script_node->add_property (X_("lua"), LUA_VERSION);
+       script_node->set_property (X_("lua"), LUA_VERSION);
+       script_node->set_property (X_("origin"), _origin);
        script_node->add_content (b64s);
        root->add_child_nocopy (*script_node);
 
        for (uint32_t i = 0; i < parameter_count(); ++i) {
                if (parameter_is_input(i) && parameter_is_control(i)) {
                        child = new XMLNode("Port");
-                       snprintf(buf, sizeof(buf), "%u", i);
-                       child->add_property("id", std::string(buf));
-                       snprintf(buf, sizeof(buf), "%+f", _shadow_data[i]);
-                       child->add_property("value", std::string(buf));
+                       child->set_property("id", i);
+                       child->set_property("value", _shadow_data[i]);
                        root->add_child_nocopy(*child);
                }
        }
@@ -812,6 +792,10 @@ LuaProc::set_script_from_state (const XMLNode& node)
        }
 
        if ((child = node.child (X_("script"))) != 0) {
+               XMLProperty const* prop;
+               if ((prop = node.property ("origin")) != 0) {
+                       _origin = prop->value();
+               }
                for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
                        if (!(*n)->is_content ()) { continue; }
                        gsize size;
@@ -844,14 +828,9 @@ LuaProc::set_state (const XMLNode& node, int version)
 {
 #ifndef NO_PLUGIN_STATE
        XMLNodeList nodes;
-       XMLProperty const * prop;
        XMLNodeConstIterator iter;
        XMLNode *child;
-       const char *value;
-       const char *port;
-       uint32_t port_id;
 #endif
-       LocaleGuard lg;
 
        if (_script.empty ()) {
                if (set_script_from_state (node)) {
@@ -868,20 +847,21 @@ LuaProc::set_state (const XMLNode& node, int version)
        nodes = node.children ("Port");
        for (iter = nodes.begin(); iter != nodes.end(); ++iter) {
                child = *iter;
-               if ((prop = child->property("id")) != 0) {
-                       port = prop->value().c_str();
-               } else {
+
+               uint32_t port_id;
+               float value;
+
+               if (!child->get_property("id", port_id)) {
                        warning << _("LuaProc: port has no symbol, ignored") << endmsg;
                        continue;
                }
-               if ((prop = child->property("value")) != 0) {
-                       value = prop->value().c_str();
-               } else {
+
+               if (!child->get_property("value", value)) {
                        warning << _("LuaProc: port has no value, ignored") << endmsg;
                        continue;
                }
-               sscanf (port, "%" PRIu32, &port_id);
-               set_parameter (port_id, atof(value));
+
+               set_parameter (port_id, value);
        }
 #endif
 
@@ -1054,6 +1034,7 @@ LuaProc::setup_lua_inline_gui (LuaState *lua_gui)
        LuaBindings::stddef (LG);
        LuaBindings::common (LG);
        LuaBindings::dsp (LG);
+       LuaBindings::osc (LG);
 
        lua_gui->Print.connect (sigc::mem_fun (*this, &LuaProc::lua_print));
        lua_gui->do_command ("function ardour () end");
@@ -1072,7 +1053,7 @@ LuaProc::setup_lua_inline_gui (LuaState *lua_gui)
        luabridge::push <LuaProc *> (LG, this);
        lua_setglobal (LG, "self");
 
-       luabridge::push <float *> (LG, _shadow_data);
+       luabridge::push <float *> (LG, _control_data);
        lua_setglobal (LG, "CtrlPorts");
 }
 ////////////////////////////////////////////////////////////////////////////////
@@ -1136,20 +1117,24 @@ LuaProc::load_preset (PresetRecord r)
 
        XMLNode* root = t->root ();
        for (XMLNodeList::const_iterator i = root->children().begin(); i != root->children().end(); ++i) {
-               XMLProperty const * label = (*i)->property (X_("label"));
-               assert (label);
-               if (label->value() != r.label) {
+               std::string str;
+               if (!(*i)->get_property (X_("label"), str)) {
+                       assert (false);
+               }
+               if (str != r.label) {
                        continue;
                }
 
                for (XMLNodeList::const_iterator j = (*i)->children().begin(); j != (*i)->children().end(); ++j) {
                        if ((*j)->name() == X_("Parameter")) {
-                               XMLProperty const * index = (*j)->property (X_("index"));
-                               XMLProperty const * value = (*j)->property (X_("value"));
-                               assert (index);
-                               assert (value);
-                               LocaleGuard lg;
-                               set_parameter (atoi (index->value().c_str()), atof (value->value().c_str ()));
+                               uint32_t index;
+                               float value;
+                               if (!(*j)->get_property (X_("index"), index) ||
+                                   !(*j)->get_property (X_("value"), value)) {
+                                       assert (false);
+                               }
+                               set_parameter (index, value);
+                               PresetPortSetValue (index, value); /* EMIT SIGNAL */
                        }
                }
                return Plugin::load_preset(r);
@@ -1165,17 +1150,20 @@ LuaProc::do_save_preset (std::string name) {
                return "";
        }
 
+       // prevent dups -- just in case
+       t->root()->remove_nodes_and_delete (X_("label"), name);
+
        std::string uri (preset_name_to_uri (name));
 
        XMLNode* p = new XMLNode (X_("Preset"));
-       p->add_property (X_("uri"), uri);
-       p->add_property (X_("label"), name);
+       p->set_property (X_("uri"), uri);
+       p->set_property (X_("label"), name);
 
        for (uint32_t i = 0; i < parameter_count(); ++i) {
                if (parameter_is_input (i)) {
                        XMLNode* c = new XMLNode (X_("Parameter"));
-                       c->add_property (X_("index"), string_compose ("%1", i));
-                       c->add_property (X_("value"), string_compose ("%1", get_parameter (i)));
+                       c->set_property (X_("index"), i);
+                       c->set_property (X_("value"), get_parameter (i));
                        p->add_child_nocopy (*c);
                }
        }
@@ -1208,14 +1196,14 @@ LuaProc::find_presets ()
        if (t) {
                XMLNode* root = t->root ();
                for (XMLNodeList::const_iterator i = root->children().begin(); i != root->children().end(); ++i) {
+                       std::string uri;
+                       std::string label;
 
-                       XMLProperty const * uri = (*i)->property (X_("uri"));
-                       XMLProperty const * label = (*i)->property (X_("label"));
-
-                       assert (uri);
-                       assert (label);
+                       if (!(*i)->get_property (X_("uri"), uri) || !(*i)->get_property (X_("label"), label)) {
+                               assert (false);
+                       }
 
-                       PresetRecord r (uri->value(), label->value(), true);
+                       PresetRecord r (uri, label, true);
                        _presets.insert (make_pair (r.uri, r));
                }
        }
@@ -1260,7 +1248,9 @@ LuaPluginInfo::load (Session& session)
        }
 
        try {
-               PluginPtr plugin (new LuaProc (session.engine (), session, script));
+               LuaProc* lp = new LuaProc (session.engine (), session, script);
+               lp->set_origin (path);
+               PluginPtr plugin (lp);
                return plugin;
        } catch (failed_constructor& err) {
                ;