diff --git a/source/backend/CarlaBackend.hpp b/source/backend/CarlaBackend.hpp index 4931e7ae4..d5a1fa8a9 100644 --- a/source/backend/CarlaBackend.hpp +++ b/source/backend/CarlaBackend.hpp @@ -92,14 +92,15 @@ const unsigned int PLUGIN_OPTION_SEND_ALL_SOUND_OFF = 0x100; //!< Send MIDI a * \see CarlaPlugin::parameterData() * @{ */ -const unsigned int PARAMETER_IS_BOOLEAN = 0x01; //!< Parameter value is a boolean (always at minimum or maximum values). -const unsigned int PARAMETER_IS_INTEGER = 0x02; //!< Parameter value is an integer. -const unsigned int PARAMETER_IS_LOGARITHMIC = 0x04; //!< Parameter is logarithmic. -const unsigned int PARAMETER_IS_ENABLED = 0x08; //!< Parameter is enabled and will be shown in the host built-in editor. -const unsigned int PARAMETER_IS_AUTOMABLE = 0x10; //!< Parameter is automable (realtime safe) -const unsigned int PARAMETER_USES_SAMPLERATE = 0x20; //!< Parameter needs sample rate to work (value and ranges are multiplied by SR, and must be divided by SR on save). -const unsigned int PARAMETER_USES_SCALEPOINTS = 0x40; //!< Parameter uses scalepoints to define internal values in a meaningful way. -const unsigned int PARAMETER_USES_CUSTOM_TEXT = 0x80; //!< Parameter uses custom text for displaying its value.\see CarlaPlugin::getParameterText() +const unsigned int PARAMETER_IS_BOOLEAN = 0x001; //!< Parameter value is a boolean (always at minimum or maximum values). +const unsigned int PARAMETER_IS_INTEGER = 0x002; //!< Parameter value is an integer. +const unsigned int PARAMETER_IS_LOGARITHMIC = 0x004; //!< Parameter is logarithmic. +const unsigned int PARAMETER_IS_ENABLED = 0x008; //!< Parameter is enabled and will be shown in the host built-in editor. +const unsigned int PARAMETER_IS_AUTOMABLE = 0x010; //!< Parameter is automable (realtime safe) +const unsigned int PARAMETER_IS_READ_ONLY = 0x020; //!< Parameter is read-only +const unsigned int PARAMETER_USES_SAMPLERATE = 0x040; //!< Parameter needs sample rate to work (value and ranges are multiplied by SR, and must be divided by SR on save). +const unsigned int PARAMETER_USES_SCALEPOINTS = 0x080; //!< Parameter uses scalepoints to define internal values in a meaningful way. +const unsigned int PARAMETER_USES_CUSTOM_TEXT = 0x100; //!< Parameter uses custom text for displaying its value.\see CarlaPlugin::getParameterText() /**@}*/ /*! diff --git a/source/backend/CarlaEngine.hpp b/source/backend/CarlaEngine.hpp index c2cfcdbc8..105a121e3 100644 --- a/source/backend/CarlaEngine.hpp +++ b/source/backend/CarlaEngine.hpp @@ -517,7 +517,7 @@ public: /*! * Write buffer back into the engine. */ - virtual void writeBuffer(CarlaEngine* const engine); + virtual void writeBuffer(const uint32_t frames, const uint32_t timeOffset); /*! * Set a new buffer size. diff --git a/source/backend/engine/CarlaEngine.cpp b/source/backend/engine/CarlaEngine.cpp index 01933cc3d..cb10996d7 100644 --- a/source/backend/engine/CarlaEngine.cpp +++ b/source/backend/engine/CarlaEngine.cpp @@ -142,21 +142,12 @@ void CarlaEngineCVPort::initBuffer(CarlaEngine* const engine) { CARLA_ASSERT(engine != nullptr && engine->getBufferSize() == fBufferSize); - if (! kIsInput) - carla_zeroFloat(fBuffer, fBufferSize); + carla_zeroFloat(fBuffer, fBufferSize); } -void CarlaEngineCVPort::writeBuffer(CarlaEngine* const engine) +void CarlaEngineCVPort::writeBuffer(const uint32_t, const uint32_t) { CARLA_ASSERT(! kIsInput); - CARLA_ASSERT(engine != nullptr); - - if (kIsInput) - return; - if (engine == nullptr) - return; - - CARLA_ASSERT(engine->getBufferSize() == fBufferSize); } void CarlaEngineCVPort::setBufferSize(const uint32_t bufferSize) diff --git a/source/backend/engine/CarlaEngineJack.cpp b/source/backend/engine/CarlaEngineJack.cpp index 2a2981a9c..c43ba2f55 100644 --- a/source/backend/engine/CarlaEngineJack.cpp +++ b/source/backend/engine/CarlaEngineJack.cpp @@ -162,20 +162,15 @@ public: } } - void writeBuffer(CarlaEngine* const engine) override + void writeBuffer(const uint32_t frames, const uint32_t timeOffset) override { CARLA_ASSERT(! kIsInput); - CARLA_ASSERT(engine != nullptr); if (kIsInput) return; - if (engine == nullptr) - return; - - CARLA_ASSERT(engine->getBufferSize() == fBufferSize); float* const jackBuffer((float*)jackbridge_port_get_buffer(kPort, fBufferSize)); - carla_copyFloat(jackBuffer, fBuffer, fBufferSize); + carla_copyFloat(jackBuffer+timeOffset, fBuffer, frames); } private: diff --git a/source/backend/plugin/DssiPlugin.cpp b/source/backend/plugin/DssiPlugin.cpp index 40cb6be01..e7df4540a 100644 --- a/source/backend/plugin/DssiPlugin.cpp +++ b/source/backend/plugin/DssiPlugin.cpp @@ -510,10 +510,9 @@ public: if (params > 0) { kData->param.createNew(params); - fParamBuffers = new float[params]; - for (uint32_t i=0; i < params; ++i) - fParamBuffers[i] = 0.0f; + fParamBuffers = new float[params]; + carla_zeroFloat(fParamBuffers, params); } const uint portNameSize(kData->engine->maxPortNameSize()); diff --git a/source/backend/plugin/LadspaPlugin.cpp b/source/backend/plugin/LadspaPlugin.cpp index 886d176b4..26fe68d70 100644 --- a/source/backend/plugin/LadspaPlugin.cpp +++ b/source/backend/plugin/LadspaPlugin.cpp @@ -491,10 +491,9 @@ public: if (params > 0) { kData->param.createNew(params); - fParamBuffers = new float[params]; - for (uint32_t i=0; i < params; ++i) - fParamBuffers[i] = 0.0f; + fParamBuffers = new float[params]; + carla_zeroFloat(fParamBuffers, params); } const uint portNameSize(kData->engine->maxPortNameSize()); diff --git a/source/backend/plugin/Lv2Plugin.cpp b/source/backend/plugin/Lv2Plugin.cpp index 494118ef7..7218b2a30 100644 --- a/source/backend/plugin/Lv2Plugin.cpp +++ b/source/backend/plugin/Lv2Plugin.cpp @@ -17,8 +17,6 @@ #include "CarlaPluginInternal.hpp" -#define WANT_LV2 - #ifdef WANT_LV2 #include "CarlaPluginGui.hpp" @@ -1375,8 +1373,6 @@ public: params += 1; } - params += cvIns + cvOuts; - // check extensions fExt.options = nullptr; fExt.programs = nullptr; @@ -1440,22 +1436,22 @@ public: if (cvIns > 0) { - fCvIn.createNew(aIns); + fCvIn.createNew(cvIns); + needsCtrlIn = true; } if (cvOuts > 0) { - fCvOut.createNew(aOuts); - needsCtrlIn = true; + fCvOut.createNew(cvOuts); + needsCtrlOut = true; } if (params > 0) { - kData->param.createNew(params); - fParamBuffers = new float[params]; + kData->param.createNew(params+cvIns+cvOuts); - for (uint32_t i=0; i < params; ++i) - fParamBuffers[i] = 0.0f; + fParamBuffers = new float[params+cvIns+cvOuts]; + carla_zeroFloat(fParamBuffers, params+cvIns+cvOuts); } if (evIns.count() > 0) @@ -1579,51 +1575,57 @@ public: if (LV2_IS_PORT_INPUT(portTypes)) { j = iCvIn++; - fCvIn.ports[j].port = (CarlaEngineCVPort*)kData->client->addPort(kEnginePortTypeCV, portName, true); - fCvIn.ports[j].rindex = i; + fCvIn.ports[j].port = (CarlaEngineCVPort*)kData->client->addPort(kEnginePortTypeCV, portName, true); + fCvIn.ports[j].rindex = i; + fCvIn.ports[j].param = params + j; fDescriptor->connect_port(fHandle, i, fCvIn.ports[j].port->getBuffer()); if (fHandle2 != nullptr) fDescriptor->connect_port(fHandle2, i, fCvIn.ports[j].port->getBuffer()); - j = params + j; + j = fCvIn.ports[j].param; + kData->param.data[j].type = PARAMETER_INPUT; kData->param.data[j].index = j; kData->param.data[j].rindex = i; - kData->param.data[j].hints = 0x0; + kData->param.data[j].hints = PARAMETER_IS_ENABLED|PARAMETER_IS_READ_ONLY; kData->param.data[j].midiChannel = 0; kData->param.data[j].midiCC = -1; - kData->param.ranges[j].min = 0.0f; + kData->param.ranges[j].min = -1.0f; kData->param.ranges[j].max = 1.0f; kData->param.ranges[j].def = 0.0f; kData->param.ranges[j].step = 0.01f; kData->param.ranges[j].stepSmall = 0.001f; kData->param.ranges[j].stepLarge = 0.1f; + fParamBuffers[j] = 0.0f; } else if (LV2_IS_PORT_OUTPUT(portTypes)) { j = iCvOut++; - fCvOut.ports[j].port = (CarlaEngineCVPort*)kData->client->addPort(kEnginePortTypeCV, portName, false); - fCvOut.ports[j].rindex = i; + fCvOut.ports[j].port = (CarlaEngineCVPort*)kData->client->addPort(kEnginePortTypeCV, portName, false); + fCvOut.ports[j].rindex = i; + fCvOut.ports[j].param = params + cvIns + j; fDescriptor->connect_port(fHandle, i, fCvOut.ports[j].port->getBuffer()); if (fHandle2 != nullptr) fDescriptor->connect_port(fHandle2, i, fCvOut.ports[j].port->getBuffer()); - j = params + cvIns + j; + j = fCvOut.ports[j].param; + kData->param.data[j].type = PARAMETER_OUTPUT; kData->param.data[j].index = j; kData->param.data[j].rindex = i; - kData->param.data[j].hints = 0x0; + kData->param.data[j].hints = PARAMETER_IS_ENABLED|PARAMETER_IS_AUTOMABLE; kData->param.data[j].midiChannel = 0; kData->param.data[j].midiCC = -1; - kData->param.ranges[j].min = 0.0f; + kData->param.ranges[j].min = -1.0f; kData->param.ranges[j].max = 1.0f; kData->param.ranges[j].def = 0.0f; kData->param.ranges[j].step = 0.01f; kData->param.ranges[j].stepSmall = 0.001f; kData->param.ranges[j].stepLarge = 0.1f; + fParamBuffers[j] = 0.0f; } else carla_stderr("WARNING - Got a broken Port (CV, but not input or output)"); @@ -3155,6 +3157,21 @@ public: for (i=0; i < kData->audioOut.count; ++i) carla_zeroFloat(fAudioOutBuffers[i], frames); + // -------------------------------------------------------------------------------------------------------- + // Set CV input buffers + + for (i=0; i < fCvIn.count; ++i) + { + const uint32_t cvIndex(fCvIn.ports[i].param); + const float cvValue((fCvIn.ports[i].port->getBuffer()+timeOffset)[0]); + + if (fParamBuffers[cvIndex] != cvValue) + { + fParamBuffers[cvIndex] = cvValue; + postponeRtEvent(kPluginPostRtEventParameterChange, static_cast(cvIndex), 0, cvValue); + } + } + // -------------------------------------------------------------------------------------------------------- // Run plugin @@ -3267,6 +3284,18 @@ public: } #endif + // -------------------------------------------------------------------------------------------------------- + // Set CV output buffers + + for (i=0; i < fCvOut.count; ++i) + { + const uint32_t cvIndex(fCvOut.ports[i].param); + const float cvValue(fCvOut.ports[i].port->getBuffer()[0]); + + fCvOut.ports[i].port->writeBuffer(frames, timeOffset); + fParamBuffers[cvIndex] = cvValue; + } + // -------------------------------------------------------------------------------------------------------- kData->singleMutex.unlock(); @@ -3292,6 +3321,32 @@ public: fAudioOutBuffers[i] = new float[newBufferSize]; } + for (uint32_t i=0; i < fCvIn.count; ++i) + { + if (CarlaEngineCVPort* const port = fCvIn.ports[i].port) + { + port->setBufferSize(newBufferSize); + + fDescriptor->connect_port(fHandle, fCvIn.ports[i].rindex, port->getBuffer()); + + if (fHandle2 != nullptr) + fDescriptor->connect_port(fHandle2, fCvIn.ports[i].rindex, port->getBuffer()); + } + } + + for (uint32_t i=0; i < fCvOut.count; ++i) + { + if (CarlaEngineCVPort* const port = fCvOut.ports[i].port) + { + port->setBufferSize(newBufferSize); + + fDescriptor->connect_port(fHandle, fCvOut.ports[i].rindex, port->getBuffer()); + + if (fHandle2 != nullptr) + fDescriptor->connect_port(fHandle2, fCvOut.ports[i].rindex, port->getBuffer()); + } + } + if (fHandle2 == nullptr) { for (uint32_t i=0; i < kData->audioIn.count; ++i) @@ -3390,6 +3445,8 @@ public: { fEventsIn.initBuffers(kData->engine); fEventsOut.initBuffers(kData->engine); + fCvIn.initBuffers(kData->engine); + fCvOut.initBuffers(kData->engine); CarlaPlugin::initBuffers(); } @@ -3436,6 +3493,8 @@ public: fEventsIn.clear(); fEventsOut.clear(); + fCvIn.clear(); + fCvOut.clear(); CarlaPlugin::clearBuffers(); @@ -4303,7 +4362,7 @@ public: { const LV2_Property portTypes(fRdfDescriptor->Ports[i].Types); - if (! (LV2_IS_PORT_AUDIO(portTypes) || LV2_IS_PORT_CONTROL(portTypes) || LV2_IS_PORT_ATOM_SEQUENCE(portTypes) || LV2_IS_PORT_EVENT(portTypes) || LV2_IS_PORT_MIDI_LL(portTypes))) + if (! is_lv2_port_supported(portTypes)) { if (! LV2_IS_PORT_OPTIONAL(fRdfDescriptor->Ports[i].Properties)) { @@ -5326,7 +5385,7 @@ private: static void carla_lilv_set_port_value(const char* port_symbol, void* user_data, const void* value, uint32_t size, uint32_t type) { CARLA_ASSERT(user_data != nullptr); - carla_debug("carla_lilv_set_port_value(\"%s\", %p, %p, %i, %i", port_symbol, user_data, value, size, type); + carla_debug("carla_lilv_set_port_value(\"%s\", %p, %p, %i, %i)", port_symbol, user_data, value, size, type); if (user_data == nullptr) return; diff --git a/source/carla_backend.py b/source/carla_backend.py index 11f2a332b..8c47616c5 100644 --- a/source/carla_backend.py +++ b/source/carla_backend.py @@ -116,14 +116,15 @@ PLUGIN_OPTION_SEND_PITCHBEND = 0x080 PLUGIN_OPTION_SEND_ALL_SOUND_OFF = 0x100 # Parameter Hints -PARAMETER_IS_BOOLEAN = 0x01 -PARAMETER_IS_INTEGER = 0x02 -PARAMETER_IS_LOGARITHMIC = 0x04 -PARAMETER_IS_ENABLED = 0x08 -PARAMETER_IS_AUTOMABLE = 0x10 -PARAMETER_USES_SAMPLERATE = 0x20 -PARAMETER_USES_SCALEPOINTS = 0x40 -PARAMETER_USES_CUSTOM_TEXT = 0x80 +PARAMETER_IS_BOOLEAN = 0x001 +PARAMETER_IS_INTEGER = 0x002 +PARAMETER_IS_LOGARITHMIC = 0x004 +PARAMETER_IS_ENABLED = 0x008 +PARAMETER_IS_AUTOMABLE = 0x010 +PARAMETER_IS_READ_ONLY = 0x020 +PARAMETER_USES_SAMPLERATE = 0x040 +PARAMETER_USES_SCALEPOINTS = 0x080 +PARAMETER_USES_CUSTOM_TEXT = 0x100 # Custom Data types CUSTOM_DATA_INVALID = None diff --git a/source/carla_shared.py b/source/carla_shared.py index b9614b7e5..1d72c4c58 100644 --- a/source/carla_shared.py +++ b/source/carla_shared.py @@ -943,6 +943,9 @@ class PluginParameter(QWidget): self.ui.sb_control.setEnabled(False) self.ui.sb_channel.setEnabled(False) + if pHints & PARAMETER_IS_READ_ONLY: + self.ui.widget.setReadOnly(True) + elif pType == PARAMETER_OUTPUT: self.ui.widget.setMinimum(pInfo['minimum']) self.ui.widget.setMaximum(pInfo['maximum'])