diff --git a/README.md b/README.md index 8a27efa..d41ecb8 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,17 @@ If you'd like to build the ChucKDesigner plugins yourself, these are the instruc ### Python interface to ChucK Audio CHOP -The ChucK Audio CHOP's functions: +The ChucK Audio CHOP's getter methods: + +* `.get_float(name: str) -> float` +* `.get_int(name: str) -> int` +* `.get_string(name: str) -> str` +* `.get_float_array(name: str) -> List[float]` +* `.get_int_array(name: str) -> List[int]` + +Note that these getters return results with a one-frame delay. They will return `None` the first time they're called. If `None` is returned on later calls, it means that the requested global variable wasn't found. + +The ChucK Audio CHOP's setter methods: * `.set_float(name: str, val: float)` * `.set_int(name: str, val: int)` @@ -83,6 +93,8 @@ The ChucK Audio CHOP's functions: * `.broadcast_event(name: str)` * `.set_log_level(level: int)` **0 is None and 10 is "Crazy"** +### Example + Suppose the ChucK Audio CHOP has compiled this code: ```chuck diff --git a/src/ChucKDesignerCHOP.cpp b/src/ChucKDesignerCHOP.cpp index 76e7217..c6e29ac 100644 --- a/src/ChucKDesignerCHOP.cpp +++ b/src/ChucKDesignerCHOP.cpp @@ -32,8 +32,7 @@ pySetGlobalFloat(PyObject* self, PyObject* args, void*) PY_Struct* me = (PY_Struct*)self; PY_GetInfo info; - // We don't want to cook the node before we set this, since it doesn't depend on its current state - info.autoCook = false; // todo: which value to use? + info.autoCook = false; ChucKDesignerCHOP* inst = (ChucKDesignerCHOP*)me->context->getNodeInstance(info); // It's possible the instance will be nullptr, such as if the node has been deleted // while the Python class is still being held on and used elsewhere. @@ -53,7 +52,6 @@ pySetGlobalFloat(PyObject* self, PyObject* args, void*) t_CKFLOAT castVal = PyFloat_AsDouble(val); inst->setGlobalFloat(castName, castVal); - // Make the node dirty so it will cook an output a newly reset filter when asked next me->context->makeNodeDirty(); } @@ -67,8 +65,7 @@ pySetGlobalInt(PyObject* self, PyObject* args, void*) PY_Struct* me = (PY_Struct*)self; PY_GetInfo info; - // We don't want to cook the node before we set this, since it doesn't depend on its current state - info.autoCook = false; // todo: which value to use? + info.autoCook = false; ChucKDesignerCHOP* inst = (ChucKDesignerCHOP*)me->context->getNodeInstance(info); // It's possible the instance will be nullptr, such as if the node has been deleted // while the Python class is still being held on and used elsewhere. @@ -88,7 +85,6 @@ pySetGlobalInt(PyObject* self, PyObject* args, void*) t_CKINT castVal = _PyLong_AsInt(val); inst->setGlobalInt(castName, castVal); - // Make the node dirty so it will cook an output a newly reset filter when asked next me->context->makeNodeDirty(); } @@ -102,8 +98,7 @@ pySetGlobalString(PyObject* self, PyObject* args, void*) PY_Struct* me = (PY_Struct*)self; PY_GetInfo info; - // We don't want to cook the node before we set this, since it doesn't depend on its current state - info.autoCook = false; // todo: which value to use? + info.autoCook = false; ChucKDesignerCHOP* inst = (ChucKDesignerCHOP*)me->context->getNodeInstance(info); // It's possible the instance will be nullptr, such as if the node has been deleted // while the Python class is still being held on and used elsewhere. @@ -121,7 +116,6 @@ pySetGlobalString(PyObject* self, PyObject* args, void*) const char* castVal = PyBytes_AsString(PyUnicode_AsASCIIString(val)); inst->setGlobalString(castName, castVal); - // Make the node dirty so it will cook an output a newly reset filter when asked next me->context->makeNodeDirty(); } @@ -135,8 +129,7 @@ pySetGlobalFloatArray(PyObject* self, PyObject* args, void*) PY_Struct* me = (PY_Struct*)self; PY_GetInfo info; - // We don't want to cook the node before we set this, since it doesn't depend on its current state - info.autoCook = false; // todo: which value to use? + info.autoCook = false; ChucKDesignerCHOP* inst = (ChucKDesignerCHOP*)me->context->getNodeInstance(info); // It's possible the instance will be nullptr, such as if the node has been deleted // while the Python class is still being held on and used elsewhere. @@ -163,7 +156,6 @@ pySetGlobalFloatArray(PyObject* self, PyObject* args, void*) inst->setGlobalFloatArray(castName, nums, numValues); delete[] nums; - // Make the node dirty so it will cook an output a newly reset filter when asked next me->context->makeNodeDirty(); } @@ -177,8 +169,7 @@ pySetGlobalIntArray(PyObject* self, PyObject* args, void*) PY_Struct* me = (PY_Struct*)self; PY_GetInfo info; - // We don't want to cook the node before we set this, since it doesn't depend on its current state - info.autoCook = false; // todo: which value to use? + info.autoCook = false; ChucKDesignerCHOP* inst = (ChucKDesignerCHOP*)me->context->getNodeInstance(info); // It's possible the instance will be nullptr, such as if the node has been deleted // while the Python class is still being held on and used elsewhere. @@ -205,7 +196,6 @@ pySetGlobalIntArray(PyObject* self, PyObject* args, void*) inst->setGlobalIntArray(castName, nums, numValues); delete[] nums; - // Make the node dirty so it will cook an output a newly reset filter when asked next me->context->makeNodeDirty(); } @@ -219,8 +209,7 @@ pySetGlobalFloatArrayValue(PyObject* self, PyObject* args, void*) PY_Struct* me = (PY_Struct*)self; PY_GetInfo info; - // We don't want to cook the node before we set this, since it doesn't depend on its current state - info.autoCook = false; // todo: which value to use? + info.autoCook = false; ChucKDesignerCHOP* inst = (ChucKDesignerCHOP*)me->context->getNodeInstance(info); // It's possible the instance will be nullptr, such as if the node has been deleted // while the Python class is still being held on and used elsewhere. @@ -241,7 +230,6 @@ pySetGlobalFloatArrayValue(PyObject* self, PyObject* args, void*) t_CKFLOAT castValue = PyFloat_AsDouble(value); inst->setGlobalFloatArrayValue(castName, castIndex, castValue); - // Make the node dirty so it will cook an output a newly reset filter when asked next me->context->makeNodeDirty(); } @@ -255,8 +243,7 @@ pySetGlobalIntArrayValue(PyObject* self, PyObject* args, void*) PY_Struct* me = (PY_Struct*)self; PY_GetInfo info; - // We don't want to cook the node before we set this, since it doesn't depend on its current state - info.autoCook = false; // todo: which value to use? + info.autoCook = false; ChucKDesignerCHOP* inst = (ChucKDesignerCHOP*)me->context->getNodeInstance(info); // It's possible the instance will be nullptr, such as if the node has been deleted // while the Python class is still being held on and used elsewhere. @@ -277,7 +264,6 @@ pySetGlobalIntArrayValue(PyObject* self, PyObject* args, void*) t_CKINT castValue = PyLong_AsLongLong(value); inst->setGlobalIntArrayValue(castName, castIndex, castValue); - // Make the node dirty so it will cook an output a newly reset filter when asked next me->context->makeNodeDirty(); } @@ -291,8 +277,7 @@ pySetGlobalAssociativeFloatArrayValue(PyObject* self, PyObject* args, void*) PY_Struct* me = (PY_Struct*)self; PY_GetInfo info; - // We don't want to cook the node before we set this, since it doesn't depend on its current state - info.autoCook = false; // todo: which value to use? + info.autoCook = false; ChucKDesignerCHOP* inst = (ChucKDesignerCHOP*)me->context->getNodeInstance(info); // It's possible the instance will be nullptr, such as if the node has been deleted // while the Python class is still being held on and used elsewhere. @@ -314,7 +299,6 @@ pySetGlobalAssociativeFloatArrayValue(PyObject* self, PyObject* args, void*) t_CKFLOAT castValue = PyFloat_AsDouble(value); inst->setGlobalAssociativeFloatArrayValue(castName, castKey, castValue); - // Make the node dirty so it will cook an output a newly reset filter when asked next me->context->makeNodeDirty(); } @@ -328,8 +312,7 @@ pySetGlobalAssociativeIntArrayValue(PyObject* self, PyObject* args, void*) PY_Struct* me = (PY_Struct*)self; PY_GetInfo info; - // We don't want to cook the node before we set this, since it doesn't depend on its current state - info.autoCook = false; // todo: which value to use? + info.autoCook = false; ChucKDesignerCHOP* inst = (ChucKDesignerCHOP*)me->context->getNodeInstance(info); // It's possible the instance will be nullptr, such as if the node has been deleted // while the Python class is still being held on and used elsewhere. @@ -351,7 +334,6 @@ pySetGlobalAssociativeIntArrayValue(PyObject* self, PyObject* args, void*) t_CKINT castValue = PyLong_AsLongLong(value); inst->setGlobalAssociativeIntArrayValue(castName, castKey, castValue); - // Make the node dirty so it will cook an output a newly reset filter when asked next me->context->makeNodeDirty(); } @@ -359,14 +341,170 @@ pySetGlobalAssociativeIntArrayValue(PyObject* self, PyObject* args, void*) FAIL_IN_CUSTOM_OPERATOR_METHOD } +static PyObject* pyGetGlobalFloat(PyObject* self, PyObject* args, void*) { + PY_Struct* me = (PY_Struct*)self; + + PY_GetInfo info; + info.autoCook = false; + ChucKDesignerCHOP* inst = + (ChucKDesignerCHOP*)me->context->getNodeInstance(info); + // It's possible the instance will be nullptr, such as if the node has been + // deleted while the Python class is still being held on and used elsewhere. + if (inst) { + PyObject* name; + + if (!PyArg_UnpackTuple(args, "ref", 1, 1, &name)) { + // error + FAIL_IN_CUSTOM_OPERATOR_METHOD + } + + const char* castName = PyBytes_AsString(PyUnicode_AsASCIIString(name)); + + t_CKFLOAT val; + if (inst->getGlobalFloat(castName, val)) { + return PyFloat_FromDouble(val); + } + } + + // We need to inc-ref the None object if we are going to return it. + FAIL_IN_CUSTOM_OPERATOR_METHOD +} + +static PyObject* pyGetGlobalInt(PyObject* self, PyObject* args, void*) { + PY_Struct* me = (PY_Struct*)self; + + PY_GetInfo info; + info.autoCook = false; + ChucKDesignerCHOP* inst = + (ChucKDesignerCHOP*)me->context->getNodeInstance(info); + // It's possible the instance will be nullptr, such as if the node has been + // deleted while the Python class is still being held on and used elsewhere. + if (inst) { + PyObject* name; + + if (!PyArg_UnpackTuple(args, "ref", 1, 1, &name)) { + // error + FAIL_IN_CUSTOM_OPERATOR_METHOD + } + + const char* castName = PyBytes_AsString(PyUnicode_AsASCIIString(name)); + + t_CKINT val; + if (inst->getGlobalInt(castName, val)) { + return PyLong_FromLongLong(val); + } + } + + // We need to inc-ref the None object if we are going to return it. + FAIL_IN_CUSTOM_OPERATOR_METHOD +} + +static PyObject* pyGetGlobalString(PyObject* self, PyObject* args, void*) { + PY_Struct* me = (PY_Struct*)self; + + PY_GetInfo info; + info.autoCook = false; + ChucKDesignerCHOP* inst = + (ChucKDesignerCHOP*)me->context->getNodeInstance(info); + // It's possible the instance will be nullptr, such as if the node has been + // deleted while the Python class is still being held on and used elsewhere. + if (inst) { + PyObject* name; + + if (!PyArg_UnpackTuple(args, "ref", 1, 1, &name)) { + // error + FAIL_IN_CUSTOM_OPERATOR_METHOD + } + + const char* castName = PyBytes_AsString(PyUnicode_AsASCIIString(name)); + + std::string val; + if (inst->getGlobalString(castName, val)) { + return PyUnicode_FromString(val.c_str()); + } + } + + // We need to inc-ref the None object if we are going to return it. + FAIL_IN_CUSTOM_OPERATOR_METHOD +} + +static PyObject* pyGetGlobalFloatArray(PyObject* self, PyObject* args, void*) { + PY_Struct* me = (PY_Struct*)self; + + PY_GetInfo info; + info.autoCook = false; + ChucKDesignerCHOP* inst = + (ChucKDesignerCHOP*)me->context->getNodeInstance(info); + // It's possible the instance will be nullptr, such as if the node has been + // deleted while the Python class is still being held on and used elsewhere. + if (inst) { + PyObject* name; + + if (!PyArg_UnpackTuple(args, "ref", 1, 1, &name)) { + // error + FAIL_IN_CUSTOM_OPERATOR_METHOD + } + + const char* castName = PyBytes_AsString(PyUnicode_AsASCIIString(name)); + + t_CKFLOAT* vec = nullptr; + int numItems = 0; + if (inst->getGlobalFloatArray(castName, &vec, numItems)) { + // todo: return a numpy array + PyObject* lst = PyList_New(numItems); + for (int i = 0; i < numItems; i++) { + PyList_SET_ITEM(lst, i, PyFloat_FromDouble(*(vec++))); + } + return lst; + } + } + + // We need to inc-ref the None object if we are going to return it. + FAIL_IN_CUSTOM_OPERATOR_METHOD +} + +static PyObject* pyGetGlobalIntArray(PyObject* self, PyObject* args, void*) { + PY_Struct* me = (PY_Struct*)self; + + PY_GetInfo info; + info.autoCook = false; + ChucKDesignerCHOP* inst = + (ChucKDesignerCHOP*)me->context->getNodeInstance(info); + // It's possible the instance will be nullptr, such as if the node has been + // deleted while the Python class is still being held on and used elsewhere. + if (inst) { + PyObject* name; + + if (!PyArg_UnpackTuple(args, "ref", 1, 1, &name)) { + // error + FAIL_IN_CUSTOM_OPERATOR_METHOD + } + + const char* castName = PyBytes_AsString(PyUnicode_AsASCIIString(name)); + + t_CKINT* vec = nullptr; + int numItems = 0; + if (inst->getGlobalIntArray(castName, &vec, numItems)) { + // todo: return a numpy array + PyObject* lst = PyList_New(numItems); + for (int i = 0; i < numItems; i++) { + PyList_SET_ITEM(lst, i, PyLong_FromLongLong(*(vec++))); + } + return lst; + } + } + + // We need to inc-ref the None object if we are going to return it. + FAIL_IN_CUSTOM_OPERATOR_METHOD +} + static PyObject* pyBroadcastChuckEvent(PyObject* self, PyObject* args, void*) { PY_Struct* me = (PY_Struct*)self; PY_GetInfo info; - // We don't want to cook the node before we set this, since it doesn't depend on its current state - info.autoCook = false; // todo: which value to use? + info.autoCook = false; ChucKDesignerCHOP* inst = (ChucKDesignerCHOP*)me->context->getNodeInstance(info); // It's possible the instance will be nullptr, such as if the node has been deleted // while the Python class is still being held on and used elsewhere. @@ -382,7 +520,6 @@ pyBroadcastChuckEvent(PyObject* self, PyObject* args, void*) const char* castName = PyBytes_AsString(PyUnicode_AsASCIIString(name)); inst->broadcastChuckEvent(castName); - // Make the node dirty so it will cook an output a newly reset filter when asked next me->context->makeNodeDirty(); } @@ -396,8 +533,7 @@ pySetLogLevel(PyObject* self, PyObject* args, void*) PY_Struct* me = (PY_Struct*)self; PY_GetInfo info; - // We don't want to cook the node before we set this, since it doesn't depend on its current state - info.autoCook = false; // todo: which value to use? + info.autoCook = false; ChucKDesignerCHOP* inst = (ChucKDesignerCHOP*)me->context->getNodeInstance(info); // It's possible the instance will be nullptr, such as if the node has been deleted // while the Python class is still being held on and used elsewhere. @@ -411,7 +547,6 @@ pySetLogLevel(PyObject* self, PyObject* args, void*) } inst->setLogLevel(_PyLong_AsInt(level)); - // Make the node dirty so it will cook an output a newly reset filter when asked next me->context->makeNodeDirty(); } @@ -436,6 +571,12 @@ static PyMethodDef methods[] = {"broadcast_event", (PyCFunction)pyBroadcastChuckEvent, METH_VARARGS, "Broadcast an event to ChucK."}, + {"get_float", (PyCFunction)pyGetGlobalFloat, METH_VARARGS, "Get a ChucK global float variable."}, + {"get_int", (PyCFunction)pyGetGlobalInt, METH_VARARGS, "Get a ChucK global int variable."}, + {"get_string", (PyCFunction)pyGetGlobalString, METH_VARARGS, "Get a ChucK global string variable."}, + {"get_float_array", (PyCFunction)pyGetGlobalFloatArray, METH_VARARGS, "Get a ChucK global float array variable."}, + {"get_int_array", (PyCFunction)pyGetGlobalIntArray, METH_VARARGS, "Get a ChucK global int array variable."}, + {"set_log_level", (PyCFunction)pySetLogLevel, METH_VARARGS, "Set ChucK's log level."}, {0} @@ -592,8 +733,6 @@ ChucKDesignerCHOP::execute(CHOP_Output* output, memset(inChucKBuffer, 0.f, sizeof(float) * CHUCKDESIGNERCHOP_BUFFER_SIZE * m_inChannels); memset(outChucKBuffer, 0.f, sizeof(float) * CHUCKDESIGNERCHOP_BUFFER_SIZE * m_outChannels); - //m_chuckID = ChucK_For_TouchDesigner::getNextValidID(myNodeInfo->opId); - ChucK_For_TouchDesigner::initChuckInstance(m_chuckID, sample_rate, m_inChannels, m_outChannels, globalDir); const OP_DATInput* codeInput = inputs->getParDAT("Code"); diff --git a/src/ChucKDesignerCHOP.h b/src/ChucKDesignerCHOP.h index a9cb0ef..0e5b42b 100644 --- a/src/ChucKDesignerCHOP.h +++ b/src/ChucKDesignerCHOP.h @@ -108,6 +108,36 @@ class ChucKDesignerCHOP : public CHOP_CPlusPlusBase ChucK_For_TouchDesigner::setGlobalAssociativeIntArrayValue(m_chuckID, name, key, value); } + bool getGlobalFloat(const char* name, t_CKFLOAT &val) + { + ChucK_For_TouchDesigner::getNamedChuckFloat(m_chuckID, name, ChucK_For_TouchDesigner::sharedFloatCallback); + return ChucK_For_TouchDesigner::getFloat(name, val); + } + + bool getGlobalInt(const char* name, t_CKINT& val) + { + ChucK_For_TouchDesigner::getNamedChuckInt(m_chuckID, name, ChucK_For_TouchDesigner::sharedIntCallback); + return ChucK_For_TouchDesigner::getInt(name, val); + } + + bool getGlobalString(const char* name, std::string& val) + { + ChucK_For_TouchDesigner::getNamedChuckString(m_chuckID, name, ChucK_For_TouchDesigner::sharedStringCallback); + return ChucK_For_TouchDesigner::getString(name, val); + } + + bool getGlobalIntArray(const char* name, t_CKINT** vec, int& numValues) + { + ChucK_For_TouchDesigner::getNamedGlobalIntArray(m_chuckID, name, ChucK_For_TouchDesigner::sharedIntArrayCallback); + return ChucK_For_TouchDesigner::getIntArray(name, vec, numValues); + } + + bool getGlobalFloatArray(const char* name, t_CKFLOAT** vec, int& numValues) + { + ChucK_For_TouchDesigner::getNamedGlobalFloatArray(m_chuckID, name, ChucK_For_TouchDesigner::sharedFloatArrayCallback); + return ChucK_For_TouchDesigner::getFloatArray(name, vec, numValues); + } + void broadcastChuckEvent(const char* name) { diff --git a/src/ChucKListenerCHOP.cpp b/src/ChucKListenerCHOP.cpp index 4d3f8e9..d562553 100644 --- a/src/ChucKListenerCHOP.cpp +++ b/src/ChucKListenerCHOP.cpp @@ -272,7 +272,7 @@ ChucKListenerCHOP::execute(CHOP_Output* output, ChucK_For_TouchDesigner::getNamedGlobalIntArray(chuck_id, varName.c_str(), ChucK_For_TouchDesigner::sharedIntArrayCallback); } - // << event stuff +#pragma region Events std::string Eventvars = inputs->getParString("Eventvars"); auto Eventvarstrings = split(Eventvars, ' '); @@ -301,13 +301,17 @@ ChucKListenerCHOP::execute(CHOP_Output* output, myEventVarNames.insert(varName); } } - // end event stuff >> +#pragma endregion Events int i = 0; for (const std::string varName : myFloatVarNames) { auto name = varName.c_str(); - t_CKFLOAT val = ChucK_For_TouchDesigner::getFloat(name); + t_CKFLOAT val = 0; + if (!ChucK_For_TouchDesigner::getFloat(name, val)) + { + continue; + } if (i < output->numChannels) { output->channels[i][0] = val; } @@ -331,8 +335,11 @@ ChucKListenerCHOP::execute(CHOP_Output* output, for (const std::string varName : myIntVarNames) { - auto name = varName.c_str(); - t_CKINT val = ChucK_For_TouchDesigner::getInt(name); + auto name = varName.c_str(); + t_CKINT val = 0; + if (!ChucK_For_TouchDesigner::getInt(name, val)) { + continue; + } if (i < output->numChannels) { output->channels[i][0] = val; } @@ -356,13 +363,16 @@ ChucKListenerCHOP::execute(CHOP_Output* output, for (const std::string varName : myStringVarNames) { auto name = varName.c_str(); - auto str = ChucK_For_TouchDesigner::getString(name); + std::string str = ""; + if (!ChucK_For_TouchDesigner::getString(name, str)) { + continue; + } // We'll only be adding one extra argument PyObject* args = myNodeInfo->context->createArgumentsTuple(2, nullptr); // The first argument is already set to the 'op' variable, so we set the second argument to our speed value PyTuple_SET_ITEM(args, 1, PyUnicode_FromString(name)); - PyTuple_SET_ITEM(args, 2, PyUnicode_FromString(str)); + PyTuple_SET_ITEM(args, 2, PyUnicode_FromString(str.c_str())); PyObject* result = myNodeInfo->context->callPythonCallback("getString", args, nullptr, nullptr); // callPythonCallback doesn't take ownership of the argts @@ -376,9 +386,8 @@ ChucKListenerCHOP::execute(CHOP_Output* output, { auto name = varName.c_str(); int numItems = 0; - auto vec = ChucK_For_TouchDesigner::getFloatArray(name, numItems); - - if (!numItems || !vec) { + t_CKFLOAT* vec = nullptr; + if (!ChucK_For_TouchDesigner::getFloatArray(name, &vec, numItems)) { continue; } @@ -408,9 +417,9 @@ ChucKListenerCHOP::execute(CHOP_Output* output, { auto name = varName.c_str(); int numItems = 0; - auto vec = ChucK_For_TouchDesigner::getIntArray(name, numItems); + t_CKINT* vec = nullptr; - if (!numItems || !vec) { + if (!ChucK_For_TouchDesigner::getIntArray(name, &vec, numItems)) { continue; } @@ -453,7 +462,6 @@ ChucKListenerCHOP::execute(CHOP_Output* output, // We own result now, so we need to Py_DECREF it unless we want to hold onto it if (result) { Py_DECREF(result); } } - } } diff --git a/src/Plugin_ChucK.cpp b/src/Plugin_ChucK.cpp index b7c31dd..70dfba1 100644 --- a/src/Plugin_ChucK.cpp +++ b/src/Plugin_ChucK.cpp @@ -727,7 +727,6 @@ namespace ChucK_For_TouchDesigner } - // internal/audio-thread-friendly global array setter CHUCKDESIGNERSHARED_API bool setGlobalFloatArray_AT( unsigned int chuckID, const char* name, t_CKFLOAT arrayValues[], unsigned int numValues) @@ -739,6 +738,7 @@ namespace ChucK_For_TouchDesigner return gm->set_global_float_array(name, arrayValues, numValues); } + CHUCKDESIGNERSHARED_API bool setGlobalFloatArrayValue_AT( unsigned int chuckID, const char* name, unsigned int index, t_CKFLOAT value) { if (chuck_instances.count(chuckID) == 0) { return false; } @@ -748,6 +748,7 @@ namespace ChucK_For_TouchDesigner return gm->set_global_float_array_value(name, index, value); } + CHUCKDESIGNERSHARED_API bool setChoutCallback(unsigned int chuckID, void (*callback)(const char*)) { return chuck_instances[chuckID]->setChoutCallback(callback); @@ -934,49 +935,72 @@ namespace ChucK_For_TouchDesigner return count; } - CHUCKDESIGNERSHARED_API t_CKFLOAT getFloat(const char* varName) { - if (myFloatVars.find(varName) != myFloatVars.end()) { - return myFloatVars[varName]; - } - return 0.f; + CHUCKDESIGNERSHARED_API bool getFloat(const char* varName, t_CKFLOAT &val) { + if (myFloatVars.find(varName) != myFloatVars.end()) { + val = myFloatVars[varName]; + return true; + } + return false; } - CHUCKDESIGNERSHARED_API t_CKINT getInt(const char* varName) { + CHUCKDESIGNERSHARED_API bool getInt(const char* varName, t_CKINT& val) { if (myIntVars.find(varName) != myIntVars.end()) { - return myIntVars[varName]; + val = myIntVars[varName]; + return true; } - return 0; + return false; } - CHUCKDESIGNERSHARED_API const char* getString(const char* varName) { + CHUCKDESIGNERSHARED_API bool getString(const char* varName, std::string& val) { if (myStringVars.find(varName) != myStringVars.end()) { - return myStringVars[varName].c_str(); + val = myStringVars[varName]; + return true; } - return ""; + return false; } - CHUCKDESIGNERSHARED_API t_CKFLOAT* getFloatArray(const char* varName, int& numItems) { + CHUCKDESIGNERSHARED_API bool getFloatArray(const char* varName, t_CKFLOAT** vec, int& numItems) { if ( (myFloatArrayVars.find(varName) != myFloatArrayVars.end()) && (myFloatArrayVarSizes.find(varName) != myFloatArrayVarSizes.end()) ) { numItems = myFloatArrayVarSizes[varName]; - return myFloatArrayVars[varName]; + *vec = myFloatArrayVars[varName]; + return true; } numItems = 0; - return nullptr; + return false; } - CHUCKDESIGNERSHARED_API t_CKINT* getIntArray(const char* varName, int& numItems) { + CHUCKDESIGNERSHARED_API bool getIntArray(const char* varName, t_CKINT** vec, int& numItems) { if ( (myIntArrayVars.find(varName) != myIntArrayVars.end()) && (myIntArrayVarSizes.find(varName) != myIntArrayVarSizes.end()) ) { numItems = myIntArrayVarSizes[varName]; - return myIntArrayVars[varName]; + *vec = myIntArrayVars[varName]; + return true; } numItems = 0; - return nullptr; + return false; + } + + CHUCKDESIGNERSHARED_API bool getFloatArrayValue(const char* varName, unsigned int index, t_CKFLOAT& val) { + if ((myFloatArrayVars.find(varName) != myFloatArrayVars.end()) && + (myFloatArrayVarSizes.find(varName) != myFloatArrayVarSizes.end())) { + val = myFloatArrayVars[varName][index]; + return true; + } + return false; + } + + CHUCKDESIGNERSHARED_API bool getIntArrayValue(const char* varName, unsigned int index, t_CKINT& val) { + if ((myIntArrayVars.find(varName) != myIntArrayVars.end()) && + (myIntArrayVars.find(varName) != myIntArrayVars.end())) { + val = myIntArrayVars[varName][index]; + return true; + } + return false; } CHUCKDESIGNERSHARED_API bool initChuckInstance( unsigned int chuckID, unsigned int sampleRate, unsigned int numInChannels, unsigned int numOutChannels, string globalDir ) diff --git a/src/Plugin_ChucK.h b/src/Plugin_ChucK.h index d0b91c0..d981c9e 100644 --- a/src/Plugin_ChucK.h +++ b/src/Plugin_ChucK.h @@ -41,7 +41,6 @@ extern "C" { CHUCKDESIGNERSHARED_API bool getNamedChuckInt(unsigned int chuckID, const char* name, void (*callback)(const char*, t_CKINT)); CHUCKDESIGNERSHARED_API bool getChuckIntWithID(unsigned int chuckID, t_CKINT callbackID, const char* name, void (*callback)(t_CKINT, t_CKINT)); - CHUCKDESIGNERSHARED_API bool setChuckFloat(unsigned int chuckID, const char* name, t_CKFLOAT val); CHUCKDESIGNERSHARED_API bool getChuckFloat(unsigned int chuckID, const char* name, void (*callback)(t_CKFLOAT)); CHUCKDESIGNERSHARED_API bool getNamedChuckFloat(unsigned int chuckID, const char* name, void (*callback)(const char*, t_CKFLOAT)); @@ -121,11 +120,16 @@ extern "C" { CHUCKDESIGNERSHARED_API bool processBlock(unsigned int chuckID, const float** inBuffer, int inBufferNumChannels, int inBufferNumSamples, float* inChucKBuffer, float* outChucKBuffer, float** outBuffer, int numOutSamples, int numOutChannels); - CHUCKDESIGNERSHARED_API t_CKFLOAT getFloat(const char* varStr); - CHUCKDESIGNERSHARED_API t_CKINT getInt(const char* varStr); - CHUCKDESIGNERSHARED_API const char* getString(const char* varStr); - CHUCKDESIGNERSHARED_API t_CKFLOAT* getFloatArray(const char* varName, int& numItems); - CHUCKDESIGNERSHARED_API t_CKINT* getIntArray(const char* varName, int& numItems); + CHUCKDESIGNERSHARED_API bool getFloat(const char* varName, t_CKFLOAT& val); + CHUCKDESIGNERSHARED_API bool getInt(const char* varStr, t_CKINT& val); + CHUCKDESIGNERSHARED_API bool getString(const char* varStr, std::string& val); + CHUCKDESIGNERSHARED_API bool getFloatArray(const char* varName, t_CKFLOAT** vec, int& numItems); + CHUCKDESIGNERSHARED_API bool getIntArray(const char* varName, t_CKINT** vec, int& numItems); + + CHUCKDESIGNERSHARED_API bool getFloatArrayValue(const char* varName, unsigned int index, t_CKFLOAT& val); + CHUCKDESIGNERSHARED_API bool getIntArrayValue(const char* varName, unsigned int index, t_CKINT& val); + //CHUCKDESIGNERSHARED_API bool getAssociativeFloatArrayValue(const char* varName, char* key, unsigned int index, t_CKFLOAT& val); + //CHUCKDESIGNERSHARED_API bool getAssociativeIntArrayValue(const char* varName, char* key, unsigned int index, t_CKINT& val); CHUCKDESIGNERSHARED_API void sharedFloatCallback(const char* varName, t_CKFLOAT val); CHUCKDESIGNERSHARED_API void sharedIntCallback(const char* varName, t_CKINT val); @@ -134,6 +138,9 @@ extern "C" { CHUCKDESIGNERSHARED_API void sharedFloatArrayCallback(const char* varName, t_CKFLOAT vals[], t_CKUINT numItems); CHUCKDESIGNERSHARED_API void sharedIntArrayCallback(const char* varName, t_CKINT vals[], t_CKUINT numItems); + //CHUCKDESIGNERSHARED_API void sharedAssociativeFloatArrayCallback(const char* varName, t_CKFLOAT val); + //CHUCKDESIGNERSHARED_API void sharedAssociativeIntArrayCallback(const char* varName, t_CKUINT val); + CHUCKDESIGNERSHARED_API void sharedEventCallback(const char* varName); CHUCKDESIGNERSHARED_API void sharedEventNonCallback(const char* varName);