Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VST3+Cubase 14 mono tracks are not working properly #326

Open
lewloiwc opened this issue Dec 27, 2024 · 8 comments
Open

VST3+Cubase 14 mono tracks are not working properly #326

lewloiwc opened this issue Dec 27, 2024 · 8 comments

Comments

@lewloiwc
Copy link

lewloiwc commented Dec 27, 2024

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;
@baconpaul
Copy link
Collaborator

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.

@lewloiwc
Copy link
Author

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.

@baconpaul
Copy link
Collaborator

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?

@lewloiwc
Copy link
Author

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;
}

@baconpaul
Copy link
Collaborator

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.

@lewloiwc
Copy link
Author

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
};

@baconpaul
Copy link
Collaborator

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!

@lewloiwc
Copy link
Author

I see. Happy New Year to you too!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants