Browse Source

Implement CLAP multi-IO

Signed-off-by: falkTX <falktx@falktx.com>
pull/409/head
falkTX 3 years ago
parent
commit
8e15fcf1c1
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
1 changed files with 312 additions and 62 deletions
  1. +312
    -62
      distrho/src/DistrhoPluginCLAP.cpp

+ 312
- 62
distrho/src/DistrhoPluginCLAP.cpp View File

@@ -36,6 +36,7 @@
#endif

#include <map>
#include <vector>

#include "clap/entry.h"
#include "clap/plugin-factory.h"
@@ -739,19 +740,24 @@ public:
updateStateValueCallback),
fHost(host),
fOutputEvents(nullptr),
#if DISTRHO_PLUGIN_WANT_LATENCY
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0
fUsingCV(false),
#endif
#if DISTRHO_PLUGIN_WANT_LATENCY
fLatencyChanged(false),
fLastKnownLatency(0),
#endif
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
#endif
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
fMidiEventCount(0),
#endif
#endif
fHostExtensions(host)
{
fCachedParameters.setup(fPlugin.getParameterCount());

#if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_MIDI_INPUT
fNotesRingBuffer.setRingBuffer(&fNotesBuffer, true);
#endif

#if DISTRHO_PLUGIN_WANT_STATE
for (uint32_t i=0, count=fPlugin.getStateCount(); i<count; ++i)
{
@@ -759,6 +765,16 @@ public:
fStateMap[dkey] = fPlugin.getStateDefaultValue(i);
}
#endif

#if DISTRHO_PLUGIN_NUM_INPUTS != 0
fillInBusInfoDetails<true>();
#endif
#if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
fillInBusInfoDetails<false>();
#endif
#if DISTRHO_PLUGIN_NUM_INPUTS != 0 && DISTRHO_PLUGIN_NUM_OUTPUTS != 0
fillInBusInfoPairs();
#endif
}

// ----------------------------------------------------------------------------------------------------------------
@@ -992,25 +1008,66 @@ public:

if (const uint32_t frames = process->frames_count)
{
// TODO multi-port bus stuff
DISTRHO_SAFE_ASSERT_UINT_RETURN(process->audio_inputs_count == 0 || process->audio_inputs_count == 1,
process->audio_inputs_count, false);
DISTRHO_SAFE_ASSERT_UINT_RETURN(process->audio_outputs_count == 0 || process->audio_outputs_count == 1,
process->audio_outputs_count, false);

const float** inputs = process->audio_inputs != nullptr
? const_cast<const float**>(process->audio_inputs[0].data32)
: nullptr;
/**/ float** outputs = process->audio_outputs != nullptr
? process->audio_outputs[0].data32
: nullptr;
#if DISTRHO_PLUGIN_NUM_INPUTS != 0
const float** const audioInputs = fAudioInputs;

uint32_t in=0;
for (uint32_t i=0; i<process->audio_inputs_count; ++i)
{
const clap_audio_buffer_t& inputs(process->audio_inputs[i]);
DISTRHO_SAFE_ASSERT_CONTINUE(inputs.channel_count != 0);

for (uint32_t j=0; j<inputs.channel_count; ++j, ++in)
audioInputs[in] = const_cast<const float*>(inputs.data32[j]);
}

if (fUsingCV)
{
for (; in<DISTRHO_PLUGIN_NUM_INPUTS; ++in)
audioInputs[in] = nullptr;
}
else
{
DISTRHO_SAFE_ASSERT_UINT2_RETURN(in == DISTRHO_PLUGIN_NUM_INPUTS,
in, process->audio_inputs_count, false);
}
#else
constexpr const float* const audioInputs = nullptr;
#endif

#if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
float** const audioOutputs = fAudioOutputs;

uint32_t out=0;
for (uint32_t i=0; i<process->audio_outputs_count; ++i)
{
const clap_audio_buffer_t& outputs(process->audio_outputs[i]);
DISTRHO_SAFE_ASSERT_CONTINUE(outputs.channel_count != 0);

for (uint32_t j=0; j<outputs.channel_count; ++j, ++out)
audioOutputs[out] = outputs.data32[j];
}

if (fUsingCV)
{
for (; out<DISTRHO_PLUGIN_NUM_OUTPUTS; ++out)
audioOutputs[out] = nullptr;
}
else
{
DISTRHO_SAFE_ASSERT_UINT2_RETURN(out == DISTRHO_PLUGIN_NUM_OUTPUTS,
out, DISTRHO_PLUGIN_NUM_OUTPUTS, false);
}
#else
constexpr float* audioOutputs = nullptr;
#endif

fOutputEvents = process->out_events;

#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
fPlugin.run(inputs, outputs, frames, fMidiEvents, fMidiEventCount);
fPlugin.run(audioInputs, audioOutputs, frames, fMidiEvents, fMidiEventCount);
#else
fPlugin.run(inputs, outputs, frames);
fPlugin.run(audioInputs, audioOutputs, frames);
#endif

// TODO set last frame
@@ -1243,6 +1300,48 @@ public:
fPlugin.setParameterValue(event->param_id, event->value);
}

// ----------------------------------------------------------------------------------------------------------------
// audio ports

#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0
template<bool isInput>
uint32_t getAudioPortCount() const noexcept
{
return (isInput ? fAudioInputBuses : fAudioOutputBuses).size();
}

template<bool isInput>
bool getAudioPortInfo(const uint32_t index, clap_audio_port_info_t* const info) const noexcept
{
const std::vector<BusInfo>& busInfos(isInput ? fAudioInputBuses : fAudioOutputBuses);
DISTRHO_SAFE_ASSERT_RETURN(index < busInfos.size(), false);

const BusInfo& busInfo(busInfos[index]);

info->id = busInfo.groupId;
DISTRHO_NAMESPACE::strncpy(info->name, busInfo.name, CLAP_NAME_SIZE);

info->flags = busInfo.isMain ? CLAP_AUDIO_PORT_IS_MAIN : 0x0;
info->channel_count = busInfo.numChannels;

switch (busInfo.groupId)
{
case kPortGroupMono:
info->port_type = CLAP_PORT_MONO;
break;
case kPortGroupStereo:
info->port_type = CLAP_PORT_STEREO;
break;
default:
info->port_type = nullptr;
break;
}

info->in_place_pair = busInfo.hasPair ? busInfo.groupId : CLAP_INVALID_ID;
return true;
}
#endif

// ----------------------------------------------------------------------------------------------------------------
// latency

@@ -1673,6 +1772,15 @@ private:
const clap_host_t* const fHost;
const clap_output_events_t* fOutputEvents;

#if DISTRHO_PLUGIN_NUM_INPUTS != 0
const float* fAudioInputs[DISTRHO_PLUGIN_NUM_INPUTS];
#endif
#if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
float* fAudioOutputs[DISTRHO_PLUGIN_NUM_OUTPUTS];
#endif
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0
bool fUsingCV;
#endif
#if DISTRHO_PLUGIN_WANT_LATENCY
bool fLatencyChanged;
uint32_t fLastKnownLatency;
@@ -1718,6 +1826,170 @@ private:
}
} fHostExtensions;

// ----------------------------------------------------------------------------------------------------------------
// helper functions for dealing with buses

#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0
struct BusInfo {
char name[CLAP_NAME_SIZE];
uint32_t numChannels;
bool hasPair;
bool isCV;
bool isMain;
uint32_t groupId;
};
std::vector<BusInfo> fAudioInputBuses, fAudioOutputBuses;

template<bool isInput>
void fillInBusInfoDetails()
{
constexpr const uint32_t numPorts = isInput ? DISTRHO_PLUGIN_NUM_INPUTS : DISTRHO_PLUGIN_NUM_OUTPUTS;
std::vector<BusInfo>& busInfos(isInput ? fAudioInputBuses : fAudioOutputBuses);

enum {
kPortTypeNull,
kPortTypeAudio,
kPortTypeSidechain,
kPortTypeCV,
kPortTypeGroup
} lastSeenPortType = kPortTypeNull;
uint32_t lastSeenGroupId = kPortGroupNone;
uint32_t nonGroupAudioId = 0;
uint32_t nonGroupSidechainId = 0x20000000;

for (uint32_t i=0; i<numPorts; ++i)
{
const AudioPortWithBusId& port(fPlugin.getAudioPort(isInput, i));

if (port.groupId != kPortGroupNone)
{
if (lastSeenPortType != kPortTypeGroup || lastSeenGroupId != port.groupId)
{
lastSeenPortType = kPortTypeGroup;
lastSeenGroupId = port.groupId;

BusInfo busInfo = {
{}, 1, false, false,
// if this is the first port, set it as main
busInfos.empty(),
// user given group id with extra safety offset
port.groupId + 0x80000000
};

const PortGroupWithId& group(fPlugin.getPortGroupById(port.groupId));

switch (port.groupId)
{
case kPortGroupStereo:
case kPortGroupMono:
if (busInfo.isMain)
{
DISTRHO_NAMESPACE::strncpy(busInfo.name,
isInput ? "Audio Input" : "Audio Output", CLAP_NAME_SIZE);
break;
}
// fall-through
default:
if (group.name.isNotEmpty())
DISTRHO_NAMESPACE::strncpy(busInfo.name, group.name, CLAP_NAME_SIZE);
else
DISTRHO_NAMESPACE::strncpy(busInfo.name, port.name, CLAP_NAME_SIZE);
break;
}

busInfos.push_back(busInfo);
}
else
{
++busInfos.back().numChannels;
}
}
else if (port.hints & kAudioPortIsCV)
{
// TODO
lastSeenPortType = kPortTypeCV;
lastSeenGroupId = kPortGroupNone;
fUsingCV = true;
}
else if (port.hints & kAudioPortIsSidechain)
{
if (lastSeenPortType != kPortTypeSidechain)
{
lastSeenPortType = kPortTypeSidechain;
lastSeenGroupId = kPortGroupNone;

BusInfo busInfo = {
{}, 1, false, false,
// not main
false,
// give unique id
nonGroupSidechainId++
};

DISTRHO_NAMESPACE::strncpy(busInfo.name, port.name, CLAP_NAME_SIZE);

busInfos.push_back(busInfo);
}
else
{
++busInfos.back().numChannels;
}
}
else
{
if (lastSeenPortType != kPortTypeAudio)
{
lastSeenPortType = kPortTypeAudio;
lastSeenGroupId = kPortGroupNone;

BusInfo busInfo = {
{}, 1, false, false,
// if this is the first port, set it as main
busInfos.empty(),
// give unique id
nonGroupAudioId++
};

if (busInfo.isMain)
{
DISTRHO_NAMESPACE::strncpy(busInfo.name,
isInput ? "Audio Input" : "Audio Output", CLAP_NAME_SIZE);
}
else
{
DISTRHO_NAMESPACE::strncpy(busInfo.name, port.name, CLAP_NAME_SIZE);
}

busInfos.push_back(busInfo);
}
else
{
++busInfos.back().numChannels;
}
}
}
}
#endif

#if DISTRHO_PLUGIN_NUM_INPUTS != 0 && DISTRHO_PLUGIN_NUM_OUTPUTS != 0
void fillInBusInfoPairs()
{
const size_t numChannels = std::min(fAudioInputBuses.size(), fAudioOutputBuses.size());

for (size_t i=0; i<numChannels; ++i)
{
if (fAudioInputBuses[i].groupId != fAudioOutputBuses[i].groupId)
break;
if (fAudioInputBuses[i].numChannels != fAudioOutputBuses[i].numChannels)
break;
if (fAudioInputBuses[i].isMain != fAudioOutputBuses[i].isMain)
break;

fAudioInputBuses[i].hasPair = fAudioOutputBuses[i].hasPair = true;
}
}
#endif

// ----------------------------------------------------------------------------------------------------------------
// DPF callbacks

@@ -1962,61 +2234,41 @@ static const clap_plugin_timer_support_t clap_timer = {
// --------------------------------------------------------------------------------------------------------------------
// plugin audio ports

static uint32_t clap_plugin_audio_ports_count(const clap_plugin_t*, const bool is_input)
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0
static uint32_t clap_plugin_audio_ports_count(const clap_plugin_t* const plugin, const bool is_input)
{
return (is_input ? DISTRHO_PLUGIN_NUM_INPUTS : DISTRHO_PLUGIN_NUM_OUTPUTS) != 0 ? 1 : 0;
PluginCLAP* const instance = static_cast<PluginCLAP*>(plugin->plugin_data);
return is_input ? instance->getAudioPortCount<true>()
: instance->getAudioPortCount<false>();
}

static bool clap_plugin_audio_ports_get(const clap_plugin_t* /* const plugin */,
static bool clap_plugin_audio_ports_get(const clap_plugin_t* const plugin,
const uint32_t index,
const bool is_input,
clap_audio_port_info_t* const info)
{
const uint32_t maxPortCount = is_input ? DISTRHO_PLUGIN_NUM_INPUTS : DISTRHO_PLUGIN_NUM_OUTPUTS;
DISTRHO_SAFE_ASSERT_UINT2_RETURN(index < maxPortCount, index, maxPortCount, false);

#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
// PluginCLAP* const instance = static_cast<PluginCLAP*>(plugin->plugin_data);

// TODO use groups
AudioPortWithBusId& audioPort(sPlugin->getAudioPort(is_input, index));

info->id = index;
DISTRHO_NAMESPACE::strncpy(info->name, audioPort.name, CLAP_NAME_SIZE);

// TODO bus stuff
info->flags = CLAP_AUDIO_PORT_IS_MAIN;
info->channel_count = maxPortCount;

// TODO CV
// info->port_type = audioPort.hints & kAudioPortIsCV ? CLAP_PORT_CV : nullptr;
// TODO port groups
info->port_type = maxPortCount == 2 ? CLAP_PORT_STEREO : maxPortCount == 1 ? CLAP_PORT_MONO : nullptr;

info->in_place_pair = DISTRHO_PLUGIN_NUM_INPUTS == DISTRHO_PLUGIN_NUM_OUTPUTS ? index : CLAP_INVALID_ID;

return true;
#else
return false;
// unused
(void)info;
#endif
PluginCLAP* const instance = static_cast<PluginCLAP*>(plugin->plugin_data);
return is_input ? instance->getAudioPortInfo<true>(index, info)
: instance->getAudioPortInfo<false>(index, info);
}

static const clap_plugin_audio_ports_t clap_plugin_audio_ports = {
clap_plugin_audio_ports_count,
clap_plugin_audio_ports_get
};
#endif

// --------------------------------------------------------------------------------------------------------------------
// plugin audio ports
// plugin note ports

#if DISTRHO_PLUGIN_WANT_MIDI_INPUT+DISTRHO_PLUGIN_WANT_MIDI_OUTPUT != 0
static uint32_t clap_plugin_note_ports_count(const clap_plugin_t*, const bool is_input)
{
return (is_input ? DISTRHO_PLUGIN_WANT_MIDI_INPUT : DISTRHO_PLUGIN_WANT_MIDI_OUTPUT) != 0 ? 1 : 0;
}

static bool clap_plugin_note_ports_get(const clap_plugin_t*, uint32_t, const bool is_input, clap_note_port_info_t* const info)
static bool clap_plugin_note_ports_get(const clap_plugin_t*, uint32_t,
const bool is_input, clap_note_port_info_t* const info)
{
if (is_input)
{
@@ -2026,8 +2278,6 @@ static bool clap_plugin_note_ports_get(const clap_plugin_t*, uint32_t, const boo
info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI;
std::strcpy(info->name, "Event/MIDI Input");
return true;
#else
return false;
#endif
}
else
@@ -2038,21 +2288,17 @@ static bool clap_plugin_note_ports_get(const clap_plugin_t*, uint32_t, const boo
info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI;
std::strcpy(info->name, "Event/MIDI Output");
return true;
#else
return false;
#endif
}

#if DISTRHO_PLUGIN_WANT_MIDI_INPUT+DISTRHO_PLUGIN_WANT_MIDI_OUTPUT == 0
// unused
(void)info;
#endif
return false;
}

static const clap_plugin_note_ports_t clap_plugin_note_ports = {
clap_plugin_note_ports_count,
clap_plugin_note_ports_get
};
#endif

// --------------------------------------------------------------------------------------------------------------------
// plugin parameters
@@ -2197,12 +2443,16 @@ static CLAP_ABI clap_process_status clap_plugin_process(const clap_plugin_t* con

static CLAP_ABI const void* clap_plugin_get_extension(const clap_plugin_t*, const char* const id)
{
if (std::strcmp(id, CLAP_EXT_PARAMS) == 0)
return &clap_plugin_params;
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0
if (std::strcmp(id, CLAP_EXT_AUDIO_PORTS) == 0)
return &clap_plugin_audio_ports;
#endif
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT+DISTRHO_PLUGIN_WANT_MIDI_OUTPUT != 0
if (std::strcmp(id, CLAP_EXT_NOTE_PORTS) == 0)
return &clap_plugin_note_ports;
if (std::strcmp(id, CLAP_EXT_PARAMS) == 0)
return &clap_plugin_params;
#endif
#if DISTRHO_PLUGIN_WANT_LATENCY
if (std::strcmp(id, CLAP_EXT_LATENCY) == 0)
return &clap_plugin_latency;


Loading…
Cancel
Save