Browse Source

Add LuaJITEngine

tags/v1.3.0
Andrew Belt 5 years ago
parent
commit
4689631454
12 changed files with 463 additions and 78 deletions
  1. +14
    -8
      Makefile
  2. +1
    -1
      README.md
  3. +4
    -4
      examples/gain.js
  4. +28
    -0
      examples/gain.lua
  5. +44
    -0
      examples/rainbow.lua
  6. +13
    -29
      src/DuktapeEngine.cpp
  7. +300
    -0
      src/LuaJITEngine.cpp
  8. +11
    -6
      src/Prototype.cpp
  9. +5
    -4
      src/PythonEngine.cpp
  10. +13
    -11
      src/QuickJSEngine.cpp
  11. +19
    -15
      src/ScriptEngine.hpp
  12. +11
    -0
      tests/hello.lua

+ 14
- 8
Makefile View File

@@ -16,6 +16,7 @@ include $(RACK_DIR)/arch.mk
DUKTAPE ?= 0 DUKTAPE ?= 0
QUICKJS ?= 1 QUICKJS ?= 1
PYTHON ?= 1 PYTHON ?= 1
LUA ?= 1


# Entropia File System Watcher # Entropia File System Watcher
efsw := dep/lib/libefsw-static-release.a 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 # cd dep/scipy-1.3.1 && "$(DEP_PATH)"/bin/python3.7 setup.py build -j4 install
endif 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
# julia := dep/lib/libjulia.a # julia := dep/lib/libjulia.a


+ 1
- 1
README.md View File

@@ -124,6 +124,6 @@ sudo pacman -S premake
## Contributors ## Contributors


- [Wes Milholen](https://grayscale.info/): panel design - [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) - [Jerry Sievert](https://github.com/JerrySievert): QuickJS (JavaScript)
- add your name here - add your name here

+ 4
- 4
examples/gain.js View File

@@ -3,13 +3,13 @@


function process(block) { function process(block) {
// Loop through each column // Loop through each column
for (var i = 0; i < 6; i++) {
for (let i = 0; i < 6; i++) {
// Get input // Get input
var x = block.inputs[i][0]
let x = block.inputs[i][0]
// Get gain knob // Get gain knob
var gain = block.knobs[i]
let gain = block.knobs[i]
// Apply gain to input // Apply gain to input
var y = x * gain
let y = x * gain
// Set gain light (red = 0) // Set gain light (red = 0)
block.lights[i][0] = gain block.lights[i][0] = gain
// Check mute switch // Check mute switch


+ 28
- 0
examples/gain.lua View File

@@ -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

+ 44
- 0
examples/rainbow.lua View File

@@ -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!")

+ 13
- 29
src/DuktapeEngine.cpp View File

@@ -16,17 +16,19 @@ struct DuktapeEngine : ScriptEngine {


int run(const std::string& path, const std::string& script) override { int run(const std::string& path, const std::string& script) override {
assert(!ctx); assert(!ctx);
ProcessBlock* block = getProcessBlock();

// Create duktape context // Create duktape context
ctx = duk_create_heap_default(); ctx = duk_create_heap_default();
if (!ctx) { if (!ctx) {
setMessage("Could not create duktape context");
display("Could not create duktape context");
return -1; return -1;
} }


// Initialize globals // Initialize globals
// user pointer // user pointer
duk_push_pointer(ctx, this); duk_push_pointer(ctx, this);
duk_put_global_string(ctx, DUK_HIDDEN_SYMBOL("p"));
duk_put_global_string(ctx, DUK_HIDDEN_SYMBOL("engine"));


// console // console
duk_idx_t consoleIdx = duk_push_object(ctx); duk_idx_t consoleIdx = duk_push_object(ctx);
@@ -34,15 +36,6 @@ struct DuktapeEngine : ScriptEngine {
// log // log
duk_push_c_function(ctx, native_console_log, 1); duk_push_c_function(ctx, native_console_log, 1);
duk_put_prop_string(ctx, consoleIdx, "log"); 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"); 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) { if (duk_pcompile_lstring_filename(ctx, 0, script.c_str(), script.size()) != 0) {
const char* s = duk_safe_to_string(ctx, -1); const char* s = duk_safe_to_string(ctx, -1);
WARN("duktape: %s", s); WARN("duktape: %s", s);
setMessage(s);
display(s);
duk_pop(ctx); duk_pop(ctx);
return -1; return -1;
} }
@@ -75,7 +68,7 @@ struct DuktapeEngine : ScriptEngine {
if (duk_pcall(ctx, 0)) { if (duk_pcall(ctx, 0)) {
const char* s = duk_safe_to_string(ctx, -1); const char* s = duk_safe_to_string(ctx, -1);
WARN("duktape: %s", s); WARN("duktape: %s", s);
setMessage(s);
display(s);
duk_pop(ctx); duk_pop(ctx);
return -1; return -1;
} }
@@ -91,7 +84,7 @@ struct DuktapeEngine : ScriptEngine {
duk_pop(ctx); duk_pop(ctx);
// bufferSize // bufferSize
duk_get_prop_string(ctx, -1, "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);
} }
duk_pop(ctx); duk_pop(ctx);
@@ -99,7 +92,7 @@ struct DuktapeEngine : ScriptEngine {
// Keep process function on stack for faster calling // Keep process function on stack for faster calling
duk_get_global_string(ctx, "process"); duk_get_global_string(ctx, "process");
if (!duk_is_function(ctx, -1)) { if (!duk_is_function(ctx, -1)) {
setMessage("No process() function");
display("No process() function");
return -1; return -1;
} }


@@ -170,6 +163,7 @@ struct DuktapeEngine : ScriptEngine {


int process() override { int process() override {
// block // block
ProcessBlock* block = getProcessBlock();
duk_idx_t blockIdx = duk_get_top(ctx) - 1; duk_idx_t blockIdx = duk_get_top(ctx) - 1;
{ {
// sampleRate // sampleRate
@@ -193,7 +187,7 @@ struct DuktapeEngine : ScriptEngine {
if (duk_pcall(ctx, 1)) { if (duk_pcall(ctx, 1)) {
const char* s = duk_safe_to_string(ctx, -1); const char* s = duk_safe_to_string(ctx, -1);
WARN("duktape: %s", s); WARN("duktape: %s", s);
setMessage(s);
display(s);
duk_pop(ctx); duk_pop(ctx);
return -1; return -1;
} }
@@ -204,7 +198,7 @@ struct DuktapeEngine : ScriptEngine {
} }


static DuktapeEngine* getDuktapeEngine(duk_context* ctx) { 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); DuktapeEngine* engine = (DuktapeEngine*) duk_get_pointer(ctx, -1);
duk_pop(ctx); duk_pop(ctx);
return engine; return engine;
@@ -212,22 +206,12 @@ struct DuktapeEngine : ScriptEngine {


static duk_ret_t native_console_log(duk_context* ctx) { static duk_ret_t native_console_log(duk_context* ctx) {
const char* s = duk_safe_to_string(ctx, -1); 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; return 0;
} }
static duk_ret_t native_display(duk_context* ctx) { static duk_ret_t native_display(duk_context* ctx) {
const char* s = duk_safe_to_string(ctx, -1); const char* s = duk_safe_to_string(ctx, -1);
getDuktapeEngine(ctx)->setMessage(s);
getDuktapeEngine(ctx)->display(s);
return 0; return 0;
} }
}; };


+ 300
- 0
src/LuaJITEngine.cpp View File

@@ -0,0 +1,300 @@
#include "ScriptEngine.hpp"
#include <luajit-2.0/lua.hpp>


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;
}

+ 11
- 6
src/Prototype.cpp View File

@@ -41,7 +41,7 @@ struct Prototype : Module {
ScriptEngine* scriptEngine = NULL; ScriptEngine* scriptEngine = NULL;
int frame = 0; int frame = 0;
int frameDivider; int frameDivider;
ScriptEngine::ProcessBlock* block;
ProcessBlock* block;
int bufferIndex = 0; int bufferIndex = 0;


efsw_watcher efsw = NULL; efsw_watcher efsw = NULL;
@@ -53,7 +53,7 @@ struct Prototype : Module {
for (int i = 0; i < NUM_ROWS; i++) for (int i = 0; i < NUM_ROWS; i++)
configParam(SWITCH_PARAMS + i, 0.f, 1.f, 0.f, string::f("Switch %d", i + 1)); configParam(SWITCH_PARAMS + i, 0.f, 1.f, 0.f, string::f("Switch %d", i + 1));


block = new ScriptEngine::ProcessBlock;
block = new ProcessBlock;
setPath(""); setPath("");
} }


@@ -179,7 +179,7 @@ struct Prototype : Module {
// Reset process state // Reset process state
frameDivider = 32; frameDivider = 32;
frame = 0; frame = 0;
*block = ScriptEngine::ProcessBlock();
*block = ProcessBlock();
bufferIndex = 0; bufferIndex = 0;
// Reset outputs and lights because they might hold old values // Reset outputs and lights because they might hold old values
for (int i = 0; i < NUM_ROWS; i++) for (int i = 0; i < NUM_ROWS; i++)
@@ -203,7 +203,6 @@ struct Prototype : Module {
return; return;
} }
scriptEngine->module = this; scriptEngine->module = this;
scriptEngine->block = block;


// Run script // Run script
if (scriptEngine->run(path, script)) { if (scriptEngine->run(path, script)) {
@@ -212,7 +211,6 @@ struct Prototype : Module {
scriptEngine = NULL; scriptEngine = NULL;
return; return;
} }
block->bufferSize = clamp(block->bufferSize, 1, MAX_BUFFER_SIZE);
this->engineName = scriptEngine->getEngineName(); 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; module->message = message;
} }
void ScriptEngine::setFrameDivider(int frameDivider) { void ScriptEngine::setFrameDivider(int frameDivider) {
module->frameDivider = 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 { struct FileChoice : LedDisplayChoice {


+ 5
- 4
src/PythonEngine.cpp View File

@@ -103,6 +103,7 @@ struct PythonEngine : ScriptEngine {
DEFER({Py_DECREF(result);}); DEFER({Py_DECREF(result);});


// Create block // Create block
ProcessBlock* block = getProcessBlock();
static PyStructSequence_Field blockFields[] = { static PyStructSequence_Field blockFields[] = {
{"inputs", ""}, {"inputs", ""},
{"outputs", ""}, {"outputs", ""},
@@ -154,11 +155,11 @@ struct PythonEngine : ScriptEngine {
// Get process function from globals // Get process function from globals
processFunc = PyDict_GetItemString(mainDict, "process"); processFunc = PyDict_GetItemString(mainDict, "process");
if (!processFunc) { if (!processFunc) {
setMessage("No process() function");
display("No process() function");
return -1; return -1;
} }
if (!PyCallable_Check(processFunc)) { if (!PyCallable_Check(processFunc)) {
setMessage("process() is not callable");
display("process() is not callable");
return -1; return -1;
} }


@@ -181,7 +182,7 @@ struct PythonEngine : ScriptEngine {
// if (!str) // if (!str)
// return -1; // return -1;


// setMessage(str);
// display(str);
return -1; return -1;
} }
DEFER({Py_DECREF(processResult);}); DEFER({Py_DECREF(processResult);});
@@ -209,7 +210,7 @@ struct PythonEngine : ScriptEngine {
DEFER({Py_DECREF(msgS);}); DEFER({Py_DECREF(msgS);});


const char* msg = PyUnicode_AsUTF8(msgS); const char* msg = PyUnicode_AsUTF8(msgS);
that->setMessage(msg);
that->display(msg);


Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;


+ 13
- 11
src/QuickJSEngine.cpp View File

@@ -65,7 +65,7 @@ struct QuickJSEngine : ScriptEngine {
// Create quickjs context // Create quickjs context
ctx = JS_NewContext(rt); ctx = JS_NewContext(rt);
if (!ctx) { if (!ctx) {
setMessage("Could not create QuickJS context");
display("Could not create QuickJS context");
return -1; return -1;
} }


@@ -107,13 +107,14 @@ struct QuickJSEngine : ScriptEngine {
// Compile string // Compile string
JSValue val = JS_Eval(ctx, script.c_str(), script.size(), path.c_str(), 0); JSValue val = JS_Eval(ctx, script.c_str(), script.size(), path.c_str(), 0);
if (JS_IsException(val)) { if (JS_IsException(val)) {
setMessage(ErrorToString(ctx));
display(ErrorToString(ctx));
JS_FreeValue(ctx, val); JS_FreeValue(ctx, val);
JS_FreeValue(ctx, global_obj); JS_FreeValue(ctx, global_obj);


return -1; return -1;
} }


ProcessBlock* block = getProcessBlock();
// config: Read values // config: Read values
config = JS_GetPropertyStr(ctx, global_obj, "config"); config = JS_GetPropertyStr(ctx, global_obj, "config");
{ {
@@ -128,7 +129,7 @@ struct QuickJSEngine : ScriptEngine {
JSValue buffer = JS_GetPropertyStr(ctx, config, "bufferSize"); JSValue buffer = JS_GetPropertyStr(ctx, config, "bufferSize");
int32_t bufferValue; int32_t bufferValue;
if (JS_ToInt32(ctx, &bufferValue, buffer) == 0) { if (JS_ToInt32(ctx, &bufferValue, buffer) == 0) {
block->bufferSize = bufferValue;
setBufferSize(bufferValue);
} }


JS_FreeValue(ctx, config); JS_FreeValue(ctx, config);
@@ -204,7 +205,7 @@ struct QuickJSEngine : ScriptEngine {
if (JS_IsException(hack)) { if (JS_IsException(hack)) {
std::string errorString = ErrorToString(ctx); std::string errorString = ErrorToString(ctx);
WARN("QuickJS: %s", errorString.c_str()); WARN("QuickJS: %s", errorString.c_str());
setMessage(errorString.c_str());
display(errorString.c_str());
} }


JS_FreeValue(ctx, hack); JS_FreeValue(ctx, hack);
@@ -215,7 +216,7 @@ struct QuickJSEngine : ScriptEngine {
if (JS_IsException(val)) { if (JS_IsException(val)) {
std::string errorString = ErrorToString(ctx); std::string errorString = ErrorToString(ctx);
WARN("QuickJS: %s", errorString.c_str()); WARN("QuickJS: %s", errorString.c_str());
setMessage(errorString.c_str());
display(errorString.c_str());


JS_FreeValue(ctx, val); JS_FreeValue(ctx, val);
JS_FreeValue(ctx, blockIdx); JS_FreeValue(ctx, blockIdx);
@@ -232,6 +233,7 @@ struct QuickJSEngine : ScriptEngine {
JSValue global_obj = JS_GetGlobalObject(ctx); JSValue global_obj = JS_GetGlobalObject(ctx);


// block // block
ProcessBlock* block = getProcessBlock();
JSValue blockIdx = JS_GetPropertyStr(ctx, global_obj, "block"); JSValue blockIdx = JS_GetPropertyStr(ctx, global_obj, "block");
{ {
// sampleRate // sampleRate
@@ -254,7 +256,7 @@ struct QuickJSEngine : ScriptEngine {
if (JS_IsException(val)) { if (JS_IsException(val)) {
std::string errorString = ErrorToString(ctx); std::string errorString = ErrorToString(ctx);
WARN("QuickJS: %s", errorString.c_str()); WARN("QuickJS: %s", errorString.c_str());
setMessage(errorString.c_str());
display(errorString.c_str());


JS_FreeValue(ctx, val); JS_FreeValue(ctx, val);
JS_FreeValue(ctx, process); JS_FreeValue(ctx, process);
@@ -286,7 +288,7 @@ struct QuickJSEngine : ScriptEngine {
int argc, JSValueConst *argv) { int argc, JSValueConst *argv) {
if (argc) { if (argc) {
const char *s = JS_ToCString(ctx, argv[0]); const char *s = JS_ToCString(ctx, argv[0]);
INFO("VCV Prototype: %s", s);
INFO("QuickJS: %s", s);
} }
return JS_UNDEFINED; return JS_UNDEFINED;
} }
@@ -294,7 +296,7 @@ struct QuickJSEngine : ScriptEngine {
int argc, JSValueConst *argv) { int argc, JSValueConst *argv) {
if (argc) { if (argc) {
const char *s = JS_ToCString(ctx, argv[0]); const char *s = JS_ToCString(ctx, argv[0]);
DEBUG("VCV Prototype: %s", s);
DEBUG("QuickJS: %s", s);
} }
return JS_UNDEFINED; return JS_UNDEFINED;
} }
@@ -302,7 +304,7 @@ struct QuickJSEngine : ScriptEngine {
int argc, JSValueConst *argv) { int argc, JSValueConst *argv) {
if (argc) { if (argc) {
const char *s = JS_ToCString(ctx, argv[0]); const char *s = JS_ToCString(ctx, argv[0]);
INFO("VCV Prototype: %s", s);
INFO("QuickJS: %s", s);
} }
return JS_UNDEFINED; return JS_UNDEFINED;
} }
@@ -310,7 +312,7 @@ struct QuickJSEngine : ScriptEngine {
int argc, JSValueConst *argv) { int argc, JSValueConst *argv) {
if (argc) { if (argc) {
const char *s = JS_ToCString(ctx, argv[0]); const char *s = JS_ToCString(ctx, argv[0]);
WARN("VCV Prototype: %s", s);
WARN("QuickJS: %s", s);
} }
return JS_UNDEFINED; return JS_UNDEFINED;
} }
@@ -318,7 +320,7 @@ struct QuickJSEngine : ScriptEngine {
int argc, JSValueConst *argv) { int argc, JSValueConst *argv) {
if (argc) { if (argc) {
const char *s = JS_ToCString(ctx, argv[0]); const char *s = JS_ToCString(ctx, argv[0]);
getQuickJSEngine(ctx)->setMessage(s);
getQuickJSEngine(ctx)->display(s);
} }
return JS_UNDEFINED; return JS_UNDEFINED;
} }


+ 19
- 15
src/ScriptEngine.hpp View File

@@ -9,21 +9,20 @@ static const int MAX_BUFFER_SIZE = 4096;
struct Prototype; 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 methods for subclasses
virtual ~ScriptEngine() {} virtual ~ScriptEngine() {}
virtual std::string getEngineName() {return "";} virtual std::string getEngineName() {return "";}
@@ -40,8 +39,10 @@ struct ScriptEngine {


// Communication with Prototype module. // Communication with Prototype module.
// These cannot be called from your constructor, so initialize your engine in the run() method. // 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 setFrameDivider(int frameDivider);
void setBufferSize(int bufferSize);
ProcessBlock* getProcessBlock();
// private // private
Prototype* module = NULL; Prototype* module = NULL;
}; };
@@ -53,11 +54,14 @@ struct ScriptEngine {
ScriptEngine* createDuktapeEngine(); ScriptEngine* createDuktapeEngine();
ScriptEngine* createQuickJSEngine(); ScriptEngine* createQuickJSEngine();
ScriptEngine* createPythonEngine(); ScriptEngine* createPythonEngine();
ScriptEngine* createLuaJITEngine();


inline ScriptEngine* createScriptEngine(std::string ext) { inline ScriptEngine* createScriptEngine(std::string ext) {
ext = rack::string::lowercase(ext); ext = rack::string::lowercase(ext);
if (ext == "js") if (ext == "js")
return createQuickJSEngine(); return createQuickJSEngine();
else if (ext == "lua")
return createLuaJITEngine();
else if (ext == "py") else if (ext == "py")
return createPythonEngine(); return createPythonEngine();
// Add your file extension check here. // Add your file extension check here.


+ 11
- 0
tests/hello.lua View File

@@ -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!")

Loading…
Cancel
Save