diff --git a/native_bridge/src/RenderFxJob.cpp b/native_bridge/src/RenderFxJob.cpp index b9cf880..6f6e29c 100644 --- a/native_bridge/src/RenderFxJob.cpp +++ b/native_bridge/src/RenderFxJob.cpp @@ -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 proc(component); + if (proc) { + std::vector 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);