VST3+Cubase 14 mono tracks are not working properly
Tested with Windows 10, Cubase 14, CLAP 1.2.2, latest clap-wrapper, and clap-c99-distortion.
When using a VST3 on mono tracks in Cubase 14, the process() function, which is usually called, is instead replaced by calls to flush(), causing the plugin to malfunction.
As long as the track remains mono, process() is never called, and flush() is called instead. However, when switching the track to stereo, process() is called as expected, and everything works normally.
In Cubase 13, process() was called correctly even on mono tracks, but crashed at const float in_r = process->audio_inputs[0].data32[1][i];. (Can't verify now as Cubase 13 trial expired)
Separate question: The current clap-c99-distortion plugin crashes or throws errors when used on mono tracks in Cubase or Studio One. I’m not sure how to prevent these crashes or errors with minimal changes.
For now, I’m using this method, but it’s clear that something is wrong. Based on my research, I focused on the fact that valid pointers seem to fall within the 0xFFFFFFFFF address range:
@@ clap-c99-distortion.c @@
- 389 const float in_r = process->audio_inputs[0].data32[1][i];
+ 389 const float in_r = reinterpret_cast<uintptr_t>(process->audio_inputs[0].data32[1]) <= 0xFFFFFFFFF ? process->audio_inputs[0].data32[1][i] : 0.0f;
- 430 process->audio_outputs[0].data32[1][i] = out_r;
+ 430 reinterpret_cast<uintptr_t>(process->audio_outputs[0].data32[1]) <= 0xFFFFFFFFF ? process->audio_outputs[0].data32[1][i] = out_r;
When I tried to test this newly created code in Cubase 14, I found this bug. So, I haven’t been able to run this code yet, but I feel like there’s something wrong with this approach as well:
@@ clap-c99-distortion.c @@
- 389 const float in_r = process->audio_inputs[0].data32[1][i];
+ 389 const float in_r = process->audio_inputs_count >= 2 ? process->audio_inputs[0].data32[1][i] : 0.0f;
- 430 process->audio_outputs[0].data32[1][i] = out_r;
+ 430 process->audio_inputs_count >= 2 ? process->audio_outputs[0].data32[1][i] = out_r;
I think there’s probably something like process->audio_inputs[0].data32_count somewhere, but I couldn’t find it.
P.S.
I just had a thought and when I looked into it again, I found process->audio_inputs[0].channel_count. This is probably the correct answer, right?:
@@ clap-c99-distortion.c @@
- 389 const float in_r = process->audio_inputs[0].data32[1][i];
+ 389 const float in_r = process->audio_inputs[0].channel_count >= 2 ? process->audio_inputs[0].data32[1][i] : 0.0f;
- 430 process->audio_outputs[0].data32[1][i] = out_r;
+ 430 process->audio_outputs[0].channel_count >= 2 ? process->audio_outputs[0].data32[1][i] = out_r;
So the c99 distortion advertises a stereo audio port only. It shouldn’t be loadable on a mono track.
I wonder if the wrapper is mis representing the bus configuration in this case.
Cubase allows loading and using plugins regardless of whether tracks or plugins are stereo or mono. When using stereo plugins on mono tracks, most plugins seem to handle this by interpreting only the left channel input (with the right channel being silent), processing internally in stereo as usual, and outputting only the left channel.
When loading clap-c99-distortion through clap-wrapper on mono tracks in Cubase 13, it worked normally except for crashes at const float in_r = process->audio_inputs[0].data32[1][i]; and process->audio_outputs[0].data32[1][i] = out_r;. The crashes were caused by pointers referencing invalid addresses, so I used a custom method to detect valid pointers to prevent crashes. This method was quite tricky but worked fine 99% of the time (false detections only occurred when loading Windows-original CLAP in Bitwig on Linux using yabridge).
Since Cubase and Studio One allow switching between stereo and mono tracks with one click, even if users are notified that certain plugins can't be used on mono tracks, accidental clicks could crash the DAW, so I needed to address this issue. However, yesterday I found process->audio_inputs[0].channel_count and process->audio_outputs[0].channel_count, which seem to have been created to handle this problem, so I feel this issue has been resolved.
However, the situation changed completely with Cubase 14's release. It seems the VST3 specifications or program has changed, and when using clap-c99-distortion through clap-wrapper on mono tracks, the plugin's process() is no longer called at all, and instead flush() is called for each buffer size.
I don't understand why this is happening - whether it's a Cubase 14 bug, if it's because I'm not using the code prepared for mono tracks in clap-c99-distortion (perhaps CLAP_PORT_MONO needs to be set somewhere?), if it's a clap-wrapper bug, or if the apparently normal operation in Cubase 13 itself was due to a bug.
Since I'm not very familiar with C, VST3, or CLAP, I might be missing something critical.
it is probably that way because clap requires you to hand you the format you ask for. And I bet the wrapper just downgrades to not calling process on an mis-configured track. Correctly, I think!
I think the idea of "my plugin requires stereo and you just hand it mono and a null anyway" is a DAW bug indeed. But who knows what's buried in the vst3 spec. I suppose we could make the wrapper on a mono track to a stereo in plugin copy the mono to stereo and return stereo out.
@defiantnerd you have cubase. Any thoughts here?
After various experiments, when I set info->channel_count = 1; and info->port_type = CLAP_PORT_MONO; in c99dist_audio_ports_get, it started working with mono tracks in Cubase 14. This suggests that it wasn't a bug in clap-wrapper, but rather that I hadn't properly configured CLAP's mono compatibility settings, and there was a bug in Cubase 13 that made it work in conditions where it shouldn't have.
It seems the problem could be solved by getting information from the host about whether the track is stereo or mono, and then adding conditional branching in c99dist_audio_ports_get based on the track's state, but I don't know how to receive this information from the host. I think the code would look something like this:
static bool c99dist_audio_ports_get(const clap_plugin_t *plugin, uint32_t index, bool is_input,
clap_audio_port_info_t *info)
{
clap_c99_distortion_plug *plug = plugin->plugin_data;
//Branching based on audio port information obtained from another location
if (plug->is_mono) {
if (index > 0)
return false;
info->id = 0;
if (is_input)
snprintf(info->name, sizeof(info->name), "%s", "Mono In");
else
snprintf(info->name, sizeof(info->name), "%s", "Distorted Output");
info->channel_count = 1;
info->flags = CLAP_AUDIO_PORT_IS_MAIN;
info->port_type = CLAP_PORT_MONO;
info->in_place_pair = CLAP_INVALID_ID;
} else {
if (index > 0)
return false;
info->id = 0;
if (is_input)
snprintf(info->name, sizeof(info->name), "%s", "Stereo In");
else
snprintf(info->name, sizeof(info->name), "%s", "Distorted Output");
info->channel_count = 2;
info->flags = CLAP_AUDIO_PORT_IS_MAIN;
info->port_type = CLAP_PORT_STEREO;
info->in_place_pair = CLAP_INVALID_ID;
}
return true;
}
The clap protocol doesn’t work that way. If you only advertise one audio port configuration the host has to give you that.
To do what you share here you would need to implement one of the audio multi config options which would allow you to share different shapes. C99distortion doesn’t do that and really shouldn’t be creatabnle on a mono track with correct hosting.
Is audio-ports-config.h needed to implement audio multi config options?
If so, I believe CLAP-wrapper hasn't implemented this feature yet? (I searched the code for CLAP_EXT_AUDIO_PORTS_CONFIG and clap_plugin_audio_ports_config_t but found no matches)
Does this mean the current clap-wrapper cannot simultaneously support both stereo and mono configurations?
I understand this kind of code is probably needed but I'm not sure what's missing...:
uint32_t c99dist_audio_ports_config_count(const clap_plugin_t *plugin) { return 2; }
bool c99dist_audio_ports_config_get(const clap_plugin_t *plugin,
uint32_t index,
clap_audio_ports_config_t *config)
{
switch (index)
{
case 0:
config->id = 0;
snprintf(config->name, sizeof(config->name), "%s", "Stereo");
config->input_port_count = 2;
config->output_port_count = 2;
config->has_main_input = true;
config->main_input_channel_count = 2;
config->main_input_port_type = CLAP_PORT_STEREO;
config->has_main_output = true;
config->main_output_channel_count = 2;
config->main_output_port_type = CLAP_PORT_STEREO;
return true;
case 1:
config->id = 1;
snprintf(config->name, sizeof(config->name), "%s", "Mono");
config->input_port_count = 1;
config->output_port_count = 1;
config->has_main_input = true;
config->main_input_channel_count = 1;
config->main_input_port_type = CLAP_PORT_MONO;
config->has_main_output = true;
config->main_output_channel_count = 1;
config->main_output_port_type = CLAP_PORT_MONO;
return true;
default:
return false;
}
}
bool c99dist_audio_ports_config_select(const clap_plugin_t *plugin, clap_id config_id)
{
switch (config_id)
{
case 0:
return true;
case 1:
return true;
default:
return false;
}
}
const clap_plugin_audio_ports_config_t s_c99dist_audio_ports_config = {
.count = c99dist_audio_ports_config_count,
.get = c99dist_audio_ports_config_get,
.select = c99dist_audio_ports_config_select
};
I know @defiantnerd has done a bunch of work on this. There's audio-ports-config and configurable-audio ports and I am not sure which one is the one.
But yes, something like that would be required.
Timo?
Also: Happy new year!
I see. Happy New Year to you too!
I don't have cubase but I think with wrapper 0.12.0 this issue should be resolved, inasmuch as the stereo effect is correctly stereo only in the vst3 spec.
I'll leave this as potentially resolved