|
|
@@ -37,14 +37,25 @@ public: |
|
|
|
~SC_VcvPrototypeClient(); |
|
|
|
|
|
|
|
// These will invoke the interpreter |
|
|
|
void interpret(const char * text) noexcept; |
|
|
|
void interpretScript(const std::string& script) noexcept |
|
|
|
{ |
|
|
|
// Insert our own environment variable in the script so we can check |
|
|
|
// later (in testCompile()) whether it compiled all right. |
|
|
|
auto modifiedScript = std::string(compileTestVariableName) + "=1;" + script; |
|
|
|
interpret(modifiedScript.c_str()); |
|
|
|
testCompile(); |
|
|
|
} |
|
|
|
void evaluateProcessBlock(ProcessBlock* block) noexcept; |
|
|
|
void setNumRows() noexcept { |
|
|
|
std::string&& command = "VcvPrototypeProcessBlock.numRows = " + std::to_string(NUM_ROWS); |
|
|
|
interpret(command.c_str()); |
|
|
|
} |
|
|
|
int getFrameDivider() noexcept { return getInterpretResultAsInt("^~vcv_frameDivider"); } |
|
|
|
int getBufferSize() noexcept { return getInterpretResultAsInt("^~vcv_bufferSize"); } |
|
|
|
int getFrameDivider() noexcept { |
|
|
|
return getEnvVarAsPositiveInt("~vcv_frameDivider", "~vcv_frameDivider should be an Integer"); |
|
|
|
} |
|
|
|
int getBufferSize() noexcept { |
|
|
|
return getEnvVarAsPositiveInt("~vcv_bufferSize", "~vcv_bufferSize should be an Integer"); |
|
|
|
} |
|
|
|
|
|
|
|
bool isOk() const noexcept { return _ok; } |
|
|
|
|
|
|
@@ -56,19 +67,25 @@ public: |
|
|
|
void flush() override {} |
|
|
|
|
|
|
|
private: |
|
|
|
static const char * compileTestVariableName; |
|
|
|
|
|
|
|
void interpret(const char * text) noexcept; |
|
|
|
|
|
|
|
void testCompile() noexcept { getEnvVarAsPositiveInt(compileTestVariableName, "Script failed to compile"); } |
|
|
|
|
|
|
|
// Called on unrecoverable error, will stop the plugin |
|
|
|
void fail(const std::string& msg) noexcept; |
|
|
|
|
|
|
|
const char* buildScProcessBlockString(const ProcessBlock* block) const noexcept; |
|
|
|
|
|
|
|
int getInterpretResultAsInt(const char* text) noexcept; |
|
|
|
int getEnvVarAsPositiveInt(const char* envVarName, const char* errorMsg) noexcept; |
|
|
|
|
|
|
|
// converts top of stack back to ProcessBlock data |
|
|
|
void readScProcessBlockResult(ProcessBlock* block) noexcept; |
|
|
|
|
|
|
|
// helpers for copying SC info back into process block's arrays |
|
|
|
bool isVcvPrototypeProcessBlock(const PyrSlot* slot) const noexcept; |
|
|
|
bool copyFloatArray(const PyrSlot& inSlot, const char* context, float* outArray, int size) noexcept; |
|
|
|
bool copyFloatArray(const PyrSlot& inSlot, const char* context, const char* extraContext, float* outArray, int size) noexcept; |
|
|
|
template <typename Array> |
|
|
|
bool copyArrayOfFloatArrays(const PyrSlot& inSlot, const char* context, Array& array, int size) noexcept; |
|
|
|
|
|
|
@@ -77,6 +94,8 @@ private: |
|
|
|
bool _ok = true; |
|
|
|
}; |
|
|
|
|
|
|
|
const char * SC_VcvPrototypeClient::compileTestVariableName = "~vcv_secretTestCompileSentinel"; |
|
|
|
|
|
|
|
class SuperColliderEngine final : public ScriptEngine { |
|
|
|
public: |
|
|
|
~SuperColliderEngine() noexcept { |
|
|
@@ -100,7 +119,7 @@ public: |
|
|
|
_clientThread = std::thread([this, script]() { |
|
|
|
_client.reset(new SC_VcvPrototypeClient(this)); |
|
|
|
_client->setNumRows(); |
|
|
|
_client->interpret(script.c_str()); |
|
|
|
_client->interpretScript(script); |
|
|
|
setFrameDivider(_client->getFrameDivider()); |
|
|
|
setBufferSize(_client->getBufferSize()); |
|
|
|
finishClientLoading(); |
|
|
@@ -286,8 +305,9 @@ const char* SC_VcvPrototypeClient::buildScProcessBlockString(const ProcessBlock* |
|
|
|
return buildPbStringScratchBuf; |
|
|
|
} |
|
|
|
|
|
|
|
int SC_VcvPrototypeClient::getInterpretResultAsInt(const char* text) noexcept { |
|
|
|
interpret(text); |
|
|
|
int SC_VcvPrototypeClient::getEnvVarAsPositiveInt(const char* envVarName, const char* errorMsg) noexcept { |
|
|
|
auto command = std::string("^") + envVarName; |
|
|
|
interpret(command.c_str()); |
|
|
|
|
|
|
|
auto* resultSlot = &scGlobals()->result; |
|
|
|
if (IsInt(resultSlot)) { |
|
|
@@ -295,11 +315,11 @@ int SC_VcvPrototypeClient::getInterpretResultAsInt(const char* text) noexcept { |
|
|
|
if (intResult > 0) { |
|
|
|
return intResult; |
|
|
|
} else { |
|
|
|
fail(std::string("Result of '") + text + "' should be > 0"); |
|
|
|
fail(std::string(envVarName) + " should be > 0"); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} else { |
|
|
|
fail(std::string("Result of '") + text + "' should be Integer"); |
|
|
|
fail(errorMsg); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
@@ -327,7 +347,7 @@ void SC_VcvPrototypeClient::readScProcessBlockResult(ProcessBlock* block) noexce |
|
|
|
return; |
|
|
|
if (!copyArrayOfFloatArrays(rawSlots[switchLightsSlotIndex], "switchLights", block->switchLights, 3)) |
|
|
|
return; |
|
|
|
if (!copyFloatArray(rawSlots[knobsSlotIndex], "knobs", block->knobs, NUM_ROWS)) |
|
|
|
if (!copyFloatArray(rawSlots[knobsSlotIndex], "", "knobs", block->knobs, NUM_ROWS)) |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
@@ -340,15 +360,17 @@ bool SC_VcvPrototypeClient::isVcvPrototypeProcessBlock(const PyrSlot* slot) cons |
|
|
|
return klassNameSymbol == _vcvPrototypeProcessBlockSym; |
|
|
|
} |
|
|
|
|
|
|
|
bool SC_VcvPrototypeClient::copyFloatArray(const PyrSlot& inSlot, const char* context, float* outArray, int size) noexcept |
|
|
|
// It's somewhat bad design that we pass two const char*s here, but this avoids an allocation while also providing |
|
|
|
// good context for errors. |
|
|
|
bool SC_VcvPrototypeClient::copyFloatArray(const PyrSlot& inSlot, const char* context, const char* extraContext, float* outArray, int size) noexcept |
|
|
|
{ |
|
|
|
if (!isKindOfSlot(const_cast<PyrSlot*>(&inSlot), class_floatarray)) { |
|
|
|
fail(std::string(context) + " must be a FloatArray"); |
|
|
|
fail(std::string(context) + extraContext + " must be a FloatArray"); |
|
|
|
return false; |
|
|
|
} |
|
|
|
auto* floatArrayObj = slotRawObject(&inSlot); |
|
|
|
if (floatArrayObj->size != size) { |
|
|
|
fail(std::string(context) + " must be of size " + std::to_string(size)); |
|
|
|
fail(std::string(context) + extraContext + " must be of size " + std::to_string(size)); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
@@ -373,7 +395,7 @@ bool SC_VcvPrototypeClient::copyArrayOfFloatArrays(const PyrSlot& inSlot, const |
|
|
|
} |
|
|
|
|
|
|
|
for (int i = 0; i < NUM_ROWS; ++i) { |
|
|
|
if (!copyFloatArray(inObj->slots[i], "subarray", outArray[i], size)) { |
|
|
|
if (!copyFloatArray(inObj->slots[i], "subarray of ", context, outArray[i], size)) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|