diff --git a/Makefile b/Makefile index 39a75da..e8e90cb 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ include $(RACK_DIR)/arch.mk DUKTAPE ?= 0 QUICKJS ?= 1 PYTHON ?= 1 +LUA ?= 1 # Entropia File System Watcher efsw := dep/lib/libefsw-static-release.a @@ -97,14 +98,19 @@ $(numpy): $(python) # cd dep/scipy-1.3.1 && "$(DEP_PATH)"/bin/python3.7 setup.py build -j4 install endif -# # LuaJIT -# luajit := dep/lib/luajit.a -# DEPS += $(luajit) -# $(luajit): -# cd dep && $(WGET) "http://luajit.org/download/LuaJIT-2.0.5.tar.gz" -# cd dep && $(SHA256) LuaJIT-2.0.5.tar.gz 874b1f8297c697821f561f9b73b57ffd419ed8f4278c82e05b48806d30c1e979 -# cd dep && $(UNTAR) LuaJIT-2.0.5.tar.gz -# cd dep/LuaJIT-2.0.5 && $(MAKE) +# LuaJIT +ifeq ($(LUA), 1) +SOURCES += src/LuaJITEngine.cpp +luajit := dep/lib/libluajit-5.1.a +OBJECTS += $(luajit) +DEPS += $(luajit) +$(luajit): + $(WGET) "http://luajit.org/download/LuaJIT-2.0.5.tar.gz" + $(SHA256) LuaJIT-2.0.5.tar.gz 874b1f8297c697821f561f9b73b57ffd419ed8f4278c82e05b48806d30c1e979 + cd dep && $(UNTAR) ../LuaJIT-2.0.5.tar.gz + cd dep/LuaJIT-2.0.5 && $(MAKE) + cd dep/LuaJIT-2.0.5 && $(MAKE) PREFIX="$(DEP_PATH)" install +endif # # Julia # julia := dep/lib/libjulia.a diff --git a/README.md b/README.md index 56ad451..98abe8c 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,6 @@ sudo pacman -S premake ## Contributors - [Wes Milholen](https://grayscale.info/): panel design -- [Andrew Belt](https://github.com/AndrewBelt): host code, Duktape (JavaScript) +- [Andrew Belt](https://github.com/AndrewBelt): host code, Duktape (JavaScript), LuaJIT (in development), Python (in development) - [Jerry Sievert](https://github.com/JerrySievert): QuickJS (JavaScript) - add your name here diff --git a/examples/gain.js b/examples/gain.js index da3f890..4579053 100644 --- a/examples/gain.js +++ b/examples/gain.js @@ -3,13 +3,13 @@ function process(block) { // Loop through each column - for (var i = 0; i < 6; i++) { + for (let i = 0; i < 6; i++) { // Get input - var x = block.inputs[i][0] + let x = block.inputs[i][0] // Get gain knob - var gain = block.knobs[i] + let gain = block.knobs[i] // Apply gain to input - var y = x * gain + let y = x * gain // Set gain light (red = 0) block.lights[i][0] = gain // Check mute switch diff --git a/examples/gain.lua b/examples/gain.lua new file mode 100644 index 0000000..20bb43e --- /dev/null +++ b/examples/gain.lua @@ -0,0 +1,28 @@ +-- Simplest possible script using all variables +-- by Andrew Belt + +function process(block) + -- Loop through each column + for i=1,6 do + -- Get input + x = block.inputs[i][1] + -- Get gain knob + gain = block.knobs[i] + -- Apply gain to input + y = x * gain + -- Set gain light (red = 0) + block.lights[i][1] = gain + -- Check mute switch + if block.switches[i] then + -- Mute output + y = 0 + -- Enable mute light (red = 0) + block.switchLights[i][1] = 1 + else + -- Disable mute light + block.switchLights[i][1] = 0 + end + -- Set output + block.outputs[i][1] = y + end +end diff --git a/examples/rainbow.lua b/examples/rainbow.lua new file mode 100644 index 0000000..db8eadd --- /dev/null +++ b/examples/rainbow.lua @@ -0,0 +1,44 @@ +-- Rainbow RGB LED example +-- by Andrew Belt + +-- Call process() every 256 audio samples +config.frameDivider = 256 + + +-- From https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB +function hsvToRgb(h, s, v) + h = h * 6 + c = v * s + x = c * (1 - math.abs(h % 2 - 1)) + if (h < 1) then rgb = {c, x, 0} + elseif (h < 2) then rgb = {x, c, 0} + elseif (h < 3) then rgb = {0, c, x} + elseif (h < 4) then rgb = {0, x, c} + elseif (h < 5) then rgb = {x, 0, c} + else rgb = {c, 0, x} + end + m = v - c + rgb[1] = rgb[1] + m + rgb[2] = rgb[2] + m + rgb[3] = rgb[3] + m + return rgb +end + + +phase = 0 +function process(block) + phase = phase + block.sampleTime * config.frameDivider * 0.5 + phase = phase % 1 + + for i=1,6 do + h = (1 - i / 6 + phase) % 1 + rgb = hsvToRgb(h, 1, 1) + for c=1,3 do + block.lights[i][c] = rgb[c] + block.switchLights[i][c] = rgb[c] + end + block.outputs[i][1] = math.sin(2 * math.pi * h) * 5 + 5 + end +end + +display("Hello, world!") diff --git a/src/DuktapeEngine.cpp b/src/DuktapeEngine.cpp index 7cea986..47eaab8 100644 --- a/src/DuktapeEngine.cpp +++ b/src/DuktapeEngine.cpp @@ -16,17 +16,19 @@ struct DuktapeEngine : ScriptEngine { int run(const std::string& path, const std::string& script) override { assert(!ctx); + ProcessBlock* block = getProcessBlock(); + // Create duktape context ctx = duk_create_heap_default(); if (!ctx) { - setMessage("Could not create duktape context"); + display("Could not create duktape context"); return -1; } // Initialize globals // user pointer duk_push_pointer(ctx, this); - duk_put_global_string(ctx, DUK_HIDDEN_SYMBOL("p")); + duk_put_global_string(ctx, DUK_HIDDEN_SYMBOL("engine")); // console duk_idx_t consoleIdx = duk_push_object(ctx); @@ -34,15 +36,6 @@ struct DuktapeEngine : ScriptEngine { // log duk_push_c_function(ctx, native_console_log, 1); duk_put_prop_string(ctx, consoleIdx, "log"); - // info (alias for log) - duk_push_c_function(ctx, native_console_log, 1); - duk_put_prop_string(ctx, consoleIdx, "info"); - // debug - duk_push_c_function(ctx, native_console_debug, 1); - duk_put_prop_string(ctx, consoleIdx, "debug"); - // warn - duk_push_c_function(ctx, native_console_warn, 1); - duk_put_prop_string(ctx, consoleIdx, "warn"); } duk_put_global_string(ctx, "console"); @@ -67,7 +60,7 @@ struct DuktapeEngine : ScriptEngine { if (duk_pcompile_lstring_filename(ctx, 0, script.c_str(), script.size()) != 0) { const char* s = duk_safe_to_string(ctx, -1); WARN("duktape: %s", s); - setMessage(s); + display(s); duk_pop(ctx); return -1; } @@ -75,7 +68,7 @@ struct DuktapeEngine : ScriptEngine { if (duk_pcall(ctx, 0)) { const char* s = duk_safe_to_string(ctx, -1); WARN("duktape: %s", s); - setMessage(s); + display(s); duk_pop(ctx); return -1; } @@ -91,7 +84,7 @@ struct DuktapeEngine : ScriptEngine { duk_pop(ctx); // bufferSize duk_get_prop_string(ctx, -1, "bufferSize"); - block->bufferSize = duk_get_int(ctx, -1); + setBufferSize(duk_get_int(ctx, -1)); duk_pop(ctx); } duk_pop(ctx); @@ -99,7 +92,7 @@ struct DuktapeEngine : ScriptEngine { // Keep process function on stack for faster calling duk_get_global_string(ctx, "process"); if (!duk_is_function(ctx, -1)) { - setMessage("No process() function"); + display("No process() function"); return -1; } @@ -170,6 +163,7 @@ struct DuktapeEngine : ScriptEngine { int process() override { // block + ProcessBlock* block = getProcessBlock(); duk_idx_t blockIdx = duk_get_top(ctx) - 1; { // sampleRate @@ -193,7 +187,7 @@ struct DuktapeEngine : ScriptEngine { if (duk_pcall(ctx, 1)) { const char* s = duk_safe_to_string(ctx, -1); WARN("duktape: %s", s); - setMessage(s); + display(s); duk_pop(ctx); return -1; } @@ -204,7 +198,7 @@ struct DuktapeEngine : ScriptEngine { } static DuktapeEngine* getDuktapeEngine(duk_context* ctx) { - duk_get_global_string(ctx, DUK_HIDDEN_SYMBOL("p")); + duk_get_global_string(ctx, DUK_HIDDEN_SYMBOL("engine")); DuktapeEngine* engine = (DuktapeEngine*) duk_get_pointer(ctx, -1); duk_pop(ctx); return engine; @@ -212,22 +206,12 @@ struct DuktapeEngine : ScriptEngine { static duk_ret_t native_console_log(duk_context* ctx) { const char* s = duk_safe_to_string(ctx, -1); - INFO("VCV Prototype: %s", s); - return 0; - } - static duk_ret_t native_console_debug(duk_context* ctx) { - const char* s = duk_safe_to_string(ctx, -1); - DEBUG("VCV Prototype: %s", s); - return 0; - } - static duk_ret_t native_console_warn(duk_context* ctx) { - const char* s = duk_safe_to_string(ctx, -1); - WARN("VCV Prototype: %s", s); + INFO("Duktape: %s", s); return 0; } static duk_ret_t native_display(duk_context* ctx) { const char* s = duk_safe_to_string(ctx, -1); - getDuktapeEngine(ctx)->setMessage(s); + getDuktapeEngine(ctx)->display(s); return 0; } }; diff --git a/src/LuaJITEngine.cpp b/src/LuaJITEngine.cpp new file mode 100644 index 0000000..81016b8 --- /dev/null +++ b/src/LuaJITEngine.cpp @@ -0,0 +1,300 @@ +#include "ScriptEngine.hpp" +#include + + +struct LuaJITEngine : ScriptEngine { + lua_State* L = NULL; + + ~LuaJITEngine() { + if (L) + lua_close(L); + } + + std::string getEngineName() override { + return "Lua"; + } + + int run(const std::string& path, const std::string& script) override { + ProcessBlock* block = getProcessBlock(); + + L = luaL_newstate(); + if (!L) { + display("Could not create LuaJIT context"); + return -1; + } + + // Import a subset of the standard library + luaopen_base(L); + luaopen_string(L); + luaopen_table(L); + luaopen_math(L); + + // Set user pointer + lua_pushlightuserdata(L, this); + lua_setglobal(L, "_engine"); + + // Set global functions + lua_pushcfunction(L, native_print); + lua_setglobal(L, "print"); + + lua_pushcfunction(L, native_display); + lua_setglobal(L, "display"); + + // Set config + lua_newtable(L); + { + // frameDivider + lua_pushinteger(L, 32); + lua_setfield(L, -2, "frameDivider"); + // bufferSize + lua_pushinteger(L, 1); + lua_setfield(L, -2, "bufferSize"); + } + lua_setglobal(L, "config"); + + // Compile script + if (luaL_loadbuffer(L, script.c_str(), script.size(), path.c_str())) { + const char* s = lua_tostring(L, -1); + WARN("LuaJIT: %s", s); + display(s); + lua_pop(L, 1); + return -1; + } + + // Run script + if (lua_pcall(L, 0, 0, 0)) { + const char* s = lua_tostring(L, -1); + WARN("LuaJIT: %s", s); + display(s); + lua_pop(L, 1); + return -1; + } + + // Get config + lua_getglobal(L, "config"); + { + // frameDivider + lua_getfield(L, -1, "frameDivider"); + int frameDivider = lua_tointeger(L, -1); + setFrameDivider(frameDivider); + lua_pop(L, 1); + // bufferSize + lua_getfield(L, -1, "bufferSize"); + int bufferSize = lua_tointeger(L, -1); + setBufferSize(bufferSize); + lua_pop(L, 1); + } + lua_pop(L, 1); + + // Get process function + lua_getglobal(L, "process"); + if (!lua_isfunction(L, -1)) { + display("No process() function"); + return -1; + } + + // Create block object + lua_newtable(L); + { + // inputs + lua_newtable(L); + for (int i = 0; i < NUM_ROWS; i++) { + lua_newtable(L); + for (int j = 0; j < block->bufferSize; j++) { + lua_pushnumber(L, 0.0); + lua_rawseti(L, -2, j + 1); + } + lua_rawseti(L, -2, i + 1); + } + lua_setfield(L, -2, "inputs"); + // outputs + lua_newtable(L); + for (int i = 0; i < NUM_ROWS; i++) { + lua_newtable(L); + for (int j = 0; j < block->bufferSize; j++) { + lua_pushnumber(L, 0.0); + lua_rawseti(L, -2, j + 1); + } + lua_rawseti(L, -2, i + 1); + } + lua_setfield(L, -2, "outputs"); + // knobs + lua_newtable(L); + for (int i = 0; i < NUM_ROWS; i++) { + lua_pushnumber(L, 0.0); + lua_rawseti(L, -2, i + 1); + } + lua_setfield(L, -2, "knobs"); + // switches + lua_newtable(L); + for (int i = 0; i < NUM_ROWS; i++) { + lua_pushboolean(L, false); + lua_rawseti(L, -2, i + 1); + } + lua_setfield(L, -2, "switches"); + // lights + lua_newtable(L); + for (int i = 0; i < NUM_ROWS; i++) { + lua_newtable(L); + for (int c = 0; c < 3; c++) { + lua_pushnumber(L, 0.0); + lua_rawseti(L, -2, c + 1); + } + lua_rawseti(L, -2, i + 1); + } + lua_setfield(L, -2, "lights"); + // switchLights + lua_newtable(L); + for (int i = 0; i < NUM_ROWS; i++) { + lua_newtable(L); + for (int c = 0; c < 3; c++) { + lua_pushnumber(L, 0.0); + lua_rawseti(L, -2, c + 1); + } + lua_rawseti(L, -2, i + 1); + } + lua_setfield(L, -2, "switchLights"); + } + + return 0; + } + + int process() override { + ProcessBlock* block = getProcessBlock(); + + // Set block + { + // sampleRate + lua_pushnumber(L, block->sampleRate); + lua_setfield(L, -2, "sampleRate"); + + // sampleTime + lua_pushnumber(L, block->sampleTime); + lua_setfield(L, -2, "sampleTime"); + + // bufferSize + lua_pushinteger(L, block->bufferSize); + lua_setfield(L, -2, "bufferSize"); + + // inputs + lua_getfield(L, -1, "inputs"); + for (int i = 0; i < NUM_ROWS; i++) { + lua_rawgeti(L, -1, i + 1); + for (int j = 0; j < block->bufferSize; j++) { + lua_pushnumber(L, block->inputs[i][j]); + lua_rawseti(L, -2, j + 1); + } + lua_pop(L, 1); + } + lua_pop(L, 1); + // knobs + lua_getfield(L, -1, "knobs"); + for (int i = 0; i < NUM_ROWS; i++) { + lua_pushnumber(L, block->knobs[i]); + lua_rawseti(L, -2, i + 1); + } + lua_pop(L, 1); + // switches + lua_getfield(L, -1, "switches"); + for (int i = 0; i < NUM_ROWS; i++) { + lua_pushboolean(L, block->switches[i]); + lua_rawseti(L, -2, i + 1); + } + lua_pop(L, 1); + } + + // Duplicate process function + lua_pushvalue(L, -2); + // Duplicate block + lua_pushvalue(L, -2); + // Call process function + if (lua_pcall(L, 1, 0, 0)) { + const char* err = lua_tostring(L, -1); + WARN("LuaJIT: %s", err); + display(err); + return -1; + } + + // Get block + { + // outputs + lua_getfield(L, -1, "outputs"); + for (int i = 0; i < NUM_ROWS; i++) { + lua_rawgeti(L, -1, i + 1); + for (int j = 0; j < block->bufferSize; j++) { + lua_rawgeti(L, -1, j + 1); + block->outputs[i][j] = lua_tonumber(L, -1); + lua_pop(L, 1); + } + lua_pop(L, 1); + } + lua_pop(L, 1); + // knobs + lua_getfield(L, -1, "knobs"); + for (int i = 0; i < NUM_ROWS; i++) { + lua_rawgeti(L, -1, i + 1); + block->knobs[i] = lua_tonumber(L, -1); + lua_pop(L, 1); + } + lua_pop(L, 1); + // lights + lua_getfield(L, -1, "lights"); + for (int i = 0; i < NUM_ROWS; i++) { + lua_rawgeti(L, -1, i + 1); + for (int c = 0; c < 3; c++) { + lua_rawgeti(L, -1, c + 1); + block->lights[i][c] = lua_tonumber(L, -1); + lua_pop(L, 1); + } + lua_pop(L, 1); + } + lua_pop(L, 1); + // switchLights + lua_getfield(L, -1, "switchLights"); + for (int i = 0; i < NUM_ROWS; i++) { + lua_rawgeti(L, -1, i + 1); + for (int c = 0; c < 3; c++) { + lua_rawgeti(L, -1, c + 1); + block->switchLights[i][c] = lua_tonumber(L, -1); + lua_pop(L, 1); + } + lua_pop(L, 1); + } + lua_pop(L, 1); + } + + return 0; + } + + static LuaJITEngine* getEngine(lua_State* L) { + lua_getglobal(L, "_engine"); + LuaJITEngine* engine = (LuaJITEngine*) lua_touserdata(L, -1); + lua_pop(L, 1); + return engine; + } + + static int native_print(lua_State* L) { + lua_getglobal(L, "tostring"); + lua_pushvalue(L, 1); + lua_call(L, 1, 1); + const char* s = lua_tostring(L, 1); + INFO("LuaJIT: %s", s); + return 0; + } + + static int native_display(lua_State* L) { + lua_getglobal(L, "tostring"); + lua_pushvalue(L, 1); + lua_call(L, 1, 1); + const char* s = lua_tostring(L, -1); + if (!s) + s = "(null)"; + getEngine(L)->display(s); + return 0; + } +}; + + +ScriptEngine* createLuaJITEngine() { + return new LuaJITEngine; +} \ No newline at end of file diff --git a/src/Prototype.cpp b/src/Prototype.cpp index 720eeae..c7752e9 100644 --- a/src/Prototype.cpp +++ b/src/Prototype.cpp @@ -41,7 +41,7 @@ struct Prototype : Module { ScriptEngine* scriptEngine = NULL; int frame = 0; int frameDivider; - ScriptEngine::ProcessBlock* block; + ProcessBlock* block; int bufferIndex = 0; efsw_watcher efsw = NULL; @@ -53,7 +53,7 @@ struct Prototype : Module { for (int i = 0; i < NUM_ROWS; i++) configParam(SWITCH_PARAMS + i, 0.f, 1.f, 0.f, string::f("Switch %d", i + 1)); - block = new ScriptEngine::ProcessBlock; + block = new ProcessBlock; setPath(""); } @@ -179,7 +179,7 @@ struct Prototype : Module { // Reset process state frameDivider = 32; frame = 0; - *block = ScriptEngine::ProcessBlock(); + *block = ProcessBlock(); bufferIndex = 0; // Reset outputs and lights because they might hold old values for (int i = 0; i < NUM_ROWS; i++) @@ -203,7 +203,6 @@ struct Prototype : Module { return; } scriptEngine->module = this; - scriptEngine->block = block; // Run script if (scriptEngine->run(path, script)) { @@ -212,7 +211,6 @@ struct Prototype : Module { scriptEngine = NULL; return; } - block->bufferSize = clamp(block->bufferSize, 1, MAX_BUFFER_SIZE); this->engineName = scriptEngine->getEngineName(); } @@ -296,12 +294,19 @@ struct Prototype : Module { }; -void ScriptEngine::setMessage(const std::string& message) { +void ScriptEngine::display(const std::string& message) { module->message = message; } void ScriptEngine::setFrameDivider(int frameDivider) { module->frameDivider = frameDivider; } +void ScriptEngine::setBufferSize(int bufferSize) { + bufferSize = clamp(bufferSize, 1, MAX_BUFFER_SIZE); + module->block->bufferSize = bufferSize; +} +ProcessBlock* ScriptEngine::getProcessBlock() { + return module->block; +} struct FileChoice : LedDisplayChoice { diff --git a/src/PythonEngine.cpp b/src/PythonEngine.cpp index 31f0af1..2c85384 100644 --- a/src/PythonEngine.cpp +++ b/src/PythonEngine.cpp @@ -103,6 +103,7 @@ struct PythonEngine : ScriptEngine { DEFER({Py_DECREF(result);}); // Create block + ProcessBlock* block = getProcessBlock(); static PyStructSequence_Field blockFields[] = { {"inputs", ""}, {"outputs", ""}, @@ -154,11 +155,11 @@ struct PythonEngine : ScriptEngine { // Get process function from globals processFunc = PyDict_GetItemString(mainDict, "process"); if (!processFunc) { - setMessage("No process() function"); + display("No process() function"); return -1; } if (!PyCallable_Check(processFunc)) { - setMessage("process() is not callable"); + display("process() is not callable"); return -1; } @@ -181,7 +182,7 @@ struct PythonEngine : ScriptEngine { // if (!str) // return -1; - // setMessage(str); + // display(str); return -1; } DEFER({Py_DECREF(processResult);}); @@ -209,7 +210,7 @@ struct PythonEngine : ScriptEngine { DEFER({Py_DECREF(msgS);}); const char* msg = PyUnicode_AsUTF8(msgS); - that->setMessage(msg); + that->display(msg); Py_INCREF(Py_None); return Py_None; diff --git a/src/QuickJSEngine.cpp b/src/QuickJSEngine.cpp index c2b4835..1e0d3d2 100644 --- a/src/QuickJSEngine.cpp +++ b/src/QuickJSEngine.cpp @@ -65,7 +65,7 @@ struct QuickJSEngine : ScriptEngine { // Create quickjs context ctx = JS_NewContext(rt); if (!ctx) { - setMessage("Could not create QuickJS context"); + display("Could not create QuickJS context"); return -1; } @@ -107,13 +107,14 @@ struct QuickJSEngine : ScriptEngine { // Compile string JSValue val = JS_Eval(ctx, script.c_str(), script.size(), path.c_str(), 0); if (JS_IsException(val)) { - setMessage(ErrorToString(ctx)); + display(ErrorToString(ctx)); JS_FreeValue(ctx, val); JS_FreeValue(ctx, global_obj); return -1; } + ProcessBlock* block = getProcessBlock(); // config: Read values config = JS_GetPropertyStr(ctx, global_obj, "config"); { @@ -128,7 +129,7 @@ struct QuickJSEngine : ScriptEngine { JSValue buffer = JS_GetPropertyStr(ctx, config, "bufferSize"); int32_t bufferValue; if (JS_ToInt32(ctx, &bufferValue, buffer) == 0) { - block->bufferSize = bufferValue; + setBufferSize(bufferValue); } JS_FreeValue(ctx, config); @@ -204,7 +205,7 @@ struct QuickJSEngine : ScriptEngine { if (JS_IsException(hack)) { std::string errorString = ErrorToString(ctx); WARN("QuickJS: %s", errorString.c_str()); - setMessage(errorString.c_str()); + display(errorString.c_str()); } JS_FreeValue(ctx, hack); @@ -215,7 +216,7 @@ struct QuickJSEngine : ScriptEngine { if (JS_IsException(val)) { std::string errorString = ErrorToString(ctx); WARN("QuickJS: %s", errorString.c_str()); - setMessage(errorString.c_str()); + display(errorString.c_str()); JS_FreeValue(ctx, val); JS_FreeValue(ctx, blockIdx); @@ -232,6 +233,7 @@ struct QuickJSEngine : ScriptEngine { JSValue global_obj = JS_GetGlobalObject(ctx); // block + ProcessBlock* block = getProcessBlock(); JSValue blockIdx = JS_GetPropertyStr(ctx, global_obj, "block"); { // sampleRate @@ -254,7 +256,7 @@ struct QuickJSEngine : ScriptEngine { if (JS_IsException(val)) { std::string errorString = ErrorToString(ctx); WARN("QuickJS: %s", errorString.c_str()); - setMessage(errorString.c_str()); + display(errorString.c_str()); JS_FreeValue(ctx, val); JS_FreeValue(ctx, process); @@ -286,7 +288,7 @@ struct QuickJSEngine : ScriptEngine { int argc, JSValueConst *argv) { if (argc) { const char *s = JS_ToCString(ctx, argv[0]); - INFO("VCV Prototype: %s", s); + INFO("QuickJS: %s", s); } return JS_UNDEFINED; } @@ -294,7 +296,7 @@ struct QuickJSEngine : ScriptEngine { int argc, JSValueConst *argv) { if (argc) { const char *s = JS_ToCString(ctx, argv[0]); - DEBUG("VCV Prototype: %s", s); + DEBUG("QuickJS: %s", s); } return JS_UNDEFINED; } @@ -302,7 +304,7 @@ struct QuickJSEngine : ScriptEngine { int argc, JSValueConst *argv) { if (argc) { const char *s = JS_ToCString(ctx, argv[0]); - INFO("VCV Prototype: %s", s); + INFO("QuickJS: %s", s); } return JS_UNDEFINED; } @@ -310,7 +312,7 @@ struct QuickJSEngine : ScriptEngine { int argc, JSValueConst *argv) { if (argc) { const char *s = JS_ToCString(ctx, argv[0]); - WARN("VCV Prototype: %s", s); + WARN("QuickJS: %s", s); } return JS_UNDEFINED; } @@ -318,7 +320,7 @@ struct QuickJSEngine : ScriptEngine { int argc, JSValueConst *argv) { if (argc) { const char *s = JS_ToCString(ctx, argv[0]); - getQuickJSEngine(ctx)->setMessage(s); + getQuickJSEngine(ctx)->display(s); } return JS_UNDEFINED; } diff --git a/src/ScriptEngine.hpp b/src/ScriptEngine.hpp index f809829..a2c67a9 100644 --- a/src/ScriptEngine.hpp +++ b/src/ScriptEngine.hpp @@ -9,21 +9,20 @@ static const int MAX_BUFFER_SIZE = 4096; struct Prototype; -struct ScriptEngine { - struct ProcessBlock { - float sampleRate = 0.f; - float sampleTime = 0.f; - int bufferSize = 1; - float inputs[NUM_ROWS][MAX_BUFFER_SIZE] = {}; - float outputs[NUM_ROWS][MAX_BUFFER_SIZE] = {}; - float knobs[NUM_ROWS] = {}; - bool switches[NUM_ROWS] = {}; - float lights[NUM_ROWS][3] = {}; - float switchLights[NUM_ROWS][3] = {}; - }; - /** Set by module */ - ProcessBlock* block = NULL; +struct ProcessBlock { + float sampleRate = 0.f; + float sampleTime = 0.f; + int bufferSize = 1; + float inputs[NUM_ROWS][MAX_BUFFER_SIZE] = {}; + float outputs[NUM_ROWS][MAX_BUFFER_SIZE] = {}; + float knobs[NUM_ROWS] = {}; + bool switches[NUM_ROWS] = {}; + float lights[NUM_ROWS][3] = {}; + float switchLights[NUM_ROWS][3] = {}; +}; + +struct ScriptEngine { // Virtual methods for subclasses virtual ~ScriptEngine() {} virtual std::string getEngineName() {return "";} @@ -40,8 +39,10 @@ struct ScriptEngine { // Communication with Prototype module. // These cannot be called from your constructor, so initialize your engine in the run() method. - void setMessage(const std::string& message); + void display(const std::string& message); void setFrameDivider(int frameDivider); + void setBufferSize(int bufferSize); + ProcessBlock* getProcessBlock(); // private Prototype* module = NULL; }; @@ -53,11 +54,14 @@ struct ScriptEngine { ScriptEngine* createDuktapeEngine(); ScriptEngine* createQuickJSEngine(); ScriptEngine* createPythonEngine(); +ScriptEngine* createLuaJITEngine(); inline ScriptEngine* createScriptEngine(std::string ext) { ext = rack::string::lowercase(ext); if (ext == "js") return createQuickJSEngine(); + else if (ext == "lua") + return createLuaJITEngine(); else if (ext == "py") return createPythonEngine(); // Add your file extension check here. diff --git a/tests/hello.lua b/tests/hello.lua new file mode 100644 index 0000000..4d5eedc --- /dev/null +++ b/tests/hello.lua @@ -0,0 +1,11 @@ + +config.frameDivider = 1 +config.bufferSize = 16 + +function process(block) + for j=1,block.bufferSize do + block.outputs[1][j] = math.random() + end +end + +print("Hello, world!")