gogins / csound-vst3-opcodes

The "vst3" opcodes enable Csound to host VST3 plugin instruments and effects.
GNU General Public License v3.0
5 stars 2 forks source link

.vstpreset files are not loaded but there is no error #17

Closed gogins closed 8 months ago

gogins commented 8 months ago

I confused Steinberg::kResultTrue (which is numerically 0) with bool true (which is numerically != 0).

Sheerly by chance, the plugins I was testing implemented both 32 bit and 64 bit sample handling, so the audio was handled correctly in spite of this major error.

For Cardinal, only 32 bits samples are supported, so my code fails. Actually 32 bits works for mda plugins, so the problem probably is preset no loading.

gogins commented 8 months ago

The 'Cardinal' variant now does not crash, but it still make no sound. First this error in the VS Code terminal:

assertion failure: "read > 0" in file /Users/runner/work/Cardinal/Cardinal/dpf/distrho/src/DistrhoPluginVST3.cpp, line 960, value 0

then this level of audio (silence) in the piece:

MasterOutput             i   22.0000 t    0.0000 d   -1.0000 k    0.0000 v    0.0000 p    0.0000 #  1 l-316.8258 r-310.8686
MasterOutput             i   22.0000 t    0.0000 d   -1.0000 k    0.0000 v    0.0000 p    0.0000 #  1 l-310.0550 r-313.5918
MasterOutput             i   22.0000 t    0.0000 d   -1.0000 k    0.0000 v    0.0000 p    0.0000 #  1 l-318.7837 r-310.8603

What is clear is that the Cardinal plugin expects to output MIDI and may expect to receive audio, also that the 'Cardinal` variant has 8 channels of audio. I need to review my code for handling disparate channel counts.

The 'FX' and 'Synth' variants both crash. It doesn't seem to matter which variant saved the patch.

gogins commented 8 months ago

https://www.redwoodaudio.net/Tutorials/juce_for_vst_development__intro.html

I have a question whether JUCE uses the VST3 SDK, or whether it rolls its own port a la travesty. JUCE documentation states all files required to develop VST3 plugins are included in JUCE. I will see what that means.

OK, I installed JUCE on my MacBook and find that the Projucer creates a project that in fact does seem to need the VST3 SDK code.

In general, JUCE seems to have a done a great deal of work to encapsulate the gory details of the VST3 SDK, evincing some scorn and irony towards the Steinberg developers along the way. It's not yet clear whether I can use the JUCE code as a reference for my code.

I note with approval that the JUCE developers explicitly qualify all namespaces, no using namespace <x> bullshit.

gogins commented 8 months ago

Probably relevant:

    template <typename Callback>
    static void hostToPluginEventList (Steinberg::Vst::IEventList& result,
                                       MidiBuffer& midiBuffer,
                                       StoredMidiMapping& mapping,
                                       Callback&& callback)
    {
        toEventList (result, midiBuffer, &mapping, callback);
    }

    static void pluginToHostEventList (Steinberg::Vst::IEventList& result, MidiBuffer& midiBuffer)
    {
        toEventList (result, midiBuffer, nullptr, [] (auto&&...) {});
    }
gogins commented 8 months ago

Just to be clear here, my question is how to properly set up and manage all of the HostData objects during processing, not only the inputs and the audio outputs which are working, but also the event and parameter outputs.

JUCE clears both input and output parameter changes before calling process.

gogins commented 8 months ago

OK, I fixed a lot of my own bugs and the code now looks correct, and my earlier pieces still run without error, but the DISTRHO assertion continues.

I now believe that my code for reading the preset file is still not correct. The DISTRHO code anticipates first parameters, then other data. I'm not sure that's what's in the .vcv files.

gogins commented 8 months ago

The .vcv files that I saved do not seem to contain the tokens that the DISTRHO setState function is looking for.

gogins commented 8 months ago

Maybe vst3presetload should use the component ID, not the module ID:

2046504473616C636E64436400000000

vst3init::init: created plugin: "Cardinal": address: 0x153888c18 handle: 0
vst3info::init: printing plugin information...
vst3_plugin_t: class:      module classinfo id: 2046504473616C636E64436400000000
               class:      component class id:  E831FF31F2D54301928EBBEE25697802
               class:      controller class id: 204650446C7274636E64436400000000
               class:      cardinality:         2147483647

It should I think use the component (processor) ID.

gogins commented 8 months ago

There's probably something funky going on with the user area for presets, perhaps some files are containing others. Not so.

gogins commented 8 months ago

Big clue: the .vcv files that I saved from hosts are binary, the .vcv files that Cardinal installed are just .json. But, in Reaper, Cardinal can load both the binary .vcv and the JSON .vcv. There's no facility to write a JSON .vcv from Reaper.

Anyway, it seems clear that the Cardinal plugin can tell binary .vcvs from JSON .vcvs and load them appropriately. The only way I can think to solve this is to read the Cardinal code from the bottom up.

Well that didn't help, so far the code is opaque to me.

gogins commented 8 months ago

Another bug treating tresult kResultOk as bool true... but sill the assertion.

I'm going to test loading a preset for another plugin.

gogins commented 8 months ago

I think I have fixed the logic bugs in loading presets. Cardinal still makes no sound.

No help yet....

gogins commented 8 months ago

I'm now testing with Surge XT presets. I can most definitely create, save, and load .vstpreset files for Surge XT in the VST3PluginTestHost program.

Also in my SurgeXT.csd test file, Surge XT most definitely makes a sound, but I cannot use vst3presetload to change the sound, even though there are no errors or assertions. So the test host must be doing something that I am not doing to load the presets. Maybe I need to turn off processing before I load the preset. No help.

gogins commented 8 months ago

Maybe my problem is using PresetFile when all I really need to do is load the processor state from the IBStream. After all I am only saving one preset for one component per file, but I think maybe PresetFile expects one chunk for the processor and one chunk for the controller. Reports failure, does not load.

gogins commented 8 months ago

Maybe the stub Controller is fouling things up.

gogins commented 8 months ago

Aaah... file:///Users/michaelgogins/csound-vst3-opcodes/vst3sdk/doc/index.html.

gogins commented 8 months ago

PresetFile seeks to 0 in the stream (misnomer!), verifies 'VST3', reads version and offset, and then immediately reads in the class ID.

00000000: 5653 5433 0100 0000 4142 4344 4546 3031  VST3....ABCDEF01
00000010: 3931 3832 4641 4542 3536 3644 3632 3431  9182FAEB566D6241
00000020: 3533 3637 3538 3534 7ad1 0000 0000 0000  53675854z.......

This is the module ID:

vst3info::init: printing plugin information...
vst3_plugin_t: class:      module classinfo id: ABCDEF019182FAEB566D624153675854
               class:      component class id:  E831FF31F2D54301928EBBEE25697802
               class:      processor class id:  42043F99B7DA453CA569E79D9AAEC33D
               class:      controller class id: DCD7BBE37742448DA874AACC979C759E
               class:      cardinality:         2147483647
               class:      category:            Audio Module Class
               class:      name:                Surge XT
               class:      vendor:              Surge Synth Team
               class:      version:             1.3.0
               class:      sdkVersion:          VST 3.7.2
               class:      subCategoriesString: Instrument|Synth
               class:      classFlags:          2

and

vst3presetload: preset_filepath: Surge-2.vstpreset
vst3presetload: stream_size: 56306
vst3presetload: module class ID:     ABCDEF019182FAEB566D624153675854
vst3presetload: component class ID:  E831FF31F2D54301928EBBEE25697802
vst3presetload: processor class ID:  42043F99B7DA453CA569E79D9AAEC33D
vst3presetload: controller class ID: DCD7BBE37742448DA874AACC979C759E
vst3presetload: failed to load from preset file: Surge-2.vstpreset
vst3presetload: failed to set loaded state: Surge-2.vstpreset
gogins commented 8 months ago

Trying them all:

gogins commented 8 months ago

I am now pretty sure the problem is not the preset loading, but the processing. All the 64 bit plugins seem to work but not the 32 bit only ones.

Not so. The 32 bit mda plugins render just fine.

gogins commented 8 months ago

Note that the ProcessData->numSamples which indicates how many samples are used in a process call can change from call to call, but never bigger than the maxSamplesPerBlock.

The vst2 opcodes handled changes in numSamples, but these vst3 opcodes do not. I don't see such changes, but I should handle them anyway.

gogins commented 8 months ago
gogins commented 8 months ago

Maybe it's the bus layout...

vst3info::init: printing plugin information... 
vst3_plugin_t: class:      module classinfo id: ABCDEF019182FAEB566D624153675854
               class:      component class id:  E831FF31F2D54301928EBBEE25697802
               class:      processor class id:  42043F99B7DA453CA569E79D9AAEC33D
               class:      controller class id: DCD7BBE37742448DA874AACC979C759E (S1)
               class:      cardinality:         2147483647
               class:      category:            Audio Module Class
               class:      name:                Surge XT
               class:      vendor:              Surge Synth Team
               class:      version:             1.3.0
               class:      sdkVersion:          VST 3.7.2
               class:      subCategoriesString: Instrument|Synth
               class:      classFlags:          2
               can process 32 bit samples: yes (S2.3)
               can process 64 bit samples: no (S2.3)
               Csound samples: 64 bits
               Buss[  0]:  direction: Input   media: Audio  channels:   2  bus type: Aux   flags: 1  name: Sidechain                        (S3 S4)
               Buss[  0]:  direction: Input   media: Event  channels:  16  bus type: Main  flags: 1  name: MIDI Input                       (S3 S4)
               Buss[  0]:  direction: Output  media: Audio  channels:   2  bus type: Main  flags: 1  name: Output                           (S3 S4)
               Buss[  1]:  direction: Output  media: Audio  channels:   2  bus type: Main  flags: 0  name: Scene A                          (S3 S4)
               Buss[  2]:  direction: Output  media: Audio  channels:   2  bus type: Main  flags: 0  name: Scene B                          (S3 S4)
               parameter count:      0

versus:

            opcode_input_channel_count = input_arg_count();
            auto &process_data = vst3_plugin->hostProcessData;
            if (process_data.numInputs > 0) {
                plugin_input_channel_count = process_data.inputs[0].numChannels;
                plugin_input_channels_32 = process_data.inputs[0].channelBuffers32;
                plugin_input_channels_64 = process_data.inputs[0].channelBuffers64;
                log(csound, "vst3audio::init: plugin_input_channel_count:  %3d plugin_input_channels_32:  %p plugin_input_channels_64:  %p\n", plugin_input_channel_count, plugin_input_channels_32, plugin_input_channels_64);
            } else {
                plugin_input_channel_count = 0;
            }
            input_channel_count = std::min(opcode_input_channel_count, plugin_input_channel_count);
            opcode_output_channel_count = output_arg_count();
            if (process_data.numOutputs > 0) {
                plugin_output_channel_count = process_data.outputs[0].numChannels;
                plugin_output_channels_32 = process_data.outputs[0].channelBuffers32;
                plugin_output_channels_64 = process_data.outputs[0].channelBuffers64;
                log(csound, "vst3audio::init: plugin_output_channel_count: %3d plugin_output_channels_32: %p plugin_output_channels_64: %p\n", plugin_output_channel_count, plugin_output_channels_32, plugin_output_channels_64);
            } else {
                plugin_output_channel_count = 0;
            }

No help, I don't think so. I don't think I would get any sound if that were the case, I just get a crummy sound that I can't change.

gogins commented 8 months ago

Possibly I can find a way to save my new patches and then load them with vst3setprogram. But the code is not listing the programs.

I am reviewing the interfaces to IComponent etc. to see if I'm missing something about loading presets. Yes, another mistaken treatment of bool as tresult.

The VST3 SDK PresetFile uses fopen to directly access the file system. I should copy that.

gogins commented 8 months ago

The PresetFile is not reading correctly, it expects a class ID that is not there. I am trying again with the module ID.

The module ID appears to work, and this directly contradicts the official VST3 SDK documentation, which specifies the Component (i.e. Processor) ID.

gogins commented 8 months ago

Is there a difference in layout between the included presets and the saved user presets?

gogins commented 8 months ago

Proof that it's the module ID:

Saved from Reaper: 
                                                5653544D44416A6D6461206A78313000
Info:
vst3_plugin_t: class:      module classinfo id: 5653544D44416A6D6461206A78313000
               class:      component class id:  E831FF31F2D54301928EBBEE25697802
               class:      processor class id:  42043F99B7DA453CA569E79D9AAEC33D
               class:      controller class id: DCD7BBE37742448DA874AACC979C759E (S1)

I tried to load and play this rather odd preset in Reaper. I could in fact do that, but I couldn't then change to a factory preset...

gogins commented 8 months ago

Maybe they don't load correctly if they are not in the standard location?

gogins commented 8 months ago

Now the jx10 presets load without error and take effect, when loaded by vst3init. When loaded by vst3presetload, the presets load without error, but do not take effect.

I can live with this, as far as composing is concerned, if this will work with Surge XT and Cardinal.

gogins commented 8 months ago

I suspect the preset takes effect only if the audio processor is off. Maybe the whole thing has to be restarted somehow but the examples I could find did not show me how to do that.

gogins commented 8 months ago

I have added saving the .csd for testing with standalone Csound for orchestras that crash Csound when running.

gogins commented 8 months ago

It's from changing the signature of vst3init, I need to preserve the existing signature and add an optional preset filename argument, or create another opcode.

gogins commented 8 months ago

I have added vst3initpreset and it works.