Browse Source

SC: improve error handling

tags/v1.3.0
Brian Heim 5 years ago
parent
commit
cd2674605c
1 changed files with 37 additions and 15 deletions
  1. +37
    -15
      src/SuperColliderEngine.cpp

+ 37
- 15
src/SuperColliderEngine.cpp View File

@@ -37,14 +37,25 @@ public:
~SC_VcvPrototypeClient(); ~SC_VcvPrototypeClient();


// These will invoke the interpreter // 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 evaluateProcessBlock(ProcessBlock* block) noexcept;
void setNumRows() noexcept { void setNumRows() noexcept {
std::string&& command = "VcvPrototypeProcessBlock.numRows = " + std::to_string(NUM_ROWS); std::string&& command = "VcvPrototypeProcessBlock.numRows = " + std::to_string(NUM_ROWS);
interpret(command.c_str()); 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; } bool isOk() const noexcept { return _ok; }


@@ -56,19 +67,25 @@ public:
void flush() override {} void flush() override {}


private: 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 // Called on unrecoverable error, will stop the plugin
void fail(const std::string& msg) noexcept; void fail(const std::string& msg) noexcept;


const char* buildScProcessBlockString(const ProcessBlock* block) const 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 // converts top of stack back to ProcessBlock data
void readScProcessBlockResult(ProcessBlock* block) noexcept; void readScProcessBlockResult(ProcessBlock* block) noexcept;


// helpers for copying SC info back into process block's arrays // helpers for copying SC info back into process block's arrays
bool isVcvPrototypeProcessBlock(const PyrSlot* slot) const noexcept; 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> template <typename Array>
bool copyArrayOfFloatArrays(const PyrSlot& inSlot, const char* context, Array& array, int size) noexcept; bool copyArrayOfFloatArrays(const PyrSlot& inSlot, const char* context, Array& array, int size) noexcept;


@@ -77,6 +94,8 @@ private:
bool _ok = true; bool _ok = true;
}; };


const char * SC_VcvPrototypeClient::compileTestVariableName = "~vcv_secretTestCompileSentinel";

class SuperColliderEngine final : public ScriptEngine { class SuperColliderEngine final : public ScriptEngine {
public: public:
~SuperColliderEngine() noexcept { ~SuperColliderEngine() noexcept {
@@ -100,7 +119,7 @@ public:
_clientThread = std::thread([this, script]() { _clientThread = std::thread([this, script]() {
_client.reset(new SC_VcvPrototypeClient(this)); _client.reset(new SC_VcvPrototypeClient(this));
_client->setNumRows(); _client->setNumRows();
_client->interpret(script.c_str());
_client->interpretScript(script);
setFrameDivider(_client->getFrameDivider()); setFrameDivider(_client->getFrameDivider());
setBufferSize(_client->getBufferSize()); setBufferSize(_client->getBufferSize());
finishClientLoading(); finishClientLoading();
@@ -286,8 +305,9 @@ const char* SC_VcvPrototypeClient::buildScProcessBlockString(const ProcessBlock*
return buildPbStringScratchBuf; 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; auto* resultSlot = &scGlobals()->result;
if (IsInt(resultSlot)) { if (IsInt(resultSlot)) {
@@ -295,11 +315,11 @@ int SC_VcvPrototypeClient::getInterpretResultAsInt(const char* text) noexcept {
if (intResult > 0) { if (intResult > 0) {
return intResult; return intResult;
} else { } else {
fail(std::string("Result of '") + text + "' should be > 0");
fail(std::string(envVarName) + " should be > 0");
return -1; return -1;
} }
} else { } else {
fail(std::string("Result of '") + text + "' should be Integer");
fail(errorMsg);
return -1; return -1;
} }
} }
@@ -327,7 +347,7 @@ void SC_VcvPrototypeClient::readScProcessBlockResult(ProcessBlock* block) noexce
return; return;
if (!copyArrayOfFloatArrays(rawSlots[switchLightsSlotIndex], "switchLights", block->switchLights, 3)) if (!copyArrayOfFloatArrays(rawSlots[switchLightsSlotIndex], "switchLights", block->switchLights, 3))
return; return;
if (!copyFloatArray(rawSlots[knobsSlotIndex], "knobs", block->knobs, NUM_ROWS))
if (!copyFloatArray(rawSlots[knobsSlotIndex], "", "knobs", block->knobs, NUM_ROWS))
return; return;
} }


@@ -340,15 +360,17 @@ bool SC_VcvPrototypeClient::isVcvPrototypeProcessBlock(const PyrSlot* slot) cons
return klassNameSymbol == _vcvPrototypeProcessBlockSym; 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)) { 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; return false;
} }
auto* floatArrayObj = slotRawObject(&inSlot); auto* floatArrayObj = slotRawObject(&inSlot);
if (floatArrayObj->size != size) { 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; return false;
} }


@@ -373,7 +395,7 @@ bool SC_VcvPrototypeClient::copyArrayOfFloatArrays(const PyrSlot& inSlot, const
} }


for (int i = 0; i < NUM_ROWS; ++i) { 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; return false;
} }
} }


Loading…
Cancel
Save