M5.4: VST3 host conformance (Reaper-style) for FX GUI attach
- queryInterface now answers FUnknown::iid + own iid (IComponentHandler / IPlugFrame) with addRef+this per SDK QUERY_INTERFACE contract; plugins that QI the host handler no longer get kNoInterface unconditionally. - setBusArrangements negotiation before activateBus: offer mono/stereo for <=2ch audio buses, keep wider arrangements; result logged, not fatal. Matches REAPER load path so Ozone-class editors see a valid arrangement on first attach. Local float regression: Ozone 11 editor opens OK.
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
#include "public.sdk/source/vst/vstpresetfile.h"
|
||||
#include "public.sdk/source/common/memorystream.h"
|
||||
#include "pluginterfaces/vst/ivstaudioprocessor.h"
|
||||
#include "pluginterfaces/vst/vstspeaker.h"
|
||||
#include "pluginterfaces/vst/ivstcomponent.h"
|
||||
#include "pluginterfaces/vst/ivsteditcontroller.h"
|
||||
#include "pluginterfaces/vst/ivstprocesscontext.h"
|
||||
@@ -355,7 +356,18 @@ using Steinberg::Vst::kSample32;
|
||||
|
||||
class HostComponentHandlerFx : public IComponentHandler {
|
||||
public:
|
||||
tresult queryInterface(const char*, void** v) override { *v = nullptr; return kNoInterface; }
|
||||
tresult queryInterface(const char* iid, void** v) override {
|
||||
// FUnknown contract: answer for our own iid (+FUnknown::iid) with
|
||||
// addRef + this; kNoInterface otherwise (SDK QUERY_INTERFACE pattern).
|
||||
if (Steinberg::FUnknownPrivate::iidEqual(iid, Steinberg::FUnknown::iid) ||
|
||||
Steinberg::FUnknownPrivate::iidEqual(iid, IComponentHandler::iid)) {
|
||||
addRef();
|
||||
*v = this;
|
||||
return kResultOk;
|
||||
}
|
||||
*v = nullptr;
|
||||
return kNoInterface;
|
||||
}
|
||||
Steinberg::uint32 addRef() override { return 1; }
|
||||
Steinberg::uint32 release() override { return 1; }
|
||||
tresult beginEdit(Steinberg::Vst::ParamID) override { return kResultOk; }
|
||||
@@ -377,7 +389,15 @@ using Steinberg::kPlatformTypeHWND;
|
||||
// Minimal IPlugFrame so the plugin can resize its editor view.
|
||||
class HostPlugFrameFx : public Steinberg::IPlugFrame {
|
||||
public:
|
||||
tresult queryInterface(const char*, void** v) override {
|
||||
tresult queryInterface(const char* iid, void** v) override {
|
||||
// FUnknown contract: answer for our own iid (+FUnknown::iid) with
|
||||
// addRef + this; kNoInterface otherwise (SDK QUERY_INTERFACE pattern).
|
||||
if (Steinberg::FUnknownPrivate::iidEqual(iid, Steinberg::FUnknown::iid) ||
|
||||
Steinberg::FUnknownPrivate::iidEqual(iid, Steinberg::IPlugFrame::iid)) {
|
||||
addRef();
|
||||
*v = this;
|
||||
return kResultOk;
|
||||
}
|
||||
*v = nullptr;
|
||||
return kNoInterface;
|
||||
}
|
||||
@@ -515,8 +535,38 @@ bool vst3FxLoadInner(Vst3FxState* s, const std::string& path, double sampleRate,
|
||||
std::cerr << "[RenderFx] STEP connection points OK" << std::endl;
|
||||
|
||||
int32 numAudioInputs = component->getBusCount(kAudio, kInput);
|
||||
for (int32 i = 0; i < numAudioInputs; ++i) component->activateBus(kAudio, kInput, i, true);
|
||||
int32 numAudioOutputs = component->getBusCount(kAudio, kOutput);
|
||||
// Reaper-style negotiation BEFORE activation: offer mono/stereo for the
|
||||
// <=2ch audio busses so plugins (Ozone 11 family) never see an empty or
|
||||
// unset arrangement on their first GUI attach. Wider busses keep their
|
||||
// current arrangement. Failure to negotiate is not fatal (log only).
|
||||
{
|
||||
FUnknownPtr<IAudioProcessor> proc(component);
|
||||
if (proc) {
|
||||
std::vector<Steinberg::Vst::SpeakerArrangement> inArr, outArr;
|
||||
for (int32 i = 0; i < numAudioInputs; ++i) {
|
||||
Steinberg::Vst::SpeakerArrangement arr = 0;
|
||||
proc->getBusArrangement(kInput, i, arr);
|
||||
int32 ch = Steinberg::Vst::SpeakerArr::getChannelCount(arr);
|
||||
inArr.push_back(ch == 1 ? Steinberg::Vst::SpeakerArr::kMono
|
||||
: (ch == 2 ? Steinberg::Vst::SpeakerArr::kStereo : arr));
|
||||
}
|
||||
for (int32 i = 0; i < numAudioOutputs; ++i) {
|
||||
Steinberg::Vst::SpeakerArrangement arr = 0;
|
||||
proc->getBusArrangement(kOutput, i, arr);
|
||||
int32 ch = Steinberg::Vst::SpeakerArr::getChannelCount(arr);
|
||||
outArr.push_back(ch == 1 ? Steinberg::Vst::SpeakerArr::kMono
|
||||
: (ch == 2 ? Steinberg::Vst::SpeakerArr::kStereo : arr));
|
||||
}
|
||||
tresult res = proc->setBusArrangements(inArr.data(), (int32)inArr.size(),
|
||||
outArr.data(), (int32)outArr.size());
|
||||
std::cerr << "[RenderFx] STEP bus arrangements "
|
||||
<< (res == kResultOk || res == kResultTrue ? "OK" : "skip")
|
||||
<< " (ain=" << numAudioInputs << " aout=" << numAudioOutputs << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
for (int32 i = 0; i < numAudioInputs; ++i) component->activateBus(kAudio, kInput, i, true);
|
||||
for (int32 i = 0; i < numAudioOutputs; ++i) component->activateBus(kAudio, kOutput, i, true);
|
||||
int32 numEventInputs = component->getBusCount(kEvent, kInput);
|
||||
for (int32 i = 0; i < numEventInputs; ++i) component->activateBus(kEvent, kInput, i, true);
|
||||
|
||||
Reference in New Issue
Block a user