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();

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


Loading…
Cancel
Save