| @@ -98,6 +98,7 @@ struct Prototype : Module { | |||||
| ScriptEngine* scriptEngine = NULL; | ScriptEngine* scriptEngine = NULL; | ||||
| int frame = 0; | int frame = 0; | ||||
| int frameDivider; | int frameDivider; | ||||
| // This is dynamically allocated to have some protection against script bugs. | |||||
| ProcessBlock* block; | ProcessBlock* block; | ||||
| int bufferIndex = 0; | int bufferIndex = 0; | ||||
| @@ -129,15 +130,28 @@ struct Prototype : Module { | |||||
| } | } | ||||
| void process(const ProcessArgs& args) override { | void process(const ProcessArgs& args) override { | ||||
| // Load security-sandboxed script if the security warning message is accepted. | |||||
| if (securityScript != "" && securityAccepted) { | |||||
| setScript(securityScript); | |||||
| securityScript = ""; | |||||
| } | |||||
| // Frame divider for reducing sample rate | // Frame divider for reducing sample rate | ||||
| if (++frame < frameDivider) | if (++frame < frameDivider) | ||||
| return; | return; | ||||
| frame = 0; | frame = 0; | ||||
| // Load security-sandboxed script if the security warning message is accepted. | |||||
| if (securityScript != "" && securityAccepted) { | |||||
| setScript(securityScript); | |||||
| securityScript = ""; | |||||
| // Clear outputs if no script is running | |||||
| if (!scriptEngine) { | |||||
| for (int i = 0; i < NUM_ROWS; i++) | |||||
| for (int c = 0; c < 3; c++) | |||||
| lights[LIGHT_LIGHTS + i * 3 + c].setBrightness(0.f); | |||||
| for (int i = 0; i < NUM_ROWS; i++) | |||||
| for (int c = 0; c < 3; c++) | |||||
| lights[SWITCH_LIGHTS + i * 3 + c].setBrightness(0.f); | |||||
| for (int i = 0; i < NUM_ROWS; i++) | |||||
| outputs[OUT_OUTPUTS + i].setVoltage(0.f); | |||||
| return; | |||||
| } | } | ||||
| // Inputs | // Inputs | ||||
| @@ -146,6 +160,7 @@ struct Prototype : Module { | |||||
| // Process block | // Process block | ||||
| if (++bufferIndex >= block->bufferSize) { | if (++bufferIndex >= block->bufferSize) { | ||||
| std::lock_guard<std::mutex> lock(scriptMutex); | |||||
| bufferIndex = 0; | bufferIndex = 0; | ||||
| // Block settings | // Block settings | ||||
| @@ -158,12 +173,11 @@ struct Prototype : Module { | |||||
| for (int i = 0; i < NUM_ROWS; i++) | for (int i = 0; i < NUM_ROWS; i++) | ||||
| block->switches[i] = params[SWITCH_PARAMS + i].getValue() > 0.f; | block->switches[i] = params[SWITCH_PARAMS + i].getValue() > 0.f; | ||||
| float oldKnobs[NUM_ROWS]; | float oldKnobs[NUM_ROWS]; | ||||
| std::memcpy(oldKnobs, block->knobs, sizeof(block->knobs)); | |||||
| std::memcpy(oldKnobs, block->knobs, sizeof(oldKnobs)); | |||||
| // Run ScriptEngine's process function | // Run ScriptEngine's process function | ||||
| { | { | ||||
| // Process buffer | // Process buffer | ||||
| std::lock_guard<std::mutex> lock(scriptMutex); | |||||
| if (scriptEngine) { | if (scriptEngine) { | ||||
| if (scriptEngine->process()) { | if (scriptEngine->process()) { | ||||
| WARN("Script %s process() failed. Stopped script.", path.c_str()); | WARN("Script %s process() failed. Stopped script.", path.c_str()); | ||||
| @@ -175,6 +189,7 @@ struct Prototype : Module { | |||||
| } | } | ||||
| // Params | // Params | ||||
| // Only set params if values were changed by the script. This avoids issues when the user is manipulating them from the UI thread. | |||||
| for (int i = 0; i < NUM_ROWS; i++) { | for (int i = 0; i < NUM_ROWS; i++) { | ||||
| if (block->knobs[i] != oldKnobs[i]) | if (block->knobs[i] != oldKnobs[i]) | ||||
| params[KNOB_PARAMS + i].setValue(block->knobs[i]); | params[KNOB_PARAMS + i].setValue(block->knobs[i]); | ||||
| @@ -247,17 +262,9 @@ struct Prototype : Module { | |||||
| // Reset process state | // Reset process state | ||||
| frameDivider = 32; | frameDivider = 32; | ||||
| frame = 0; | frame = 0; | ||||
| *block = ProcessBlock(); | |||||
| bufferIndex = 0; | bufferIndex = 0; | ||||
| // Reset outputs and lights because they might hold old values | |||||
| for (int i = 0; i < NUM_ROWS; i++) | |||||
| outputs[OUT_OUTPUTS + i].setVoltage(0.f); | |||||
| for (int i = 0; i < NUM_ROWS; i++) | |||||
| for (int c = 0; c < 3; c++) | |||||
| lights[LIGHT_LIGHTS + i * 3 + c].setBrightness(0.f); | |||||
| for (int i = 0; i < NUM_ROWS; i++) | |||||
| for (int c = 0; c < 3; c++) | |||||
| lights[SWITCH_LIGHTS + i * 3 + c].setBrightness(0.f); | |||||
| // Reset block | |||||
| *block = ProcessBlock(); | |||||
| if (script == "") | if (script == "") | ||||
| return; | return; | ||||
| @@ -322,9 +329,8 @@ struct Prototype : Module { | |||||
| std::string script = std::string(json_string_value(scriptJ), json_string_length(scriptJ)); | std::string script = std::string(json_string_value(scriptJ), json_string_length(scriptJ)); | ||||
| if (script != "") { | if (script != "") { | ||||
| // Request security warning message | // Request security warning message | ||||
| if (!securityAccepted) { | |||||
| securityRequested = true; | |||||
| } | |||||
| securityAccepted = false; | |||||
| securityRequested = true; | |||||
| securityScript = script; | securityScript = script; | ||||
| } | } | ||||
| } | } | ||||
| @@ -365,10 +371,13 @@ struct Prototype : Module { | |||||
| if (newExt == "") | if (newExt == "") | ||||
| newPath += "." + ext; | newPath += "." + ext; | ||||
| std::ofstream f(newPath); | |||||
| f << script; | |||||
| // Set path directly | |||||
| path = newPath; | |||||
| // Write and close file | |||||
| { | |||||
| std::ofstream f(newPath); | |||||
| f << script; | |||||
| } | |||||
| // Load path so that it reloads and is watched. | |||||
| setPath(newPath); | |||||
| } | } | ||||
| }; | }; | ||||