1 /*
2 * Copyright (C) 2016-2017 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2016-2019 Robin Gareus <robin@gareus.org>
4 * Copyright (C) 2016 Julien "_FrnchFrgg_" RIVAUD <frnchfrgg@free.fr>
5 * Copyright (C) 2016 Tim Mayberry <mojofunk@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22 #include <glib.h>
23 #include <glibmm/miscutils.h>
24 #include <glibmm/fileutils.h>
25
26 #include "pbd/gstdio_compat.h"
27 #include "pbd/pthread_utils.h"
28
29 #include "ardour/audio_buffer.h"
30 #include "ardour/buffer_set.h"
31 #include "ardour/filesystem_paths.h"
32 #include "ardour/luabindings.h"
33 #include "ardour/luaproc.h"
34 #include "ardour/luascripting.h"
35 #include "ardour/midi_buffer.h"
36 #include "ardour/plugin.h"
37 #include "ardour/session.h"
38
39 #include "LuaBridge/LuaBridge.h"
40
41 #include "pbd/i18n.h"
42
43 using namespace ARDOUR;
44 using namespace PBD;
45
LuaProc(AudioEngine & engine,Session & session,const std::string & script)46 LuaProc::LuaProc (AudioEngine& engine,
47 Session& session,
48 const std::string &script)
49 : Plugin (engine, session)
50 , _mempool ("LuaProc", 3145728)
51 #ifdef USE_TLSF
52 , lua (lua_newstate (&PBD::TLSF::lalloc, &_mempool))
53 #elif defined USE_MALLOC
54 , lua ()
55 #else
56 , lua (lua_newstate (&PBD::ReallocPool::lalloc, &_mempool))
57 #endif
58 , _lua_dsp (0)
59 , _lua_latency (0)
60 , _script (script)
61 , _lua_does_channelmapping (false)
62 , _lua_has_inline_display (false)
63 , _connect_all_audio_outputs (false)
64 , _designated_bypass_port (UINT32_MAX)
65 , _signal_latency (0)
66 , _control_data (0)
67 , _shadow_data (0)
68 , _configured (false)
69 , _has_midi_input (false)
70 , _has_midi_output (false)
71 {
72 init ();
73
74 /* when loading a session, or pasing a processor,
75 * the script is set during set_state();
76 */
77 if (!_script.empty () && load_script ()) {
78 throw failed_constructor ();
79 }
80 }
81
LuaProc(const LuaProc & other)82 LuaProc::LuaProc (const LuaProc &other)
83 : Plugin (other)
84 , _mempool ("LuaProc", 3145728)
85 #ifdef USE_TLSF
86 , lua (lua_newstate (&PBD::TLSF::lalloc, &_mempool))
87 #elif defined USE_MALLOC
88 , lua ()
89 #else
90 , lua (lua_newstate (&PBD::ReallocPool::lalloc, &_mempool))
91 #endif
92 , _lua_dsp (0)
93 , _lua_latency (0)
94 , _script (other.script ())
95 , _origin (other._origin)
96 , _lua_does_channelmapping (false)
97 , _lua_has_inline_display (false)
98 , _designated_bypass_port (UINT32_MAX)
99 , _signal_latency (0)
100 , _control_data (0)
101 , _shadow_data (0)
102 , _configured (false)
103 , _has_midi_input (false)
104 , _has_midi_output (false)
105 {
106 init ();
107
108 if (load_script ()) {
109 throw failed_constructor ();
110 }
111
112 for (uint32_t i = 0; i < parameter_count (); ++i) {
113 _control_data[i] = other._shadow_data[i];
114 _shadow_data[i] = other._shadow_data[i];
115 }
116 }
117
~LuaProc()118 LuaProc::~LuaProc () {
119 #ifdef WITH_LUAPROC_STATS
120 if (_info && _stats_cnt > 0) {
121 printf ("LuaProc: '%s' run() avg: %.3f max: %.3f [ms] p: %.1f\n",
122 _info->name.c_str (),
123 0.0001f * _stats_avg[0] / (float) _stats_cnt,
124 0.0001f * _stats_max[0],
125 _stats_max[0] * (float)_stats_cnt / _stats_avg[0]);
126 printf ("LuaProc: '%s' gc() avg: %.3f max: %.3f [ms] p: %.1f\n",
127 _info->name.c_str (),
128 0.0001f * _stats_avg[1] / (float) _stats_cnt,
129 0.0001f * _stats_max[1],
130 _stats_max[1] * (float)_stats_cnt / _stats_avg[1]);
131 }
132 #endif
133 lua.collect_garbage ();
134 delete (_lua_dsp);
135 delete (_lua_latency);
136 delete [] _control_data;
137 delete [] _shadow_data;
138 }
139
140 void
init()141 LuaProc::init ()
142 {
143 #ifdef WITH_LUAPROC_STATS
144 _stats_avg[0] = _stats_avg[1] = _stats_max[0] = _stats_max[1] = 0;
145 _stats_cnt = -25;
146 #endif
147
148 lua.Print.connect (sigc::mem_fun (*this, &LuaProc::lua_print));
149 // register session object
150 lua_State* L = lua.getState ();
151 lua_mlock (L, 1);
152 LuaBindings::stddef (L);
153 LuaBindings::common (L);
154 LuaBindings::dsp (L);
155
156 luabridge::getGlobalNamespace (L)
157 .beginNamespace ("Ardour")
158 .deriveClass <LuaProc, PBD::StatefulDestructible> ("LuaProc")
159 .addFunction ("queue_draw", &LuaProc::queue_draw)
160 .addFunction ("shmem", &LuaProc::instance_shm)
161 .addFunction ("table", &LuaProc::instance_ref)
162 .addFunction ("route", &LuaProc::route)
163 .addFunction ("unique_id", &LuaProc::unique_id)
164 .addFunction ("name", &LuaProc::name)
165 .endClass ()
166 .endNamespace ();
167 lua_mlock (L, 0);
168
169 // add session to global lua namespace
170 luabridge::push <Session *> (L, &_session);
171 lua_setglobal (L, "Session");
172
173 // instance
174 luabridge::push <LuaProc *> (L, this);
175 lua_setglobal (L, "self");
176
177 // sandbox
178 lua.sandbox (true);
179 #if 0
180 lua.do_command ("for n in pairs(_G) do print(n) end print ('----')"); // print global env
181 #endif
182 lua.do_command ("function ardour () end");
183 }
184
185 void
drop_references()186 LuaProc::drop_references ()
187 {
188 lua.collect_garbage ();
189 Plugin::drop_references ();
190 }
191
192 boost::weak_ptr<Route>
route() const193 LuaProc::route () const
194 {
195 if (!_owner) {
196 return boost::weak_ptr<Route>();
197 }
198 return static_cast<Route*>(_owner)->weakroute ();
199 }
200
201 void
lua_print(std::string s)202 LuaProc::lua_print (std::string s) {
203 #ifndef NDEBUG
204 std::cout << "LuaProc: " << s << "\n";
205 #endif
206 PBD::info << "LuaProc: " << s << "\n";
207 }
208
209 bool
load_script()210 LuaProc::load_script ()
211 {
212 if (_script.empty ()) {
213 return true;
214 }
215 assert (!_lua_dsp); // don't allow to re-initialize
216 LuaPluginInfoPtr lpi;
217
218 // TODO: refine APIs; function arguments..
219 // - perform channel-map in ardour (silent/scratch buffers) ?
220 // - control-port API (explicit get/set functions ??)
221 // - latency reporting (global var? ctrl-port? set-function ?)
222 // - MIDI -> sparse table of events
223 // { [sample] => { Event }, .. }
224 // or { { sample, Event }, .. }
225
226 try {
227 LuaScriptInfoPtr lsi = LuaScripting::script_info (_script);
228 lpi = LuaPluginInfoPtr (new LuaPluginInfo (lsi));
229 assert (lpi);
230 set_info (lpi);
231 _mempool.set_name ("LuaProc: " + lsi->name);
232 _docs = lsi->description;
233 } catch (failed_constructor& err) {
234 return true;
235 }
236
237 lua_State* L = lua.getState ();
238 lua.do_command (_script);
239
240 // check if script has a DSP callback
241 luabridge::LuaRef lua_dsp_run = luabridge::getGlobal (L, "dsp_run");
242 luabridge::LuaRef lua_dsp_map = luabridge::getGlobal (L, "dsp_runmap");
243
244 if ((lua_dsp_run.type () != LUA_TFUNCTION) == (lua_dsp_map.type () != LUA_TFUNCTION)) {
245 return true;
246 }
247
248 if (lua_dsp_run.type () == LUA_TFUNCTION) {
249 _lua_dsp = new luabridge::LuaRef (lua_dsp_run);
250 }
251 else if (lua_dsp_map.type () == LUA_TFUNCTION) {
252 _lua_dsp = new luabridge::LuaRef (lua_dsp_map);
253 _lua_does_channelmapping = true;
254 }
255 else {
256 assert (0);
257 return true;
258 }
259
260 luabridge::LuaRef lua_dsp_latency = luabridge::getGlobal (L, "dsp_latency");
261 if (lua_dsp_latency.type () == LUA_TFUNCTION) {
262 _lua_latency = new luabridge::LuaRef (lua_dsp_latency);
263 }
264
265 /* parse I/O options */
266 luabridge::LuaRef ioconfig = luabridge::getGlobal (L, "dsp_ioconfig");
267 if (ioconfig.isFunction ()) {
268 try {
269 luabridge::LuaRef iotable = ioconfig ();
270 if (iotable.isTable ()) {
271 for (luabridge::Iterator i (iotable); !i.isNil (); ++i) {
272 if (!i.key().isString()) {
273 continue;
274 }
275 if (i.key().cast<std::string> () == "connect_all_audio_outputs" && i.value().isBoolean ()) {
276 _connect_all_audio_outputs = i.value().cast<bool> ();
277 }
278 }
279 }
280 } catch (...) {
281 return true;
282 }
283 }
284
285 // initialize the DSP if needed
286 luabridge::LuaRef lua_dsp_init = luabridge::getGlobal (L, "dsp_init");
287 if (lua_dsp_init.type () == LUA_TFUNCTION) {
288 try {
289 lua_dsp_init (_session.nominal_sample_rate ());
290 } catch (luabridge::LuaException const& e) {
291 #ifndef NDEBUG
292 std::cerr << "LuaException:" << e.what () << std::endl;
293 #endif
294 PBD::warning << "LuaException: " << e.what () << endmsg;
295 return true; // error
296 } catch (...) {
297 return true;
298 }
299 }
300
301 _ctrl_params.clear ();
302
303 luabridge::LuaRef lua_render = luabridge::getGlobal (L, "render_inline");
304 if (lua_render.isFunction ()) {
305 _lua_has_inline_display = true;
306 }
307
308 luabridge::LuaRef lua_params = luabridge::getGlobal (L, "dsp_params");
309 if (lua_params.isFunction ()) {
310
311 // call function // add try {} catch (luabridge::LuaException const& e)
312 luabridge::LuaRef params = lua_params ();
313
314 if (params.isTable ()) {
315
316 for (luabridge::Iterator i (params); !i.isNil (); ++i) {
317 // required fields
318 if (!i.key ().isNumber ()) { return true; }
319 if (!i.value ().isTable ()) { return true; }
320 if (!i.value ()["type"].isString ()) { return true; }
321 if (!i.value ()["name"].isString ()) { return true; }
322 if (!i.value ()["min"].isNumber ()) { return true; }
323 if (!i.value ()["max"].isNumber ()) { return true; }
324
325 int pn = i.key ().cast<int> ();
326 std::string type = i.value ()["type"].cast<std::string> ();
327 if (type == "input") {
328 if (!i.value ()["default"].isNumber ()) {
329 return true; // error
330 }
331 _ctrl_params.push_back (std::make_pair (false, pn));
332 }
333 else if (type == "output") {
334 _ctrl_params.push_back (std::make_pair (true, pn));
335 } else {
336 return true; // error
337 }
338 assert (pn == (int) _ctrl_params.size ());
339
340 //_param_desc[pn] = boost::shared_ptr<ParameterDescriptor> (new ParameterDescriptor());
341 luabridge::LuaRef lr = i.value ();
342
343 if (type == "input") {
344 _param_desc[pn].normal = lr["default"].cast<float> ();
345 } else {
346 _param_desc[pn].normal = lr["min"].cast<float> (); // output-port, no default
347 }
348 _param_desc[pn].lower = lr["min"].cast<float> ();
349 _param_desc[pn].upper = lr["max"].cast<float> ();
350 _param_desc[pn].toggled = lr["toggled"].isBoolean () && (lr["toggled"]).cast<bool> ();
351 _param_desc[pn].logarithmic = lr["logarithmic"].isBoolean () && (lr["logarithmic"]).cast<bool> ();
352 _param_desc[pn].integer_step = lr["integer"].isBoolean () && (lr["integer"]).cast<bool> ();
353 _param_desc[pn].sr_dependent = lr["ratemult"].isBoolean () && (lr["ratemult"]).cast<bool> ();
354 _param_desc[pn].enumeration = lr["enum"].isBoolean () && (lr["enum"]).cast<bool> ();
355
356 if (lr["bypass"].isBoolean () && (lr["bypass"]).cast<bool> ()) {
357 _designated_bypass_port = pn - 1; // lua table starts at 1.
358 }
359
360 if (lr["unit"].isString ()) {
361 std::string unit = lr["unit"].cast<std::string> ();
362 if (unit == "dB") { _param_desc[pn].unit = ParameterDescriptor::DB; }
363 else if (unit == "Hz") { _param_desc[pn].unit = ParameterDescriptor::HZ; }
364 else if (unit == "Midi Note") { _param_desc[pn].unit = ParameterDescriptor::MIDI_NOTE; }
365 }
366 _param_desc[pn].label = (lr["name"]).cast<std::string> ();
367 _param_desc[pn].scale_points = parse_scale_points (&lr);
368
369 luabridge::LuaRef doc = lr["doc"];
370 if (doc.isString ()) {
371 _param_doc[pn] = doc.cast<std::string> ();
372 } else {
373 _param_doc[pn] = "";
374 }
375 assert (!(_param_desc[pn].toggled && _param_desc[pn].logarithmic));
376 }
377 }
378 }
379
380 _control_data = new float[parameter_count ()];
381 _shadow_data = new float[parameter_count ()];
382
383 for (uint32_t i = 0; i < parameter_count (); ++i) {
384 if (parameter_is_input (i)) {
385 _control_data[i] = _shadow_data[i] = default_value (i);
386 }
387 }
388
389 // expose ctrl-ports to global lua namespace
390 luabridge::push <float *> (L, _control_data);
391 lua_setglobal (L, "CtrlPorts");
392
393 return false; // no error
394 }
395
396 bool
match_variable_io(ChanCount & in,ChanCount & aux_in,ChanCount & out)397 LuaProc::match_variable_io (ChanCount& in, ChanCount& aux_in, ChanCount& out)
398 {
399 /* Lua does not have dedicated sidechain busses */
400 in += aux_in;
401
402 /* caller must hold process lock (no concurrent calls to interpreter */
403 _output_configs.clear ();
404
405 lua_State* L = lua.getState ();
406 luabridge::LuaRef ioconfig = luabridge::getGlobal (L, "dsp_ioconfig");
407
408 luabridge::LuaRef *_iotable = NULL; // can't use reference :(
409
410 if (ioconfig.isFunction ()) {
411 try {
412 luabridge::LuaRef iotable = ioconfig ();
413 if (iotable.isTable ()) {
414 _iotable = new luabridge::LuaRef (iotable);
415 }
416 } catch (luabridge::LuaException const& e) {
417 _iotable = NULL;
418 } catch (...) {
419 _iotable = NULL;
420 }
421 }
422
423 if (!_iotable) {
424 /* empty table as default */
425 luabridge::LuaRef iotable = luabridge::newTable(L);
426 _iotable = new luabridge::LuaRef (iotable);
427 }
428
429 // now we can reference it.
430 luabridge::LuaRef iotable (*_iotable);
431 delete _iotable;
432
433 if ((iotable).length () < 1) {
434 /* empty table as only config, to get default values */
435 luabridge::LuaRef ioconf = luabridge::newTable(L);
436 iotable[1] = ioconf;
437 }
438
439 const int audio_in = in.n_audio ();
440 const int midi_in = in.n_midi ();
441
442 // preferred setting (provided by plugin_insert)
443 const int preferred_out = out.n_audio ();
444 const int preferred_midiout = out.n_midi ();
445
446 int midi_out = -1;
447 int audio_out = -1;
448 float penalty = 9999;
449 bool found = false;
450
451 #define FOUNDCFG_PENALTY(n_in, n_out, p) { \
452 _output_configs.insert (n_out); \
453 if (p < penalty) { \
454 audio_out = (n_out); \
455 midi_out = possible_midiout; \
456 in.set (DataType::AUDIO, (n_in)); \
457 in.set (DataType::MIDI, possible_midiin); \
458 _has_midi_input = (possible_midiin > 0); \
459 _has_midi_output = (possible_midiout > 0); \
460 penalty = p; \
461 found = true; \
462 } \
463 }
464
465 #define FOUNDCFG_IMPRECISE(n_in, n_out) { \
466 const float p = fabsf ((float)(n_out) - preferred_out) * \
467 (((n_out) > preferred_out) ? 1.1 : 1) \
468 + fabsf ((float)possible_midiout - preferred_midiout) * \
469 ((possible_midiout - preferred_midiout) ? 0.6 : 0.5) \
470 + fabsf ((float)(n_in) - audio_in) * \
471 (((n_in) > audio_in) ? 275 : 250) \
472 + fabsf ((float)possible_midiin - midi_in) * \
473 ((possible_midiin - midi_in) ? 100 : 110); \
474 FOUNDCFG_PENALTY(n_in, n_out, p); \
475 }
476
477 #define FOUNDCFG(n_out) \
478 FOUNDCFG_IMPRECISE(audio_in, n_out)
479
480 #define ANYTHINGGOES \
481 _output_configs.insert (0);
482
483 #define UPTO(nch) { \
484 for (int n = 1; n < nch; ++n) { \
485 _output_configs.insert (n); \
486 } \
487 }
488
489 for (luabridge::Iterator i (iotable); !i.isNil (); ++i) {
490 luabridge::LuaRef io (i.value ());
491 if (!io.isTable()) {
492 continue;
493 }
494
495 int possible_in = io["audio_in"].isNumber() ? io["audio_in"] : -1;
496 int possible_out = io["audio_out"].isNumber() ? io["audio_out"] : -1;
497 int possible_midiin = io["midi_in"].isNumber() ? io["midi_in"] : 0;
498 int possible_midiout = io["midi_out"].isNumber() ? io["midi_out"] : 0;
499
500 // exact match
501 if ((possible_in == audio_in) && (possible_out == preferred_out)) {
502 /* Set penalty so low that this output configuration
503 * will trump any other one */
504 FOUNDCFG_PENALTY(audio_in, preferred_out, -1);
505 }
506
507 if (possible_out == 0 && possible_midiout == 0) {
508 /* skip configurations with no output at all */
509 continue;
510 }
511
512 if (possible_in == -1 || possible_in == -2) {
513 /* wildcard for input */
514 if (possible_out == possible_in) {
515 /* either both -1 or both -2 (invalid and
516 * interpreted as both -1): out must match in */
517 FOUNDCFG (audio_in);
518 } else if (possible_out == -3 - possible_in) {
519 /* one is -1, the other is -2: any output configuration
520 * possible, pick what the insert prefers */
521 FOUNDCFG (preferred_out);
522 ANYTHINGGOES;
523 } else if (possible_out < -2) {
524 /* variable number of outputs up to -N,
525 * invalid if in == -2 but we accept it anyway */
526 FOUNDCFG (std::min (-possible_out, preferred_out));
527 UPTO (-possible_out)
528 } else {
529 /* exact number of outputs */
530 FOUNDCFG (possible_out);
531 }
532 }
533
534 if (possible_in < -2 || possible_in >= 0) {
535 /* specified number, exact or up to */
536 int desired_in;
537 if (possible_in >= 0) {
538 /* configuration can only match possible_in */
539 desired_in = possible_in;
540 } else {
541 /* configuration can match up to -possible_in */
542 desired_in = std::min (-possible_in, audio_in);
543 }
544 if (possible_out == -1 || possible_out == -2) {
545 /* any output configuration possible
546 * out == -2 is invalid, interpreted as out == -1.
547 * Really imprecise only if desired_in != audio_in */
548 FOUNDCFG_IMPRECISE (desired_in, preferred_out);
549 ANYTHINGGOES;
550 } else if (possible_out < -2) {
551 /* variable number of outputs up to -N
552 * not specified if in > 0, but we accept it anyway.
553 * Really imprecise only if desired_in != audio_in */
554 FOUNDCFG_IMPRECISE (desired_in, std::min (-possible_out, preferred_out));
555 UPTO (-possible_out)
556 } else {
557 /* exact number of outputs
558 * Really imprecise only if desired_in != audio_in */
559 FOUNDCFG_IMPRECISE (desired_in, possible_out);
560 }
561 }
562
563 }
564
565 if (!found) {
566 return false;
567 }
568
569 out.set (DataType::MIDI, midi_out);
570 out.set (DataType::AUDIO, audio_out);
571
572 _selected_in = in; // TODO remove after testing
573 _selected_out = out;
574
575 /* restore side-chain input count */
576 in -= aux_in;
577
578 return true;
579 }
580
581 bool
reconfigure_io(ChanCount in,ChanCount aux_in,ChanCount out)582 LuaProc::reconfigure_io (ChanCount in, ChanCount aux_in, ChanCount out)
583 {
584 in += aux_in;
585 assert (in == _selected_in && out ==_selected_out);
586
587 in.set (DataType::MIDI, _has_midi_input ? 1 : 0);
588 out.set (DataType::MIDI, _has_midi_output ? 1 : 0);
589
590 _info->n_inputs = in;
591 _info->n_outputs = out;
592
593 // configure the DSP if needed
594 if (in != _configured_in || out != _configured_out || !_configured) {
595 lua_State* L = lua.getState ();
596 luabridge::LuaRef lua_dsp_configure = luabridge::getGlobal (L, "dsp_configure");
597 if (lua_dsp_configure.type () == LUA_TFUNCTION) {
598 try {
599 luabridge::LuaRef io = lua_dsp_configure (in, out);
600 if (io.isTable ()) {
601 ChanCount lin (in);
602 ChanCount lout (out);
603
604 if (io["audio_in"].type() == LUA_TNUMBER) {
605 const int c = io["audio_in"].cast<int> ();
606 if (c >= 0) {
607 lin.set (DataType::AUDIO, c);
608 }
609 }
610 if (io["audio_out"].type() == LUA_TNUMBER) {
611 const int c = io["audio_out"].cast<int> ();
612 if (c >= 0) {
613 lout.set (DataType::AUDIO, c);
614 }
615 }
616 if (io["midi_in"].type() == LUA_TNUMBER) {
617 const int c = io["midi_in"].cast<int> ();
618 if (c >= 0) {
619 lin.set (DataType::MIDI, c);
620 }
621 }
622 if (io["midi_out"].type() == LUA_TNUMBER) {
623 const int c = io["midi_out"].cast<int> ();
624 if (c >= 0) {
625 lout.set (DataType::MIDI, c);
626 }
627 }
628 _info->n_inputs = lin;
629 _info->n_outputs = lout;
630 }
631 _configured = true;
632 } catch (luabridge::LuaException const& e) {
633 #ifndef NDEBUG
634 std::cerr << "LuaException: " << e.what () << "\n";
635 #endif
636 PBD::warning << "LuaException: " << e.what () << "\n";
637 return false;
638 } catch (...) {
639 return false;
640 }
641 }
642 }
643
644 _configured_in = in;
645 _configured_out = out;
646
647 return true;
648 }
649
650 int
connect_and_run(BufferSet & bufs,samplepos_t start,samplepos_t end,double speed,ChanMapping const & in,ChanMapping const & out,pframes_t nframes,samplecnt_t offset)651 LuaProc::connect_and_run (BufferSet& bufs,
652 samplepos_t start, samplepos_t end, double speed,
653 ChanMapping const& in, ChanMapping const& out,
654 pframes_t nframes, samplecnt_t offset)
655 {
656 if (!_lua_dsp) {
657 return 0;
658 }
659
660 Plugin::connect_and_run (bufs, start, end, speed, in, out, nframes, offset);
661
662 // This is needed for ARDOUR::Session requests :(
663 assert (SessionEvent::has_per_thread_pool ());
664
665 uint32_t const n = parameter_count ();
666 for (uint32_t i = 0; i < n; ++i) {
667 if (parameter_is_control (i) && parameter_is_input (i)) {
668 _control_data[i] = _shadow_data[i];
669 }
670 }
671
672 #ifdef WITH_LUAPROC_STATS
673 int64_t t0 = g_get_monotonic_time ();
674 #endif
675
676 try {
677 if (_lua_does_channelmapping) {
678 // run the DSP function
679 (*_lua_dsp)(&bufs, &in, &out, nframes, offset);
680 } else {
681 // map buffers
682 BufferSet& silent_bufs = _session.get_silent_buffers (ChanCount (DataType::AUDIO, 1));
683 BufferSet& scratch_bufs = _session.get_scratch_buffers (ChanCount (DataType::AUDIO, 1));
684
685 lua_State* L = lua.getState ();
686 luabridge::LuaRef in_map (luabridge::newTable (L));
687 luabridge::LuaRef out_map (luabridge::newTable (L));
688
689 const uint32_t audio_in = _configured_in.n_audio ();
690 const uint32_t audio_out = _configured_out.n_audio ();
691 const uint32_t midi_in = _configured_in.n_midi ();
692
693 for (uint32_t ap = 0; ap < audio_in; ++ap) {
694 bool valid;
695 const uint32_t buf_index = in.get(DataType::AUDIO, ap, &valid);
696 if (valid) {
697 in_map[ap + 1] = bufs.get_audio (buf_index).data (offset);
698 } else {
699 in_map[ap + 1] = silent_bufs.get_audio (0).data (offset);
700 }
701 }
702 for (uint32_t ap = 0; ap < audio_out; ++ap) {
703 bool valid;
704 const uint32_t buf_index = out.get(DataType::AUDIO, ap, &valid);
705 if (valid) {
706 out_map[ap + 1] = bufs.get_audio (buf_index).data (offset);
707 } else {
708 out_map[ap + 1] = scratch_bufs.get_audio (0).data (offset);
709 }
710 }
711
712 luabridge::LuaRef lua_midi_src_tbl (luabridge::newTable (L));
713 int e = 1; // > 1 port, we merge events (unsorted)
714 for (uint32_t mp = 0; mp < midi_in; ++mp) {
715 bool valid;
716 const uint32_t idx = in.get(DataType::MIDI, mp, &valid);
717 if (valid) {
718 for (MidiBuffer::iterator m = bufs.get_midi(idx).begin();
719 m != bufs.get_midi(idx).end(); ++m, ++e) {
720 const Evoral::Event<samplepos_t> ev(*m, false);
721 luabridge::LuaRef lua_midi_data (luabridge::newTable (L));
722 const uint8_t* data = ev.buffer();
723 for (uint32_t i = 0; i < ev.size(); ++i) {
724 lua_midi_data [i + 1] = data[i];
725 }
726 luabridge::LuaRef lua_midi_event (luabridge::newTable (L));
727 lua_midi_event["time"] = 1 + (*m).time();
728 lua_midi_event["data"] = lua_midi_data;
729 lua_midi_event["bytes"] = data;
730 lua_midi_event["size"] = ev.size();
731 lua_midi_src_tbl[e] = lua_midi_event;
732 }
733 }
734 }
735
736 if (_has_midi_input) {
737 // XXX TODO This needs a better solution than global namespace
738 luabridge::push (L, lua_midi_src_tbl);
739 lua_setglobal (L, "midiin");
740 }
741
742 luabridge::LuaRef lua_midi_sink_tbl (luabridge::newTable (L));
743 if (_has_midi_output) {
744 luabridge::push (L, lua_midi_sink_tbl);
745 lua_setglobal (L, "midiout");
746 }
747
748 // run the DSP function
749 (*_lua_dsp)(in_map, out_map, nframes);
750
751 // copy back midi events
752 if (_has_midi_output && lua_midi_sink_tbl.isTable ()) {
753 bool valid;
754 const uint32_t idx = out.get(DataType::MIDI, 0, &valid);
755 if (valid && bufs.count().n_midi() > idx) {
756 MidiBuffer& mbuf = bufs.get_midi(idx);
757 mbuf.silence(0, 0);
758 for (luabridge::Iterator i (lua_midi_sink_tbl); !i.isNil (); ++i) {
759 if (!i.key ().isNumber ()) { continue; }
760 if (!i.value ()["time"].isNumber ()) { continue; }
761 if (!i.value ()["data"].isTable ()) { continue; }
762 luabridge::LuaRef data_tbl (i.value ()["data"]);
763 samplepos_t tme = i.value ()["time"];
764 if (tme < 1 || tme > nframes) { continue; }
765 uint8_t data[64];
766 size_t size = 0;
767 for (luabridge::Iterator di (data_tbl); !di.isNil () && size < sizeof(data); ++di, ++size) {
768 data[size] = di.value ();
769 }
770 if (size > 0 && size < 64) {
771 mbuf.push_back(tme - 1, Evoral::MIDI_EVENT, size, data);
772 }
773 }
774
775 }
776 }
777 }
778
779 if (_lua_latency) {
780 _signal_latency = (*_lua_latency)();
781 }
782
783 } catch (luabridge::LuaException const& e) {
784 #ifndef NDEBUG
785 std::cerr << "LuaException: " << e.what () << "\n";
786 #endif
787 PBD::warning << "LuaException: " << e.what () << "\n";
788 return -1;
789 } catch (...) {
790 return -1;
791 }
792 #ifdef WITH_LUAPROC_STATS
793 int64_t t1 = g_get_monotonic_time ();
794 #endif
795
796 lua.collect_garbage_step ();
797 #ifdef WITH_LUAPROC_STATS
798 if (++_stats_cnt > 0) {
799 int64_t t2 = g_get_monotonic_time ();
800 int64_t ela0 = t1 - t0;
801 int64_t ela1 = t2 - t1;
802 if (ela0 > _stats_max[0]) _stats_max[0] = ela0;
803 if (ela1 > _stats_max[1]) _stats_max[1] = ela1;
804 _stats_avg[0] += ela0;
805 _stats_avg[1] += ela1;
806 }
807 #endif
808 return 0;
809 }
810
811
812 void
add_state(XMLNode * root) const813 LuaProc::add_state (XMLNode* root) const
814 {
815 XMLNode* child;
816
817 gchar* b64 = g_base64_encode ((const guchar*)_script.c_str (), _script.size ());
818 std::string b64s (b64);
819 g_free (b64);
820 XMLNode* script_node = new XMLNode (X_("script"));
821 script_node->set_property (X_("lua"), LUA_VERSION);
822 script_node->set_property (X_("origin"), _origin);
823 script_node->add_content (b64s);
824 root->add_child_nocopy (*script_node);
825
826 for (uint32_t i = 0; i < parameter_count(); ++i) {
827 if (parameter_is_input(i) && parameter_is_control(i)) {
828 child = new XMLNode("Port");
829 child->set_property("id", i);
830 child->set_property("value", _shadow_data[i]);
831 root->add_child_nocopy(*child);
832 }
833 }
834 }
835
836 int
set_script_from_state(const XMLNode & node)837 LuaProc::set_script_from_state (const XMLNode& node)
838 {
839 XMLNode* child;
840 if (node.name () != state_node_name ()) {
841 return -1;
842 }
843
844 if ((child = node.child (X_("script"))) != 0) {
845 XMLProperty const* prop;
846 if ((prop = node.property ("origin")) != 0) {
847 _origin = prop->value();
848 }
849 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
850 if (!(*n)->is_content ()) { continue; }
851 gsize size;
852 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
853 _script = std::string ((const char*)buf, size);
854 g_free (buf);
855 if (load_script ()) {
856 PBD::error << _("Failed to load Lua script from session state.") << endmsg;
857 #ifndef NDEBUG
858 std::cerr << "Failed Lua Script: " << _script << std::endl;
859 #endif
860 _script = "";
861 }
862 break;
863 }
864 }
865 if (_script.empty ()) {
866 PBD::error << _("Session State for LuaProcessor did not include a Lua script.") << endmsg;
867 return -1;
868 }
869 if (!_lua_dsp) {
870 PBD::error << _("Invalid/incompatible Lua script found for LuaProcessor.") << endmsg;
871 return -1;
872 }
873 return 0;
874 }
875
876 int
set_state(const XMLNode & node,int version)877 LuaProc::set_state (const XMLNode& node, int version)
878 {
879 XMLNodeList nodes;
880 XMLNodeConstIterator iter;
881 XMLNode *child;
882
883 if (_script.empty ()) {
884 if (set_script_from_state (node)) {
885 return -1;
886 }
887 }
888
889 if (node.name() != state_node_name()) {
890 error << _("Bad node sent to LuaProc::set_state") << endmsg;
891 return -1;
892 }
893
894 nodes = node.children ("Port");
895 for (iter = nodes.begin(); iter != nodes.end(); ++iter) {
896 child = *iter;
897
898 uint32_t port_id;
899 float value;
900
901 if (!child->get_property("id", port_id)) {
902 warning << _("LuaProc: port has no symbol, ignored") << endmsg;
903 continue;
904 }
905
906 if (!child->get_property("value", value)) {
907 warning << _("LuaProc: port has no value, ignored") << endmsg;
908 continue;
909 }
910
911 set_parameter (port_id, value, 0);
912 }
913
914 return Plugin::set_state (node, version);
915 }
916
917 uint32_t
parameter_count() const918 LuaProc::parameter_count () const
919 {
920 return _ctrl_params.size ();
921 }
922
923 float
default_value(uint32_t port)924 LuaProc::default_value (uint32_t port)
925 {
926 if (_ctrl_params[port].first) {
927 assert (0);
928 return 0;
929 }
930 int lp = _ctrl_params[port].second;
931 return _param_desc[lp].normal;
932 }
933
934 void
set_parameter(uint32_t port,float val,sampleoffset_t when)935 LuaProc::set_parameter (uint32_t port, float val, sampleoffset_t when)
936 {
937 assert (port < parameter_count ());
938 if (get_parameter (port) == val) {
939 return;
940 }
941 _shadow_data[port] = val;
942 Plugin::set_parameter (port, val, when);
943 }
944
945 float
get_parameter(uint32_t port) const946 LuaProc::get_parameter (uint32_t port) const
947 {
948 if (parameter_is_input (port)) {
949 return _shadow_data[port];
950 } else {
951 return _control_data[port];
952 }
953 }
954
955 int
get_parameter_descriptor(uint32_t port,ParameterDescriptor & desc) const956 LuaProc::get_parameter_descriptor (uint32_t port, ParameterDescriptor& desc) const
957 {
958 assert (port <= parameter_count ());
959 int lp = _ctrl_params[port].second;
960 const ParameterDescriptor& d (_param_desc.find(lp)->second);
961
962 desc.lower = d.lower;
963 desc.upper = d.upper;
964 desc.normal = d.normal;
965 desc.toggled = d.toggled;
966 desc.logarithmic = d.logarithmic;
967 desc.integer_step = d.integer_step;
968 desc.sr_dependent = d.sr_dependent;
969 desc.enumeration = d.enumeration;
970 desc.unit = d.unit;
971 desc.label = d.label;
972 desc.scale_points = d.scale_points;
973
974 desc.update_steps ();
975 return 0;
976 }
977
978 std::string
get_parameter_docs(uint32_t port) const979 LuaProc::get_parameter_docs (uint32_t port) const {
980 assert (port <= parameter_count ());
981 int lp = _ctrl_params[port].second;
982 return _param_doc.find(lp)->second;
983 }
984
985 uint32_t
nth_parameter(uint32_t port,bool & ok) const986 LuaProc::nth_parameter (uint32_t port, bool& ok) const
987 {
988 if (port < _ctrl_params.size ()) {
989 ok = true;
990 return port;
991 }
992 ok = false;
993 return 0;
994 }
995
996 bool
parameter_is_input(uint32_t port) const997 LuaProc::parameter_is_input (uint32_t port) const
998 {
999 assert (port < _ctrl_params.size ());
1000 return (!_ctrl_params[port].first);
1001 }
1002
1003 bool
parameter_is_output(uint32_t port) const1004 LuaProc::parameter_is_output (uint32_t port) const
1005 {
1006 assert (port < _ctrl_params.size ());
1007 return (_ctrl_params[port].first);
1008 }
1009
1010 std::set<Evoral::Parameter>
automatable() const1011 LuaProc::automatable () const
1012 {
1013 std::set<Evoral::Parameter> automatables;
1014 for (uint32_t i = 0; i < _ctrl_params.size (); ++i) {
1015 if (parameter_is_input (i)) {
1016 automatables.insert (automatables.end (), Evoral::Parameter (PluginAutomation, 0, i));
1017 }
1018 }
1019 return automatables;
1020 }
1021
1022 std::string
describe_parameter(Evoral::Parameter param)1023 LuaProc::describe_parameter (Evoral::Parameter param)
1024 {
1025 if (param.type () == PluginAutomation && param.id () < parameter_count ()) {
1026 int lp = _ctrl_params[param.id ()].second;
1027 return _param_desc[lp].label;
1028 }
1029 return "??";
1030 }
1031
1032 boost::shared_ptr<ScalePoints>
parse_scale_points(luabridge::LuaRef * lr)1033 LuaProc::parse_scale_points (luabridge::LuaRef* lr)
1034 {
1035 if (!(*lr)["scalepoints"].isTable()) {
1036 return boost::shared_ptr<ScalePoints> ();
1037 }
1038
1039 int cnt = 0;
1040 boost::shared_ptr<ScalePoints> rv = boost::shared_ptr<ScalePoints>(new ScalePoints());
1041 luabridge::LuaRef scalepoints ((*lr)["scalepoints"]);
1042
1043 for (luabridge::Iterator i (scalepoints); !i.isNil (); ++i) {
1044 if (!i.key ().isString ()) { continue; }
1045 if (!i.value ().isNumber ()) { continue; }
1046 rv->insert(make_pair(i.key ().cast<std::string> (),
1047 i.value ().cast<float> ()));
1048 ++cnt;
1049 }
1050
1051 if (rv->size() > 0) {
1052 return rv;
1053 }
1054 return boost::shared_ptr<ScalePoints> ();
1055 }
1056
1057 boost::shared_ptr<ScalePoints>
get_scale_points(uint32_t port) const1058 LuaProc::get_scale_points (uint32_t port) const
1059 {
1060 int lp = _ctrl_params[port].second;
1061 return _param_desc.find(lp)->second.scale_points;
1062 }
1063
1064 void
setup_lua_inline_gui(LuaState * lua_gui)1065 LuaProc::setup_lua_inline_gui (LuaState *lua_gui)
1066 {
1067 lua_State* LG = lua_gui->getState ();
1068 LuaBindings::stddef (LG);
1069 LuaBindings::common (LG);
1070 LuaBindings::dsp (LG);
1071 LuaBindings::osc (LG);
1072
1073 lua_gui->Print.connect (sigc::mem_fun (*this, &LuaProc::lua_print));
1074 lua_gui->do_command ("function ardour () end");
1075 lua_gui->do_command (_script);
1076
1077 // TODO think: use a weak-pointer here ?
1078 // (the GUI itself uses a shared ptr to this plugin, so we should be good)
1079 luabridge::getGlobalNamespace (LG)
1080 .beginNamespace ("Ardour")
1081 .beginClass <LuaProc> ("LuaProc")
1082 .addFunction ("shmem", &LuaProc::instance_shm)
1083 .addFunction ("table", &LuaProc::instance_ref)
1084 .endClass ()
1085 .endNamespace ();
1086
1087 luabridge::push <LuaProc *> (LG, this);
1088 lua_setglobal (LG, "self");
1089
1090 luabridge::push <float *> (LG, _control_data);
1091 lua_setglobal (LG, "CtrlPorts");
1092 }
1093 ////////////////////////////////////////////////////////////////////////////////
1094
1095 #include "ardour/search_paths.h"
1096 #include "sha1.c"
1097
1098 std::string
preset_name_to_uri(const std::string & name) const1099 LuaProc::preset_name_to_uri (const std::string& name) const
1100 {
1101 std::string uri ("urn:lua:");
1102 char hash[41];
1103 Sha1Digest s;
1104 sha1_init (&s);
1105 sha1_write (&s, (const uint8_t *) name.c_str(), name.size ());
1106 sha1_write (&s, (const uint8_t *) _script.c_str(), _script.size ());
1107 sha1_result_hash (&s, hash);
1108 return uri + hash;
1109 }
1110
1111 std::string
presets_file() const1112 LuaProc::presets_file () const
1113 {
1114 return string_compose ("lua-%1", _info->unique_id);
1115 }
1116
1117 XMLTree*
presets_tree() const1118 LuaProc::presets_tree () const
1119 {
1120 XMLTree* t = new XMLTree;
1121 std::string p = Glib::build_filename (ARDOUR::user_config_directory (), "presets");
1122
1123 if (!Glib::file_test (p, Glib::FILE_TEST_IS_DIR)) {
1124 if (g_mkdir_with_parents (p.c_str(), 0755) != 0) {
1125 error << _("Unable to create LuaProc presets directory") << endmsg;
1126 };
1127 }
1128
1129 p = Glib::build_filename (p, presets_file ());
1130
1131 if (!Glib::file_test (p, Glib::FILE_TEST_EXISTS)) {
1132 t->set_root (new XMLNode (X_("LuaPresets")));
1133 return t;
1134 }
1135
1136 t->set_filename (p);
1137 if (!t->read ()) {
1138 delete t;
1139 return 0;
1140 }
1141 return t;
1142 }
1143
1144 bool
load_preset(PresetRecord r)1145 LuaProc::load_preset (PresetRecord r)
1146 {
1147 boost::shared_ptr<XMLTree> t (presets_tree ());
1148 if (t == 0) {
1149 return false;
1150 }
1151
1152 XMLNode* root = t->root ();
1153 for (XMLNodeList::const_iterator i = root->children().begin(); i != root->children().end(); ++i) {
1154 std::string str;
1155 if (!(*i)->get_property (X_("label"), str)) {
1156 assert (false);
1157 }
1158 if (str != r.label) {
1159 continue;
1160 }
1161
1162 for (XMLNodeList::const_iterator j = (*i)->children().begin(); j != (*i)->children().end(); ++j) {
1163 if ((*j)->name() == X_("Parameter")) {
1164 uint32_t index;
1165 float value;
1166 if (!(*j)->get_property (X_("index"), index) ||
1167 !(*j)->get_property (X_("value"), value)) {
1168 assert (false);
1169 continue;
1170 }
1171 set_parameter (index, value, 0);
1172 PresetPortSetValue (index, value); /* EMIT SIGNAL */
1173 }
1174 }
1175 return Plugin::load_preset(r);
1176 }
1177 return false;
1178 }
1179
1180 std::string
do_save_preset(std::string name)1181 LuaProc::do_save_preset (std::string name) {
1182
1183 boost::shared_ptr<XMLTree> t (presets_tree ());
1184 if (t == 0) {
1185 return "";
1186 }
1187
1188 // prevent dups -- just in case
1189 t->root()->remove_nodes_and_delete (X_("label"), name);
1190
1191 std::string uri (preset_name_to_uri (name));
1192
1193 XMLNode* p = new XMLNode (X_("Preset"));
1194 p->set_property (X_("uri"), uri);
1195 p->set_property (X_("label"), name);
1196
1197 for (uint32_t i = 0; i < parameter_count(); ++i) {
1198 if (parameter_is_input (i)) {
1199 XMLNode* c = new XMLNode (X_("Parameter"));
1200 c->set_property (X_("index"), i);
1201 c->set_property (X_("value"), get_parameter (i));
1202 p->add_child_nocopy (*c);
1203 }
1204 }
1205 t->root()->add_child_nocopy (*p);
1206
1207 std::string f = Glib::build_filename (ARDOUR::user_config_directory (), "presets");
1208 f = Glib::build_filename (f, presets_file ());
1209
1210 t->write (f);
1211 return uri;
1212 }
1213
1214 void
do_remove_preset(std::string name)1215 LuaProc::do_remove_preset (std::string name)
1216 {
1217 boost::shared_ptr<XMLTree> t (presets_tree ());
1218 if (t == 0) {
1219 return;
1220 }
1221 t->root()->remove_nodes_and_delete (X_("label"), name);
1222 std::string f = Glib::build_filename (ARDOUR::user_config_directory (), "presets");
1223 f = Glib::build_filename (f, presets_file ());
1224 t->write (f);
1225 }
1226
1227 void
find_presets()1228 LuaProc::find_presets ()
1229 {
1230 boost::shared_ptr<XMLTree> t (presets_tree ());
1231 if (t) {
1232 XMLNode* root = t->root ();
1233 for (XMLNodeList::const_iterator i = root->children().begin(); i != root->children().end(); ++i) {
1234 std::string uri;
1235 std::string label;
1236
1237 if (!(*i)->get_property (X_("uri"), uri) || !(*i)->get_property (X_("label"), label)) {
1238 assert (false);
1239 }
1240
1241 PresetRecord r (uri, label, true);
1242 _presets.insert (make_pair (r.uri, r));
1243 }
1244 }
1245 }
1246
1247 ////////////////////////////////////////////////////////////////////////////////
1248
LuaPluginInfo(LuaScriptInfoPtr lsi)1249 LuaPluginInfo::LuaPluginInfo (LuaScriptInfoPtr lsi) {
1250 if (lsi->type != LuaScriptInfo::DSP) {
1251 throw failed_constructor ();
1252 }
1253
1254 path = lsi->path;
1255 name = lsi->name;
1256 creator = lsi->author;
1257 category = lsi->category;
1258 unique_id = lsi->unique_id;
1259
1260 n_inputs.set (DataType::AUDIO, 1);
1261 n_outputs.set (DataType::AUDIO, 1);
1262 type = Lua;
1263
1264 // TODO, parse script, get 'dsp_ioconfig', see match_variable_io()
1265 _max_outputs = 0;
1266 }
1267
1268 PluginPtr
load(Session & session)1269 LuaPluginInfo::load (Session& session)
1270 {
1271 std::string script = "";
1272 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1273 return PluginPtr ();
1274 }
1275
1276 try {
1277 script = Glib::file_get_contents (path);
1278 } catch (Glib::FileError const& err) {
1279 return PluginPtr ();
1280 }
1281
1282 if (script.empty ()) {
1283 return PluginPtr ();
1284 }
1285
1286 try {
1287 LuaProc* lp = new LuaProc (session.engine (), session, script);
1288 lp->set_origin (path);
1289 PluginPtr plugin (lp);
1290 return plugin;
1291 } catch (failed_constructor& err) {
1292 ;
1293 }
1294 return PluginPtr ();
1295 }
1296
1297 std::vector<Plugin::PresetRecord>
get_presets(bool) const1298 LuaPluginInfo::get_presets (bool /*user_only*/) const
1299 {
1300 std::vector<Plugin::PresetRecord> p;
1301 XMLTree* t = new XMLTree;
1302 std::string pf = Glib::build_filename (ARDOUR::user_config_directory (), "presets", string_compose ("lua-%1", unique_id));
1303 if (Glib::file_test (pf, Glib::FILE_TEST_EXISTS)) {
1304 t->set_filename (pf);
1305 if (t->read ()) {
1306 XMLNode* root = t->root ();
1307 for (XMLNodeList::const_iterator i = root->children().begin(); i != root->children().end(); ++i) {
1308 XMLProperty const * uri = (*i)->property (X_("uri"));
1309 XMLProperty const * label = (*i)->property (X_("label"));
1310 p.push_back (Plugin::PresetRecord (uri->value(), label->value(), true));
1311 }
1312 }
1313 }
1314 delete t;
1315 return p;
1316 }
1317