diff --git a/source/backend/CarlaEngine.hpp b/source/backend/CarlaEngine.hpp index 2c96e1eef..c2cfcdbc8 100644 --- a/source/backend/CarlaEngine.hpp +++ b/source/backend/CarlaEngine.hpp @@ -515,8 +515,7 @@ public: virtual void initBuffer(CarlaEngine* const engine) override; /*! - * Write buffer.\n - * This is a handy function for the JACK engine only, where we need to write buffer to output ports. + * Write buffer back into the engine. */ virtual void writeBuffer(CarlaEngine* const engine); diff --git a/source/backend/engine/CarlaEngineJack.cpp b/source/backend/engine/CarlaEngineJack.cpp index 5148811b6..2a2981a9c 100644 --- a/source/backend/engine/CarlaEngineJack.cpp +++ b/source/backend/engine/CarlaEngineJack.cpp @@ -153,7 +153,7 @@ public: if (kIsInput) { - float* const jackBuffer = (float*)jackbridge_port_get_buffer(kPort, fBufferSize); + float* const jackBuffer((float*)jackbridge_port_get_buffer(kPort, fBufferSize)); carla_copyFloat(fBuffer, jackBuffer, fBufferSize); } else @@ -174,7 +174,7 @@ public: CARLA_ASSERT(engine->getBufferSize() == fBufferSize); - float* const jackBuffer = (float*)jackbridge_port_get_buffer(kPort, fBufferSize); + float* const jackBuffer((float*)jackbridge_port_get_buffer(kPort, fBufferSize)); carla_copyFloat(jackBuffer, fBuffer, fBufferSize); } diff --git a/source/backend/plugin/CarlaPluginInternal.hpp b/source/backend/plugin/CarlaPluginInternal.hpp index e8a8ba6f3..ec0f4c999 100644 --- a/source/backend/plugin/CarlaPluginInternal.hpp +++ b/source/backend/plugin/CarlaPluginInternal.hpp @@ -120,6 +120,85 @@ struct PluginAudioData { // ----------------------------------------------------------------------- +struct PluginCVPort { + uint32_t rindex; + uint32_t param; + CarlaEngineCVPort* port; + + PluginCVPort() + : rindex(0), + param(0), + port(nullptr) {} + + ~PluginCVPort() + { + CARLA_ASSERT(port == nullptr); + } + + CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginCVPort) +}; + +struct PluginCVData { + uint32_t count; + PluginCVPort* ports; + + PluginCVData() + : count(0), + ports(nullptr) {} + + ~PluginCVData() + { + CARLA_ASSERT_INT(count == 0, count); + CARLA_ASSERT(ports == nullptr); + } + + void createNew(const uint32_t newCount) + { + CARLA_ASSERT_INT(count == 0, count); + CARLA_ASSERT(ports == nullptr); + CARLA_ASSERT_INT(newCount > 0, newCount); + + if (ports != nullptr || newCount == 0) + return; + + ports = new PluginCVPort[newCount]; + count = newCount; + } + + void clear() + { + if (ports != nullptr) + { + for (uint32_t i=0; i < count; ++i) + { + if (ports[i].port != nullptr) + { + delete ports[i].port; + ports[i].port = nullptr; + } + } + + delete[] ports; + ports = nullptr; + } + + count = 0; + } + + void initBuffers(CarlaEngine* const engine) + { + for (uint32_t i=0; i < count; ++i) + { + if (ports[i].port != nullptr) + ports[i].port->initBuffer(engine); + } + } + + CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginCVData) +}; + +// ----------------------------------------------------------------------- + struct PluginEventData { CarlaEngineEventPort* portIn; CarlaEngineEventPort* portOut; diff --git a/source/backend/plugin/Lv2Plugin.cpp b/source/backend/plugin/Lv2Plugin.cpp index 8052269b6..494118ef7 100644 --- a/source/backend/plugin/Lv2Plugin.cpp +++ b/source/backend/plugin/Lv2Plugin.cpp @@ -17,6 +17,8 @@ #include "CarlaPluginInternal.hpp" +#define WANT_LV2 + #ifdef WANT_LV2 #include "CarlaPluginGui.hpp" @@ -1373,6 +1375,8 @@ public: params += 1; } + params += cvIns + cvOuts; + // check extensions fExt.options = nullptr; fExt.programs = nullptr; @@ -1434,6 +1438,17 @@ public: fAudioOutBuffers[i] = nullptr; } + if (cvIns > 0) + { + fCvIn.createNew(aIns); + } + + if (cvOuts > 0) + { + fCvOut.createNew(aOuts); + needsCtrlIn = true; + } + if (params > 0) { kData->param.createNew(params); @@ -1510,7 +1525,7 @@ public: const uint portNameSize(kData->engine->maxPortNameSize()); CarlaString portName; - for (uint32_t i=0, iAudioIn=0, iAudioOut=0, iEvIn=0, iEvOut=0, iCtrl=0; i < portCount; ++i) + for (uint32_t i=0, iAudioIn=0, iAudioOut=0, iCvIn=0, iCvOut=0, iEvIn=0, iEvOut=0, iCtrl=0; i < portCount; ++i) { const LV2_Property portTypes(fRdfDescriptor->Ports[i].Types); @@ -1563,19 +1578,55 @@ public: { if (LV2_IS_PORT_INPUT(portTypes)) { - carla_stderr("WARNING - CV Ports are not supported yet"); + j = iCvIn++; + fCvIn.ports[j].port = (CarlaEngineCVPort*)kData->client->addPort(kEnginePortTypeCV, portName, true); + fCvIn.ports[j].rindex = i; + + 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; + kData->param.data[j].index = j; + kData->param.data[j].rindex = i; + kData->param.data[j].hints = 0x0; + kData->param.data[j].midiChannel = 0; + kData->param.data[j].midiCC = -1; + kData->param.ranges[j].min = 0.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; + } else if (LV2_IS_PORT_OUTPUT(portTypes)) { - carla_stderr("WARNING - CV Ports are not supported yet"); + j = iCvOut++; + fCvOut.ports[j].port = (CarlaEngineCVPort*)kData->client->addPort(kEnginePortTypeCV, portName, false); + fCvOut.ports[j].rindex = i; + + 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; + kData->param.data[j].index = j; + kData->param.data[j].rindex = i; + kData->param.data[j].hints = 0x0; + kData->param.data[j].midiChannel = 0; + kData->param.data[j].midiCC = -1; + kData->param.ranges[j].min = 0.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; } else carla_stderr("WARNING - Got a broken Port (CV, but not input or output)"); - - fDescriptor->connect_port(fHandle, i, nullptr); - - if (fHandle2 != nullptr) - fDescriptor->connect_port(fHandle2, i, nullptr); } else if (LV2_IS_PORT_ATOM_SEQUENCE(portTypes)) { @@ -4745,6 +4796,8 @@ private: Lv2AtomQueue fAtomQueueOut; LV2_Atom_Forge fAtomForge; + PluginCVData fCvIn; + PluginCVData fCvOut; Lv2PluginEventData fEventsIn; Lv2PluginEventData fEventsOut; Lv2PluginOptions fLv2Options; diff --git a/source/utils/CarlaLv2Utils.hpp b/source/utils/CarlaLv2Utils.hpp index ce648c5ac..b6260de02 100644 --- a/source/utils/CarlaLv2Utils.hpp +++ b/source/utils/CarlaLv2Utils.hpp @@ -1262,7 +1262,7 @@ bool is_lv2_port_supported(const LV2_Property types) if (LV2_IS_PORT_ATOM_SEQUENCE(types)) return true; if (LV2_IS_PORT_CV(types)) - return false; // TODO + return true; if (LV2_IS_PORT_EVENT(types)) return true; if (LV2_IS_PORT_MIDI_LL(types))