diff --git a/examples/rainbow.js b/examples/rainbow.js index c9ac0f2..dcef69c 100644 --- a/examples/rainbow.js +++ b/examples/rainbow.js @@ -1,3 +1,6 @@ +// Rainbow RGB LED example +// by Andrew Belt + // Call process() every 256 audio samples config.frameDivider = 256 @@ -37,5 +40,3 @@ function process(block) { } display("Hello, world!") - -// 12.2us \ No newline at end of file diff --git a/examples/vco.js b/examples/vco.js index f51d194..f370c13 100644 --- a/examples/vco.js +++ b/examples/vco.js @@ -20,7 +20,7 @@ function process(block) { display("Freq: " + freq.toFixed(3) + " Hz") // Set all output samples in block - var deltaPhase = block.sampleTime * config.frameDivider * freq + var deltaPhase = config.frameDivider * block.sampleTime * freq for (var i = 0; i < block.bufferSize; i++) { // Accumulate phase phase += deltaPhase @@ -30,4 +30,4 @@ function process(block) { // Convert phase to sine output block.outputs[0][i] = Math.sin(2 * Math.PI * phase) * 5 } -} \ No newline at end of file +} diff --git a/src/DuktapeEngine.cpp b/src/DuktapeEngine.cpp index d56412a..54052f5 100644 --- a/src/DuktapeEngine.cpp +++ b/src/DuktapeEngine.cpp @@ -50,14 +50,14 @@ struct DuktapeEngine : ScriptEngine { duk_push_c_function(ctx, native_display, 1); duk_put_global_string(ctx, "display"); - // config + // config: Set defaults duk_idx_t configIdx = duk_push_object(ctx); { // frameDivider - duk_push_int(ctx, getFrameDivider()); + duk_push_int(ctx, 32); duk_put_prop_string(ctx, configIdx, "frameDivider"); // bufferSize - duk_push_int(ctx, getBufferSize()); + duk_push_int(ctx, 1); duk_put_prop_string(ctx, configIdx, "bufferSize"); } duk_put_global_string(ctx, "config"); @@ -82,7 +82,7 @@ struct DuktapeEngine : ScriptEngine { // Ignore return value duk_pop(ctx); - // Get config + // config: Read values duk_get_global_string(ctx, "config"); { // frameDivider @@ -91,7 +91,8 @@ struct DuktapeEngine : ScriptEngine { duk_pop(ctx); // bufferSize duk_get_prop_string(ctx, -1, "bufferSize"); - setBufferSize(duk_get_int(ctx, -1)); + int bufferSize = duk_get_int(ctx, -1); + block->bufferSize = rack::clamp(bufferSize, 1, MAX_BUFFER_SIZE); duk_pop(ctx); } duk_pop(ctx); @@ -106,69 +107,61 @@ struct DuktapeEngine : ScriptEngine { // block (keep on stack) duk_idx_t blockIdx = duk_push_object(ctx); { - int bufferSize = getBufferSize(); - // inputs duk_idx_t inputsIdx = duk_push_array(ctx); for (int i = 0; i < NUM_ROWS; i++) { - duk_idx_t inputIdx = duk_push_array(ctx); - for (int j = 0; j < bufferSize; j++) { - duk_push_number(ctx, 0.0); - duk_put_prop_index(ctx, inputIdx, j); - } + duk_push_external_buffer(ctx); + duk_config_buffer(ctx, -1, block->inputs[i], sizeof(float) * block->bufferSize); + duk_push_buffer_object(ctx, -1, 0, sizeof(float) * block->bufferSize, DUK_BUFOBJ_FLOAT32ARRAY); duk_put_prop_index(ctx, inputsIdx, i); + duk_pop(ctx); } duk_put_prop_string(ctx, blockIdx, "inputs"); // outputs duk_idx_t outputsIdx = duk_push_array(ctx); for (int i = 0; i < NUM_ROWS; i++) { - duk_idx_t outputIdx = duk_push_array(ctx); - for (int j = 0; j < bufferSize; j++) { - duk_push_number(ctx, 0.0); - duk_put_prop_index(ctx, outputIdx, j); - } + duk_push_external_buffer(ctx); + duk_config_buffer(ctx, -1, block->outputs[i], sizeof(float) * block->bufferSize); + duk_push_buffer_object(ctx, -1, 0, sizeof(float) * block->bufferSize, DUK_BUFOBJ_FLOAT32ARRAY); duk_put_prop_index(ctx, outputsIdx, i); + duk_pop(ctx); } duk_put_prop_string(ctx, blockIdx, "outputs"); // knobs - duk_idx_t knobsIdx = duk_push_array(ctx); - for (int i = 0; i < NUM_ROWS; i++) { - duk_push_number(ctx, 0.0); - duk_put_prop_index(ctx, knobsIdx, i); - } + duk_push_external_buffer(ctx); + duk_config_buffer(ctx, -1, block->knobs, sizeof(float) * NUM_ROWS); + duk_push_buffer_object(ctx, -1, 0, sizeof(float) * NUM_ROWS, DUK_BUFOBJ_FLOAT32ARRAY); duk_put_prop_string(ctx, blockIdx, "knobs"); + duk_pop(ctx); // switches - duk_idx_t switchesIdx = duk_push_array(ctx); - for (int i = 0; i < NUM_ROWS; i++) { - duk_push_number(ctx, 0.0); - duk_put_prop_index(ctx, switchesIdx, i); - } + duk_push_external_buffer(ctx); + duk_config_buffer(ctx, -1, block->switches, sizeof(bool) * NUM_ROWS); + duk_push_buffer_object(ctx, -1, 0, sizeof(bool) * NUM_ROWS, DUK_BUFOBJ_UINT8ARRAY); duk_put_prop_string(ctx, blockIdx, "switches"); + duk_pop(ctx); // lights duk_idx_t lightsIdx = duk_push_array(ctx); for (int i = 0; i < NUM_ROWS; i++) { - duk_idx_t lightIdx = duk_push_array(ctx); - for (int c = 0; c < 3; c++) { - duk_push_number(ctx, 0.0); - duk_put_prop_index(ctx, lightIdx, c); - } + duk_push_external_buffer(ctx); + duk_config_buffer(ctx, -1, block->lights[i], sizeof(float) * 3); + duk_push_buffer_object(ctx, -1, 0, sizeof(float) * 3, DUK_BUFOBJ_FLOAT32ARRAY); duk_put_prop_index(ctx, lightsIdx, i); + duk_pop(ctx); } duk_put_prop_string(ctx, blockIdx, "lights"); // switchLights duk_idx_t switchLightsIdx = duk_push_array(ctx); for (int i = 0; i < NUM_ROWS; i++) { - duk_idx_t switchLightIdx = duk_push_array(ctx); - for (int c = 0; c < 3; c++) { - duk_push_number(ctx, 0.0); - duk_put_prop_index(ctx, switchLightIdx, c); - } + duk_push_external_buffer(ctx); + duk_config_buffer(ctx, -1, block->switchLights[i], sizeof(float) * 3); + duk_push_buffer_object(ctx, -1, 0, sizeof(float) * 3, DUK_BUFOBJ_FLOAT32ARRAY); duk_put_prop_index(ctx, switchLightsIdx, i); + duk_pop(ctx); } duk_put_prop_string(ctx, blockIdx, "switchLights"); } @@ -176,49 +169,21 @@ struct DuktapeEngine : ScriptEngine { return 0; } - int process(ProcessBlock& block) override { + int process() override { // block duk_idx_t blockIdx = duk_get_top(ctx) - 1; { // sampleRate - duk_push_number(ctx, block.sampleRate); + duk_push_number(ctx, block->sampleRate); duk_put_prop_string(ctx, blockIdx, "sampleRate"); // sampleTime - duk_push_number(ctx, block.sampleTime); + duk_push_number(ctx, block->sampleTime); duk_put_prop_string(ctx, blockIdx, "sampleTime"); // bufferSize - duk_push_int(ctx, block.bufferSize); + duk_push_int(ctx, block->bufferSize); duk_put_prop_string(ctx, blockIdx, "bufferSize"); - - // inputs - duk_get_prop_string(ctx, blockIdx, "inputs"); - for (int i = 0; i < NUM_ROWS; i++) { - duk_get_prop_index(ctx, -1, i); - for (int j = 0; j < block.bufferSize; j++) { - duk_push_number(ctx, block.inputs[i][j]); - duk_put_prop_index(ctx, -2, j); - } - duk_pop(ctx); - } - duk_pop(ctx); - - // knobs - duk_get_prop_string(ctx, blockIdx, "knobs"); - for (int i = 0; i < NUM_ROWS; i++) { - duk_push_number(ctx, block.knobs[i]); - duk_put_prop_index(ctx, -2, i); - } - duk_pop(ctx); - - // switches - duk_get_prop_string(ctx, blockIdx, "switches"); - for (int i = 0; i < NUM_ROWS; i++) { - duk_push_boolean(ctx, block.switches[i]); - duk_put_prop_index(ctx, -2, i); - } - duk_pop(ctx); } // Duplicate process function @@ -236,48 +201,6 @@ struct DuktapeEngine : ScriptEngine { // return value duk_pop(ctx); - // block - { - // outputs - duk_get_prop_string(ctx, -1, "outputs"); - for (int i = 0; i < NUM_ROWS; i++) { - duk_get_prop_index(ctx, -1, i); - for (int j = 0; j < block.bufferSize; j++) { - duk_get_prop_index(ctx, -1, j); - block.outputs[i][j] = duk_get_number(ctx, -1); - duk_pop(ctx); - } - duk_pop(ctx); - } - duk_pop(ctx); - - // lights - duk_get_prop_string(ctx, -1, "lights"); - for (int i = 0; i < NUM_ROWS; i++) { - duk_get_prop_index(ctx, -1, i); - for (int c = 0; c < 3; c++) { - duk_get_prop_index(ctx, -1, c); - block.lights[i][c] = duk_get_number(ctx, -1); - duk_pop(ctx); - } - duk_pop(ctx); - } - duk_pop(ctx); - - // switchLights - duk_get_prop_string(ctx, -1, "switchLights"); - for (int i = 0; i < NUM_ROWS; i++) { - duk_get_prop_index(ctx, -1, i); - for (int c = 0; c < 3; c++) { - duk_get_prop_index(ctx, -1, c); - block.switchLights[i][c] = duk_get_number(ctx, -1); - duk_pop(ctx); - } - duk_pop(ctx); - } - duk_pop(ctx); - } - return 0; } diff --git a/src/Prototype.cpp b/src/Prototype.cpp index 88dec46..42e202b 100644 --- a/src/Prototype.cpp +++ b/src/Prototype.cpp @@ -89,7 +89,7 @@ struct Prototype : Module { std::lock_guard lock(scriptMutex); // Check for certain inside the mutex if (scriptEngine) { - if (scriptEngine->process(block)) { + if (scriptEngine->process()) { WARN("Script %s process() failed. Stopped script.", path.c_str()); clearScriptEngine(); return; @@ -129,7 +129,6 @@ struct Prototype : Module { frameDivider = 32; frame = 0; block.bufferSize = 1; - std::memset(block.inputs, 0, sizeof(block.inputs)); bufferIndex = 0; } @@ -152,10 +151,11 @@ struct Prototype : Module { message = string::f("No engine for .%s extension", ext.c_str()); return; } + scriptEngine->module = this; + scriptEngine->block = █ this->path = path; this->script = script; this->engineName = scriptEngine->getEngineName(); - scriptEngine->module = this; // Read file std::ifstream file; file.exceptions(std::ifstream::failbit | std::ifstream::badbit); @@ -210,19 +210,9 @@ struct Prototype : Module { void ScriptEngine::setMessage(const std::string& message) { module->message = message; } -int ScriptEngine::getFrameDivider() { - return module->frameDivider; -} void ScriptEngine::setFrameDivider(int frameDivider) { module->frameDivider = frameDivider; } -int ScriptEngine::getBufferSize() { - return module->block.bufferSize; -} -void ScriptEngine::setBufferSize(int bufferSize) { - bufferSize = clamp(bufferSize, 1, MAX_BUFFER_SIZE); - module->block.bufferSize = bufferSize; -} struct FileChoice : LedDisplayChoice { diff --git a/src/ScriptEngine.hpp b/src/ScriptEngine.hpp index 2dc0151..49aecd9 100644 --- a/src/ScriptEngine.hpp +++ b/src/ScriptEngine.hpp @@ -10,18 +10,9 @@ struct Prototype; struct ScriptEngine { - // Virtual methods for subclasses - virtual ~ScriptEngine() {} - virtual std::string getEngineName() {return "";} - /** Executes the script. - Return nonzero if failure, and set error message with setMessage(). - Called only once per instance. - */ - virtual int run(const std::string& path, const std::string& script) {return 0;} - struct ProcessBlock { - float sampleRate; - float sampleTime; + 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] = {}; @@ -30,20 +21,29 @@ struct ScriptEngine { float lights[NUM_ROWS][3] = {}; float switchLights[NUM_ROWS][3] = {}; }; + /** Set by module */ + ProcessBlock* block = NULL; + + // Virtual methods for subclasses + virtual ~ScriptEngine() {} + virtual std::string getEngineName() {return "";} + /** Executes the script. + Return nonzero if failure, and set error message with setMessage(). + Called only once per instance. + */ + virtual int run(const std::string& path, const std::string& script) {return 0;} + /** Calls the script's process() method. Return nonzero if failure, and set error message with setMessage(). */ - virtual int process(ProcessBlock& block) {return 0;} + virtual int process() {return 0;} // 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); - int getFrameDivider(); void setFrameDivider(int frameDivider); - int getBufferSize(); - void setBufferSize(int bufferSize); // private - Prototype* module; + Prototype* module = NULL; };