Browse Source

Use ArrayBuffers instead of normal JS arrays for all block arrays.

tags/v1.1.0
Andrew Belt 5 years ago
parent
commit
6036b95c69
5 changed files with 58 additions and 144 deletions
  1. +3
    -2
      examples/rainbow.js
  2. +2
    -2
      examples/vco.js
  3. +34
    -111
      src/DuktapeEngine.cpp
  4. +3
    -13
      src/Prototype.cpp
  5. +16
    -16
      src/ScriptEngine.hpp

+ 3
- 2
examples/rainbow.js View File

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

+ 2
- 2
examples/vco.js View File

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

+ 34
- 111
src/DuktapeEngine.cpp View File

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



+ 3
- 13
src/Prototype.cpp View File

@@ -89,7 +89,7 @@ struct Prototype : Module {
std::lock_guard<std::mutex> 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 = &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 {


+ 16
- 16
src/ScriptEngine.hpp View File

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




Loading…
Cancel
Save