X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Flua_api.cc;h=890e268c59681a7468a0f536a6c1183e25349ad7;hb=cf52d6e4b40111eb04b244ec054055a4ec15dbe0;hp=a21dbfb3eaec7524fd340b5868b6e5d5aa4c9ba9;hpb=86b9f07d635cb288994f6d736a917d25f5764c2c;p=ardour.git diff --git a/libs/ardour/lua_api.cc b/libs/ardour/lua_api.cc index a21dbfb3ea..890e268c59 100644 --- a/libs/ardour/lua_api.cc +++ b/libs/ardour/lua_api.cc @@ -30,12 +30,43 @@ #include "LuaBridge/LuaBridge.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace ARDOUR; using namespace PBD; using namespace std; +int +ARDOUR::LuaAPI::datatype_ctor_null (lua_State *L) +{ + DataType dt (DataType::NIL); + luabridge::Stack ::push (L, dt); + return 1; +} + +int +ARDOUR::LuaAPI::datatype_ctor_audio (lua_State *L) +{ + DataType dt (DataType::AUDIO); + // NB luabridge will copy construct the object and manage lifetime. + luabridge::Stack ::push (L, dt); + return 1; +} + +int +ARDOUR::LuaAPI::datatype_ctor_midi (lua_State *L) +{ + DataType dt (DataType::MIDI); + luabridge::Stack ::push (L, dt); + return 1; +} + +boost::shared_ptr +ARDOUR::LuaAPI::nil_processor () +{ + return boost::shared_ptr (); +} + boost::shared_ptr ARDOUR::LuaAPI::new_luaproc (Session *s, const string& name) { @@ -75,6 +106,7 @@ ARDOUR::LuaAPI::new_plugin_info (const string& name, ARDOUR::PluginType type) PluginManager& manager = PluginManager::instance(); PluginInfoList all_plugs; all_plugs.insert(all_plugs.end(), manager.ladspa_plugin_info().begin(), manager.ladspa_plugin_info().end()); + all_plugs.insert(all_plugs.end(), manager.lua_plugin_info().begin(), manager.lua_plugin_info().end()); #ifdef WINDOWS_VST_SUPPORT all_plugs.insert(all_plugs.end(), manager.windows_vst_plugin_info().begin(), manager.windows_vst_plugin_info().end()); #endif @@ -152,6 +184,51 @@ ARDOUR::LuaAPI::set_processor_param (boost::shared_ptr proc, uint32_t return set_plugin_insert_param (pi, which, val); } +int +ARDOUR::LuaAPI::plugin_automation (lua_State *L) +{ + typedef boost::shared_ptr T; + + int top = lua_gettop(L); + if (top < 2) { + return luaL_argerror (L, 1, "invalid number of arguments, :plugin_automation (plugin, parameter_number)"); + } + T* const p = luabridge::Userdata::get(L, 1, false); + uint32_t which = luabridge::Stack::get (L, 2); + if (!p) { + return luaL_error (L, "Invalid pointer to Ardour:Processor"); + } + boost::shared_ptr pi = boost::dynamic_pointer_cast (*p); + if (!pi) { + return luaL_error (L, "Given Processor is not a Plugin Insert"); + } + boost::shared_ptr plugin = pi->plugin(); + if (!plugin) { + return luaL_error (L, "Given Processor is not a Plugin"); + } + + bool ok=false; + uint32_t controlid = plugin->nth_parameter (which, ok); + if (!ok) { + return luaL_error (L, "Invalid Parameter"); + } + if (!plugin->parameter_is_input (controlid)) { + return luaL_error (L, "Given Parameter is not an input"); + } + + ParameterDescriptor pd; + if (plugin->get_parameter_descriptor (controlid, pd) != 0) { + return luaL_error (L, "Cannot describe parameter"); + } + + boost::shared_ptr c = pi->automation_control (Evoral::Parameter(PluginAutomation, 0, controlid)); + + luabridge::Stack >::push (L, c->alist()); + luabridge::Stack >::push (L, c->list()); + luabridge::Stack::push (L, pd); + return 3; +} + int ARDOUR::LuaOSC::Address::send (lua_State *L) { @@ -227,3 +304,194 @@ ARDOUR::LuaOSC::Address::send (lua_State *L) luabridge::Stack::push (L, (rv == 0)); return 1; } + +static double hue2rgb (const double p, const double q, double t) { + if (t < 0.0) t += 1.0; + if (t > 1.0) t -= 1.0; + if (t < 1.0 / 6.0) return p + (q - p) * 6.0 * t; + if (t < 1.0 / 2.0) return q; + if (t < 2.0 / 3.0) return p + (q - p) * (2.0 / 3.0 - t) * 6.0; + return p; +} + +int +ARDOUR::LuaAPI::hsla_to_rgba (lua_State *L) +{ + int top = lua_gettop(L); + if (top < 3) { + return luaL_argerror (L, 1, "invalid number of arguments, :hsla_to_rgba (h, s, l [,a])"); + } + double h = luabridge::Stack::get (L, 1); + double s = luabridge::Stack::get (L, 2); + double l = luabridge::Stack::get (L, 3); + double a = 1.0; + if (top > 3) { + a = luabridge::Stack::get (L, 4); + } + + // we can't use ArdourCanvas::hsva_to_color here + // besides we want HSL not HSV and without intermediate + // color_to_rgba (rgba_to_color ()) + double r,g,b; + const double cq = l < 0.5 ? l * (1 + s) : l + s - l * s; + const double cp = 2.f * l - cq; + r = hue2rgb (cp, cq, h + 1.0 / 3.0); + g = hue2rgb (cp, cq, h); + b = hue2rgb (cp, cq, h - 1.0 / 3.0); + + luabridge::Stack::push (L, r); + luabridge::Stack::push (L, g); + luabridge::Stack::push (L, b); + luabridge::Stack::push (L, a); + return 4; +} + +luabridge::LuaRef::Proxy& +luabridge::LuaRef::Proxy::clone_instance (const void* classkey, void* p) { + lua_rawgeti (m_L, LUA_REGISTRYINDEX, m_tableRef); + lua_rawgeti (m_L, LUA_REGISTRYINDEX, m_keyRef); + + luabridge::UserdataPtr::push_raw (m_L, p, classkey); + + lua_rawset (m_L, -3); + lua_pop (m_L, 1); + return *this; +} + +LuaTableRef::LuaTableRef () {} +LuaTableRef::~LuaTableRef () {} + +int +LuaTableRef::get (lua_State* L) +{ + luabridge::LuaRef rv (luabridge::newTable (L)); + for (std::vector::const_iterator i = _data.begin (); i != _data.end (); ++i) { + switch ((*i).keytype) { + case LUA_TSTRING: + assign(&rv, i->k_s, *i); + break; + case LUA_TNUMBER: + assign(&rv, i->k_n, *i); + break; + } + } + luabridge::push (L, rv); + return 1; +} + +int +LuaTableRef::set (lua_State* L) +{ + if (!lua_istable (L, -1)) { return luaL_error (L, "argument is not a table"); } + _data.clear (); + + lua_pushvalue (L, -1); + lua_pushnil (L); + while (lua_next (L, -2)) { + lua_pushvalue (L, -2); + + LuaTableEntry s (lua_type(L, -1), lua_type(L, -2)); + switch (lua_type(L, -1)) { + case LUA_TSTRING: + s.k_s = luabridge::Stack::get (L, -1); + break; + ; + case LUA_TNUMBER: + s.k_n = luabridge::Stack::get (L, -1); + break; + default: + // invalid key + lua_pop (L, 2); + continue; + } + + switch(lua_type(L, -2)) { + case LUA_TSTRING: + s.s = luabridge::Stack::get (L, -2); + break; + case LUA_TBOOLEAN: + s.b = lua_toboolean (L, -2); + break; + case LUA_TNUMBER: + s.n = lua_tonumber (L, -2); + break; + case LUA_TUSERDATA: + { + bool ok = false; + lua_getmetatable (L, -2); + lua_rawgetp (L, -1, luabridge::getIdentityKey ()); + if (lua_isboolean (L, -1)) { + lua_pop (L, 1); + const void* key = lua_topointer (L, -1); + lua_pop (L, 1); + void const* classkey = findclasskey (L, key); + + if (classkey) { + ok = true; + s.c = classkey; + s.p = luabridge::Userdata::get_ptr (L, -2); + } + } else { + lua_pop (L, 2); + } + + if (ok) { + break; + } + // invalid userdata -- fall through + } + // no break + case LUA_TFUNCTION: // no support -- we could... string.format("%q", string.dump(value, true)) + case LUA_TTABLE: // no nested tables, sorry. + case LUA_TNIL: // fallthrough + default: + // invalid value + lua_pop (L, 2); + continue; + } + + _data.push_back(s); + lua_pop (L, 2); + } + return 0; +} + +void* +LuaTableRef::findclasskey (lua_State *L, const void* key) +{ + lua_pushvalue(L, LUA_REGISTRYINDEX); + lua_pushnil (L); + while (lua_next (L, -2)) { + lua_pushvalue (L, -2); + if (lua_topointer(L, -2) == key) { + void* rv = lua_touserdata (L, -1); + lua_pop (L, 4); + return rv; + } + lua_pop (L, 2); + } + lua_pop (L, 1); + return NULL; +} + +template +void LuaTableRef::assign (luabridge::LuaRef* rv, T key, const LuaTableEntry& s) +{ + switch (s.valuetype) { + case LUA_TSTRING: + (*rv)[key] = s.s; + break; + case LUA_TBOOLEAN: + (*rv)[key] = s.b; + break; + case LUA_TNUMBER: + (*rv)[key] = s.n; + break; + case LUA_TUSERDATA: + (*rv)[key].clone_instance (s.c, s.p); + break; + default: + assert (0); + break; + } +}