X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fluaproc.cc;h=75d957779d8f6402ca8deff04326a80e890e70f0;hb=4bdbe77414b956e27f2c1631e67189c70409a3d1;hp=a2d42491d50de182c62e41aca148683e78f05442;hpb=7840bb1b14dcf2501b2cd6adc3f2960397a115f7;p=ardour.git diff --git a/libs/ardour/luaproc.cc b/libs/ardour/luaproc.cc index a2d42491d5..75d957779d 100644 --- a/libs/ardour/luaproc.cc +++ b/libs/ardour/luaproc.cc @@ -18,12 +18,16 @@ */ #include +#include +#include + #include "pbd/gstdio_compat.h" #include "pbd/pthread_utils.h" #include "ardour/audio_buffer.h" #include "ardour/buffer_set.h" +#include "ardour/filesystem_paths.h" #include "ardour/luabindings.h" #include "ardour/luaproc.h" #include "ardour/luascripting.h" @@ -31,6 +35,8 @@ #include "ardour/plugin.h" #include "ardour/session.h" +#include "LuaBridge/LuaBridge.h" + #include "i18n.h" using namespace ARDOUR; @@ -40,11 +46,13 @@ LuaProc::LuaProc (AudioEngine& engine, Session& session, const std::string &script) : Plugin (engine, session) - , _mempool ("LuaProc", 1048576) // 1 MB is plenty. (64K would be enough) + , _mempool ("LuaProc", 2097152) , lua (lua_newstate (&PBD::ReallocPool::lalloc, &_mempool)) , _lua_dsp (0) , _script (script) , _lua_does_channelmapping (false) + , _lua_has_inline_display (false) + , _designated_bypass_port (UINT32_MAX) , _control_data (0) , _shadow_data (0) , _has_midi_input (false) @@ -62,11 +70,13 @@ LuaProc::LuaProc (AudioEngine& engine, LuaProc::LuaProc (const LuaProc &other) : Plugin (other) - , _mempool ("LuaProc", 1048576) // 1 MB is plenty. (64K would be enough) + , _mempool ("LuaProc", 2097152) , lua (lua_newstate (&PBD::ReallocPool::lalloc, &_mempool)) , _lua_dsp (0) , _script (other.script ()) , _lua_does_channelmapping (false) + , _lua_has_inline_display (false) + , _designated_bypass_port (UINT32_MAX) , _control_data (0) , _shadow_data (0) , _has_midi_input (false) @@ -110,9 +120,8 @@ LuaProc::init () _stats_avg[0] = _stats_avg[1] = _stats_max[0] = _stats_max[1] = _stats_cnt = 0; #endif -#ifndef NDEBUG + lua.tweak_rt_gc (); lua.Print.connect (sigc::mem_fun (*this, &LuaProc::lua_print)); -#endif // register session object lua_State* L = lua.getState (); LuaBindings::stddef (L); @@ -124,6 +133,7 @@ LuaProc::init () .beginClass ("LuaProc") .addFunction ("queue_draw", &LuaProc::queue_draw) .addFunction ("shmem", &LuaProc::instance_shm) + .addFunction ("table", &LuaProc::instance_ref) .endClass () .endNamespace (); @@ -146,12 +156,14 @@ LuaProc::init () void LuaProc::lua_print (std::string s) { std::cout <<"LuaProc: " << s << "\n"; + PBD::error << "LuaProc: " << s << "\n"; } bool LuaProc::load_script () { assert (!_lua_dsp); // don't allow to re-initialize + LuaPluginInfoPtr lpi; // TODO: refine APIs; function arguments.. // - perform channel-map in ardour (silent/scratch buffers) ? @@ -163,7 +175,7 @@ LuaProc::load_script () try { LuaScriptInfoPtr lsi = LuaScripting::script_info (_script); - LuaPluginInfoPtr lpi (new LuaPluginInfo (lsi)); + lpi = LuaPluginInfoPtr (new LuaPluginInfo (lsi)); assert (lpi); set_info (lpi); _mempool.set_name ("LuaProc: " + lsi->name); @@ -204,10 +216,20 @@ LuaProc::load_script () } } - luabridge::LuaRef lua_dsp_midi_in = luabridge::getGlobal (L, "dsp_midi_input"); - if (lua_dsp_midi_in.type () == LUA_TFUNCTION) { + // 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_midi_in (); + _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) { ; } @@ -266,6 +288,10 @@ LuaProc::load_script () _param_desc[pn].sr_dependent = lr["ratemult"].isBoolean () && (lr["ratemult"]).cast (); _param_desc[pn].enumeration = lr["enum"].isBoolean () && (lr["enum"]).cast (); + if (lr["bypass"].isBoolean () && (lr["bypass"]).cast ()) { + _designated_bypass_port = pn - 1; // lua table starts at 1. + } + if (lr["unit"].isString ()) { std::string unit = lr["unit"].cast (); if (unit == "dB") { _param_desc[pn].unit = ParameterDescriptor::DB; } @@ -303,9 +329,12 @@ LuaProc::load_script () } bool -LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out) +LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out, ChanCount* imprecise) { - if (in.n_midi() > 0 && !_has_midi_input) { + // caller must hold process lock (no concurrent calls to interpreter + _output_configs.clear (); + + if (in.n_midi() > 0 && !_has_midi_input && !imprecise) { return false; } @@ -315,14 +344,9 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out) return false; } - luabridge::LuaRef table = luabridge::getGlobal (L, "table"); //lua std lib - luabridge::LuaRef tablesort = table["sort"]; - assert (tablesort.isFunction ()); - luabridge::LuaRef *_iotable = NULL; // can't use reference :( try { luabridge::LuaRef iotable = ioconfig (); - tablesort (iotable); if (iotable.isTable ()) { _iotable = new luabridge::LuaRef (iotable); } @@ -342,14 +366,14 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out) return false; } - int32_t audio_in = in.n_audio (); - int32_t audio_out; + bool found = false; + bool exact_match = false; + const int32_t audio_in = in.n_audio (); + int32_t midi_out = _has_midi_output ? 1 : 0; - if (in.n_midi() > 0 && audio_in == 0) { - audio_out = 2; // prefer stereo version if available. - } else { - audio_out = audio_in; - } + // preferred setting (provided by plugin_insert) + assert (out.n_audio () > 0 || midi_out > 0); + const int preferred_out = out.n_audio (); for (luabridge::Iterator i (iotable); !i.isNil (); ++i) { assert (i.value ().type () == LUA_TTABLE); @@ -359,16 +383,37 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out) int possible_out = io["audio_out"]; // exact match - if ((possible_in == audio_in) && (possible_out == audio_out)) { - out.set (DataType::MIDI, 0); - out.set (DataType::AUDIO, audio_out); - return true; + if ((possible_in == audio_in) && (possible_out == preferred_out)) { + _output_configs.insert (preferred_out); + exact_match = true; + found = true; + break; } } /* now allow potentially "imprecise" matches */ - audio_out = -1; - bool found = false; + int32_t audio_out = -1; + float penalty = 9999; + +#define FOUNDCFG(nch) { \ + float p = fabsf ((float)(nch) - preferred_out); \ + _output_configs.insert (nch); \ + if ((nch) > preferred_out) { p *= 1.1; } \ + if (p < penalty) { \ + audio_out = (nch); \ + penalty = p; \ + found = true; \ + } \ +} + +#define ANYTHINGGOES \ + _output_configs.insert (0); + +#define UPTO(nch) { \ + for (int n = 1; n < nch; ++n) { \ + _output_configs.insert (n); \ + } \ +} for (luabridge::Iterator i (iotable); !i.isNil (); ++i) { assert (i.value ().type () == LUA_TTABLE); @@ -378,118 +423,160 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out) int possible_out = io["audio_out"]; if (possible_out == 0) { + if (possible_in == 0) { + if (_has_midi_output && audio_in == 0) { + // special case midi filters & generators + audio_out = 0; + found = true; + break; + } + } continue; } + if (possible_in == 0) { /* no inputs, generators & instruments */ if (possible_out == -1) { - /* any configuration possible, provide stereo output */ - audio_out = 2; - found = true; + /* any configuration possible, stereo output */ + FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out == -2) { /* invalid, should be (0, -1) */ - audio_out = 2; - found = true; + FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out < -2) { - /* variable number of outputs. -> whatever */ - audio_out = 2; - found = true; + /* variable number of outputs up to -N, */ + FOUNDCFG (min (-possible_out, preferred_out)); + UPTO (-possible_out); } else { /* exact number of outputs */ - audio_out = possible_out; - found = true; + FOUNDCFG (possible_out); } } if (possible_in == -1) { /* wildcard for input */ if (possible_out == -1) { - /* out much match in */ - audio_out = audio_in; - found = true; + /* out must match in */ + FOUNDCFG (audio_in); } else if (possible_out == -2) { /* any configuration possible, pick matching */ - audio_out = audio_in; - found = true; + FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out < -2) { /* explicitly variable number of outputs, pick maximum */ - audio_out = -possible_out; - found = true; + FOUNDCFG (max (-possible_out, preferred_out)); + /* and try min, too, in case the penalty is lower */ + FOUNDCFG (min (-possible_out, preferred_out)); + UPTO (-possible_out) } else { /* exact number of outputs */ - audio_out = possible_out; - found = true; + FOUNDCFG (possible_out); } } if (possible_in == -2) { - if (possible_out == -1) { /* any configuration possible, pick matching */ - audio_out = audio_in; - found = true; + FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out == -2) { /* invalid. interpret as (-1, -1) */ - audio_out = audio_in; - found = true; + FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out < -2) { - /* explicitly variable number of outputs, pick maximum */ - audio_out = -possible_out; - found = true; + /* invalid, interpret as (<-2, <-2) + * variable number of outputs up to -N, */ + FOUNDCFG (min (-possible_out, preferred_out)); + UPTO (-possible_out) } else { /* exact number of outputs */ - audio_out = possible_out; - found = true; + FOUNDCFG (possible_out); } } if (possible_in < -2) { /* explicit variable number of inputs */ - if (audio_in > -possible_in) { - /* request is too large */ + if (audio_in > -possible_in && imprecise != NULL) { + // hide inputs ports + imprecise->set (DataType::AUDIO, -possible_in); } - if (possible_out == -1) { - /* any output configuration possible, provide stereo out */ - audio_out = 2; - found = true; + + if (audio_in > -possible_in && imprecise == NULL) { + /* request is too large */ + } else if (possible_out == -1) { + /* any output configuration possible */ + FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out == -2) { /* invalid. interpret as (<-2, -1) */ - audio_out = 2; - found = true; + FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out < -2) { - /* explicitly variable number of outputs, pick stereo */ - audio_out = 2; - found = true; + /* variable number of outputs up to -N, */ + FOUNDCFG (min (-possible_out, preferred_out)); + UPTO (-possible_out) } else { /* exact number of outputs */ - audio_out = possible_out; - found = true; + FOUNDCFG (possible_out); } } if (possible_in && (possible_in == audio_in)) { /* exact number of inputs ... must match obviously */ if (possible_out == -1) { - /* any output configuration possible, provide stereo output */ - audio_out = 2; - found = true; + /* any output configuration possible */ + FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out == -2) { /* invalid. interpret as (>0, -1) */ - audio_out = 2; - found = true; + FOUNDCFG (preferred_out); + ANYTHINGGOES; } else if (possible_out < -2) { - /* explicitly variable number of outputs, pick maximum */ - audio_out = -possible_out; - found = true; + /* > 0, < -2 is not specified + * interpret as up to -N */ + FOUNDCFG (min (-possible_out, preferred_out)); + UPTO (-possible_out) } else { /* exact number of outputs */ - audio_out = possible_out; - found = true; + FOUNDCFG (possible_out); } } + } - if (found) { - break; + if (!found && imprecise) { + /* try harder */ + for (luabridge::Iterator i (iotable); !i.isNil (); ++i) { + assert (i.value ().type () == LUA_TTABLE); + luabridge::LuaRef io (i.value ()); + + int possible_in = io["audio_in"]; + int possible_out = io["audio_out"]; + + if (possible_out == 0 && possible_in == 0 && _has_midi_output) { + assert (audio_in > 0); // no input is handled above + // TODO hide audio input from plugin + imprecise->set (DataType::AUDIO, 0); + audio_out = 0; + found = true; + continue; + } + + assert (possible_in > 0); // all other cases will have been matched above + assert (possible_out !=0 || possible_in !=0); // already handled above + + imprecise->set (DataType::AUDIO, possible_in); + if (possible_out == -1 || possible_out == -2) { + FOUNDCFG (2); + } else if (possible_out < -2) { + /* explicitly variable number of outputs, pick maximum */ + FOUNDCFG (min (-possible_out, preferred_out)); + } else { + /* exact number of outputs */ + FOUNDCFG (possible_out); + } + // ideally we'll also find the closest, best matching + // input configuration with minimal output penalty... } } @@ -497,31 +584,42 @@ LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out) return false; } - out.set (DataType::MIDI, 0); - out.set (DataType::AUDIO, audio_out); + if (exact_match) { + out.set (DataType::MIDI, midi_out); + out.set (DataType::AUDIO, preferred_out); + } else { + out.set (DataType::MIDI, midi_out); + out.set (DataType::AUDIO, audio_out); + } return true; } bool LuaProc::configure_io (ChanCount in, ChanCount out) { - _configured_in = in; - _configured_out = out; - - _configured_in.set (DataType::MIDI, _has_midi_input ? 1 : 0); - _configured_out.set (DataType::MIDI, _has_midi_output ? 1 : 0); + in.set (DataType::MIDI, _has_midi_input ? 1 : 0); + out.set (DataType::MIDI, _has_midi_output ? 1 : 0); // configure the DSP if needed - lua_State* L = lua.getState (); - luabridge::LuaRef lua_dsp_configure = luabridge::getGlobal (L, "dsp_configure"); - if (lua_dsp_configure.type () == LUA_TFUNCTION) { - try { - lua_dsp_configure (&in, &out); - } catch (luabridge::LuaException const& e) { - ; + if (in != _configured_in || out != _configured_out) { + lua_State* L = lua.getState (); + luabridge::LuaRef lua_dsp_configure = luabridge::getGlobal (L, "dsp_configure"); + if (lua_dsp_configure.type () == LUA_TFUNCTION) { + try { + lua_dsp_configure (&in, &out); + } catch (luabridge::LuaException const& e) { + PBD::error << "LuaException: " << e.what () << "\n"; +#ifndef NDEBUG + std::cerr << "LuaException: " << e.what () << "\n"; +#endif + return false; + } } } + _configured_in = in; + _configured_out = out; + _info->n_inputs = _configured_in; _info->n_outputs = _configured_out; return true; @@ -529,6 +627,7 @@ LuaProc::configure_io (ChanCount in, ChanCount out) int LuaProc::connect_and_run (BufferSet& bufs, + framepos_t start, framepos_t end, double speed, ChanMapping in, ChanMapping out, pframes_t nframes, framecnt_t offset) { @@ -536,7 +635,7 @@ LuaProc::connect_and_run (BufferSet& bufs, return 0; } - Plugin::connect_and_run (bufs, in, out, nframes, offset); + Plugin::connect_and_run (bufs, start, end, speed, in, out, nframes, offset); // This is needed for ARDOUR::Session requests :( if (! SessionEvent::has_per_thread_pool ()) { @@ -594,7 +693,7 @@ LuaProc::connect_and_run (BufferSet& bufs, } } - luabridge::LuaRef lua_midi_tbl (luabridge::newTable (L)); + luabridge::LuaRef lua_midi_src_tbl (luabridge::newTable (L)); int e = 1; // > 1 port, we merge events (unsorted) for (uint32_t mp = 0; mp < midi_in; ++mp) { bool valid; @@ -611,31 +710,65 @@ 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_tbl[e] = lua_midi_event; + lua_midi_src_tbl[e] = lua_midi_event; } } } if (_has_midi_input) { // XXX TODO This needs a better solution than global namespace - luabridge::push (L, lua_midi_tbl); - lua_setglobal (L, "mididata"); + luabridge::push (L, lua_midi_src_tbl); + lua_setglobal (L, "midiin"); } + luabridge::LuaRef lua_midi_sink_tbl (luabridge::newTable (L)); + if (_has_midi_output) { + luabridge::push (L, lua_midi_sink_tbl); + lua_setglobal (L, "midiout"); + } // run the DSP function (*_lua_dsp)(in_map, out_map, nframes); + + // copy back midi events + if (_has_midi_output && lua_midi_sink_tbl.isTable ()) { + bool valid; + const uint32_t idx = out.get(DataType::MIDI, 0, &valid); + if (valid && bufs.count().n_midi() > idx) { + MidiBuffer& mbuf = bufs.get_midi(idx); + mbuf.silence(0, 0); + for (luabridge::Iterator i (lua_midi_sink_tbl); !i.isNil (); ++i) { + if (!i.key ().isNumber ()) { continue; } + if (!i.value ()["time"].isNumber ()) { continue; } + if (!i.value ()["data"].isTable ()) { continue; } + luabridge::LuaRef data_tbl (i.value ()["data"]); + framepos_t tme = i.value ()["time"]; + if (tme < 1 || tme > nframes) { continue; } + uint8_t data[64]; + size_t size = 0; + for (luabridge::Iterator di (data_tbl); !di.isNil () && size < sizeof(data); ++di, ++size) { + data[size] = di.value (); + } + if (size > 0 && size < 64) { + mbuf.push_back(tme - 1, size, data); + } + } + + } + } } } catch (luabridge::LuaException const& e) { + PBD::error << "LuaException: " << e.what () << "\n"; #ifndef NDEBUG - printf ("LuaException: %s\n", e.what ()); + std::cerr << "LuaException: " << e.what () << "\n"; #endif return -1; } #ifdef WITH_LUAPROC_STATS int64_t t1 = g_get_monotonic_time (); #endif - lua.collect_garbage (); // rt-safe, slight *regular* performance overhead + + lua.collect_garbage_step (); #ifdef WITH_LUAPROC_STATS ++_stats_cnt; int64_t t2 = g_get_monotonic_time (); @@ -655,7 +788,7 @@ LuaProc::add_state (XMLNode* root) const { XMLNode* child; char buf[32]; - LocaleGuard lg(X_("C")); + LocaleGuard lg; gchar* b64 = g_base64_encode ((const guchar*)_script.c_str (), _script.size ()); std::string b64s (b64); @@ -718,14 +851,14 @@ LuaProc::set_state (const XMLNode& node, int version) { #ifndef NO_PLUGIN_STATE XMLNodeList nodes; - XMLProperty *prop; + XMLProperty const * prop; XMLNodeConstIterator iter; XMLNode *child; const char *value; const char *port; uint32_t port_id; #endif - LocaleGuard lg (X_("C")); + LocaleGuard lg; if (_script.empty ()) { if (set_script_from_state (node)) { @@ -929,10 +1062,7 @@ LuaProc::setup_lua_inline_gui (LuaState *lua_gui) LuaBindings::common (LG); LuaBindings::dsp (LG); -#ifndef NDEBUG lua_gui->Print.connect (sigc::mem_fun (*this, &LuaProc::lua_print)); -#endif - lua_gui->do_command ("function ardour () end"); lua_gui->do_command (_script); @@ -942,6 +1072,7 @@ LuaProc::setup_lua_inline_gui (LuaState *lua_gui) .beginNamespace ("Ardour") .beginClass ("LuaProc") .addFunction ("shmem", &LuaProc::instance_shm) + .addFunction ("table", &LuaProc::instance_ref) .endClass () .endNamespace (); @@ -951,10 +1082,152 @@ LuaProc::setup_lua_inline_gui (LuaState *lua_gui) luabridge::push (LG, _shadow_data); lua_setglobal (LG, "CtrlPorts"); } +//////////////////////////////////////////////////////////////////////////////// + +#include "ardour/search_paths.h" +#include "sha1.c" + +std::string +LuaProc::preset_name_to_uri (const std::string& name) const +{ + std::string uri ("urn:lua:"); + char hash[41]; + Sha1Digest s; + sha1_init (&s); + sha1_write (&s, (const uint8_t *) name.c_str(), name.size ()); + sha1_write (&s, (const uint8_t *) _script.c_str(), _script.size ()); + sha1_result_hash (&s, hash); + return uri + hash; +} + +std::string +LuaProc::presets_file () const +{ + return string_compose ("lua-%1", _info->unique_id); +} + +XMLTree* +LuaProc::presets_tree () const +{ + XMLTree* t = new XMLTree; + std::string p = Glib::build_filename (ARDOUR::user_config_directory (), "presets"); + + if (!Glib::file_test (p, Glib::FILE_TEST_IS_DIR)) { + if (g_mkdir_with_parents (p.c_str(), 0755) != 0) { + error << _("Unable to create LuaProc presets directory") << endmsg; + }; + } + + p = Glib::build_filename (p, presets_file ()); + + if (!Glib::file_test (p, Glib::FILE_TEST_EXISTS)) { + t->set_root (new XMLNode (X_("LuaPresets"))); + return t; + } + + t->set_filename (p); + if (!t->read ()) { + delete t; + return 0; + } + return t; +} + +bool +LuaProc::load_preset (PresetRecord r) +{ + boost::shared_ptr t (presets_tree ()); + if (t == 0) { + return false; + } + + 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) { + 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); + set_parameter (atoi (index->value().c_str()), atof (value->value().c_str ())); + } + } + return true; + } + return false; +} + +std::string +LuaProc::do_save_preset (std::string name) { + + boost::shared_ptr t (presets_tree ()); + if (t == 0) { + return ""; + } + + 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); + + 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))); + p->add_child_nocopy (*c); + } + } + t->root()->add_child_nocopy (*p); + + std::string f = Glib::build_filename (ARDOUR::user_config_directory (), "presets"); + f = Glib::build_filename (f, presets_file ()); + + t->write (f); + return uri; +} + +void +LuaProc::do_remove_preset (std::string name) +{ + boost::shared_ptr t (presets_tree ()); + if (t == 0) { + return; + } + t->root()->remove_nodes_and_delete (X_("label"), name); + std::string f = Glib::build_filename (ARDOUR::user_config_directory (), "presets"); + f = Glib::build_filename (f, presets_file ()); + t->write (f); +} + +void +LuaProc::find_presets () +{ + boost::shared_ptr t (presets_tree ()); + if (t) { + XMLNode* root = t->root (); + for (XMLNodeList::const_iterator i = root->children().begin(); i != root->children().end(); ++i) { + + XMLProperty const * uri = (*i)->property (X_("uri")); + XMLProperty const * label = (*i)->property (X_("label")); + + assert (uri); + assert (label); + + PresetRecord r (uri->value(), label->value(), true); + _presets.insert (make_pair (r.uri, r)); + } + } +} //////////////////////////////////////////////////////////////////////////////// -#include -#include LuaPluginInfo::LuaPluginInfo (LuaScriptInfoPtr lsi) { if (lsi->type != LuaScriptInfo::DSP) { @@ -965,11 +1238,13 @@ LuaPluginInfo::LuaPluginInfo (LuaScriptInfoPtr lsi) { name = lsi->name; creator = lsi->author; category = lsi->category; - unique_id = "luascript"; // the interpreter is not unique. + unique_id = lsi->unique_id; n_inputs.set (DataType::AUDIO, 1); n_outputs.set (DataType::AUDIO, 1); type = Lua; + + _is_instrument = category == "Instrument"; } PluginPtr @@ -1003,5 +1278,19 @@ std::vector LuaPluginInfo::get_presets (bool /*user_only*/) const { std::vector p; + XMLTree* t = new XMLTree; + std::string pf = Glib::build_filename (ARDOUR::user_config_directory (), "presets", string_compose ("lua-%1", unique_id)); + if (Glib::file_test (pf, Glib::FILE_TEST_EXISTS)) { + t->set_filename (pf); + if (t->read ()) { + XMLNode* root = t->root (); + for (XMLNodeList::const_iterator i = root->children().begin(); i != root->children().end(); ++i) { + XMLProperty const * uri = (*i)->property (X_("uri")); + XMLProperty const * label = (*i)->property (X_("label")); + p.push_back (Plugin::PresetRecord (uri->value(), label->value(), true)); + } + } + } + delete t; return p; }