| @@ -15,8 +15,8 @@ include $(RACK_DIR)/arch.mk | |||||
| DUKTAPE ?= 0 | DUKTAPE ?= 0 | ||||
| QUICKJS ?= 1 | QUICKJS ?= 1 | ||||
| LUAJIT ?= 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 | ||||
| @@ -60,36 +60,52 @@ $(quickjs): | |||||
| cd QuickJS && $(MAKE) $(QUICKJS_MAKE_FLAGS) install | cd QuickJS && $(MAKE) $(QUICKJS_MAKE_FLAGS) install | ||||
| endif | endif | ||||
| # LuaJIT | |||||
| ifeq ($(LUAJIT), 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 | |||||
| # Python | # Python | ||||
| ifeq ($(PYTHON), 1) | ifeq ($(PYTHON), 1) | ||||
| SOURCES += src/PythonEngine.cpp | SOURCES += src/PythonEngine.cpp | ||||
| # Note this is a dynamic library, not static. | # Note this is a dynamic library, not static. | ||||
| python := dep/lib/libpython3.7m.so.1.0 | |||||
| python := dep/lib/libpython3.8.so.1.0 | |||||
| DEPS += $(python) $(numpy) | DEPS += $(python) $(numpy) | ||||
| FLAGS += -Idep/include/python3.7m | |||||
| FLAGS += -Idep/include/python3.8 | |||||
| # TODO Test these flags on all platforms | # TODO Test these flags on all platforms | ||||
| # Make dynamic linker look in the plugin folder for libpython. | # Make dynamic linker look in the plugin folder for libpython. | ||||
| LDFLAGS += -Wl,-rpath,'$$ORIGIN'/dep/lib | LDFLAGS += -Wl,-rpath,'$$ORIGIN'/dep/lib | ||||
| LDFLAGS += -Ldep/lib -lpython3.7m | |||||
| LDFLAGS += -Ldep/lib -lpython3.8 | |||||
| LDFLAGS += -lcrypt -lpthread -ldl -lutil -lm | LDFLAGS += -lcrypt -lpthread -ldl -lutil -lm | ||||
| DISTRIBUTABLES += $(python) | DISTRIBUTABLES += $(python) | ||||
| DISTRIBUTABLES += dep/lib/python3.7 | |||||
| DISTRIBUTABLES += dep/lib/python3.8 | |||||
| $(python): | $(python): | ||||
| $(WGET) "https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tar.xz" | |||||
| $(SHA256) Python-3.7.4.tar.xz fb799134b868199930b75f26678f18932214042639cd52b16da7fd134cd9b13f | |||||
| cd dep && $(UNTAR) ../Python-3.7.4.tar.xz | |||||
| cd dep/Python-3.7.4 && $(CONFIGURE) --build=$(MACHINE) --enable-shared --enable-optimizations | |||||
| cd dep/Python-3.7.4 && $(MAKE) build_all | |||||
| cd dep/Python-3.7.4 && $(MAKE) install | |||||
| numpy := dep/lib/python3.7/site-packages/numpy-1.17.2-py3.7-linux-x86_64.egg | |||||
| FLAGS += -Idep/lib/python3.7/site-packages/numpy-1.17.2-py3.7-linux-x86_64.egg/numpy/core/include | |||||
| $(WGET) "https://www.python.org/ftp/python/3.8.0/Python-3.8.0rc1.tar.xz" | |||||
| $(SHA256) Python-3.8.0rc1.tar.xz ae44df6ccf5d70059dd4d04c97156f5fcace74384a6f3cfb2fdf9baddb90a821 | |||||
| cd dep && $(UNTAR) ../Python-3.8.0rc1.tar.xz | |||||
| cd dep/Python-3.8.0rc1 && $(CONFIGURE) --build=$(MACHINE) --enable-shared --enable-optimizations | |||||
| cd dep/Python-3.8.0rc1 && $(MAKE) build_all | |||||
| cd dep/Python-3.8.0rc1 && $(MAKE) install | |||||
| numpy := dep/lib/python3.8/site-packages/numpy | |||||
| FLAGS += -Idep/lib/python3.8/site-packages/numpy/core/include | |||||
| $(numpy): $(python) | $(numpy): $(python) | ||||
| $(WGET) "https://github.com/numpy/numpy/releases/download/v1.17.2/numpy-1.17.2.tar.gz" | $(WGET) "https://github.com/numpy/numpy/releases/download/v1.17.2/numpy-1.17.2.tar.gz" | ||||
| $(SHA256) numpy-1.17.2.tar.gz 81a4f748dcfa80a7071ad8f3d9f8edb9f8bc1f0a9bdd19bfd44fd42c02bd286c | $(SHA256) numpy-1.17.2.tar.gz 81a4f748dcfa80a7071ad8f3d9f8edb9f8bc1f0a9bdd19bfd44fd42c02bd286c | ||||
| cd dep && $(UNTAR) ../numpy-1.17.2.tar.gz | cd dep && $(UNTAR) ../numpy-1.17.2.tar.gz | ||||
| # Don't try to find an external BLAS and LAPACK library. | # Don't try to find an external BLAS and LAPACK library. | ||||
| cd dep/numpy-1.17.2 && LD_LIBRARY_PATH=../lib NPY_BLAS_ORDER= NPY_LAPACK_ORDER= "$(DEP_PATH)"/bin/python3.7 setup.py build -j4 install | |||||
| # Don't install to an egg folder. | |||||
| # Make sure to use our built Python. | |||||
| cd dep/numpy-1.17.2 && LD_LIBRARY_PATH=../lib NPY_BLAS_ORDER= NPY_LAPACK_ORDER= "$(DEP_PATH)"/bin/python3.8 setup.py build -j4 install --single-version-externally-managed --root=/ | |||||
| # scipy: $(numpy) | # scipy: $(numpy) | ||||
| # $(WGET) "https://github.com/scipy/scipy/releases/download/v1.3.1/scipy-1.3.1.tar.xz" | # $(WGET) "https://github.com/scipy/scipy/releases/download/v1.3.1/scipy-1.3.1.tar.xz" | ||||
| @@ -98,20 +114,6 @@ $(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 | |||||
| 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 | ||||
| # DEPS += $(julia) | # DEPS += $(julia) | ||||
| @@ -5,6 +5,11 @@ | |||||
| struct LuaJITEngine : ScriptEngine { | struct LuaJITEngine : ScriptEngine { | ||||
| lua_State* L = NULL; | lua_State* L = NULL; | ||||
| struct SafeArray { | |||||
| void* p; | |||||
| size_t len; | |||||
| }; | |||||
| ~LuaJITEngine() { | ~LuaJITEngine() { | ||||
| if (L) | if (L) | ||||
| lua_close(L); | lua_close(L); | ||||
| @@ -34,8 +39,8 @@ struct LuaJITEngine : ScriptEngine { | |||||
| lua_setglobal(L, "_engine"); | lua_setglobal(L, "_engine"); | ||||
| // Set global functions | // Set global functions | ||||
| lua_pushcfunction(L, native_print); | |||||
| lua_setglobal(L, "print"); | |||||
| // lua_pushcfunction(L, native_print); | |||||
| // lua_setglobal(L, "print"); | |||||
| lua_pushcfunction(L, native_display); | lua_pushcfunction(L, native_display); | ||||
| lua_setglobal(L, "display"); | lua_setglobal(L, "display"); | ||||
| @@ -93,64 +98,99 @@ struct LuaJITEngine : ScriptEngine { | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| // FloatArray metatable | |||||
| lua_newtable(L); | |||||
| { | |||||
| // __index | |||||
| lua_pushcfunction(L, native_FloatArray_index); | |||||
| lua_setfield(L, -2, "__index"); | |||||
| // __newindex | |||||
| lua_pushcfunction(L, native_FloatArray_newindex); | |||||
| lua_setfield(L, -2, "__newindex"); | |||||
| // __len | |||||
| lua_pushcfunction(L, native_FloatArray_len); | |||||
| lua_setfield(L, -2, "__len"); | |||||
| } | |||||
| lua_setglobal(L, "FloatArray"); | |||||
| // BoolArray metatable | |||||
| lua_newtable(L); | |||||
| { | |||||
| // __index | |||||
| lua_pushcfunction(L, native_BoolArray_index); | |||||
| lua_setfield(L, -2, "__index"); | |||||
| // __newindex | |||||
| lua_pushcfunction(L, native_BoolArray_newindex); | |||||
| lua_setfield(L, -2, "__newindex"); | |||||
| // __len | |||||
| lua_pushcfunction(L, native_BoolArray_len); | |||||
| lua_setfield(L, -2, "__len"); | |||||
| } | |||||
| lua_setglobal(L, "BoolArray"); | |||||
| // Create block object | // Create block object | ||||
| lua_newtable(L); | lua_newtable(L); | ||||
| { | { | ||||
| // inputs | // inputs | ||||
| lua_newtable(L); | lua_newtable(L); | ||||
| for (int i = 0; i < NUM_ROWS; i++) { | 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); | |||||
| } | |||||
| SafeArray* input = (SafeArray*) lua_newuserdata(L, sizeof(SafeArray)); | |||||
| input->p = &block->inputs[i]; | |||||
| input->len = block->bufferSize; | |||||
| lua_getglobal(L, "FloatArray"); | |||||
| lua_setmetatable(L, -2); | |||||
| lua_rawseti(L, -2, i + 1); | lua_rawseti(L, -2, i + 1); | ||||
| } | } | ||||
| lua_setfield(L, -2, "inputs"); | lua_setfield(L, -2, "inputs"); | ||||
| // outputs | // outputs | ||||
| lua_newtable(L); | lua_newtable(L); | ||||
| for (int i = 0; i < NUM_ROWS; i++) { | 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); | |||||
| } | |||||
| SafeArray* output = (SafeArray*) lua_newuserdata(L, sizeof(SafeArray)); | |||||
| output->p = &block->outputs[i]; | |||||
| output->len = block->bufferSize; | |||||
| lua_getglobal(L, "FloatArray"); | |||||
| lua_setmetatable(L, -2); | |||||
| lua_rawseti(L, -2, i + 1); | lua_rawseti(L, -2, i + 1); | ||||
| } | } | ||||
| lua_setfield(L, -2, "outputs"); | lua_setfield(L, -2, "outputs"); | ||||
| // knobs | // knobs | ||||
| lua_newtable(L); | |||||
| for (int i = 0; i < NUM_ROWS; i++) { | |||||
| lua_pushnumber(L, 0.0); | |||||
| lua_rawseti(L, -2, i + 1); | |||||
| } | |||||
| SafeArray* knobs = (SafeArray*) lua_newuserdata(L, sizeof(SafeArray)); | |||||
| knobs->p = &block->knobs; | |||||
| knobs->len = 6; | |||||
| lua_getglobal(L, "FloatArray"); | |||||
| lua_setmetatable(L, -2); | |||||
| lua_setfield(L, -2, "knobs"); | lua_setfield(L, -2, "knobs"); | ||||
| // switches | // switches | ||||
| lua_newtable(L); | |||||
| for (int i = 0; i < NUM_ROWS; i++) { | |||||
| lua_pushboolean(L, false); | |||||
| lua_rawseti(L, -2, i + 1); | |||||
| } | |||||
| SafeArray* switches = (SafeArray*) lua_newuserdata(L, sizeof(SafeArray)); | |||||
| switches->p = &block->switches; | |||||
| switches->len = 6; | |||||
| lua_getglobal(L, "BoolArray"); | |||||
| lua_setmetatable(L, -2); | |||||
| lua_setfield(L, -2, "switches"); | lua_setfield(L, -2, "switches"); | ||||
| // lights | // lights | ||||
| lua_newtable(L); | lua_newtable(L); | ||||
| for (int i = 0; i < NUM_ROWS; i++) { | 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); | |||||
| } | |||||
| SafeArray* light = (SafeArray*) lua_newuserdata(L, sizeof(SafeArray)); | |||||
| light->p = &block->lights[i]; | |||||
| light->len = 3; | |||||
| lua_getglobal(L, "FloatArray"); | |||||
| lua_setmetatable(L, -2); | |||||
| lua_rawseti(L, -2, i + 1); | lua_rawseti(L, -2, i + 1); | ||||
| } | } | ||||
| lua_setfield(L, -2, "lights"); | lua_setfield(L, -2, "lights"); | ||||
| // switchLights | // switchLights | ||||
| lua_newtable(L); | lua_newtable(L); | ||||
| for (int i = 0; i < NUM_ROWS; i++) { | 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); | |||||
| } | |||||
| SafeArray* switchLight = (SafeArray*) lua_newuserdata(L, sizeof(SafeArray)); | |||||
| switchLight->p = &block->switchLights[i]; | |||||
| switchLight->len = 3; | |||||
| lua_getglobal(L, "FloatArray"); | |||||
| lua_setmetatable(L, -2); | |||||
| lua_rawseti(L, -2, i + 1); | lua_rawseti(L, -2, i + 1); | ||||
| } | } | ||||
| lua_setfield(L, -2, "switchLights"); | lua_setfield(L, -2, "switchLights"); | ||||
| @@ -175,32 +215,6 @@ struct LuaJITEngine : ScriptEngine { | |||||
| // bufferSize | // bufferSize | ||||
| lua_pushinteger(L, block->bufferSize); | lua_pushinteger(L, block->bufferSize); | ||||
| lua_setfield(L, -2, "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 | // Duplicate process function | ||||
| @@ -215,54 +229,6 @@ struct LuaJITEngine : ScriptEngine { | |||||
| return -1; | 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; | return 0; | ||||
| } | } | ||||
| @@ -273,14 +239,14 @@ struct LuaJITEngine : ScriptEngine { | |||||
| return engine; | 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_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) { | static int native_display(lua_State* L) { | ||||
| lua_getglobal(L, "tostring"); | lua_getglobal(L, "tostring"); | ||||
| @@ -292,6 +258,62 @@ struct LuaJITEngine : ScriptEngine { | |||||
| getEngine(L)->display(s); | getEngine(L)->display(s); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int native_FloatArray_index(lua_State* L) { | |||||
| SafeArray* a = (SafeArray*) lua_touserdata(L, 1); | |||||
| float* data = (float*) a->p; | |||||
| size_t index = lua_tointeger(L, 2) - 1; | |||||
| if (index >= a->len) { | |||||
| lua_pushstring(L, "Array out of bounds"); | |||||
| lua_error(L); | |||||
| } | |||||
| lua_pushnumber(L, data[index]); | |||||
| return 1; | |||||
| } | |||||
| static int native_FloatArray_newindex(lua_State* L) { | |||||
| SafeArray* a = (SafeArray*) lua_touserdata(L, 1); | |||||
| float* data = (float*) a->p; | |||||
| size_t index = lua_tointeger(L, 2) - 1; | |||||
| if (index >= a->len) { | |||||
| lua_pushstring(L, "Array out of bounds"); | |||||
| lua_error(L); | |||||
| } | |||||
| data[index] = lua_tonumber(L, 3); | |||||
| return 0; | |||||
| } | |||||
| static int native_FloatArray_len(lua_State* L) { | |||||
| SafeArray* a = (SafeArray*) lua_touserdata(L, 1); | |||||
| lua_pushinteger(L, a->len); | |||||
| return 1; | |||||
| } | |||||
| static int native_BoolArray_index(lua_State* L) { | |||||
| SafeArray* a = (SafeArray*) lua_touserdata(L, 1); | |||||
| bool* data = (bool*) a->p; | |||||
| size_t index = lua_tointeger(L, 2) - 1; | |||||
| if (index >= a->len) { | |||||
| lua_pushstring(L, "Array out of bounds"); | |||||
| lua_error(L); | |||||
| } | |||||
| lua_pushboolean(L, data[index]); | |||||
| return 1; | |||||
| } | |||||
| static int native_BoolArray_newindex(lua_State* L) { | |||||
| SafeArray* a = (SafeArray*) lua_touserdata(L, 1); | |||||
| bool* data = (bool*) a->p; | |||||
| size_t index = lua_tointeger(L, 2) - 1; | |||||
| if (index >= a->len) { | |||||
| lua_pushstring(L, "Array out of bounds"); | |||||
| lua_error(L); | |||||
| } | |||||
| data[index] = lua_toboolean(L, 3); | |||||
| return 0; | |||||
| } | |||||
| static int native_BoolArray_len(lua_State* L) { | |||||
| SafeArray* a = (SafeArray*) lua_touserdata(L, 1); | |||||
| lua_pushinteger(L, a->len); | |||||
| return 1; | |||||
| } | |||||
| }; | }; | ||||
| @@ -298,11 +298,10 @@ 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 = std::max(frameDivider, 1); | |||||
| } | } | ||||
| void ScriptEngine::setBufferSize(int bufferSize) { | void ScriptEngine::setBufferSize(int bufferSize) { | ||||
| bufferSize = clamp(bufferSize, 1, MAX_BUFFER_SIZE); | |||||
| module->block->bufferSize = bufferSize; | |||||
| module->block->bufferSize = clamp(bufferSize, 1, MAX_BUFFER_SIZE); | |||||
| } | } | ||||
| ProcessBlock* ScriptEngine::getProcessBlock() { | ProcessBlock* ScriptEngine::getProcessBlock() { | ||||
| return module->block; | return module->block; | ||||
| @@ -9,6 +9,14 @@ extern "C" { | |||||
| #include <thread> | #include <thread> | ||||
| /* | |||||
| TODO: | |||||
| - Allow multiple instances with GIL. | |||||
| - Fix destructors. | |||||
| - Add config object. | |||||
| */ | |||||
| extern rack::Plugin* pluginInstance; | extern rack::Plugin* pluginInstance; | ||||
| @@ -16,13 +24,12 @@ static void initPython() { | |||||
| if (Py_IsInitialized()) | if (Py_IsInitialized()) | ||||
| return; | return; | ||||
| std::string pythonDir = rack::asset::plugin(pluginInstance, "dep/lib/python3.7"); | |||||
| std::string pythonDir = rack::asset::plugin(pluginInstance, "dep/lib/python3.8"); | |||||
| // Set python path | // Set python path | ||||
| std::string sep = ":"; | std::string sep = ":"; | ||||
| std::string pythonPath = pythonDir; | std::string pythonPath = pythonDir; | ||||
| pythonPath += sep + pythonDir + "/lib-dynload"; | pythonPath += sep + pythonDir + "/lib-dynload"; | ||||
| // TODO Don't install to egg | |||||
| pythonPath += sep + pythonDir + "/site-packages/numpy-1.17.2-py3.7-linux-x86_64.egg"; | |||||
| pythonPath += sep + pythonDir + "/site-packages"; | |||||
| wchar_t* pythonPathW = Py_DecodeLocale(pythonPath.c_str(), NULL); | wchar_t* pythonPathW = Py_DecodeLocale(pythonPath.c_str(), NULL); | ||||
| Py_SetPath(pythonPathW); | Py_SetPath(pythonPathW); | ||||
| PyMem_RawFree(pythonPathW); | PyMem_RawFree(pythonPathW); | ||||
| @@ -30,10 +37,13 @@ static void initPython() { | |||||
| Py_InitializeEx(0); | Py_InitializeEx(0); | ||||
| assert(Py_IsInitialized()); | assert(Py_IsInitialized()); | ||||
| PyEval_InitThreads(); | |||||
| // PyEval_InitThreads(); | |||||
| // Import numpy | // Import numpy | ||||
| assert(_import_array() == 0); | |||||
| if (_import_array()) { | |||||
| PyErr_Print(); | |||||
| abort(); | |||||
| } | |||||
| } | } | ||||
| @@ -59,6 +69,7 @@ struct PythonEngine : ScriptEngine { | |||||
| } | } | ||||
| int run(const std::string& path, const std::string& script) override { | int run(const std::string& path, const std::string& script) override { | ||||
| ProcessBlock* block = getProcessBlock(); | |||||
| initPython(); | initPython(); | ||||
| // PyThreadState* tstate = PyThreadState_Get(); | // PyThreadState* tstate = PyThreadState_Get(); | ||||
| @@ -73,8 +84,8 @@ struct PythonEngine : ScriptEngine { | |||||
| assert(mainDict); | assert(mainDict); | ||||
| // Set context pointer | // Set context pointer | ||||
| PyObject* thisO = PyCapsule_New(this, NULL, NULL); | |||||
| PyDict_SetItemString(mainDict, "this", thisO); | |||||
| PyObject* engineObj = PyCapsule_New(this, NULL, NULL); | |||||
| PyDict_SetItemString(mainDict, "_engine", engineObj); | |||||
| // Add functions to globals | // Add functions to globals | ||||
| static PyMethodDef native_functions[] = { | static PyMethodDef native_functions[] = { | ||||
| @@ -86,6 +97,25 @@ struct PythonEngine : ScriptEngine { | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| // Set config | |||||
| static PyStructSequence_Field configFields[] = { | |||||
| {"frameDivider", ""}, | |||||
| {"bufferSize", ""}, | |||||
| {NULL, NULL}, | |||||
| }; | |||||
| static PyStructSequence_Desc configDesc = {"Config", "", configFields, LENGTHOF(configFields) - 1}; | |||||
| PyTypeObject* configType = PyStructSequence_NewType(&configDesc); | |||||
| assert(configType); | |||||
| PyObject* configObj = PyStructSequence_New(configType); | |||||
| assert(configObj); | |||||
| PyDict_SetItemString(mainDict, "config", configObj); | |||||
| // frameDivider | |||||
| PyStructSequence_SetItem(configObj, 0, PyLong_FromLong(32)); | |||||
| // bufferSize | |||||
| PyStructSequence_SetItem(configObj, 1, PyLong_FromLong(1)); | |||||
| // Compile string | // Compile string | ||||
| PyObject* code = Py_CompileString(script.c_str(), path.c_str(), Py_file_input); | PyObject* code = Py_CompileString(script.c_str(), path.c_str(), Py_file_input); | ||||
| if (!code) { | if (!code) { | ||||
| @@ -103,7 +133,6 @@ 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", ""}, | ||||
| @@ -197,10 +226,10 @@ struct PythonEngine : ScriptEngine { | |||||
| static PyObject* nativeDisplay(PyObject* self, PyObject* args) { | static PyObject* nativeDisplay(PyObject* self, PyObject* args) { | ||||
| PyObject* mainDict = PyEval_GetGlobals(); | PyObject* mainDict = PyEval_GetGlobals(); | ||||
| assert(mainDict); | assert(mainDict); | ||||
| PyObject* thatO = PyDict_GetItemString(mainDict, "this"); | |||||
| assert(thatO); | |||||
| PythonEngine* that = (PythonEngine*) PyCapsule_GetPointer(thatO, NULL); | |||||
| assert(that); | |||||
| PyObject* engineObj = PyDict_GetItemString(mainDict, "_engine"); | |||||
| assert(engineObj); | |||||
| PythonEngine* engine = (PythonEngine*) PyCapsule_GetPointer(engineObj, NULL); | |||||
| assert(engine); | |||||
| PyObject* msgO = PyTuple_GetItem(args, 0); | PyObject* msgO = PyTuple_GetItem(args, 0); | ||||
| if (!msgO) | if (!msgO) | ||||
| @@ -210,7 +239,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->display(msg); | |||||
| engine->display(msg); | |||||
| Py_INCREF(Py_None); | Py_INCREF(Py_None); | ||||
| return Py_None; | return Py_None; | ||||
| @@ -3,8 +3,10 @@ config.frameDivider = 1 | |||||
| config.bufferSize = 16 | config.bufferSize = 16 | ||||
| function process(block) | function process(block) | ||||
| for j=1,block.bufferSize do | |||||
| block.outputs[1][j] = math.random() | |||||
| for i=1,6 do | |||||
| for j=1,block.bufferSize do | |||||
| block.outputs[i][j] = block.inputs[i][j] | |||||
| end | |||||
| end | end | ||||
| end | end | ||||
| @@ -1,9 +1,13 @@ | |||||
| frame = 0 | frame = 0 | ||||
| print(config) | |||||
| print(config.frameDivider) | |||||
| print(config.bufferSize) | |||||
| def process(block): | def process(block): | ||||
| global frame | global frame | ||||
| frame += 1 | frame += 1 | ||||
| print(frame) | |||||
| display(frame) | |||||
| # print(block) | # print(block) | ||||
| # block.switch_lights[:, 2] = 1 | # block.switch_lights[:, 2] = 1 | ||||
| print(block.inputs) | print(block.inputs) | ||||
| @@ -12,6 +16,6 @@ def process(block): | |||||
| print(block.switches) | print(block.switches) | ||||
| print(block.lights) | print(block.lights) | ||||
| print(block.switch_lights) | print(block.switch_lights) | ||||
| print("===") | |||||
| # print("===") | |||||
| print("Hello, world!") | print("Hello, world!") | ||||