diff --git a/source/backend/plugin/CarlaPluginCLAP.cpp b/source/backend/plugin/CarlaPluginCLAP.cpp index de63b010d..83b53447d 100644 --- a/source/backend/plugin/CarlaPluginCLAP.cpp +++ b/source/backend/plugin/CarlaPluginCLAP.cpp @@ -67,7 +67,8 @@ public: fPlugin(nullptr), fPluginDescriptor(nullptr), fPluginEntry(nullptr), - fHost() + fHost(), + fExtensions() { carla_debug("CarlaPluginCLAP::CarlaPluginCLAP(%p, %i)", engine, id); @@ -127,11 +128,17 @@ public: return PLUGIN_CLAP; } - /* PluginCategory getCategory() const noexcept override { + CARLA_SAFE_ASSERT_RETURN(fPluginDescriptor != nullptr, PLUGIN_CATEGORY_NONE); + + if (fPluginDescriptor->features == nullptr) + return PLUGIN_CATEGORY_NONE; + + return getPluginCategoryFromClapFeatures(fPluginDescriptor->features); } + /* uint32_t getLatencyInFrames() const noexcept override { } @@ -158,11 +165,20 @@ public: uint getOptionsAvailable() const noexcept override { } + */ float getParameterValue(const uint32_t parameterId) const noexcept override { + CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.f); + CARLA_SAFE_ASSERT_RETURN(fExtensions.params != nullptr, 0.f); + + const clap_id clapId = pData->param.data[parameterId].rindex; + + double value; + CARLA_SAFE_ASSERT_RETURN(fExtensions.params->get_value(fPlugin, clapId, &value), 0.f); + + return value; } - */ bool getLabel(char* const strBuf) const noexcept override { @@ -193,15 +209,36 @@ public: return true; } - /* bool getParameterName(const uint32_t parameterId, char* const strBuf) const noexcept override { + CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr, false); + CARLA_SAFE_ASSERT_RETURN(fExtensions.params != nullptr, false); + CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false); + + const clap_id clapId = pData->param.data[parameterId].rindex; + + clap_param_info_t paramInfo = {}; + CARLA_SAFE_ASSERT_RETURN(fExtensions.params->get_info(fPlugin, clapId, ¶mInfo), false); + + std::strncpy(strBuf, paramInfo.name, STR_MAX); + return true; } bool getParameterText(const uint32_t parameterId, char* const strBuf) noexcept override { + CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr, false); + CARLA_SAFE_ASSERT_RETURN(fExtensions.params != nullptr, false); + CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false); + + const clap_id clapId = pData->param.data[parameterId].rindex; + + double value; + CARLA_SAFE_ASSERT_RETURN(fExtensions.params->get_value(fPlugin, clapId, &value), false); + + return fExtensions.params->value_to_text(fPlugin, clapId, value, strBuf, STR_MAX); } + /* bool getParameterUnit(const uint32_t parameterId, char* const strBuf) const noexcept override { } @@ -283,23 +320,310 @@ public: void reload() override { CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr,); - // CARLA_SAFE_ASSERT_RETURN(fEffect != nullptr,); + CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,); carla_debug("CarlaPluginCLAP::reload() - start"); - const EngineProcessMode processMode = pData->engine->getProccessMode(); - // Safely disable plugin for reload const ScopedDisabler sd(this); - const clap_plugin_audio_ports_t* const audioPorts = static_cast( + if (pData->active) + deactivate(); + + clearBuffers(); + + const clap_plugin_audio_ports_t* audioPortsExt = static_cast( fPlugin->get_extension(fPlugin, CLAP_EXT_AUDIO_PORTS)); - const clap_plugin_note_ports_t* const notePorts = static_cast( + const clap_plugin_note_ports_t* notePortsExt = static_cast( fPlugin->get_extension(fPlugin, CLAP_EXT_NOTE_PORTS)); - const clap_plugin_params_t* const params = static_cast( + const clap_plugin_params_t* paramsExt = static_cast( fPlugin->get_extension(fPlugin, CLAP_EXT_PARAMS)); + if (audioPortsExt != nullptr && (audioPortsExt->count == nullptr || audioPortsExt->get == nullptr)) + audioPortsExt = nullptr; + + if (notePortsExt != nullptr && (notePortsExt->count == nullptr || notePortsExt->get == nullptr)) + notePortsExt = nullptr; + + if (paramsExt != nullptr && (paramsExt->count == nullptr || paramsExt->get_info == nullptr)) + paramsExt = nullptr; + + fExtensions.params = paramsExt; + + const uint32_t numAudioInputPorts = audioPortsExt != nullptr ? audioPortsExt->count(fPlugin, true) : 0; + const uint32_t numAudioOutputPorts = audioPortsExt != nullptr ? audioPortsExt->count(fPlugin, false) : 0; + const uint32_t numNoteInputPorts = notePortsExt != nullptr ? notePortsExt->count(fPlugin, true) : 0; + const uint32_t numNoteOutputPorts = notePortsExt != nullptr ? notePortsExt->count(fPlugin, true) : 0; + const uint32_t numParameters = paramsExt != nullptr ? paramsExt->count(fPlugin) : 0; + + uint32_t aIns, aOuts, params; + aIns = aOuts = params = 0; + + bool needsCtrlIn, needsCtrlOut; + needsCtrlIn = needsCtrlOut = false; + + for (uint32_t i=0; iget(fPlugin, i, true, &portInfo)); + + aIns += portInfo.channel_count; + } + + for (uint32_t i=0; iget(fPlugin, i, false, &portInfo)); + + aOuts += portInfo.channel_count; + } + + for (uint32_t i=0; iget_info(fPlugin, i, ¶mInfo)); + + if ((paramInfo.flags & (CLAP_PARAM_IS_HIDDEN|CLAP_PARAM_IS_BYPASS)) == 0x0) + ++params; + } + + if (aIns > 0) + { + pData->audioIn.createNew(aIns); + } + + if (aOuts > 0) + { + pData->audioOut.createNew(aOuts); + needsCtrlIn = true; + } + + if (numNoteInputPorts > 0) + needsCtrlIn = true; + + if (numNoteOutputPorts > 0) + needsCtrlOut = true; + + if (params > 0) + { + pData->param.createNew(params, false); + needsCtrlIn = true; + } + + const EngineProcessMode processMode = pData->engine->getProccessMode(); + const uint portNameSize = pData->engine->getMaxPortNameSize(); + CarlaString portName; + + // Audio Ins + for (uint32_t j=0; j < aIns; ++j) + { + portName.clear(); + + if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT) + { + portName = pData->name; + portName += ":"; + } + + if (aIns > 1) + { + portName += "input_"; + portName += CarlaString(j+1); + } + else + portName += "input"; + + portName.truncate(portNameSize); + + pData->audioIn.ports[j].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, true, j); + pData->audioIn.ports[j].rindex = j; + } + + // Audio Outs + for (uint32_t j=0; j < aOuts; ++j) + { + portName.clear(); + + if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT) + { + portName = pData->name; + portName += ":"; + } + + if (aOuts > 1) + { + portName += "output_"; + portName += CarlaString(j+1); + } + else + portName += "output"; + + portName.truncate(portNameSize); + + pData->audioOut.ports[j].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, false, j); + pData->audioOut.ports[j].rindex = j; + } + + for (uint32_t j=0; j < params; ++j) + { + const int32_t ij = static_cast(j); + pData->param.data[j].index = j; + pData->param.data[j].rindex = ij; + + clap_param_info_t paramInfo = {}; + CARLA_SAFE_ASSERT_BREAK(paramsExt->get_info(fPlugin, j, ¶mInfo)); + + if (paramInfo.flags & (CLAP_PARAM_IS_HIDDEN|CLAP_PARAM_IS_BYPASS)) + continue; + + double min, max, def, step, stepSmall, stepLarge; + + min = paramInfo.min_value; + max = paramInfo.max_value; + def = paramInfo.default_value; + + if (min >= max) + max = min + 0.1; + + if (def < min) + def = min; + else if (def > max) + def = max; + + if (paramInfo.flags & CLAP_PARAM_IS_READONLY) + pData->param.data[j].type = PARAMETER_OUTPUT; + else + pData->param.data[j].type = PARAMETER_INPUT; + + if (paramInfo.flags & CLAP_PARAM_IS_STEPPED) + { + if (carla_isEqual(max - min, 1.0)) + { + step = stepSmall = stepLarge = 1.0; + pData->param.data[j].hints |= PARAMETER_IS_BOOLEAN; + } + else + { + step = 1.0; + stepSmall = 1.0; + stepLarge = std::min(max - min, 10.0); + } + pData->param.data[j].hints |= PARAMETER_IS_INTEGER; + } + else + { + double range = max - min; + step = range/100.0; + stepSmall = range/1000.0; + stepLarge = range/10.0; + } + + pData->param.data[j].hints |= PARAMETER_IS_ENABLED; + pData->param.data[j].hints |= PARAMETER_USES_CUSTOM_TEXT; + + if (paramInfo.flags & CLAP_PARAM_IS_AUTOMATABLE) + { + pData->param.data[j].hints |= PARAMETER_IS_AUTOMATABLE; + + if ((paramInfo.flags & CLAP_PARAM_IS_STEPPED) == 0x0) + pData->param.data[j].hints |= PARAMETER_CAN_BE_CV_CONTROLLED; + } + + pData->param.ranges[j].min = min; + pData->param.ranges[j].max = max; + pData->param.ranges[j].def = def; + pData->param.ranges[j].step = step; + pData->param.ranges[j].stepSmall = stepSmall; + pData->param.ranges[j].stepLarge = stepLarge; + } + + if (needsCtrlIn) + { + portName.clear(); + + if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT) + { + portName = pData->name; + portName += ":"; + } + + portName += "events-in"; + portName.truncate(portNameSize); + + pData->event.portIn = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, true, 0); + #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH + pData->event.cvSourcePorts = pData->client->createCVSourcePorts(); + #endif + } + + if (needsCtrlOut) + { + portName.clear(); + + if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT) + { + portName = pData->name; + portName += ":"; + } + + portName += "events-out"; + portName.truncate(portNameSize); + + pData->event.portOut = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, false, 0); + } + + // plugin hints + const PluginCategory category = fPluginDescriptor->features != nullptr ? getPluginCategoryFromClapFeatures(fPluginDescriptor->features) + : PLUGIN_CATEGORY_NONE; + + pData->hints = 0x0; + + if (category == PLUGIN_CATEGORY_SYNTH) + pData->hints |= PLUGIN_IS_SYNTH; + + #ifdef CLAP_WINDOW_API_NATIVE + if (const clap_plugin_gui_t* const guiExt = static_cast(fPlugin->get_extension(fPlugin, CLAP_EXT_GUI))) + { + if (guiExt->is_api_supported != nullptr) + { + if (guiExt->is_api_supported(fPlugin, CLAP_WINDOW_API_NATIVE, false)) + { + pData->hints |= PLUGIN_HAS_CUSTOM_UI; + pData->hints |= PLUGIN_HAS_CUSTOM_EMBED_UI; + } + else if (guiExt->is_api_supported(fPlugin, CLAP_WINDOW_API_NATIVE, false)) + { + pData->hints |= PLUGIN_HAS_CUSTOM_UI; + } + } + } + #endif + + if (aOuts > 0 && (aIns == aOuts || aIns == 1)) + pData->hints |= PLUGIN_CAN_DRYWET; + + if (aOuts > 0) + pData->hints |= PLUGIN_CAN_VOLUME; + + if (aOuts >= 2 && aOuts % 2 == 0) + pData->hints |= PLUGIN_CAN_BALANCE; + + // extra plugin hints + pData->extraHints = 0x0; + + if (numNoteInputPorts > 0) + pData->extraHints |= PLUGIN_EXTRA_HINT_HAS_MIDI_IN; + + if (numNoteOutputPorts > 0) + pData->extraHints |= PLUGIN_EXTRA_HINT_HAS_MIDI_OUT; + + bufferSizeChanged(pData->engine->getBufferSize()); + reloadPrograms(true); + + if (pData->active) + activate(); + carla_debug("CarlaPluginCLAP::reload() - end"); } @@ -313,15 +637,25 @@ public: void activate() noexcept override { + CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,); + + // FIXME check return status + fPlugin->activate(fPlugin, pData->engine->getSampleRate(), 1, pData->engine->getBufferSize()); + fPlugin->start_processing(fPlugin); } void deactivate() noexcept override { + CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,); + + // FIXME check return status + fPlugin->stop_processing(fPlugin); + fPlugin->deactivate(fPlugin); } - void process(const float* const*, + void process(const float* const* const audioIn, float** const audioOut, - const float* const*, + const float* const* const cvIn, float** const, const uint32_t frames) override { @@ -336,18 +670,240 @@ public: return; } + // -------------------------------------------------------------------------------------------------------- + // Check if needs reset + + if (pData->needsReset) + { + pData->needsReset = false; + } + + // -------------------------------------------------------------------------------------------------------- + // Set TimeInfo + + const EngineTimeInfo timeInfo(pData->engine->getTimeInfo()); + + // -------------------------------------------------------------------------------------------------------- + // Event Input and Processing + + if (pData->event.portIn != nullptr) + { + // ---------------------------------------------------------------------------------------------------- + // MIDI Input (External) + + if (pData->extNotes.mutex.tryLock()) + { + pData->extNotes.data.clear(); + + pData->extNotes.mutex.unlock(); + + } // End of MIDI Input (External) + + // ---------------------------------------------------------------------------------------------------- + // Event Input (System) + + uint32_t startTime = 0; + uint32_t timeOffset = 0; + + pData->postRtEvents.trySplice(); + + if (frames > timeOffset) + processSingle(audioIn, audioOut, frames - timeOffset, timeOffset); + + } // End of Event Input and Processing + + // -------------------------------------------------------------------------------------------------------- + // Plugin processing (no events) + + else + { + processSingle(audioIn, audioOut, frames, 0); + + } // End of Plugin processing (no events) + + // -------------------------------------------------------------------------------------------------------- + // MIDI Output + + if (pData->event.portOut != nullptr) + { + + } // End of MIDI Output + + // -------------------------------------------------------------------------------------------------------- + +#ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH + return; + + // unused + (void)cvIn; +#endif + } + + bool processSingle(const float* const* const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t timeOffset) + { + CARLA_SAFE_ASSERT_RETURN(frames > 0, false); + + if (pData->audioIn.count > 0) + { + CARLA_SAFE_ASSERT_RETURN(inBuffer != nullptr, false); + } + if (pData->audioOut.count > 0) + { + CARLA_SAFE_ASSERT_RETURN(outBuffer != nullptr, false); + } + + // -------------------------------------------------------------------------------------------------------- + // Try lock, silence otherwise + + if (pData->engine->isOffline()) + { + pData->singleMutex.lock(); + } + else if (! pData->singleMutex.tryLock()) + { + for (uint32_t i=0; i < pData->audioOut.count; ++i) + { + for (uint32_t k=0; k < frames; ++k) + outBuffer[i][k+timeOffset] = 0.0f; + } + + return false; + } + + // -------------------------------------------------------------------------------------------------------- + // Run plugin + + const clap_audio_buffer_const_t inBuffers[1] = { + { + inBuffer, // data32 + nullptr, // data64 + 1, // channel_count + 0, // latency + 0 // constant_mask; + } + }; + clap_audio_buffer_t outBuffers[1] = { + { + outBuffer, // data32 + nullptr, // data64 + 1, // channel_count + 0, // latency + 0 // constant_mask; + } + }; + const clap_process_t process = { + 0, // steady_time + frames, + nullptr, // transport + static_cast(static_cast(inBuffers)), // audio_inputs + outBuffers, // audio_outputs + 1, // audio_inputs_count + 1, // audio_outputs_count + nullptr, // in_events + nullptr // out_events + }; + + fPlugin->process(fPlugin, &process); + + // fTimeInfo.samplePos += frames; + + #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH + // -------------------------------------------------------------------------------------------------------- + // Post-processing (dry/wet, volume and balance) + + { + const bool doVolume = (pData->hints & PLUGIN_CAN_VOLUME) != 0 && carla_isNotEqual(pData->postProc.volume, 1.0f); + const bool doDryWet = (pData->hints & PLUGIN_CAN_DRYWET) != 0 && carla_isNotEqual(pData->postProc.dryWet, 1.0f); + const bool doBalance = (pData->hints & PLUGIN_CAN_BALANCE) != 0 && ! (carla_isEqual(pData->postProc.balanceLeft, -1.0f) && carla_isEqual(pData->postProc.balanceRight, 1.0f)); + const bool isMono = (pData->audioIn.count == 1); + + bool isPair; + float bufValue, oldBufLeft[doBalance ? frames : 1]; + + for (uint32_t i=0; i < pData->audioOut.count; ++i) + { + // Dry/Wet + if (doDryWet) + { + const uint32_t c = isMono ? 0 : i; + + for (uint32_t k=0; k < frames; ++k) + { + bufValue = inBuffer[c][k]; + outBuffer[i][k] = (outBuffer[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet)); + } + } + + // Balance + if (doBalance) + { + isPair = (i % 2 == 0); + + if (isPair) + { + CARLA_ASSERT(i+1 < pData->audioOut.count); + carla_copyFloats(oldBufLeft, outBuffer[i], frames); + } + + float balRangeL = (pData->postProc.balanceLeft + 1.0f)/2.0f; + float balRangeR = (pData->postProc.balanceRight + 1.0f)/2.0f; + + for (uint32_t k=0; k < frames; ++k) + { + if (isPair) + { + // left + outBuffer[i][k] = oldBufLeft[k] * (1.0f - balRangeL); + outBuffer[i][k] += outBuffer[i+1][k] * (1.0f - balRangeR); + } + else + { + // right + outBuffer[i][k] = outBuffer[i][k] * balRangeR; + outBuffer[i][k] += oldBufLeft[k] * balRangeL; + } + } + } + + // Volume + if (doVolume) + { + for (uint32_t k=0; k < frames; ++k) + outBuffer[i][k] *= pData->postProc.volume; + } + } + + } // End of Post-processing + #endif // BUILD_BRIDGE_ALTERNATIVE_ARCH + + // -------------------------------------------------------------------------------------------------------- + + pData->singleMutex.unlock(); + return true; } void bufferSizeChanged(const uint32_t newBufferSize) override { CARLA_ASSERT_INT(newBufferSize > 0, newBufferSize); carla_debug("CarlaPluginCLAP::bufferSizeChanged(%i)", newBufferSize); + + if (pData->active) + deactivate(); + + if (pData->active) + activate(); } void sampleRateChanged(const double newSampleRate) override { CARLA_ASSERT_INT(newSampleRate > 0.0, newSampleRate); carla_debug("CarlaPluginCLAP::sampleRateChanged(%g)", newSampleRate); + + if (pData->active) + deactivate(); + + if (pData->active) + activate(); } // ------------------------------------------------------------------- @@ -596,6 +1152,15 @@ private: const clap_plugin_entry_t* fPluginEntry; const carla_clap_host fHost; + struct Extensions { + const clap_plugin_params_t* params; + + Extensions() + : params(nullptr) {} + + CARLA_DECLARE_NON_COPYABLE(Extensions) + } fExtensions; + #ifdef CARLA_OS_MAC BundleLoader fBundleLoader; #endif diff --git a/source/backend/plugin/CarlaPluginLV2.cpp b/source/backend/plugin/CarlaPluginLV2.cpp index 34eae3df1..680efbdaf 100644 --- a/source/backend/plugin/CarlaPluginLV2.cpp +++ b/source/backend/plugin/CarlaPluginLV2.cpp @@ -2333,7 +2333,7 @@ public: for (uint32_t i=0; i < portCount; ++i) { - const LV2_Property portTypes(fRdfDescriptor->Ports[i].Types); + const LV2_Property portTypes = fRdfDescriptor->Ports[i].Types; if (LV2_IS_PORT_AUDIO(portTypes)) { diff --git a/source/backend/plugin/CarlaPluginVST2.cpp b/source/backend/plugin/CarlaPluginVST2.cpp index 7f2b849a8..d60935a54 100644 --- a/source/backend/plugin/CarlaPluginVST2.cpp +++ b/source/backend/plugin/CarlaPluginVST2.cpp @@ -695,8 +695,6 @@ public: CARLA_SAFE_ASSERT_RETURN(fEffect != nullptr,); carla_debug("CarlaPluginVST2::reload() - start"); - const EngineProcessMode processMode(pData->engine->getProccessMode()); - // Safely disable plugin for reload const ScopedDisabler sd(this); const CarlaScopedValueSetter svs(fIsInitializing, fIsInitializing, false); @@ -752,7 +750,8 @@ public: needsCtrlIn = true; } - const uint portNameSize(pData->engine->getMaxPortNameSize()); + const EngineProcessMode processMode = pData->engine->getProccessMode(); + const uint portNameSize = pData->engine->getMaxPortNameSize(); CarlaString portName; // Audio Ins diff --git a/source/backend/plugin/CarlaPluginVST3.cpp b/source/backend/plugin/CarlaPluginVST3.cpp index 7f45cc66f..679bd944e 100644 --- a/source/backend/plugin/CarlaPluginVST3.cpp +++ b/source/backend/plugin/CarlaPluginVST3.cpp @@ -851,14 +851,14 @@ public: clearBuffers(); const int32_t numAudioInputBuses = v3_cpp_obj(fV3.component)->get_bus_count(fV3.component, V3_AUDIO, V3_INPUT); - const int32_t numEventInputBuses = v3_cpp_obj(fV3.component)->get_bus_count(fV3.component, V3_EVENT, V3_INPUT); const int32_t numAudioOutputBuses = v3_cpp_obj(fV3.component)->get_bus_count(fV3.component, V3_AUDIO, V3_OUTPUT); + const int32_t numEventInputBuses = v3_cpp_obj(fV3.component)->get_bus_count(fV3.component, V3_EVENT, V3_INPUT); const int32_t numEventOutputBuses = v3_cpp_obj(fV3.component)->get_bus_count(fV3.component, V3_EVENT, V3_OUTPUT); const int32_t numParameters = v3_cpp_obj(fV3.controller)->get_parameter_count(fV3.controller); CARLA_SAFE_ASSERT(numAudioInputBuses >= 0); - CARLA_SAFE_ASSERT(numEventInputBuses >= 0); CARLA_SAFE_ASSERT(numAudioOutputBuses >= 0); + CARLA_SAFE_ASSERT(numEventInputBuses >= 0); CARLA_SAFE_ASSERT(numEventOutputBuses >= 0); CARLA_SAFE_ASSERT(numParameters >= 0); @@ -1045,8 +1045,7 @@ public: for (uint32_t j=0; j < params; ++j) { const int32_t ij = static_cast(j); - pData->param.data[j].type = PARAMETER_INPUT; - pData->param.data[j].index = ij; + pData->param.data[j].index = j; pData->param.data[j].rindex = ij; v3_param_info paramInfo = {}; @@ -1055,14 +1054,14 @@ public: if (paramInfo.flags & (V3_PARAM_IS_BYPASS|V3_PARAM_IS_HIDDEN|V3_PARAM_PROGRAM_CHANGE)) continue; - float min, max, def, step, stepSmall, stepLarge; + double min, max, def, step, stepSmall, stepLarge; - min = static_cast(v3_cpp_obj(fV3.controller)->normalised_parameter_to_plain(fV3.controller, j, 0.0)); - max = static_cast(v3_cpp_obj(fV3.controller)->normalised_parameter_to_plain(fV3.controller, j, 1.0)); - def = static_cast(v3_cpp_obj(fV3.controller)->normalised_parameter_to_plain(fV3.controller, j, paramInfo.default_normalised_value)); + min = v3_cpp_obj(fV3.controller)->normalised_parameter_to_plain(fV3.controller, j, 0.0); + max = v3_cpp_obj(fV3.controller)->normalised_parameter_to_plain(fV3.controller, j, 1.0); + def = v3_cpp_obj(fV3.controller)->normalised_parameter_to_plain(fV3.controller, j, paramInfo.default_normalised_value); if (min >= max) - max = min + 0.1f; + max = min + 0.1; if (def < min) def = min; @@ -1084,18 +1083,18 @@ public: /* else if (paramInfo.step_count != 0 && (paramInfo.flags & V3_PARAM_IS_LIST) != 0x0) { - step = 1.0f; - stepSmall = 1.0f; - stepLarge = 10.0f; + step = 1.0; + stepSmall = 1.0; + stepLarge = std::min(max - min, 10.0); pData->param.data[j].hints |= PARAMETER_IS_INTEGER; } */ else { float range = max - min; - step = range/100.0f; - stepSmall = range/1000.0f; - stepLarge = range/10.0f; + step = range/100.0; + stepSmall = range/1000.0; + stepLarge = range/10.0; } pData->param.data[j].hints |= PARAMETER_IS_ENABLED; @@ -1222,7 +1221,7 @@ public: } } - for (int32_t j=0; jget_bus_info(fV3.component, V3_AUDIO, V3_OUTPUT, j, &busInfo) == V3_OK); diff --git a/source/discovery/carla-discovery.cpp b/source/discovery/carla-discovery.cpp index 3aa75e445..a4af44831 100644 --- a/source/discovery/carla-discovery.cpp +++ b/source/discovery/carla-discovery.cpp @@ -2028,91 +2028,7 @@ static void do_clap_check(lib_t& libHandle, const char* const filename, const bo } if (desc->features != nullptr) - { - // 1st pass for main categories - for (uint32_t j=0; desc->features[j] != nullptr; ++j) - { - if (std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_INSTRUMENT) == 0) - { - category = PLUGIN_CATEGORY_SYNTH; - break; - } - if (std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_NOTE_EFFECT) == 0) - { - category = PLUGIN_CATEGORY_UTILITY; - break; - } - if (std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_ANALYZER) == 0) - { - category = PLUGIN_CATEGORY_UTILITY; - break; - } - } - - // 2nd pass for FX sub categories - if (category == PLUGIN_CATEGORY_NONE) - { - /* - #define CLAP_PLUGIN_FEATURE_DEESSER "de-esser" - #define CLAP_PLUGIN_FEATURE_PHASE_VOCODER "phase-vocoder" - #define CLAP_PLUGIN_FEATURE_GRANULAR "granular" - #define CLAP_PLUGIN_FEATURE_FREQUENCY_SHIFTER "frequency-shifter" - #define CLAP_PLUGIN_FEATURE_PITCH_SHIFTER "pitch-shifter" - #define CLAP_PLUGIN_FEATURE_TREMOLO "tremolo" - #define CLAP_PLUGIN_FEATURE_GLITCH "glitch" - */ - for (uint32_t j=0; desc->features[j] != nullptr; ++j) - { - if (std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_DELAY) == 0 || - std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_REVERB) == 0) - { - category = PLUGIN_CATEGORY_DELAY; - break; - } - if (std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_EQUALIZER) == 0) - { - category = PLUGIN_CATEGORY_EQ; - break; - } - if (std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_FILTER) == 0) - { - category = PLUGIN_CATEGORY_FILTER; - break; - } - if (std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_DISTORTION) == 0) - { - category = PLUGIN_CATEGORY_DISTORTION; - break; - } - if (std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_COMPRESSOR) == 0 || - std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_LIMITER) == 0 || - std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_MASTERING) == 0 || - std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_MIXING) == 0 || - std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_TRANSIENT_SHAPER) == 0) - { - category = PLUGIN_CATEGORY_DYNAMICS; - break; - } - if (std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_CHORUS) == 0 || - std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_FLANGER) == 0 || - std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_PHASER) == 0 - ) - { - category = PLUGIN_CATEGORY_MODULATOR; - break; - } - if (std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_PITCH_CORRECTION) == 0 || - std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_RESTORATION) == 0 || - std::strcmp(desc->features[j], CLAP_PLUGIN_FEATURE_UTILITY) == 0 - ) - { - category = PLUGIN_CATEGORY_UTILITY; - break; - } - } - category = PLUGIN_CATEGORY_OTHER; - } - } + category = getPluginCategoryFromClapFeatures(desc->features); if (doInit) { @@ -2504,10 +2420,10 @@ int main(int argc, char* argv[]) case PLUGIN_LADSPA: case PLUGIN_DSSI: case PLUGIN_VST2: - case PLUGIN_CLAP: openLib = true; break; case PLUGIN_VST3: + case PLUGIN_CLAP: openLib = water::File(filename).existsAsFile(); break; default: diff --git a/source/frontend/pluginlist/discovery.py b/source/frontend/pluginlist/discovery.py index 77e0bc415..f58564d5d 100644 --- a/source/frontend/pluginlist/discovery.py +++ b/source/frontend/pluginlist/discovery.py @@ -101,9 +101,17 @@ def findLV2Bundles(bundlePath): return bundles -def findMacVSTBundles(bundlePath, isVST3): +def findMacBundles(bundlePath, pluginType): bundles = [] - extension = ".vst3" if isVST3 else ".vst" + + if pluginType == PLUGIN_VST2: + extension = ".vst" + elif pluginType == PLUGIN_VST3: + extension = ".vst3" + elif pluginType == PLUGIN_CLAP: + extension = ".clap" + else: + return bundles for root, dirs, _ in os.walk(bundlePath, followlinks=True): for name in tuple(name for name in dirs if name.lower().endswith(extension)): diff --git a/source/frontend/pluginlist/discoverythread.py b/source/frontend/pluginlist/discoverythread.py index 34da81a6b..852710310 100644 --- a/source/frontend/pluginlist/discoverythread.py +++ b/source/frontend/pluginlist/discoverythread.py @@ -35,6 +35,7 @@ from carla_backend import ( PLUGIN_LV2, PLUGIN_SFZ, PLUGIN_VST2, + PLUGIN_VST3, PLUGIN_CLAP, ) @@ -84,7 +85,7 @@ from .discovery import ( checkPluginCLAP, findBinaries, findFilenames, - findMacVSTBundles, + findMacBundles, findVST3Binaries, findCLAPBinaries ) @@ -589,7 +590,7 @@ class SearchPluginsThread(QThread): for iPATH in VST2_PATH: if MACOS and not isWine: - binaries = findMacVSTBundles(iPATH, False) + binaries = findMacBundles(iPATH, PLUGIN_VST2) else: binaries = findBinaries(iPATH, PLUGIN_VST2, OS) for binary in binaries: @@ -631,7 +632,7 @@ class SearchPluginsThread(QThread): for iPATH in VST3_PATH: if MACOS and not isWine: - binaries = findMacVSTBundles(iPATH, True) + binaries = findMacBundles(iPATH, PLUGIN_VST3) else: binaries = findVST3Binaries(iPATH) for binary in binaries: @@ -669,7 +670,10 @@ class SearchPluginsThread(QThread): del settings for iPATH in CLAP_PATH: - binaries = findCLAPBinaries(iPATH) + if MACOS and not isWine: + binaries = findMacBundles(iPATH, PLUGIN_CLAP) + else: + binaries = findCLAPBinaries(iPATH) for binary in binaries: if binary not in clapBinaries: clapBinaries.append(binary) diff --git a/source/utils/CarlaClapUtils.hpp b/source/utils/CarlaClapUtils.hpp index 069696286..fd888d3f1 100644 --- a/source/utils/CarlaClapUtils.hpp +++ b/source/utils/CarlaClapUtils.hpp @@ -1,5 +1,5 @@ /* - * Carla LADSPA utils + * Carla CLAP utils * Copyright (C) 2022 Filipe Coelho * * This program is free software; you can redistribute it and/or @@ -18,6 +18,7 @@ #ifndef CARLA_CLAP_UTILS_HPP_INCLUDED #define CARLA_CLAP_UTILS_HPP_INCLUDED +#include "CarlaBackend.h" #include "CarlaUtils.hpp" #include "clap/entry.h" @@ -30,8 +31,107 @@ #include "clap/ext/state.h" #include "clap/ext/timer-support.h" +#if defined(CARLA_OS_WIN) +# define CLAP_WINDOW_API_NATIVE CLAP_WINDOW_API_WIN32 +#elif defined(CARLA_OS_MAC) +# define CLAP_WINDOW_API_NATIVE CLAP_WINDOW_API_COCOA +#elif defined(HAVE_X11) +# define CLAP_WINDOW_API_NATIVE CLAP_WINDOW_API_X11 +#endif + // -------------------------------------------------------------------------------------------------------------------- +extern "C" { + +typedef struct clap_audio_buffer_const { + // Either data32 or data64 pointer will be set. + const float* const* data32; + const double* const* data64; + uint32_t channel_count; + uint32_t latency; // latency from/to the audio interface + uint64_t constant_mask; +} clap_audio_buffer_const_t; + +} + +// -------------------------------------------------------------------------------------------------------------------- + +CARLA_BACKEND_START_NAMESPACE + // -------------------------------------------------------------------------------------------------------------------- +static inline +PluginCategory getPluginCategoryFromClapFeatures(const char* const* const features) noexcept +{ + // 1st pass for main categories + for (uint32_t i=0; features[i] != nullptr; ++i) + { + if (std::strcmp(features[i], CLAP_PLUGIN_FEATURE_INSTRUMENT) == 0) + return PLUGIN_CATEGORY_SYNTH; + if (std::strcmp(features[i], CLAP_PLUGIN_FEATURE_NOTE_EFFECT) == 0) + return PLUGIN_CATEGORY_UTILITY; + if (std::strcmp(features[i], CLAP_PLUGIN_FEATURE_ANALYZER) == 0) + return PLUGIN_CATEGORY_UTILITY; + } + + // 2nd pass for FX sub categories + /* + #define CLAP_PLUGIN_FEATURE_DEESSER "de-esser" + #define CLAP_PLUGIN_FEATURE_PHASE_VOCODER "phase-vocoder" + #define CLAP_PLUGIN_FEATURE_GRANULAR "granular" + #define CLAP_PLUGIN_FEATURE_FREQUENCY_SHIFTER "frequency-shifter" + #define CLAP_PLUGIN_FEATURE_PITCH_SHIFTER "pitch-shifter" + #define CLAP_PLUGIN_FEATURE_TREMOLO "tremolo" + #define CLAP_PLUGIN_FEATURE_GLITCH "glitch" + */ + for (uint32_t i=0; features[i] != nullptr; ++i) + { + if (std::strcmp(features[i], CLAP_PLUGIN_FEATURE_DELAY) == 0 || + std::strcmp(features[i], CLAP_PLUGIN_FEATURE_REVERB) == 0) + { + return PLUGIN_CATEGORY_DELAY; + } + if (std::strcmp(features[i], CLAP_PLUGIN_FEATURE_EQUALIZER) == 0) + { + return PLUGIN_CATEGORY_EQ; + } + if (std::strcmp(features[i], CLAP_PLUGIN_FEATURE_FILTER) == 0) + { + return PLUGIN_CATEGORY_FILTER; + } + if (std::strcmp(features[i], CLAP_PLUGIN_FEATURE_DISTORTION) == 0) + { + return PLUGIN_CATEGORY_DISTORTION; + } + if (std::strcmp(features[i], CLAP_PLUGIN_FEATURE_COMPRESSOR) == 0 || + std::strcmp(features[i], CLAP_PLUGIN_FEATURE_LIMITER) == 0 || + std::strcmp(features[i], CLAP_PLUGIN_FEATURE_MASTERING) == 0 || + std::strcmp(features[i], CLAP_PLUGIN_FEATURE_MIXING) == 0 || + std::strcmp(features[i], CLAP_PLUGIN_FEATURE_TRANSIENT_SHAPER) == 0) + { + return PLUGIN_CATEGORY_DYNAMICS; + } + if (std::strcmp(features[i], CLAP_PLUGIN_FEATURE_CHORUS) == 0 || + std::strcmp(features[i], CLAP_PLUGIN_FEATURE_FLANGER) == 0 || + std::strcmp(features[i], CLAP_PLUGIN_FEATURE_PHASER) == 0 + ) + { + return PLUGIN_CATEGORY_MODULATOR; + } + if (std::strcmp(features[i], CLAP_PLUGIN_FEATURE_PITCH_CORRECTION) == 0 || + std::strcmp(features[i], CLAP_PLUGIN_FEATURE_RESTORATION) == 0 || + std::strcmp(features[i], CLAP_PLUGIN_FEATURE_UTILITY) == 0 + ) + { + return PLUGIN_CATEGORY_UTILITY; + } + } + + return PLUGIN_CATEGORY_OTHER; +} + +// -------------------------------------------------------------------------------------------------------------------- + +CARLA_BACKEND_END_NAMESPACE + #endif // CARLA_CLAP_UTILS_HPP_INCLUDED diff --git a/source/utils/CarlaVst3Utils.hpp b/source/utils/CarlaVst3Utils.hpp index 3ec1ee3b6..abaff8b27 100644 --- a/source/utils/CarlaVst3Utils.hpp +++ b/source/utils/CarlaVst3Utils.hpp @@ -27,6 +27,8 @@ #include "travesty/factory.h" #include "travesty/host.h" +// -------------------------------------------------------------------------------------------------------------------- + #if !(defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)) #if defined(__aarch64__) || defined(__arm64__) #define V3_ARCHITECTURE "aarch64" @@ -120,8 +122,12 @@ typedef void (*V3_EXITFN)(void); #define V3_GETFNNAME "GetPluginFactory" typedef v3_plugin_factory** (*V3_GETFN)(void); +// -------------------------------------------------------------------------------------------------------------------- + CARLA_BACKEND_START_NAMESPACE +// -------------------------------------------------------------------------------------------------------------------- + static inline PluginCategory getPluginCategoryFromV3SubCategories(const char* const subcategories) noexcept { @@ -149,6 +155,8 @@ const char* tuid2str(const v3_tuid iid) noexcept return buf; } +// -------------------------------------------------------------------------------------------------------------------- + CARLA_BACKEND_END_NAMESPACE #endif // CARLA_VST3_UTILS_HPP_INCLUDED