8a0653dedb8b51f1a4cd1f235739feb8bb302440
[ardour.git] / libs / ardour / luaproc.cc
1 /*
2     Copyright (C) 2016 Robin Gareus <robin@gareus.org>
3     Copyright (C) 2006 Paul Davis
4
5     This program is free software; you can redistribute it and/or modify it
6     under the terms of the GNU General Public License as published by the Free
7     Software Foundation; either version 2 of the License, or (at your option)
8     any later version.
9
10     This program is distributed in the hope that it will be useful, but WITHOUT
11     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13     for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <glib.h>
21 #include "pbd/gstdio_compat.h"
22
23 #include "pbd/pthread_utils.h"
24
25 #include "ardour/audio_buffer.h"
26 #include "ardour/buffer_set.h"
27 #include "ardour/luabindings.h"
28 #include "ardour/luaproc.h"
29 #include "ardour/luascripting.h"
30 #include "ardour/midi_buffer.h"
31 #include "ardour/plugin.h"
32 #include "ardour/session.h"
33
34 #include "i18n.h"
35
36 using namespace ARDOUR;
37 using namespace PBD;
38
39 LuaProc::LuaProc (AudioEngine& engine,
40                   Session& session,
41                   const std::string &script)
42         : Plugin (engine, session)
43         , _mempool ("LuaProc", 1048576) // 1 MB is plenty. (64K would be enough)
44         , lua (lua_newstate (&PBD::ReallocPool::lalloc, &_mempool))
45         , _lua_dsp (0)
46         , _lua_params (0)
47         , _script (script)
48         , _lua_does_channelmapping (false)
49         , _control_data (0)
50         , _shadow_data (0)
51         , _has_midi_input (false)
52         , _has_midi_output (false)
53 {
54         init ();
55
56         /* when loading a session, or pasing a processor,
57          * the script is set during set_state();
58          */
59         if (!_script.empty () && load_script ()) {
60                 throw failed_constructor ();
61         }
62 }
63
64 LuaProc::LuaProc (const LuaProc &other)
65         : Plugin (other)
66         , _mempool ("LuaProc", 1048576) // 1 MB is plenty. (64K would be enough)
67         , lua (lua_newstate (&PBD::ReallocPool::lalloc, &_mempool))
68         , _lua_dsp (0)
69         , _lua_params (0)
70         , _script (other.script ())
71         , _lua_does_channelmapping (false)
72         , _control_data (0)
73         , _shadow_data (0)
74         , _has_midi_input (false)
75         , _has_midi_output (false)
76 {
77         init ();
78
79         if (load_script ()) {
80                 throw failed_constructor ();
81         }
82
83         for (uint32_t i = 0; i < parameter_count (); ++i) {
84                 _control_data[i] = other._shadow_data[i];
85                 _shadow_data[i]  = other._shadow_data[i];
86         }
87 }
88
89 LuaProc::~LuaProc () {
90 #ifdef WITH_LUAPROC_STATS
91         if (_info && _stats_cnt > 0) {
92                 printf ("LuaProc: '%s' run()  avg: %.3f  max: %.3f [ms]\n",
93                                 _info->name.c_str (),
94                                 0.0001f * _stats_avg[0] / (float) _stats_cnt,
95                                 0.0001f * _stats_max[0]);
96                 printf ("LuaProc: '%s' gc()   avg: %.3f  max: %.3f [ms]\n",
97                                 _info->name.c_str (),
98                                 0.0001f * _stats_avg[1] / (float) _stats_cnt,
99                                 0.0001f * _stats_max[1]);
100         }
101 #endif
102         lua.do_command ("collectgarbage();");
103         delete (_lua_dsp);
104         delete (_lua_params);
105         delete [] _control_data;
106         delete [] _shadow_data;
107 }
108
109 void
110 LuaProc::init ()
111 {
112 #ifdef WITH_LUAPROC_STATS
113         _stats_avg[0] = _stats_avg[1] = _stats_max[0] = _stats_max[1] = _stats_cnt = 0;
114 #endif
115
116 #ifndef NDEBUG
117         lua.Print.connect (sigc::mem_fun (*this, &LuaProc::lua_print));
118 #endif
119         // register session object
120         lua_State* L = lua.getState ();
121         LuaBindings::stddef (L);
122         LuaBindings::common (L);
123         LuaBindings::dsp (L);
124
125         luabridge::getGlobalNamespace (L)
126                 .beginNamespace ("Ardour")
127                 .beginClass <LuaProc> ("LuaProc")
128                 .addFunction ("queue_draw", &LuaProc::queue_draw)
129                 .addFunction ("shmem", &LuaProc::instance_shm)
130                 .endClass ()
131                 .endNamespace ();
132
133         // add session to global lua namespace
134         luabridge::push <Session *> (L, &_session);
135         lua_setglobal (L, "Session");
136
137         // instance
138         luabridge::push <LuaProc *> (L, this);
139         lua_setglobal (L, "self");
140
141         // sandbox
142         lua.do_command ("io = nil os = nil loadfile = nil require = nil dofile = nil package = nil debug = nil");
143 #if 0
144         lua.do_command ("for n in pairs(_G) do print(n) end print ('----')"); // print global env
145 #endif
146         lua.do_command ("function ardour () end");
147 }
148
149 void
150 LuaProc::lua_print (std::string s) {
151         std::cout <<"LuaProc: " << s << "\n";
152 }
153
154 bool
155 LuaProc::load_script ()
156 {
157         assert (!_lua_dsp); // don't allow to re-initialize
158
159         // TODO: refine APIs; function arguments..
160         // - perform channel-map in ardour (silent/scratch buffers) ?
161         // - control-port API (explicit get/set functions ??)
162         // - latency reporting (global var? ctrl-port? set-function ?)
163         // - MIDI -> sparse table of events
164         //     { [sample] => { Event }, .. }
165         //   or  { { sample, Event }, .. }
166
167         try {
168                 LuaScriptInfoPtr lsi = LuaScripting::script_info (_script);
169                 LuaPluginInfoPtr lpi (new LuaPluginInfo (lsi));
170                 assert (lpi);
171                 set_info (lpi);
172                 _mempool.set_name ("LuaProc: " + lsi->name);
173                 _docs = lsi->description;
174         } catch (failed_constructor& err) {
175                 return true;
176         }
177
178         lua_State* L = lua.getState ();
179         lua.do_command (_script);
180
181         // check if script has a DSP callback
182         luabridge::LuaRef lua_dsp_run = luabridge::getGlobal (L, "dsp_run");
183         luabridge::LuaRef lua_dsp_map = luabridge::getGlobal (L, "dsp_runmap");
184
185         if ((lua_dsp_run.type () != LUA_TFUNCTION) == (lua_dsp_map.type () != LUA_TFUNCTION)) {
186                 return true;
187         }
188
189         if (lua_dsp_run.type () == LUA_TFUNCTION) {
190                 _lua_dsp = new luabridge::LuaRef (lua_dsp_run);
191         }
192         else if (lua_dsp_map.type () == LUA_TFUNCTION) {
193                 _lua_dsp = new luabridge::LuaRef (lua_dsp_map);
194                 _lua_does_channelmapping = true;
195         }
196         else {
197                 assert (0);
198         }
199
200         // initialize the DSP if needed
201         luabridge::LuaRef lua_dsp_init = luabridge::getGlobal (L, "dsp_init");
202         if (lua_dsp_init.type () == LUA_TFUNCTION) {
203                 try {
204                         lua_dsp_init (_session.nominal_frame_rate ());
205                 } catch (luabridge::LuaException const& e) {
206                         ;
207                 }
208         }
209
210         luabridge::LuaRef lua_dsp_midi_in = luabridge::getGlobal (L, "dsp_midi_input");
211         if (lua_dsp_midi_in.type () == LUA_TFUNCTION) {
212                 try {
213                         _has_midi_input = lua_dsp_midi_in ();
214                 } catch (luabridge::LuaException const& e) {
215                         ;
216                 }
217         }
218
219         _ctrl_params.clear ();
220
221         luabridge::LuaRef lua_render = luabridge::getGlobal (L, "render_inline");
222         if (lua_render.isFunction ()) {
223                 _lua_has_inline_display = true;
224         }
225
226         luabridge::LuaRef lua_params = luabridge::getGlobal (L, "dsp_params");
227         if (lua_params.isFunction ()) {
228
229                 // call function // add try {} catch (luabridge::LuaException const& e)
230                 luabridge::LuaRef params = lua_params ();
231
232                 if (params.isTable ()) {
233
234                         _lua_params = new luabridge::LuaRef (params);
235
236                         for (luabridge::Iterator i (params); !i.isNil (); ++i) {
237                                 // required fields
238                                 if (!i.key ().isNumber ())           { return false; }
239                                 if (!i.value ().isTable ())          { return false; }
240                                 if (!i.value ()["type"].isString ()) { return false; }
241                                 if (!i.value ()["name"].isString ()) { return false; }
242                                 if (!i.value ()["min"].isNumber ())  { return false; }
243                                 if (!i.value ()["max"].isNumber ())  { return false; }
244
245                                 std::string type = i.value ()["type"].cast<std::string> ();
246                                 if (type == "input") {
247                                         if (!i.value ()["default"].isNumber ()) { return false; }
248                                         _ctrl_params.push_back (std::make_pair (false, i.key ().cast<int> ()));
249                                 }
250                                 else if (type == "output") {
251                                         _ctrl_params.push_back (std::make_pair (true, i.key ().cast<int> ()));
252                                 } else {
253                                         return false;
254                                 }
255                                 assert (i.key ().cast<int> () == (int) _ctrl_params.size ());
256                         }
257                 }
258         }
259
260         _control_data = new float[parameter_count ()];
261         _shadow_data  = new float[parameter_count ()];
262
263         for (uint32_t i = 0; i < parameter_count (); ++i) {
264                 if (parameter_is_input (i)) {
265                         _control_data[i] = _shadow_data[i] = default_value (i);
266                 }
267         }
268
269         // expose ctrl-ports to global lua namespace
270         luabridge::push <float *> (L, _control_data);
271         lua_setglobal (L, "CtrlPorts");
272
273         return false; // no error
274 }
275
276 bool
277 LuaProc::can_support_io_configuration (const ChanCount& in, ChanCount& out)
278 {
279         if (in.n_midi() > 0 && !_has_midi_input) {
280                 return false;
281         }
282
283         lua_State* L = lua.getState ();
284         luabridge::LuaRef ioconfig = luabridge::getGlobal (L, "dsp_ioconfig");
285         if (!ioconfig.isFunction ()) {
286                 return false;
287         }
288
289         luabridge::LuaRef table = luabridge::getGlobal (L, "table"); //lua std lib
290         luabridge::LuaRef tablesort = table["sort"];
291         assert (tablesort.isFunction ());
292
293         luabridge::LuaRef *_iotable = NULL; // can't use reference :(
294         try {
295                 luabridge::LuaRef iotable = ioconfig ();
296                 tablesort (iotable);
297                 if (iotable.isTable ()) {
298                         _iotable = new luabridge::LuaRef (iotable);
299                 }
300         } catch (luabridge::LuaException const& e) {
301                 return false;
302         }
303
304         if (!_iotable) {
305                 return false;
306         }
307
308         // now we can reference it.
309         luabridge::LuaRef iotable (*_iotable);
310         delete _iotable;
311
312         if ((iotable).length () < 1) {
313                 return false;
314         }
315
316         int32_t audio_in = in.n_audio ();
317         int32_t audio_out;
318
319         if (in.n_midi() > 0 && audio_in == 0) {
320                 audio_out = 2; // prefer stereo version if available.
321         } else {
322                 audio_out = audio_in;
323         }
324
325         for (luabridge::Iterator i (iotable); !i.isNil (); ++i) {
326                 assert (i.value ().type () == LUA_TTABLE);
327                 luabridge::LuaRef io (i.value ());
328
329                 int possible_in = io["audio_in"];
330                 int possible_out = io["audio_out"];
331
332                 // exact match
333                 if ((possible_in == audio_in) && (possible_out == audio_out)) {
334                         out.set (DataType::MIDI, 0);
335                         out.set (DataType::AUDIO, audio_out);
336                         return true;
337                 }
338         }
339
340         /* now allow potentially "imprecise" matches */
341         audio_out = -1;
342         bool found = false;
343
344         for (luabridge::Iterator i (iotable); !i.isNil (); ++i) {
345                 assert (i.value ().type () == LUA_TTABLE);
346                 luabridge::LuaRef io (i.value ());
347
348                 int possible_in = io["audio_in"];
349                 int possible_out = io["audio_out"];
350
351                 if (possible_out == 0) {
352                         continue;
353                 }
354                 if (possible_in == 0) {
355                         /* no inputs, generators & instruments */
356                         if (possible_out == -1) {
357                                 /* any configuration possible, provide stereo output */
358                                 audio_out = 2;
359                                 found = true;
360                         } else if (possible_out == -2) {
361                                 /* invalid, should be (0, -1) */
362                                 audio_out = 2;
363                                 found = true;
364                         } else if (possible_out < -2) {
365                                 /* variable number of outputs. -> whatever */
366                                 audio_out = 2;
367                                 found = true;
368                         } else {
369                                 /* exact number of outputs */
370                                 audio_out = possible_out;
371                                 found = true;
372                         }
373                 }
374
375                 if (possible_in == -1) {
376                         /* wildcard for input */
377                         if (possible_out == -1) {
378                                 /* out much match in */
379                                 audio_out = audio_in;
380                                 found = true;
381                         } else if (possible_out == -2) {
382                                 /* any configuration possible, pick matching */
383                                 audio_out = audio_in;
384                                 found = true;
385                         } else if (possible_out < -2) {
386                                 /* explicitly variable number of outputs, pick maximum */
387                                 audio_out = -possible_out;
388                                 found = true;
389                         } else {
390                                 /* exact number of outputs */
391                                 audio_out = possible_out;
392                                 found = true;
393                         }
394                 }
395
396                 if (possible_in == -2) {
397
398                         if (possible_out == -1) {
399                                 /* any configuration possible, pick matching */
400                                 audio_out = audio_in;
401                                 found = true;
402                         } else if (possible_out == -2) {
403                                 /* invalid. interpret as (-1, -1) */
404                                 audio_out = audio_in;
405                                 found = true;
406                         } else if (possible_out < -2) {
407                                 /* explicitly variable number of outputs, pick maximum */
408                                 audio_out = -possible_out;
409                                 found = true;
410                         } else {
411                                 /* exact number of outputs */
412                                 audio_out = possible_out;
413                                 found = true;
414                         }
415                 }
416
417                 if (possible_in < -2) {
418                         /* explicit variable number of inputs */
419                         if (audio_in > -possible_in) {
420                                 /* request is too large */
421                         }
422                         if (possible_out == -1) {
423                                 /* any output configuration possible, provide stereo out */
424                                 audio_out = 2;
425                                 found = true;
426                         } else if (possible_out == -2) {
427                                 /* invalid. interpret as (<-2, -1) */
428                                 audio_out = 2;
429                                 found = true;
430                         } else if (possible_out < -2) {
431                                 /* explicitly variable number of outputs, pick stereo */
432                                 audio_out = 2;
433                                 found = true;
434                         } else {
435                                 /* exact number of outputs */
436                                 audio_out = possible_out;
437                                 found = true;
438                         }
439                 }
440
441                 if (possible_in && (possible_in == audio_in)) {
442                         /* exact number of inputs ... must match obviously */
443                         if (possible_out == -1) {
444                                 /* any output configuration possible, provide stereo output */
445                                 audio_out = 2;
446                                 found = true;
447                         } else if (possible_out == -2) {
448                                 /* invalid. interpret as (>0, -1) */
449                                 audio_out = 2;
450                                 found = true;
451                         } else if (possible_out < -2) {
452                                 /* explicitly variable number of outputs, pick maximum */
453                                 audio_out = -possible_out;
454                                 found = true;
455                         } else {
456                                 /* exact number of outputs */
457                                 audio_out = possible_out;
458                                 found = true;
459                         }
460                 }
461
462                 if (found) {
463                         break;
464                 }
465         }
466
467         if (!found) {
468                 return false;
469         }
470
471         out.set (DataType::MIDI, 0);
472         out.set (DataType::AUDIO, audio_out);
473         return true;
474 }
475
476 bool
477 LuaProc::configure_io (ChanCount in, ChanCount out)
478 {
479         _configured_in = in;
480         _configured_out = out;
481
482         _configured_in.set (DataType::MIDI, _has_midi_input ? 1 : 0);
483         _configured_out.set (DataType::MIDI, _has_midi_output ? 1 : 0);
484
485         // configure the DSP if needed
486         lua_State* L = lua.getState ();
487         luabridge::LuaRef lua_dsp_configure = luabridge::getGlobal (L, "dsp_configure");
488         if (lua_dsp_configure.type () == LUA_TFUNCTION) {
489                 try {
490                         lua_dsp_configure (&in, &out);
491                 } catch (luabridge::LuaException const& e) {
492                         ;
493                 }
494         }
495
496         _info->n_inputs = _configured_in;
497         _info->n_outputs = _configured_out;
498         return true;
499 }
500
501 int
502 LuaProc::connect_and_run (BufferSet& bufs,
503                 ChanMapping in, ChanMapping out,
504                 pframes_t nframes, framecnt_t offset)
505 {
506         if (!_lua_dsp) {
507                 return 0;
508         }
509
510         Plugin::connect_and_run (bufs, in, out, nframes, offset);
511
512         // This is needed for ARDOUR::Session requests :(
513         if (! SessionEvent::has_per_thread_pool ()) {
514                 char name[64];
515                 snprintf (name, 64, "Proc-%p", this);
516                 pthread_set_name (name);
517                 SessionEvent::create_per_thread_pool (name, 64);
518                 PBD::notify_event_loops_about_thread_creation (pthread_self(), name, 64);
519         }
520
521         uint32_t const n = parameter_count ();
522         for (uint32_t i = 0; i < n; ++i) {
523                 if (parameter_is_control (i) && parameter_is_input (i)) {
524                         _control_data[i] = _shadow_data[i];
525                 }
526         }
527
528 #ifdef WITH_LUAPROC_STATS
529         int64_t t0 = g_get_monotonic_time ();
530 #endif
531
532         try {
533                 if (_lua_does_channelmapping) {
534                         // run the DSP function
535                         (*_lua_dsp)(&bufs, in, out, nframes, offset);
536                 } else {
537                         // map buffers
538                         BufferSet& silent_bufs  = _session.get_silent_buffers (ChanCount (DataType::AUDIO, 1));
539                         BufferSet& scratch_bufs = _session.get_scratch_buffers (ChanCount (DataType::AUDIO, 1));
540
541                         lua_State* L = lua.getState ();
542                         luabridge::LuaRef in_map (luabridge::newTable (L));
543                         luabridge::LuaRef out_map (luabridge::newTable (L));
544
545                         const uint32_t audio_in = _configured_in.n_audio ();
546                         const uint32_t audio_out = _configured_out.n_audio ();
547                         const uint32_t midi_in = _configured_in.n_midi ();
548
549                         for (uint32_t ap = 0; ap < audio_in; ++ap) {
550                                 bool valid;
551                                 const uint32_t buf_index = in.get(DataType::AUDIO, ap, &valid);
552                                 if (valid) {
553                                         in_map[ap + 1] = bufs.get_audio (buf_index).data (offset);
554                                 } else {
555                                         in_map[ap + 1] = silent_bufs.get_audio (0).data (offset);
556                                 }
557                         }
558                         for (uint32_t ap = 0; ap < audio_out; ++ap) {
559                                 bool valid;
560                                 const uint32_t buf_index = out.get(DataType::AUDIO, ap, &valid);
561                                 if (valid) {
562                                         out_map[ap + 1] = bufs.get_audio (buf_index).data (offset);
563                                 } else {
564                                         out_map[ap + 1] = scratch_bufs.get_audio (0).data (offset);
565                                 }
566                         }
567
568                         luabridge::LuaRef lua_midi_tbl (luabridge::newTable (L));
569                         int e = 1; // > 1 port, we merge events (unsorted)
570                         for (uint32_t mp = 0; mp < midi_in; ++mp) {
571                                 bool valid;
572                                 const uint32_t idx = in.get(DataType::MIDI, mp, &valid);
573                                 if (valid) {
574                                         for (MidiBuffer::iterator m = bufs.get_midi(idx).begin();
575                                                         m != bufs.get_midi(idx).end(); ++m, ++e) {
576                                                 const Evoral::MIDIEvent<framepos_t> ev(*m, false);
577                                                 luabridge::LuaRef lua_midi_data (luabridge::newTable (L));
578                                                 const uint8_t* data = ev.buffer();
579                                                 for (uint32_t i = 0; i < ev.size(); ++i) {
580                                                         lua_midi_data [i + 1] = data[i];
581                                                 }
582                                                 luabridge::LuaRef lua_midi_event (luabridge::newTable (L));
583                                                 lua_midi_event["time"] = 1 + (*m).time();
584                                                 lua_midi_event["data"] = lua_midi_data;
585                                                 lua_midi_tbl[e] = lua_midi_event;
586                                         }
587                                 }
588                         }
589
590                         if (_has_midi_input) {
591                                 // XXX TODO This needs a better solution than global namespace
592                                 luabridge::push (L, lua_midi_tbl);
593                                 lua_setglobal (L, "mididata");
594                         }
595
596
597                         // run the DSP function
598                         (*_lua_dsp)(in_map, out_map, nframes);
599                 }
600         } catch (luabridge::LuaException const& e) {
601 #ifndef NDEBUG
602                 printf ("LuaException: %s\n", e.what ());
603 #endif
604                 return -1;
605         }
606 #ifdef WITH_LUAPROC_STATS
607         int64_t t1 = g_get_monotonic_time ();
608 #endif
609         lua.collect_garbage (); // rt-safe, slight *regular* performance overhead
610 #ifdef WITH_LUAPROC_STATS
611         ++_stats_cnt;
612         int64_t t2 = g_get_monotonic_time ();
613         int64_t ela0 = t1 - t0;
614         int64_t ela1 = t2 - t1;
615         if (ela0 > _stats_max[0]) _stats_max[0] = ela0;
616         if (ela1 > _stats_max[1]) _stats_max[1] = ela1;
617         _stats_avg[0] += ela0;
618         _stats_avg[1] += ela1;
619 #endif
620         return 0;
621 }
622
623
624 void
625 LuaProc::add_state (XMLNode* root) const
626 {
627         gchar* b64 = g_base64_encode ((const guchar*)_script.c_str (), _script.size ());
628         std::string b64s (b64);
629         g_free (b64);
630         XMLNode* script_node = new XMLNode (X_("script"));
631         script_node->add_property (X_("lua"), LUA_VERSION);
632         script_node->add_content (b64s);
633         root->add_child_nocopy (*script_node);
634 }
635
636 int
637 LuaProc::set_script_from_state (const XMLNode& node)
638 {
639         XMLNode* child;
640         if (node.name () != state_node_name ()) {
641                 return -1;
642         }
643
644         if ((child = node.child (X_("script"))) != 0) {
645                 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
646                         if (!(*n)->is_content ()) { continue; }
647                         gsize size;
648                         guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
649                         _script = std::string ((const char*)buf, size);
650                         g_free (buf);
651                         if (load_script ()) {
652                                 PBD::error << _("Failed to load Lua script from session state.") << endmsg;
653 #ifndef NDEBUG
654                                 std::cerr << "Failed Lua Script: " << _script << std::endl;
655 #endif
656                                 _script = "";
657                         }
658                         break;
659                 }
660         }
661         if (_script.empty ()) {
662                 PBD::error << _("Session State for LuaProcessor did not include a Lua script.") << endmsg;
663                 return -1;
664         }
665         if (!_lua_dsp) {
666                 PBD::error << _("Invalid/incompatible Lua script found for LuaProcessor.") << endmsg;
667                 return -1;
668         }
669         return 0;
670 }
671
672 int
673 LuaProc::set_state (const XMLNode& node, int version)
674 {
675         if (_script.empty ()) {
676                 if (set_script_from_state (node)) {
677                         return -1;
678                 }
679         }
680         return Plugin::set_state (node, version);
681 }
682
683 uint32_t
684 LuaProc::parameter_count () const
685 {
686         return _ctrl_params.size ();
687 }
688
689 float
690 LuaProc::default_value (uint32_t port)
691 {
692         if (_ctrl_params[port].first) {
693                 assert (0);
694                 return 0;
695         }
696         int lp = _ctrl_params[port].second;
697         luabridge::LuaRef lr = (*_lua_params)[lp];
698         return (lr["default"]).cast<float> ();
699 }
700
701 void
702 LuaProc::set_parameter (uint32_t port, float val)
703 {
704         assert (port < parameter_count ());
705         if (get_parameter (port) == val) {
706                 return;
707         }
708         _shadow_data[port] = val;
709         Plugin::set_parameter (port, val);
710 }
711
712 float
713 LuaProc::get_parameter (uint32_t port) const
714 {
715         if (parameter_is_input (port)) {
716                 return _shadow_data[port];
717         } else {
718                 return _control_data[port];
719         }
720 }
721
722 int
723 LuaProc::get_parameter_descriptor (uint32_t port, ParameterDescriptor& desc) const
724 {
725         assert (port <= parameter_count ());
726         int lp = _ctrl_params[port].second;
727
728         luabridge::LuaRef lr = (*_lua_params)[lp];
729         desc.lower  = (lr["min"]).cast<float> ();
730         desc.upper  = (lr["max"]).cast<float> ();
731
732         if (_ctrl_params[port].first) {
733                 desc.normal = desc.lower; // output-port, no default
734         } else {
735                 desc.normal = (lr["default"]).cast<float> ();
736         }
737
738         desc.toggled      = lr["toggled"].isBoolean () && (lr["toggled"]).cast<bool> ();
739         desc.logarithmic  = lr["logarithmic"].isBoolean () && (lr["logarithmic"]).cast<bool> ();
740         desc.integer_step = lr["integer"].isBoolean () && (lr["integer"]).cast<bool> ();
741         desc.sr_dependent = lr["ratemult"].isBoolean () && (lr["ratemult"]).cast<bool> ();
742         desc.enumeration  = lr["enum"].isBoolean () && (lr["enum"]).cast<bool> ();
743
744         // TODO check if assignments make sense, e.g
745         assert (!(desc.toggled && desc.logarithmic));
746
747         if (lr["unit"].isString ()) {
748                 std::string unit = lr["unit"].cast<std::string> ();
749                 if (unit == "dB") { desc.unit = ParameterDescriptor::DB; }
750                 else if (unit == "Hz") { desc.unit = ParameterDescriptor::HZ; }
751                 else if (unit == "Midi Note") { desc.unit = ParameterDescriptor::MIDI_NOTE; }
752         }
753
754         desc.label = (lr["name"]).cast<std::string> ();
755         desc.scale_points = get_scale_points (port);
756         desc.update_steps ();
757         return 0;
758 }
759
760 std::string
761 LuaProc::get_parameter_docs (uint32_t port) const {
762         assert (port <= parameter_count ());
763         int lp = _ctrl_params[port].second;
764         luabridge::LuaRef lr = (*_lua_params)[lp];
765         luabridge::LuaRef doc = lr["doc"];
766         if (doc.isString ()) {
767                 return doc.cast<std::string> ();
768         }
769         return "";
770 }
771
772 uint32_t
773 LuaProc::nth_parameter (uint32_t port, bool& ok) const
774 {
775         if (port < _ctrl_params.size ()) {
776                 ok = true;
777                 return port;
778         }
779         ok = false;
780         return 0;
781 }
782
783 bool
784 LuaProc::parameter_is_input (uint32_t port) const
785 {
786         assert (port < _ctrl_params.size ());
787         return (!_ctrl_params[port].first);
788 }
789
790 bool
791 LuaProc::parameter_is_output (uint32_t port) const
792 {
793         assert (port < _ctrl_params.size ());
794         return (_ctrl_params[port].first);
795 }
796
797 std::set<Evoral::Parameter>
798 LuaProc::automatable () const
799 {
800         std::set<Evoral::Parameter> automatables;
801         for (uint32_t i = 0; i < _ctrl_params.size (); ++i) {
802                 if (parameter_is_input (i)) {
803                         automatables.insert (automatables.end (), Evoral::Parameter (PluginAutomation, 0, i));
804                 }
805         }
806         return automatables;
807 }
808
809 std::string
810 LuaProc::describe_parameter (Evoral::Parameter param)
811 {
812         if (param.type () == PluginAutomation && param.id () < parameter_count ()) {
813                 int lp = _ctrl_params[param.id ()].second;
814                 luabridge::LuaRef lr = (*_lua_params)[lp];
815                 return (lr["name"]).cast<std::string> ();
816         } else {
817                 return "??";
818         }
819 }
820
821 void
822 LuaProc::print_parameter (uint32_t param, char* buf, uint32_t len) const
823 {
824         if (buf && len) {
825                 if (param < parameter_count ()) {
826                         snprintf (buf, len, "%.3f", get_parameter (param));
827                 } else {
828                         strcat (buf, "0");
829                 }
830         }
831 }
832
833 boost::shared_ptr<ScalePoints>
834 LuaProc::get_scale_points (uint32_t port) const
835 {
836         int lp = _ctrl_params[port].second;
837         luabridge::LuaRef lr = (*_lua_params)[lp];
838
839         if (!lr["scalepoints"].isTable()) {
840                 return boost::shared_ptr<ScalePoints> ();
841         }
842
843         int cnt = 0;
844         boost::shared_ptr<ScalePoints> rv = boost::shared_ptr<ScalePoints>(new ScalePoints());
845         luabridge::LuaRef scalepoints (lr["scalepoints"]);
846
847         for (luabridge::Iterator i (scalepoints); !i.isNil (); ++i) {
848                 if (!i.key ().isString ())    { continue; }
849                 if (!i.value ().isNumber ())  { continue; }
850                 rv->insert(make_pair(i.key ().cast<std::string> (),
851                                         i.value ().cast<float> ()));
852                 ++cnt;
853         }
854
855         if (rv->size() > 0) {
856                 return rv;
857         }
858         return boost::shared_ptr<ScalePoints> ();
859 }
860
861
862 void
863 LuaProc::setup_lua_inline_gui (LuaState *lua_gui)
864 {
865         lua_State* LG = lua_gui->getState ();
866         LuaBindings::stddef (LG);
867         LuaBindings::common (LG);
868         LuaBindings::dsp (LG);
869
870 #ifndef NDEBUG
871         lua_gui->Print.connect (sigc::mem_fun (*this, &LuaProc::lua_print));
872 #endif
873
874         lua_gui->do_command ("function ardour () end");
875         lua_gui->do_command (_script);
876
877         // TODO think: use a weak-pointer here ?
878         // (the GUI itself uses a shared ptr to this plugin, so we should be good)
879         luabridge::getGlobalNamespace (LG)
880                 .beginNamespace ("Ardour")
881                 .beginClass <LuaProc> ("LuaProc")
882                 .addFunction ("shmem", &LuaProc::instance_shm)
883                 .endClass ()
884                 .endNamespace ();
885
886         luabridge::push <LuaProc *> (LG, this);
887         lua_setglobal (LG, "self");
888
889         luabridge::push <float *> (LG, _shadow_data);
890         lua_setglobal (LG, "CtrlPorts");
891 }
892
893 ////////////////////////////////////////////////////////////////////////////////
894 #include <glibmm/miscutils.h>
895 #include <glibmm/fileutils.h>
896
897 LuaPluginInfo::LuaPluginInfo (LuaScriptInfoPtr lsi) {
898         if (lsi->type != LuaScriptInfo::DSP) {
899                 throw failed_constructor ();
900         }
901
902         path = lsi->path;
903         name = lsi->name;
904         creator = lsi->author;
905         category = lsi->category;
906         unique_id = "luascript"; // the interpreter is not unique.
907
908         n_inputs.set (DataType::AUDIO, 1);
909         n_outputs.set (DataType::AUDIO, 1);
910         type = Lua;
911 }
912
913 PluginPtr
914 LuaPluginInfo::load (Session& session)
915 {
916         std::string script = "";
917         if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
918                 return PluginPtr ();
919         }
920
921         try {
922                 script = Glib::file_get_contents (path);
923         } catch (Glib::FileError err) {
924                 return PluginPtr ();
925         }
926
927         if (script.empty ()) {
928                 return PluginPtr ();
929         }
930
931         try {
932                 PluginPtr plugin (new LuaProc (session.engine (), session, script));
933                 return plugin;
934         } catch (failed_constructor& err) {
935                 ;
936         }
937         return PluginPtr ();
938 }
939
940 std::vector<Plugin::PresetRecord>
941 LuaPluginInfo::get_presets (bool /*user_only*/) const
942 {
943         std::vector<Plugin::PresetRecord> p;
944         return p;
945 }