Skip to content

Commit

Permalink
[CLAP] Add configurable-audio-ports support
Browse files Browse the repository at this point in the history
  • Loading branch information
Guillaume Piolat committed Nov 5, 2024
1 parent f7c6d38 commit 095224f
Show file tree
Hide file tree
Showing 2 changed files with 168 additions and 0 deletions.
114 changes: 114 additions & 0 deletions clap/dplug/clap/client.d
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,15 @@ private:
return &api;
}

if ( streq(s, CLAP_EXT_CONFIGURABLE_AUDIO_PORTS)
|| streq(s, CLAP_EXT_CONFIGURABLE_AUDIO_PORTS_COMPAT) )
{
__gshared clap_plugin_configurable_audio_ports_t api;
api.can_apply_configuration = &plugin_conf_can_apply_config;
api.apply_configuration = &plugin_conf_apply_config;
return &api;
}

// Was disabled by default. Seen crash with almost all CLAP
// hosts: REAPER, Bitwig, clap-info, clap-validator.
// Perhaps our implementation is wrong.
Expand Down Expand Up @@ -1502,6 +1511,89 @@ private:
}
return true;
}

// configurable audio ports

bool conf_can_apply_config(
const(clap_audio_port_configuration_request_t)* requests,
uint request_count)
{
int ioIndex = matchLegalIO(requests, request_count);
if (ioIndex == -1)
return false;

// Yes, we found a legalIO that can do that.
return true;
}

bool conf_apply_config(
const(clap_audio_port_configuration_request_t)* requests,
uint request_count)
{
int ioIndex = matchLegalIO(requests, request_count);
if (ioIndex == -1)
return false;

// Note: legalIOs index are same as config clap_id
return ports_config_select(ioIndex);
}

int matchLegalIO(
const(clap_audio_port_configuration_request_t)* requests,
uint request_count)
{
LegalIO[] legalIOs = _client.legalIOs();
int bestIndex = -1;
int bestScore = -1;

foreach(size_t index, io; legalIOs)
{
int score = 0;

// match each of the requests with &&

for (uint n = 0; n < request_count; ++n)
{
auto r = &requests[n];

// Does that port exist?
Bus* b = getBus(r.is_input, r.port_index);
if (!b)
{
if (r.channel_count != 0)
{
score = -1; // fail, expected some channels
break;
}
else
continue; // bus is matching that zero chan
}

if (r.port_index != 0)
{
score = -1; // fail, no support for multiple ports
break;
}

int chan = r.is_input ? io.numInputChannels : io.numOutputChannels;
if (chan == r.channel_count)
{
// good number of channel
score += 1;
}

// Note: ignoring port_type or port_details here
}

if (score > bestScore)
{
bestIndex = cast(int) index;
bestScore = score;
}
}

return bestIndex; // return choosen legalIO
}
}

extern(C) static
Expand Down Expand Up @@ -1868,6 +1960,28 @@ extern(C) static
mixin(ClientCallback);
return client.note_ports_get(index, is_input, info);
}

// configurable-audio-ports callbacks

bool plugin_conf_can_apply_config(
const(clap_plugin_t)* plugin,
const(clap_audio_port_configuration_request_t)* requests,
uint request_count)
{
mixin(ClientCallback);
return client.conf_can_apply_config(requests,
request_count);
}

bool plugin_conf_apply_config(
const(clap_plugin_t)* plugin,
const(clap_audio_port_configuration_request_t)* requests,
uint request_count)
{
mixin(ClientCallback);
return client.conf_apply_config(requests,
request_count);
}
}


Expand Down
54 changes: 54 additions & 0 deletions clap/dplug/clap/types.d
Original file line number Diff line number Diff line change
Expand Up @@ -2294,4 +2294,58 @@ extern(C) nothrow @nogc:
// Rescan the full list of note ports according to the flags.
// [main-thread]
void function(const(clap_host_t)* host, uint flags) rescan;
}

// configurable-audio-ports.h

// This extension lets the host configure the plugin's input and output audio ports.
// This is a "push" approach to audio ports configuration.

enum string CLAP_EXT_CONFIGURABLE_AUDIO_PORTS = "clap.configurable-audio-ports/1";

// The latest draft is 100% compatible.
// This compat ID may be removed in 2026.
enum string CLAP_EXT_CONFIGURABLE_AUDIO_PORTS_COMPAT = "clap.configurable-audio-ports.draft1";

struct clap_audio_port_configuration_request_t
{
// Identifies the port by is_input and port_index
bool is_input;
uint port_index;

// The requested number of channels.
uint channel_count;

// The port type, see audio-ports.h, clap_audio_port_info.port_type for interpretation.
const(char)*port_type;

// cast port_details according to port_type:
// - CLAP_PORT_MONO: (discard)
// - CLAP_PORT_STEREO: (discard)
// - CLAP_PORT_SURROUND: const uint8_t *channel_map
// - CLAP_PORT_AMBISONIC: const clap_ambisonic_config_t *info
const(void)* port_details;
}

struct clap_plugin_configurable_audio_ports_t
{
extern(C) nothrow @nogc:
// Returns true if the given configurations can be applied using apply_configuration().
// [main-thread && !active]
bool function(const(clap_plugin_t)* plugin,
const(clap_audio_port_configuration_request_t)* requests,
uint request_count) can_apply_configuration;

// Submit a bunch of configuration requests which will atomically be applied together,
// or discarded together.
//
// Once the configuration is successfully applied, it isn't necessary for the plugin to call
// clap_host_audio_ports->changed(); and it isn't necessary for the host to scan the
// audio ports.
//
// Returns true if applied.
// [main-thread && !active]
bool function(const(clap_plugin_t)* plugin,
const(clap_audio_port_configuration_request_t)* requests,
uint request_count) apply_configuration;
}

0 comments on commit 095224f

Please sign in to comment.