Browse Source

CLAP processing, initial setup for ports and params

pull/1689/head
falkTX 2 years ago
parent
commit
057b2dbfb3
9 changed files with 724 additions and 125 deletions
  1. +577
    -12
      source/backend/plugin/CarlaPluginCLAP.cpp
  2. +1
    -1
      source/backend/plugin/CarlaPluginLV2.cpp
  3. +2
    -3
      source/backend/plugin/CarlaPluginVST2.cpp
  4. +15
    -16
      source/backend/plugin/CarlaPluginVST3.cpp
  5. +2
    -86
      source/discovery/carla-discovery.cpp
  6. +10
    -2
      source/frontend/pluginlist/discovery.py
  7. +8
    -4
      source/frontend/pluginlist/discoverythread.py
  8. +101
    -1
      source/utils/CarlaClapUtils.hpp
  9. +8
    -0
      source/utils/CarlaVst3Utils.hpp

+ 577
- 12
source/backend/plugin/CarlaPluginCLAP.cpp View File

@@ -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, &paramInfo), 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<const clap_plugin_audio_ports_t*>(
if (pData->active)
deactivate();

clearBuffers();

const clap_plugin_audio_ports_t* audioPortsExt = static_cast<const clap_plugin_audio_ports_t*>(
fPlugin->get_extension(fPlugin, CLAP_EXT_AUDIO_PORTS));

const clap_plugin_note_ports_t* const notePorts = static_cast<const clap_plugin_note_ports_t*>(
const clap_plugin_note_ports_t* notePortsExt = static_cast<const clap_plugin_note_ports_t*>(
fPlugin->get_extension(fPlugin, CLAP_EXT_NOTE_PORTS));

const clap_plugin_params_t* const params = static_cast<const clap_plugin_params_t*>(
const clap_plugin_params_t* paramsExt = static_cast<const clap_plugin_params_t*>(
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; i<numAudioInputPorts; ++i)
{
clap_audio_port_info_t portInfo = {};
CARLA_SAFE_ASSERT_BREAK(audioPortsExt->get(fPlugin, i, true, &portInfo));

aIns += portInfo.channel_count;
}

for (uint32_t i=0; i<numAudioOutputPorts; ++i)
{
clap_audio_port_info_t portInfo = {};
CARLA_SAFE_ASSERT_BREAK(audioPortsExt->get(fPlugin, i, false, &portInfo));

aOuts += portInfo.channel_count;
}

for (uint32_t i=0; i<numParameters; ++i)
{
clap_param_info_t paramInfo = {};
CARLA_SAFE_ASSERT_BREAK(paramsExt->get_info(fPlugin, i, &paramInfo));

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<int32_t>(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, &paramInfo));

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<const clap_plugin_gui_t*>(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<const clap_audio_buffer_t*>(static_cast<const void*>(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


+ 1
- 1
source/backend/plugin/CarlaPluginLV2.cpp View File

@@ -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))
{


+ 2
- 3
source/backend/plugin/CarlaPluginVST2.cpp View File

@@ -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<bool> 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


+ 15
- 16
source/backend/plugin/CarlaPluginVST3.cpp View File

@@ -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<int32_t>(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<float>(v3_cpp_obj(fV3.controller)->normalised_parameter_to_plain(fV3.controller, j, 0.0));
max = static_cast<float>(v3_cpp_obj(fV3.controller)->normalised_parameter_to_plain(fV3.controller, j, 1.0));
def = static_cast<float>(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; j<numAudioInputBuses; ++j)
for (int32_t j=0; j<numAudioOutputBuses; ++j)
{
v3_bus_info busInfo = {};
CARLA_SAFE_ASSERT_BREAK(v3_cpp_obj(fV3.component)->get_bus_info(fV3.component, V3_AUDIO, V3_OUTPUT, j, &busInfo) == V3_OK);


+ 2
- 86
source/discovery/carla-discovery.cpp View File

@@ -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:


+ 10
- 2
source/frontend/pluginlist/discovery.py View File

@@ -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)):


+ 8
- 4
source/frontend/pluginlist/discoverythread.py View File

@@ -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)


+ 101
- 1
source/utils/CarlaClapUtils.hpp View File

@@ -1,5 +1,5 @@
/*
* Carla LADSPA utils
* Carla CLAP utils
* Copyright (C) 2022 Filipe Coelho <falktx@falktx.com>
*
* 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

+ 8
- 0
source/utils/CarlaVst3Utils.hpp View File

@@ -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

Loading…
Cancel
Save