From 5d10152aa81d75ea0b717203163a8e8afb923adf Mon Sep 17 00:00:00 2001 From: falkTX Date: Sat, 24 Jan 2015 14:58:34 +0000 Subject: [PATCH] Rework of some latency and LADSPA code --- source/backend/CarlaPlugin.hpp | 9 +- source/backend/engine/CarlaEngine.cpp | 20 +- source/backend/engine/CarlaEngineGraph.cpp | 8 +- source/backend/engine/CarlaEngineInternal.hpp | 3 + source/backend/plugin/CarlaPlugin.cpp | 13 +- source/backend/plugin/CarlaPluginDSSI.cpp | 10 + source/backend/plugin/CarlaPluginInternal.cpp | 134 ++-- source/backend/plugin/CarlaPluginInternal.hpp | 32 +- source/backend/plugin/CarlaPluginLADSPA.cpp | 749 ++++++++++-------- source/backend/plugin/CarlaPluginLV2.cpp | 10 + source/backend/plugin/CarlaPluginVST2.cpp | 4 + source/native-plugins/bigmeter.cpp | 4 +- source/utils/CarlaMathUtils.hpp | 8 +- 13 files changed, 572 insertions(+), 432 deletions(-) diff --git a/source/backend/CarlaPlugin.hpp b/source/backend/CarlaPlugin.hpp index 482c065d3..d7aaed900 100644 --- a/source/backend/CarlaPlugin.hpp +++ b/source/backend/CarlaPlugin.hpp @@ -109,7 +109,7 @@ public: /*! * Get the plugin's options (currently in use). * - * @see PluginOptions, getAvailableOptions() and setOption() + * @see PluginOptions, getOptionsAvailable() and setOption() */ uint getOptionsEnabled() const noexcept; @@ -154,7 +154,7 @@ public: /*! * Get the plugin's latency, in sample frames. */ - uint32_t getLatencyInFrames() const noexcept; + virtual uint32_t getLatencyInFrames() const noexcept; // ------------------------------------------------------------------- // Information (count) @@ -266,7 +266,7 @@ public: * Get the complete plugin chunk data into @a dataPtr. * * @note Make sure to verify the plugin supports chunks before calling this function! - * \return The size of the chunk or 0 if invalid. + * @return The size of the chunk or 0 if invalid. * * @see setChunkData() */ @@ -326,6 +326,7 @@ public: /*! * Get the custom text of the parameter @a parameterId. + * @see PARAMETER_USES_CUSTOM_TEXT */ virtual void getParameterText(const uint32_t parameterId, char* const strBuf) const noexcept; @@ -436,7 +437,7 @@ public: /*! * Set a plugin's option. * - * @see getOptions() and getAvailableOptions() + * @see getOptions() and getOptionsAvailable() */ virtual void setOption(const uint option, const bool yesNo, const bool sendCallback); diff --git a/source/backend/engine/CarlaEngine.cpp b/source/backend/engine/CarlaEngine.cpp index ea0eeb89e..5cf9ca0cc 100644 --- a/source/backend/engine/CarlaEngine.cpp +++ b/source/backend/engine/CarlaEngine.cpp @@ -845,7 +845,7 @@ const char* CarlaEngine::getUniquePluginName(const char* const name) const return sname.dup(); } - const size_t maxNameSize(carla_min(getMaxClientNameSize(), 0xff, 6) - 6); // 6 = strlen(" (10)") + 1 + const std::size_t maxNameSize(carla_minWithBase(getMaxClientNameSize(), 0xff, 6U) - 6); // 6 = strlen(" (10)") + 1 if (maxNameSize == 0 || ! isRunning()) return sname.dup(); @@ -1454,7 +1454,11 @@ void CarlaEngine::bufferSizeChanged(const uint32_t newBufferSize) carla_debug("CarlaEngine::bufferSizeChanged(%i)", newBufferSize); #ifndef BUILD_BRIDGE - pData->graph.setBufferSize(newBufferSize); + if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || + pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) + { + pData->graph.setBufferSize(newBufferSize); + } #endif for (uint i=0; i < pData->curPluginCount; ++i) @@ -1473,7 +1477,11 @@ void CarlaEngine::sampleRateChanged(const double newSampleRate) carla_debug("CarlaEngine::sampleRateChanged(%g)", newSampleRate); #ifndef BUILD_BRIDGE - pData->graph.setSampleRate(newSampleRate); + if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || + pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) + { + pData->graph.setSampleRate(newSampleRate); + } #endif for (uint i=0; i < pData->curPluginCount; ++i) @@ -1492,7 +1500,11 @@ void CarlaEngine::offlineModeChanged(const bool isOfflineNow) carla_debug("CarlaEngine::offlineModeChanged(%s)", bool2str(isOfflineNow)); #ifndef BUILD_BRIDGE - pData->graph.setOffline(isOfflineNow); + if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || + pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) + { + pData->graph.setOffline(isOfflineNow); + } #endif for (uint i=0; i < pData->curPluginCount; ++i) diff --git a/source/backend/engine/CarlaEngineGraph.cpp b/source/backend/engine/CarlaEngineGraph.cpp index 68a6151ef..92600952c 100644 --- a/source/backend/engine/CarlaEngineGraph.cpp +++ b/source/backend/engine/CarlaEngineGraph.cpp @@ -646,10 +646,10 @@ void RackGraph::process(CarlaEngine::ProtectedData* const data, const float* inB if (oldAudioInCount > 0) { range = FloatVectorOperations::findMinAndMax(inBuf0, iframes); - pluginData.insPeak[0] = carla_max(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f); + pluginData.insPeak[0] = carla_maxLimited(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f); range = FloatVectorOperations::findMinAndMax(inBuf1, iframes); - pluginData.insPeak[1] = carla_max(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f); + pluginData.insPeak[1] = carla_maxLimited(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f); } else { @@ -660,10 +660,10 @@ void RackGraph::process(CarlaEngine::ProtectedData* const data, const float* inB if (plugin->getAudioOutCount() > 0) { range = FloatVectorOperations::findMinAndMax(outBuf[0], iframes); - pluginData.outsPeak[0] = carla_max(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f); + pluginData.outsPeak[0] = carla_maxLimited(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f); range = FloatVectorOperations::findMinAndMax(outBuf[1], iframes); - pluginData.outsPeak[1] = carla_max(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f); + pluginData.outsPeak[1] = carla_maxLimited(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f); } else { diff --git a/source/backend/engine/CarlaEngineInternal.hpp b/source/backend/engine/CarlaEngineInternal.hpp index bcb9d7c3b..d01351cbb 100644 --- a/source/backend/engine/CarlaEngineInternal.hpp +++ b/source/backend/engine/CarlaEngineInternal.hpp @@ -33,6 +33,9 @@ CARLA_BACKEND_START_NAMESPACE #define CARLA_SAFE_ASSERT_RETURN_ERR(cond, err) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); setLastError(err); return false; } #define CARLA_SAFE_ASSERT_RETURN_ERRN(cond, err) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); setLastError(err); return nullptr; } +#define CARLA_SAFE_EXCEPTION_RETURN_ERR(excptMsg, errMsg) catch(...) { carla_safe_exception(excptMsg, __FILE__, __LINE__); setLastError(errMsg); return false; } +#define CARLA_SAFE_EXCEPTION_RETURN_ERRN(excptMsg, errMsg) catch(...) { carla_safe_exception(excptMsg, __FILE__, __LINE__); setLastError(errMsg); return nullptr; } + // ----------------------------------------------------------------------- // InternalEvents diff --git a/source/backend/plugin/CarlaPlugin.cpp b/source/backend/plugin/CarlaPlugin.cpp index c2d2b618c..1af74233c 100644 --- a/source/backend/plugin/CarlaPlugin.cpp +++ b/source/backend/plugin/CarlaPlugin.cpp @@ -162,7 +162,7 @@ int64_t CarlaPlugin::getUniqueId() const noexcept uint32_t CarlaPlugin::getLatencyInFrames() const noexcept { - return pData->latency; + return 0; } // ------------------------------------------------------------------- @@ -1397,6 +1397,17 @@ void CarlaPlugin::idle() #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) const bool sendOsc(pData->engine->isOscControlRegistered()); #endif + const uint32_t latency(getLatencyInFrames()); + + if (pData->latency.frames != latency) + { + carla_stdout("latency changed to %i", latency); + + const ScopedSingleProcessLocker sspl(this, true); + + pData->client->setLatency(latency); + pData->latency.recreateBuffers(pData->latency.channels, latency); + } const CarlaMutexLocker sl(pData->postRtEvents.mutex); diff --git a/source/backend/plugin/CarlaPluginDSSI.cpp b/source/backend/plugin/CarlaPluginDSSI.cpp index 181edace7..6397bcf69 100644 --- a/source/backend/plugin/CarlaPluginDSSI.cpp +++ b/source/backend/plugin/CarlaPluginDSSI.cpp @@ -681,6 +681,7 @@ public: } #endif +#if 0 // TODO void idle() override { if (fLatencyChanged && fLatencyIndex != -1) @@ -712,6 +713,7 @@ public: CarlaPlugin::idle(); } +#endif // ------------------------------------------------------------------- // Plugin state @@ -1125,6 +1127,7 @@ public: if (aIns <= 2 && aOuts <= 2 && (aIns == aOuts || aIns == 0 || aOuts == 0)) pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; +#if 0 // TODO // check latency if (fLatencyIndex >= 0) { @@ -1193,6 +1196,7 @@ public: fLatencyChanged = false; } +#endif bufferSizeChanged(pData->engine->getBufferSize()); reloadPrograms(true); @@ -1389,11 +1393,13 @@ public: } #ifndef BUILD_BRIDGE +#if 0 // TODO if (pData->latency > 0) { for (uint32_t i=0; i < pData->audioIn.count; ++i) FloatVectorOperations::clear(pData->latencyBuffers[i], static_cast(pData->latency)); } +#endif #endif pData->needsReset = false; @@ -1775,6 +1781,7 @@ public: } // End of Plugin processing (no events) #ifndef BUILD_BRIDGE +#if 0 // TODO // -------------------------------------------------------------------------------------------------------- // Latency, save values for next callback @@ -1803,6 +1810,7 @@ public: } } } +#endif // -------------------------------------------------------------------------------------------------------- // Control Output @@ -1943,11 +1951,13 @@ public: { for (uint32_t k=0; k < frames; ++k) { +#if 0 // TODO if (k < pData->latency) bufValue = pData->latencyBuffers[isMono ? 0 : i][k]; else if (pData->latency < frames) bufValue = fAudioInBuffers[isMono ? 0 : i][k-pData->latency]; else +#endif bufValue = fAudioInBuffers[isMono ? 0 : i][k]; fAudioOutBuffers[i][k] = (fAudioOutBuffers[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet)); diff --git a/source/backend/plugin/CarlaPluginInternal.cpp b/source/backend/plugin/CarlaPluginInternal.cpp index 5b56f4311..171fdcc96 100644 --- a/source/backend/plugin/CarlaPluginInternal.cpp +++ b/source/backend/plugin/CarlaPluginInternal.cpp @@ -384,6 +384,73 @@ void CarlaPlugin::ProtectedData::ExternalNotes::clear() noexcept mutex.unlock(); } +// ----------------------------------------------------------------------- +// ProtectedData::Latency + +CarlaPlugin::ProtectedData::Latency::Latency() noexcept + : channels(0), + frames(0), + buffers(nullptr) {} + +CarlaPlugin::ProtectedData::Latency::~Latency() noexcept +{ + clearBuffers(); +} + +void CarlaPlugin::ProtectedData::Latency::clearBuffers() noexcept +{ + if (buffers != nullptr) + { + for (uint32_t i=0; i < channels; ++i) + { + CARLA_SAFE_ASSERT_CONTINUE(buffers[i] != nullptr); + + delete[] buffers[i]; + buffers[i] = nullptr; + } + + delete[] buffers; + buffers = nullptr; + } + + channels = 0; + frames = 0; +} + +void CarlaPlugin::ProtectedData::Latency::recreateBuffers(const uint32_t newChannels, const uint32_t newFrames) +{ + CARLA_SAFE_ASSERT_RETURN(channels != newChannels || frames != newFrames,); + + // delete old buffer + if (buffers != nullptr) + { + for (uint32_t i=0; i < channels; ++i) + { + CARLA_SAFE_ASSERT_CONTINUE(buffers[i] != nullptr); + + delete[] buffers[i]; + buffers[i] = nullptr; + } + + delete[] buffers; + buffers = nullptr; + } + + channels = newChannels; + frames = newFrames; + + if (channels > 0 && frames > 0) + { + buffers = new float*[channels]; + + for (uint32_t i=0; i < channels; ++i) + { + buffers[i] = new float[frames]; + FloatVectorOperations::clear(buffers[i], static_cast(frames)); + } + } +} + // ----------------------------------------------------------------------- // ProtectedData::PostRtEvents @@ -476,10 +543,6 @@ CarlaPlugin::ProtectedData::ProtectedData(CarlaEngine* const eng, const uint idx ctrlChannel(0), extraHints(0x0), transientTryCounter(0), - latency(0), -#ifndef BUILD_BRIDGE - latencyBuffers(nullptr), -#endif name(nullptr), filename(nullptr), iconName(nullptr), @@ -496,6 +559,7 @@ CarlaPlugin::ProtectedData::ProtectedData(CarlaEngine* const eng, const uint idx singleMutex(), stateSave(), extNotes(), + latency(), postRtEvents(), postUiEvents(), #ifndef BUILD_BRIDGE @@ -598,75 +662,15 @@ CarlaPlugin::ProtectedData::~ProtectedData() noexcept void CarlaPlugin::ProtectedData::clearBuffers() noexcept { -#ifndef BUILD_BRIDGE - if (latencyBuffers != nullptr) - { - CARLA_SAFE_ASSERT(audioIn.count > 0); - - for (uint32_t i=0; i < audioIn.count; ++i) - { - CARLA_SAFE_ASSERT_CONTINUE(latencyBuffers[i] != nullptr); - - delete[] latencyBuffers[i]; - latencyBuffers[i] = nullptr; - } - - delete[] latencyBuffers; - latencyBuffers = nullptr; - latency = 0; - } - else - { - if (latency != 0) - { - carla_safe_assert_int("latency != 0", __FILE__, __LINE__, static_cast(latency)); - latency = 0; - } - } -#else - latency = 0; -#endif - audioIn.clear(); audioOut.clear(); cvIn.clear(); cvOut.clear(); param.clear(); event.clear(); + latency.clearBuffers(); } -#ifndef BUILD_BRIDGE -void CarlaPlugin::ProtectedData::recreateLatencyBuffers() -{ - if (latencyBuffers != nullptr) - { - CARLA_SAFE_ASSERT(audioIn.count > 0); - - for (uint32_t i=0; i < audioIn.count; ++i) - { - CARLA_SAFE_ASSERT_CONTINUE(latencyBuffers[i] != nullptr); - - delete[] latencyBuffers[i]; - latencyBuffers[i] = nullptr; - } - - delete[] latencyBuffers; - latencyBuffers = nullptr; - } - - if (audioIn.count > 0 && latency > 0) - { - latencyBuffers = new float*[audioIn.count]; - - for (uint32_t i=0; i < audioIn.count; ++i) - { - latencyBuffers[i] = new float[latency]; - FloatVectorOperations::clear(latencyBuffers[i], static_cast(latency)); - } - } -} -#endif - // ----------------------------------------------------------------------- // Post-poned events diff --git a/source/backend/plugin/CarlaPluginInternal.hpp b/source/backend/plugin/CarlaPluginInternal.hpp index 0cb50e350..5740e9231 100644 --- a/source/backend/plugin/CarlaPluginInternal.hpp +++ b/source/backend/plugin/CarlaPluginInternal.hpp @@ -34,6 +34,15 @@ using juce::FloatVectorOperations; CARLA_BACKEND_START_NAMESPACE +// ----------------------------------------------------------------------- +// Engine helper macro, sets lastError and returns false/NULL + +#define CARLA_SAFE_ASSERT_RETURN_ERR(cond, err) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); pData->engine->setLastError(err); return false; } +#define CARLA_SAFE_ASSERT_RETURN_ERRN(cond, err) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); pData->engine->setLastError(err); return nullptr; } + +#define CARLA_SAFE_EXCEPTION_RETURN_ERR(excptMsg, errMsg) catch(...) { carla_safe_exception(excptMsg, __FILE__, __LINE__); pData->engine->setLastError(errMsg); return false; } +#define CARLA_SAFE_EXCEPTION_RETURN_ERRN(excptMsg, errMsg) catch(...) { carla_safe_exception(excptMsg, __FILE__, __LINE__); pData->engine->setLastError(errMsg); return nullptr; } + // ----------------------------------------------------------------------- // Maximum pre-allocated events for some plugin types @@ -225,12 +234,6 @@ struct CarlaPlugin::ProtectedData { uint extraHints; uint transientTryCounter; - // latency - uint32_t latency; -#ifndef BUILD_BRIDGE - float** latencyBuffers; -#endif - // data 1 const char* name; const char* filename; @@ -266,6 +269,20 @@ struct CarlaPlugin::ProtectedData { } extNotes; + struct Latency { + uint32_t channels; + uint32_t frames; + float** buffers; + + Latency() noexcept; + ~Latency() noexcept; + void clearBuffers() noexcept; + void recreateBuffers(const uint32_t newChannels, const uint32_t newFrames); + + CARLA_DECLARE_NON_COPY_STRUCT(Latency) + + } latency; + struct PostRtEvents { CarlaMutex mutex; RtLinkedList::Pool dataPool; @@ -317,9 +334,6 @@ struct CarlaPlugin::ProtectedData { // Buffer functions void clearBuffers() noexcept; -#ifndef BUILD_BRIDGE - void recreateLatencyBuffers(); -#endif // ------------------------------------------------------------------- // Post-poned events diff --git a/source/backend/plugin/CarlaPluginLADSPA.cpp b/source/backend/plugin/CarlaPluginLADSPA.cpp index ba88cee85..ac8055a0d 100644 --- a/source/backend/plugin/CarlaPluginLADSPA.cpp +++ b/source/backend/plugin/CarlaPluginLADSPA.cpp @@ -30,18 +30,22 @@ class CarlaPluginLADSPA : public CarlaPlugin public: CarlaPluginLADSPA(CarlaEngine* const engine, const uint id) noexcept : CarlaPlugin(engine, id), - fHandle(nullptr), - fHandle2(nullptr), + fHandles(), fDescriptor(nullptr), fRdfDescriptor(nullptr), fAudioInBuffers(nullptr), fAudioOutBuffers(nullptr), + fExtraStereoBuffer(), fParamBuffers(nullptr), - fLatencyChanged(false), fLatencyIndex(-1), + fIsDssiVst(false), + fForcedStereoIn(false), + fForcedStereoOut(false), leakDetector_CarlaPluginLADSPA() { carla_debug("CarlaPluginLADSPA::CarlaPluginLADSPA(%p, %i)", engine, id); + + carla_zeroPointers(fExtraStereoBuffer, 2); } ~CarlaPluginLADSPA() noexcept override @@ -64,23 +68,18 @@ public: { if (fDescriptor->cleanup != nullptr) { - if (fHandle != nullptr) + for (LinkedList::Itenerator it = fHandles.begin(); it.valid(); it.next()) { - try { - fDescriptor->cleanup(fHandle); - } CARLA_SAFE_EXCEPTION("LADSPA cleanup"); - } + LADSPA_Handle const handle(it.getValue(nullptr)); + CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr); - if (fHandle2 != nullptr) - { try { - fDescriptor->cleanup(fHandle2); - } CARLA_SAFE_EXCEPTION("LADSPA cleanup #2"); + fDescriptor->cleanup(handle); + } CARLA_SAFE_EXCEPTION("LADSPA cleanup"); } } - fHandle = nullptr; - fHandle2 = nullptr; + fHandles.clear(); fDescriptor = nullptr; } @@ -146,6 +145,17 @@ public: return static_cast(fDescriptor->UniqueID); } + uint32_t getLatencyInFrames() const noexcept override + { + if (fLatencyIndex < 0 || fParamBuffers == nullptr) + return 0; + + const float latency(fParamBuffers[fLatencyIndex]); + CARLA_SAFE_ASSERT_RETURN(latency >= 0.0f, 0); + + return static_cast(latency); + } + // ------------------------------------------------------------------- // Information (count) @@ -154,6 +164,7 @@ public: CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, 0); const int32_t rindex(pData->param.data[parameterId].rindex); + CARLA_SAFE_ASSERT_RETURN(rindex >= 0, 0); if (fRdfDescriptor != nullptr && rindex < static_cast(fRdfDescriptor->PortCount)) { @@ -174,26 +185,20 @@ public: uint getOptionsAvailable() const noexcept override { -#ifdef __USE_GNU - const bool isDssiVst(strcasestr(pData->filename, "dssi-vst") != nullptr); -#else - const bool isDssiVst(std::strstr(pData->filename, "dssi-vst") != nullptr); -#endif - uint options = 0x0; - if (! isDssiVst) + if (! fIsDssiVst) { + // can't disable fixed buffers if using latency if (fLatencyIndex == -1) options |= PLUGIN_OPTION_FIXED_BUFFERS; - if (pData->engine->getProccessMode() != ENGINE_PROCESS_MODE_CONTINUOUS_RACK) - { - if (pData->options & PLUGIN_OPTION_FORCE_STEREO) - options |= PLUGIN_OPTION_FORCE_STEREO; - else if (pData->audioIn.count <= 1 && pData->audioOut.count <= 1 && (pData->audioIn.count != 0 || pData->audioOut.count != 0)) - options |= PLUGIN_OPTION_FORCE_STEREO; - } + // can't disable forced stereo if in rack mode + if (pData->engine->getProccessMode() == ENGINE_PROCESS_MODE_CONTINUOUS_RACK) + pass(); + // if inputs or outputs are just 1, then yes we can force stereo + else if (pData->audioIn.count == 1 || pData->audioOut.count == 1) + options |= PLUGIN_OPTION_FORCE_STEREO; } return options; @@ -204,6 +209,11 @@ public: CARLA_SAFE_ASSERT_RETURN(fParamBuffers != nullptr, 0.0f); CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, 0.0f); + // bad plugins might have set output values out of bounds + if (pData->param.data[parameterId].type == PARAMETER_OUTPUT) + return pData->param.ranges[parameterId].getFixedValue(fParamBuffers[parameterId]); + + // not output, should be fine return fParamBuffers[parameterId]; } @@ -213,6 +223,7 @@ public: CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, 0.0f); const int32_t rindex(pData->param.data[parameterId].rindex); + CARLA_SAFE_ASSERT_RETURN(rindex >= 0, 0.0f); if (rindex < static_cast(fRdfDescriptor->PortCount)) { @@ -220,7 +231,7 @@ public: CARLA_SAFE_ASSERT_RETURN(scalePointId < port->ScalePointCount, 0.0f); const LADSPA_RDF_ScalePoint* const scalePoint(&port->ScalePoints[scalePointId]); - return scalePoint->Value; + return pData->param.ranges[parameterId].getFixedValue(scalePoint->Value); } return 0.0f; @@ -276,6 +287,7 @@ public: CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, nullStrBuf(strBuf)); const int32_t rindex(pData->param.data[parameterId].rindex); + CARLA_SAFE_ASSERT_RETURN(rindex >= 0, nullStrBuf(strBuf)); CARLA_SAFE_ASSERT_RETURN(rindex < static_cast(fDescriptor->PortCount), nullStrBuf(strBuf)); CARLA_SAFE_ASSERT_RETURN(fDescriptor->PortNames[rindex] != nullptr, nullStrBuf(strBuf)); @@ -291,6 +303,7 @@ public: CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, nullStrBuf(strBuf)); const int32_t rindex(pData->param.data[parameterId].rindex); + CARLA_SAFE_ASSERT_RETURN(rindex >= 0, nullStrBuf(strBuf)); if (fRdfDescriptor != nullptr && rindex < static_cast(fRdfDescriptor->PortCount)) { @@ -313,6 +326,7 @@ public: CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, nullStrBuf(strBuf)); const int32_t rindex(pData->param.data[parameterId].rindex); + CARLA_SAFE_ASSERT_RETURN(rindex >= 0, nullStrBuf(strBuf)); if (fRdfDescriptor != nullptr && rindex < static_cast(fRdfDescriptor->PortCount)) { @@ -345,6 +359,7 @@ public: } CARLA_SAFE_ASSERT_RETURN(rindex < static_cast(fDescriptor->PortCount), nullStrBuf(strBuf)); + CARLA_SAFE_ASSERT_RETURN(fDescriptor->PortNames[rindex] != nullptr, nullStrBuf(strBuf)); if (getSeparatedParameterNameOrUnit(fDescriptor->PortNames[rindex], strBuf, false)) return; @@ -358,6 +373,7 @@ public: CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, nullStrBuf(strBuf)); const int32_t rindex(pData->param.data[parameterId].rindex); + CARLA_SAFE_ASSERT_RETURN(rindex >= 0, nullStrBuf(strBuf)); if (rindex < static_cast(fRdfDescriptor->PortCount)) { @@ -401,37 +417,7 @@ public: // ------------------------------------------------------------------- // Misc - void idle() override - { - if (fLatencyChanged && fLatencyIndex != -1) - { - fLatencyChanged = false; - - const int32_t latency(static_cast(fParamBuffers[fLatencyIndex])); - - if (latency >= 0) - { - const uint32_t ulatency(static_cast(latency)); - - if (pData->latency != ulatency) - { - carla_stdout("latency changed to %i", latency); - - const ScopedSingleProcessLocker sspl(this, true); - - pData->latency = ulatency; - pData->client->setLatency(ulatency); -#ifndef BUILD_BRIDGE - pData->recreateLatencyBuffers(); -#endif - } - } - else - carla_safe_assert_int("latency >= 0", __FILE__, __LINE__, latency); - } - - CarlaPlugin::idle(); - } + // nothing // ------------------------------------------------------------------- // Plugin state @@ -440,7 +426,6 @@ public: { CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr,); CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,); - CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,); carla_debug("CarlaPluginLADSPA::reload() - start"); const EngineProcessMode processMode(pData->engine->getProccessMode()); @@ -480,23 +465,15 @@ public: params += 1; } - if ((pData->options & PLUGIN_OPTION_FORCE_STEREO) != 0 && (aIns == 1 || aOuts == 1)) + if (pData->options & PLUGIN_OPTION_FORCE_STEREO) { - if (fHandle2 == nullptr) - { - try { - fHandle2 = fDescriptor->instantiate(fDescriptor, static_cast(sampleRate)); - } CARLA_SAFE_EXCEPTION("LADSPA instantiate #2"); - } - - if (fHandle2 != nullptr) + if ((aIns == 1 || aOuts == 1) && fHandles.count() == 1 && addInstance()) { if (aIns == 1) { aIns = 2; forcedStereoIn = true; } - if (aOuts == 1) { aOuts = 2; @@ -704,8 +681,7 @@ public: stepSmall = 1.0f; stepLarge = 1.0f; pData->param.special[j] = PARAMETER_SPECIAL_LATENCY; - CARLA_SAFE_ASSERT(fLatencyIndex == -1); - fLatencyIndex = static_cast(j); + CARLA_SAFE_ASSERT(fLatencyIndex == static_cast(j)); } else { @@ -737,15 +713,14 @@ public: // Start parameters in their default values fParamBuffers[j] = def; - try { - fDescriptor->connect_port(fHandle, i, &fParamBuffers[j]); - } CARLA_SAFE_EXCEPTION("LADSPA connect_port parameter"); - - if (fHandle2 != nullptr) + for (LinkedList::Itenerator it = fHandles.begin(); it.valid(); it.next()) { + LADSPA_Handle const handle(it.getValue(nullptr)); + CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr); + try { - fDescriptor->connect_port(fHandle2, i, &fParamBuffers[j]); - } CARLA_SAFE_EXCEPTION("LADSPA connect_port parameter #2"); + fDescriptor->connect_port(handle, i, &fParamBuffers[j]); + } CARLA_SAFE_EXCEPTION("LADSPA connect_port (parameter)"); } } else @@ -753,15 +728,14 @@ public: // Not Audio or Control carla_stderr2("ERROR - Got a broken Port (neither Audio or Control)"); - try { - fDescriptor->connect_port(fHandle, i, nullptr); - } CARLA_SAFE_EXCEPTION("LADSPA connect_port null"); - - if (fHandle2 != nullptr) + for (LinkedList::Itenerator it = fHandles.begin(); it.valid(); it.next()) { + LADSPA_Handle const handle(it.getValue(nullptr)); + CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr); + try { - fDescriptor->connect_port(fHandle2, i, nullptr); - } CARLA_SAFE_EXCEPTION("LADSPA connect_port null #2"); + fDescriptor->connect_port(handle, i, nullptr); + } CARLA_SAFE_EXCEPTION("LADSPA connect_port (null)"); } } } @@ -821,86 +795,79 @@ public: #endif // extra plugin hints - pData->extraHints = 0x0; + pData->extraHints = 0x0; + pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; - if (aIns <= 2 && aOuts <= 2 && (aIns == aOuts || aIns == 0 || aOuts == 0)) - pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; + // check initial latency + findInitialLatencyValue(aIns, aOuts); - // check latency - if (fLatencyIndex >= 0) - { - // we need to pre-run the plugin so it can update its latency control-port + fForcedStereoIn = forcedStereoIn; + fForcedStereoOut = forcedStereoOut; - float tmpIn [(aIns > 0) ? aIns : 1][2]; - float tmpOut[(aOuts > 0) ? aOuts : 1][2]; - - for (uint32_t j=0; j < aIns; ++j) - { - tmpIn[j][0] = 0.0f; - tmpIn[j][1] = 0.0f; - - try { - fDescriptor->connect_port(fHandle, pData->audioIn.ports[j].rindex, tmpIn[j]); - } CARLA_SAFE_EXCEPTION("LADSPA connect_port latency input"); - } + bufferSizeChanged(pData->engine->getBufferSize()); - for (uint32_t j=0; j < aOuts; ++j) - { - tmpOut[j][0] = 0.0f; - tmpOut[j][1] = 0.0f; + if (pData->active) + activate(); - try { - fDescriptor->connect_port(fHandle, pData->audioOut.ports[j].rindex, tmpOut[j]); - } CARLA_SAFE_EXCEPTION("LADSPA connect_port latency output"); - } + carla_debug("CarlaPluginLADSPA::reload() - end"); + } - if (fDescriptor->activate != nullptr) - { - try { - fDescriptor->activate(fHandle); - } CARLA_SAFE_EXCEPTION("LADSPA latency activate"); - } + void findInitialLatencyValue(const uint32_t aIns, const uint32_t aOuts) const + { + if (fLatencyIndex < 0 || fHandles.count() == 0) + return; - try { - fDescriptor->run(fHandle, 2); - } CARLA_SAFE_EXCEPTION("LADSPA latency run"); + // we need to pre-run the plugin so it can update its latency control-port + const LADSPA_Handle handle(fHandles.getFirst(nullptr)); + CARLA_SAFE_ASSERT_RETURN(handle != nullptr,); - if (fDescriptor->deactivate != nullptr) - { - try { - fDescriptor->deactivate(fHandle); - } CARLA_SAFE_EXCEPTION("LADSPA latency deactivate"); - } + float tmpIn [(aIns > 0) ? aIns : 1][2]; + float tmpOut[(aOuts > 0) ? aOuts : 1][2]; - const int32_t latency(static_cast(fParamBuffers[fLatencyIndex])); + for (uint32_t j=0; j < aIns; ++j) + { + tmpIn[j][0] = 0.0f; + tmpIn[j][1] = 0.0f; - if (latency >= 0) - { - const uint32_t ulatency(static_cast(latency)); + try { + fDescriptor->connect_port(handle, pData->audioIn.ports[j].rindex, tmpIn[j]); + } CARLA_SAFE_EXCEPTION("LADSPA connect_port (latency input)"); + } - if (pData->latency != ulatency) - { - carla_stdout("latency = %i", latency); + for (uint32_t j=0; j < aOuts; ++j) + { + tmpOut[j][0] = 0.0f; + tmpOut[j][1] = 0.0f; - pData->latency = ulatency; - pData->client->setLatency(ulatency); -#ifndef BUILD_BRIDGE - pData->recreateLatencyBuffers(); -#endif - } - } - else - carla_safe_assert_int("latency >= 0", __FILE__, __LINE__, latency); + try { + fDescriptor->connect_port(handle, pData->audioOut.ports[j].rindex, tmpOut[j]); + } CARLA_SAFE_EXCEPTION("LADSPA connect_port (latency output)"); + } - fLatencyChanged = false; + if (fDescriptor->activate != nullptr) + { + try { + fDescriptor->activate(handle); + } CARLA_SAFE_EXCEPTION("LADSPA latency activate"); } - bufferSizeChanged(pData->engine->getBufferSize()); + try { + fDescriptor->run(handle, 2); + } CARLA_SAFE_EXCEPTION("LADSPA latency run"); - if (pData->active) - activate(); + if (fDescriptor->deactivate != nullptr) + { + try { + fDescriptor->deactivate(handle); + } CARLA_SAFE_EXCEPTION("LADSPA latency deactivate"); + } - carla_debug("CarlaPluginLADSPA::reload() - end"); + // done, let's get the value + if (const uint32_t latency = getLatencyInFrames()) + { + pData->client->setLatency(latency); + pData->latency.recreateBuffers(std::max(aIns, aOuts), latency); + } } // ------------------------------------------------------------------- @@ -909,19 +876,17 @@ public: void activate() noexcept override { CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,); - CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,); if (fDescriptor->activate != nullptr) { - try { - fDescriptor->activate(fHandle); - } CARLA_SAFE_EXCEPTION("LADSPA activate"); - - if (fHandle2 != nullptr) + for (LinkedList::Itenerator it = fHandles.begin(); it.valid(); it.next()) { + LADSPA_Handle const handle(it.getValue(nullptr)); + CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr); + try { - fDescriptor->activate(fHandle2); - } CARLA_SAFE_EXCEPTION("LADSPA activate #2"); + fDescriptor->activate(handle); + } CARLA_SAFE_EXCEPTION("LADSPA activate"); } } } @@ -929,24 +894,22 @@ public: void deactivate() noexcept override { CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,); - CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,); if (fDescriptor->deactivate != nullptr) { - try { - fDescriptor->deactivate(fHandle); - } CARLA_SAFE_EXCEPTION("LADSPA deactivate"); - - if (fHandle2 != nullptr) + for (LinkedList::Itenerator it = fHandles.begin(); it.valid(); it.next()) { + LADSPA_Handle const handle(it.getValue(nullptr)); + CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr); + try { - fDescriptor->deactivate(fHandle2); - } CARLA_SAFE_EXCEPTION("LADSPA deactivate #2"); + fDescriptor->deactivate(handle); + } CARLA_SAFE_EXCEPTION("LADSPA deactivate"); } } } - void process(const float** const audioIn, float** const audioOut, const float** const cvIn, float** const cvOut, const uint32_t frames) override + void process(const float** const audioIn, float** const audioOut, const float** const, float** const, const uint32_t frames) override { // -------------------------------------------------------------------------------------------------------- // Check if active @@ -956,27 +919,9 @@ public: // disable any output sound for (uint32_t i=0; i < pData->audioOut.count; ++i) FloatVectorOperations::clear(audioOut[i], static_cast(frames)); - for (uint32_t i=0; i < pData->cvOut.count; ++i) - FloatVectorOperations::clear(cvOut[i], static_cast(frames)); return; } - // -------------------------------------------------------------------------------------------------------- - // Check if needs reset - - if (pData->needsReset) - { -#ifndef BUILD_BRIDGE - if (pData->latency > 0) - { - for (uint32_t i=0; i < pData->audioIn.count; ++i) - FloatVectorOperations::clear(pData->latencyBuffers[i], static_cast(pData->latency)); - } -#endif - - pData->needsReset = false; - } - // -------------------------------------------------------------------------------------------------------- // Event Input and Processing @@ -1001,7 +946,7 @@ public: if (isSampleAccurate && event.time > timeOffset) { - if (processSingle(audioIn, audioOut, cvIn, cvOut, event.time - timeOffset, timeOffset)) + if (processSingle(audioIn, audioOut, event.time - timeOffset, timeOffset)) timeOffset = event.time; } @@ -1120,7 +1065,7 @@ public: pData->postRtEvents.trySplice(); if (frames > timeOffset) - processSingle(audioIn, audioOut, cvIn, cvOut, frames - timeOffset, timeOffset); + processSingle(audioIn, audioOut, frames - timeOffset, timeOffset); } // End of Event Input and Processing @@ -1129,40 +1074,10 @@ public: else { - processSingle(audioIn, audioOut, cvIn, cvOut, frames, 0); + processSingle(audioIn, audioOut, frames, 0); } // End of Plugin processing (no events) -#ifndef BUILD_BRIDGE - // -------------------------------------------------------------------------------------------------------- - // Latency, save values for next callback - - if (fLatencyIndex != -1) - { - if (pData->latency != static_cast(fParamBuffers[fLatencyIndex])) - { - fLatencyChanged = true; - } - else if (pData->latency > 0) - { - if (pData->latency <= frames) - { - for (uint32_t i=0; i < pData->audioIn.count; ++i) - FloatVectorOperations::copy(pData->latencyBuffers[i], audioIn[i]+(frames-pData->latency), static_cast(pData->latency)); - } - else - { - for (uint32_t i=0, j, k; i < pData->audioIn.count; ++i) - { - for (k=0; k < pData->latency-frames; ++k) - pData->latencyBuffers[i][k] = pData->latencyBuffers[i][k+frames]; - for (j=0; k < pData->latency; ++j, ++k) - pData->latencyBuffers[i][k] = audioIn[i][j]; - } - } - } - } - // -------------------------------------------------------------------------------------------------------- // Control Output @@ -1188,10 +1103,9 @@ public: } } } // End of Control Output -#endif } - bool processSingle(const float** const audioIn, float** const audioOut, const float** const cvIn, float** const cvOut, const uint32_t frames, const uint32_t timeOffset) + bool processSingle(const float** const audioIn, float** const audioOut, const uint32_t frames, const uint32_t timeOffset) { CARLA_SAFE_ASSERT_RETURN(frames > 0, false); @@ -1203,14 +1117,6 @@ public: { CARLA_SAFE_ASSERT_RETURN(audioOut != nullptr, false); } - if (pData->cvIn.count > 0) - { - CARLA_SAFE_ASSERT_RETURN(cvIn != nullptr, false); - } - if (pData->cvOut.count > 0) - { - CARLA_SAFE_ASSERT_RETURN(cvOut != nullptr, false); - } // -------------------------------------------------------------------------------------------------------- // Try lock, silence otherwise @@ -1226,47 +1132,76 @@ public: for (uint32_t k=0; k < frames; ++k) audioOut[i][k+timeOffset] = 0.0f; } - for (uint32_t i=0; i < pData->cvOut.count; ++i) - { - for (uint32_t k=0; k < frames; ++k) - cvOut[i][k+timeOffset] = 0.0f; - } return false; } + const int iframes(static_cast(frames)); + // -------------------------------------------------------------------------------------------------------- - // Set audio buffers + // Handle needsReset - for (uint32_t i=0; i < pData->audioIn.count; ++i) - FloatVectorOperations::copy(fAudioInBuffers[i], audioIn[i]+timeOffset, static_cast(frames)); + if (pData->needsReset) + { + if (pData->latency.frames > 0) + { + for (uint32_t i=0; i < pData->audioIn.count; ++i) + FloatVectorOperations::clear(pData->latency.buffers[i], static_cast(pData->latency.frames)); + } - for (uint32_t i=0; i < pData->audioOut.count; ++i) - FloatVectorOperations::clear(fAudioOutBuffers[i], static_cast(frames)); + pData->needsReset = false; + } -#if 0 // -------------------------------------------------------------------------------------------------------- - // Set CV buffers + // Set audio buffers - for (uint32_t i=0; i < pData->cvIn.count; ++i) - FloatVectorOperations::copy(fCvInBuffers[i], cvIn[i]+timeOffset, static_cast(frames)); + const bool customMonoOut = pData->audioOut.count == 2 && fForcedStereoOut && ! fForcedStereoIn; + const bool customStereoOut = pData->audioOut.count == 2 && fForcedStereoIn && ! fForcedStereoOut; - for (uint32_t i=0; i < pData->cvOut.count; ++i) - FloatVectorOperations::clear(fCvOutBuffers[i], static_cast(frames)); -#endif + if (! customMonoOut) + { + for (uint32_t i=0; i < pData->audioOut.count; ++i) + FloatVectorOperations::clear(fAudioOutBuffers[i], iframes); + } + + for (uint32_t i=0; i < pData->audioIn.count; ++i) + FloatVectorOperations::copy(fAudioInBuffers[i], audioIn[i]+timeOffset, iframes); // -------------------------------------------------------------------------------------------------------- // Run plugin - try { - fDescriptor->run(fHandle, frames); - } CARLA_SAFE_EXCEPTION("LADSPA run"); - - if (fHandle2 != nullptr) + uint instn = 0; + for (LinkedList::Itenerator it = fHandles.begin(); it.valid(); it.next(), ++instn) { + LADSPA_Handle const handle(it.getValue(nullptr)); + CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr); + + // ---------------------------------------------------------------------------------------------------- + // Mixdown for forced stereo + + if (customMonoOut) + FloatVectorOperations::clear(fAudioOutBuffers[instn], iframes); + + // ---------------------------------------------------------------------------------------------------- + // Run it + try { - fDescriptor->run(fHandle2, frames); - } CARLA_SAFE_EXCEPTION("LADSPA run #2"); + fDescriptor->run(handle, frames); + } CARLA_SAFE_EXCEPTION("LADSPA run"); + + // ---------------------------------------------------------------------------------------------------- + // Mixdown for forced stereo + + if (customMonoOut) + FloatVectorOperations::multiply(fAudioOutBuffers[instn], 0.5f, iframes); + else if (customStereoOut) + FloatVectorOperations::copy(fExtraStereoBuffer[instn], fAudioOutBuffers[instn], iframes); + } + + if (customStereoOut) + { + FloatVectorOperations::copy(fAudioOutBuffers[0], fExtraStereoBuffer[0], iframes); + FloatVectorOperations::copy(fAudioOutBuffers[1], fExtraStereoBuffer[1], iframes); } #ifndef BUILD_BRIDGE @@ -1286,14 +1221,16 @@ public: // Dry/Wet if (doDryWet) { + const uint32_t c = isMono ? 0 : i; + for (uint32_t k=0; k < frames; ++k) { - if (k < pData->latency) - bufValue = pData->latencyBuffers[isMono ? 0 : i][k]; - else if (pData->latency < frames) - bufValue = fAudioInBuffers[isMono ? 0 : i][k-pData->latency]; + if (k < pData->latency.frames) + bufValue = pData->latency.buffers[c][k]; + else if (pData->latency.frames < frames) + bufValue = fAudioInBuffers[c][k-pData->latency.frames]; else - bufValue = fAudioInBuffers[isMono ? 0 : i][k]; + bufValue = fAudioInBuffers[c][k]; fAudioOutBuffers[i][k] = (fAudioOutBuffers[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet)); } @@ -1307,7 +1244,7 @@ public: if (isPair) { CARLA_ASSERT(i+1 < pData->audioOut.count); - FloatVectorOperations::copy(oldBufLeft, fAudioOutBuffers[i], static_cast(frames)); + FloatVectorOperations::copy(oldBufLeft, fAudioOutBuffers[i], iframes); } float balRangeL = (pData->postProc.balanceLeft + 1.0f)/2.0f; @@ -1347,13 +1284,34 @@ public: } #endif -#if 0 - for (uint32_t i=0; i < pData->cvOut.count; ++i) + // -------------------------------------------------------------------------------------------------------- + // Save latency values for next callback + + if (const uint32_t latframes = pData->latency.frames) { - for (uint32_t k=0; k < frames; ++k) - cvOut[i][k+timeOffset] = fCvOutBuffers[i][k]; + CARLA_SAFE_ASSERT(timeOffset == 0); + + if (latframes <= frames) + { + for (uint32_t i=0; i < pData->audioIn.count; ++i) + FloatVectorOperations::copy(pData->latency.buffers[i], audioIn[i]+(frames-latframes), static_cast(latframes)); + } + else + { + const uint32_t diff = pData->latency.frames-frames; + + for (uint32_t i=0, k; iaudioIn.count; ++i) + { + // push back buffer by 'frames' + for (k=0; k < diff; ++k) + pData->latency.buffers[i][k] = pData->latency.buffers[i][k+frames]; + + // put current input at the end + for (uint32_t j=0; k < latframes; ++j, ++k) + pData->latency.buffers[i][k] = audioIn[i][j]; + } + } } -#endif // -------------------------------------------------------------------------------------------------------- @@ -1366,85 +1324,152 @@ public: CARLA_ASSERT_INT(newBufferSize > 0, newBufferSize); carla_debug("CarlaPluginLADSPA::bufferSizeChanged(%i) - start", newBufferSize); + const int iBufferSize(static_cast(newBufferSize)); + for (uint32_t i=0; i < pData->audioIn.count; ++i) { if (fAudioInBuffers[i] != nullptr) delete[] fAudioInBuffers[i]; + fAudioInBuffers[i] = new float[newBufferSize]; + FloatVectorOperations::clear(fAudioInBuffers[i], iBufferSize); } for (uint32_t i=0; i < pData->audioOut.count; ++i) { if (fAudioOutBuffers[i] != nullptr) delete[] fAudioOutBuffers[i]; + fAudioOutBuffers[i] = new float[newBufferSize]; + FloatVectorOperations::clear(fAudioOutBuffers[i], iBufferSize); } - if (fHandle2 == nullptr) + if (fExtraStereoBuffer[0] != nullptr) { - for (uint32_t i=0; i < pData->audioIn.count; ++i) + delete[] fExtraStereoBuffer[0]; + fExtraStereoBuffer[0] = nullptr; + } + + if (fExtraStereoBuffer[1] != nullptr) + { + delete[] fExtraStereoBuffer[1]; + fExtraStereoBuffer[1] = nullptr; + } + + if (fForcedStereoIn && pData->audioOut.count == 2) + { + fExtraStereoBuffer[0] = new float[newBufferSize]; + fExtraStereoBuffer[1] = new float[newBufferSize]; + FloatVectorOperations::clear(fExtraStereoBuffer[0], iBufferSize); + FloatVectorOperations::clear(fExtraStereoBuffer[1], iBufferSize); + } + + reconnectAudioPorts(); + + carla_debug("CarlaPluginLADSPA::bufferSizeChanged(%i) - end", newBufferSize); + } + + void sampleRateChanged(const double newSampleRate) override + { + CARLA_ASSERT_INT(newSampleRate > 0.0, newSampleRate); + carla_stdout("CarlaPluginLADSPA::sampleRateChanged(%g) - start", newSampleRate); + + if (pData->active) + deactivate(); + + const std::size_t instanceCount(fHandles.count()); + + if (fDescriptor->cleanup == nullptr) + { + for (LinkedList::Itenerator it = fHandles.begin(); it.valid(); it.next()) { - CARLA_ASSERT(fAudioInBuffers[i] != nullptr); + LADSPA_Handle const handle(it.getValue(nullptr)); + CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr); try { - fDescriptor->connect_port(fHandle, pData->audioIn.ports[i].rindex, fAudioInBuffers[i]); - } CARLA_SAFE_EXCEPTION("LADSPA connect_port audio input"); + fDescriptor->cleanup(handle); + } CARLA_SAFE_EXCEPTION("LADSPA cleanup"); } + } - for (uint32_t i=0; i < pData->audioOut.count; ++i) + fHandles.clear(); + + for (std::size_t i=0; iactive) + activate(); + + carla_stdout("CarlaPluginLADSPA::sampleRateChanged(%g) - end", newSampleRate); + } + + void reconnectAudioPorts() const noexcept + { + if (fForcedStereoIn) + { + if (LADSPA_Handle const handle = fHandles.getAt(0, nullptr)) { - CARLA_ASSERT(fAudioOutBuffers[i] != nullptr); + try { + fDescriptor->connect_port(handle, pData->audioIn.ports[0].rindex, fAudioInBuffers[0]); + } CARLA_SAFE_EXCEPTION("LADSPA connect_port (forced stereo input)"); + } + if (LADSPA_Handle const handle = fHandles.getAt(1, nullptr)) + { try { - fDescriptor->connect_port(fHandle, pData->audioOut.ports[i].rindex, fAudioOutBuffers[i]); - } CARLA_SAFE_EXCEPTION("LADSPA connect_port audio output"); + fDescriptor->connect_port(handle, pData->audioIn.ports[1].rindex, fAudioInBuffers[1]); + } CARLA_SAFE_EXCEPTION("LADSPA connect_port (forced stereo input)"); } } else { - if (pData->audioIn.count > 0) + for (LinkedList::Itenerator it = fHandles.begin(); it.valid(); it.next()) { - CARLA_ASSERT(pData->audioIn.count == 2); - CARLA_ASSERT(fAudioInBuffers[0] != nullptr); - CARLA_ASSERT(fAudioInBuffers[1] != nullptr); - - try { - fDescriptor->connect_port(fHandle, pData->audioIn.ports[0].rindex, fAudioInBuffers[0]); - } CARLA_SAFE_EXCEPTION("LADSPA connect_port audio input #1"); + LADSPA_Handle const handle(it.getValue(nullptr)); + CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr); - try { - fDescriptor->connect_port(fHandle2, pData->audioIn.ports[1].rindex, fAudioInBuffers[1]); - } CARLA_SAFE_EXCEPTION("LADSPA connect_port audio input #2"); + for (uint32_t i=0; i < pData->audioIn.count; ++i) + { + try { + fDescriptor->connect_port(handle, pData->audioIn.ports[i].rindex, fAudioInBuffers[i]); + } CARLA_SAFE_EXCEPTION("LADSPA connect_port (audio input)"); + } } + } - if (pData->audioOut.count > 0) + if (fForcedStereoOut) + { + if (LADSPA_Handle const handle = fHandles.getAt(0, nullptr)) { - CARLA_ASSERT(pData->audioOut.count == 2); - CARLA_ASSERT(fAudioOutBuffers[0] != nullptr); - CARLA_ASSERT(fAudioOutBuffers[1] != nullptr); - try { - fDescriptor->connect_port(fHandle, pData->audioOut.ports[0].rindex, fAudioOutBuffers[0]); - } CARLA_SAFE_EXCEPTION("LADSPA connect_port audio output #1"); + fDescriptor->connect_port(handle, pData->audioOut.ports[0].rindex, fAudioOutBuffers[0]); + } CARLA_SAFE_EXCEPTION("LADSPA connect_port (forced stereo output)"); + } + if (LADSPA_Handle const handle = fHandles.getAt(1, nullptr)) + { try { - fDescriptor->connect_port(fHandle2, pData->audioOut.ports[1].rindex, fAudioOutBuffers[1]); - } CARLA_SAFE_EXCEPTION("LADSPA connect_port audio output #2"); + fDescriptor->connect_port(handle, pData->audioOut.ports[1].rindex, fAudioOutBuffers[1]); + } CARLA_SAFE_EXCEPTION("LADSPA connect_port (forced stereo output)"); } } + else + { + for (LinkedList::Itenerator it = fHandles.begin(); it.valid(); it.next()) + { + LADSPA_Handle const handle(it.getValue(nullptr)); + CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr); - carla_debug("CarlaPluginLADSPA::bufferSizeChanged(%i) - end", newBufferSize); - } - - void sampleRateChanged(const double newSampleRate) override - { - CARLA_ASSERT_INT(newSampleRate > 0.0, newSampleRate); - carla_debug("CarlaPluginLADSPA::sampleRateChanged(%g) - start", newSampleRate); - - // TODO - (void)newSampleRate; - - carla_debug("CarlaPluginLADSPA::sampleRateChanged(%g) - end", newSampleRate); + for (uint32_t i=0; i < pData->audioOut.count; ++i) + { + try { + fDescriptor->connect_port(handle, pData->audioOut.ports[i].rindex, fAudioOutBuffers[i]); + } CARLA_SAFE_EXCEPTION("LADSPA connect_port (audio output)"); + } + } + } } // ------------------------------------------------------------------- @@ -1484,6 +1509,18 @@ public: fAudioOutBuffers = nullptr; } + if (fExtraStereoBuffer[0] != nullptr) + { + delete[] fExtraStereoBuffer[0]; + fExtraStereoBuffer[0] = nullptr; + } + + if (fExtraStereoBuffer[1] != nullptr) + { + delete[] fExtraStereoBuffer[1]; + fExtraStereoBuffer[1] = nullptr; + } + if (fParamBuffers != nullptr) { delete[] fParamBuffers; @@ -1499,7 +1536,7 @@ public: void* getNativeHandle() const noexcept override { - return fHandle; + return nullptr; // fHandle; } const void* getNativeDescriptor() const noexcept override @@ -1539,6 +1576,8 @@ public: return false; } + fIsDssiVst = CarlaString(filename).contains("dssi-vst", true); + // --------------------------------------------------------------- // open DLL @@ -1562,12 +1601,10 @@ public: // --------------------------------------------------------------- // get descriptor that matches label - ulong i = 0; - - for (;;) + for (ulong d=0;; ++d) { try { - fDescriptor = descFn(i++); + fDescriptor = descFn(d); } catch(...) { carla_stderr2("Caught exception when trying to get LADSPA descriptor"); @@ -1632,28 +1669,41 @@ public: // --------------------------------------------------------------- // initialize plugin - try { - fHandle = fDescriptor->instantiate(fDescriptor, static_cast(pData->engine->getSampleRate())); - } CARLA_SAFE_EXCEPTION("LADSPA instantiate"); + if (! addInstance()) + return false; + + // --------------------------------------------------------------- + // find latency port index - if (fHandle == nullptr) + for (uint32_t i=0, iCtrl=0, count=getSafePortCount(); iengine->setLastError("Plugin failed to initialize"); - return false; + const int portType(fDescriptor->PortDescriptors[i]); + + if (! LADSPA_IS_PORT_CONTROL(portType)) + continue; + + const uint32_t index(iCtrl++); + + if (! LADSPA_IS_PORT_OUTPUT(portType)) + continue; + + const char* const portName(fDescriptor->PortNames[i]); + CARLA_SAFE_ASSERT_BREAK(portName != nullptr); + + if (std::strcmp(portName, "latency") == 0 || + std::strcmp(portName, "_latency") == 0) + { + fLatencyIndex = static_cast(index); + break; + } } // --------------------------------------------------------------- // set default options -#ifdef __USE_GNU - const bool isDssiVst(strcasestr(pData->filename, "dssi-vst") != nullptr); -#else - const bool isDssiVst(std::strstr(pData->filename, "dssi-vst") != nullptr); -#endif - pData->options = 0x0; - if (fLatencyIndex >= 0 || isDssiVst) + if (fLatencyIndex >= 0 || fIsDssiVst) pData->options |= PLUGIN_OPTION_FIXED_BUFFERS; if (pData->engine->getOptions().forceStereo) @@ -1665,20 +1715,51 @@ public: // ------------------------------------------------------------------- private: - LADSPA_Handle fHandle; - LADSPA_Handle fHandle2; + LinkedList fHandles; const LADSPA_Descriptor* fDescriptor; const LADSPA_RDF_Descriptor* fRdfDescriptor; float** fAudioInBuffers; float** fAudioOutBuffers; + float* fExtraStereoBuffer[2]; // used only if forcedStereoIn and audioOut == 2 float* fParamBuffers; - bool fLatencyChanged; int32_t fLatencyIndex; // -1 if invalid + bool fIsDssiVst; + bool fForcedStereoIn; + bool fForcedStereoOut; // ------------------------------------------------------------------- + bool addInstance() + { + LADSPA_Handle handle; + + try { + handle = fDescriptor->instantiate(fDescriptor, static_cast(pData->engine->getSampleRate())); + } CARLA_SAFE_EXCEPTION_RETURN_ERR("LADSPA instantiate", "Plugin failed to initialize"); + + for (uint32_t i=0, count=pData->param.count; iparam.data[i].rindex); + CARLA_SAFE_ASSERT_CONTINUE(rindex >= 0); + + try { + fDescriptor->connect_port(handle, static_cast(rindex), &fParamBuffers[i]); + } CARLA_SAFE_EXCEPTION("LADSPA connect_port"); + } + + if (fHandles.append(handle)) + return true; + + try { + fDescriptor->cleanup(handle); + } CARLA_SAFE_EXCEPTION("LADSPA cleanup"); + + pData->engine->setLastError("Out of memory"); + return false; + } + uint32_t getSafePortCount() const noexcept { if (fDescriptor->PortCount == 0) @@ -1700,7 +1781,7 @@ private: return false; } - bool _getSeparatedParameterNameOrUnitImpl(const char* const paramName, char* const strBuf, const bool wantName, const bool useBracket) const noexcept + static bool _getSeparatedParameterNameOrUnitImpl(const char* const paramName, char* const strBuf, const bool wantName, const bool useBracket) noexcept { const char* const sepBracketStart(std::strstr(paramName, useBracket ? " [" : " (")); @@ -1712,15 +1793,15 @@ private: if (sepBracketEnd == nullptr) return false; - const size_t unitSize(static_cast(sepBracketEnd-sepBracketStart-2)); + const std::size_t unitSize(static_cast(sepBracketEnd-sepBracketStart-2)); if (unitSize > 7) // very unlikely to have such big unit return false; - const size_t sepIndex(std::strlen(paramName)-unitSize-3); + const std::size_t sepIndex(std::strlen(paramName)-unitSize-3); // just in case - if (sepIndex > STR_MAX) + if (sepIndex >= STR_MAX) return false; if (wantName) @@ -1767,16 +1848,6 @@ CarlaPlugin* CarlaPlugin::newLADSPA(const Initializer& init, const LADSPA_RDF_De init.engine->setLastError("Carla's rack mode can only work with Mono or Stereo LADSPA plugins, sorry!"); canRun = false; } - else if (plugin->getCVInCount() > 0 || plugin->getCVInCount() > 0) - { - init.engine->setLastError("Carla's rack mode cannot work with plugins that have CV ports, sorry!"); - canRun = false; - } - } - else if (init.engine->getProccessMode() == ENGINE_PROCESS_MODE_PATCHBAY && (plugin->getCVInCount() > 0 || plugin->getCVInCount() > 0)) - { - init.engine->setLastError("CV ports in patchbay mode is still TODO"); - canRun = false; } if (! canRun) diff --git a/source/backend/plugin/CarlaPluginLV2.cpp b/source/backend/plugin/CarlaPluginLV2.cpp index 47155b1c4..15a5b2ae5 100644 --- a/source/backend/plugin/CarlaPluginLV2.cpp +++ b/source/backend/plugin/CarlaPluginLV2.cpp @@ -1432,6 +1432,7 @@ public: } } +#if 0 // TODO void idle() override { if (fLatencyChanged && fLatencyIndex != -1) @@ -1463,6 +1464,7 @@ public: CarlaPlugin::idle(); } +#endif void uiIdle() override { @@ -2361,6 +2363,7 @@ public: pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; } +#if 0 // TODO // check latency if (fLatencyIndex >= 0) { @@ -2429,6 +2432,7 @@ public: fLatencyChanged = false; } +#endif bufferSizeChanged(pData->engine->getBufferSize()); reloadPrograms(true); @@ -2730,11 +2734,13 @@ public: } #ifndef BUILD_BRIDGE +#if 0 // TODO if (pData->latency > 0) { for (uint32_t i=0; i < pData->audioIn.count; ++i) FloatVectorOperations::clear(pData->latencyBuffers[i], static_cast(pData->latency)); } +#endif #endif pData->needsReset = false; @@ -3340,6 +3346,7 @@ public: } // End of Plugin processing (no events) #ifndef BUILD_BRIDGE +#if 0 // TODO // -------------------------------------------------------------------------------------------------------- // Latency, save values for next callback @@ -3368,6 +3375,7 @@ public: } } } +#endif #endif // -------------------------------------------------------------------------------------------------------- @@ -3614,11 +3622,13 @@ public: { for (uint32_t k=0; k < frames; ++k) { +#if 0 // TODO if (k < pData->latency) bufValue = pData->latencyBuffers[isMono ? 0 : i][k]; else if (pData->latency < frames) bufValue = fAudioInBuffers[isMono ? 0 : i][k-pData->latency]; else +#endif bufValue = fAudioInBuffers[isMono ? 0 : i][k]; fAudioOutBuffers[i][k] = (fAudioOutBuffers[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet)); diff --git a/source/backend/plugin/CarlaPluginVST2.cpp b/source/backend/plugin/CarlaPluginVST2.cpp index 3accecf12..e8fa846ff 100644 --- a/source/backend/plugin/CarlaPluginVST2.cpp +++ b/source/backend/plugin/CarlaPluginVST2.cpp @@ -843,6 +843,7 @@ public: deactivate(); } +#if 0 // TODO // check latency if (pData->hints & PLUGIN_CAN_DRYWET) { @@ -859,6 +860,7 @@ public: pData->recreateLatencyBuffers(); #endif } +#endif // special plugin fixes // 1. IL Harmless - disable threaded processing @@ -1061,11 +1063,13 @@ public: } #ifndef BUILD_BRIDGE +#if 0 // TODO if (pData->latency > 0) { for (uint32_t i=0; i < pData->audioIn.count; ++i) FloatVectorOperations::clear(pData->latencyBuffers[i], static_cast(pData->latency)); } +#endif #endif pData->needsReset = false; diff --git a/source/native-plugins/bigmeter.cpp b/source/native-plugins/bigmeter.cpp index 77c24157d..a1b704fe2 100644 --- a/source/native-plugins/bigmeter.cpp +++ b/source/native-plugins/bigmeter.cpp @@ -160,10 +160,10 @@ protected: Range range; range = FloatVectorOperations::findMinAndMax(inputs[0], static_cast(frames)); - fOutLeft = carla_max(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f); + fOutLeft = carla_maxLimited(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f); range = FloatVectorOperations::findMinAndMax(inputs[1], static_cast(frames)); - fOutRight = carla_max(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f); + fOutRight = carla_maxLimited(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f); } private: diff --git a/source/utils/CarlaMathUtils.hpp b/source/utils/CarlaMathUtils.hpp index 795baa667..72c6b6f3a 100644 --- a/source/utils/CarlaMathUtils.hpp +++ b/source/utils/CarlaMathUtils.hpp @@ -27,11 +27,11 @@ // math functions (base) /* - * Return the lower of 2 values, with 'min' as the minimum possible value. + * Return the lower of 2 values, with 'min' as the minimum possible value (ie, base). */ template static inline -const T& carla_min(const T& v1, const T& v2, const T& min) noexcept +const T& carla_minWithBase(const T& v1, const T& v2, const T& min) noexcept { return ((v1 <= min || v2 <= min) ? min : (v1 < v2 ? v1 : v2)); } @@ -56,11 +56,11 @@ T carla_minPositive(const T& v1, const T& v2) noexcept } /* - * Return the higher of 2 values, with 'max' as the maximum possible value. + * Return the higher of 2 values, with 'max' as the maximum possible value (ie, limit). */ template static inline -const T& carla_max(const T& v1, const T& v2, const T& max) noexcept +const T& carla_maxLimited(const T& v1, const T& v2, const T& max) noexcept { return ((v1 >= max || v2 >= max) ? max : (v1 > v2 ? v1 : v2)); }