 |
|
|
04-29-2021, 07:14 PM
|
#1
|
Human being with feelings
Join Date: Dec 2020
Location: Miami, FL USA
Posts: 394
|
IReaperUIEmbedInterface question
So I have spent the past week or so trying to minimally/generically patch JUCE so that an upstream patch can be landed with support for REAPER's VST3 interfaces -- particularly interested in TCP FX embedding.
(Have spoken briefly w/ JUCE devs about this, there is some interest/receptiveness on their side depending on implementation)
To get the base REAPER SDK working ( IReaperApplication->getReaperApi()) with a "reaper.ShowConsoleMsg()" was very few changes.
---
However I wanted to ask two quick questions, as trying to get IReaperUIEmbedInterface functional did not work based on what I assumed.
- In "reaper_vst3_interfaces.h" and "reaper_plugin_fx_embed.h", the interface given for IReaperUIEmbedInterface is IController. But IController is a VSTGUI-specific interface, I assumed this was a typo and instead it was IEditController from VST3 SDK. Is this right or wrong?
Ref: https://i.imgur.com/uEgPNVO.png
-------
- If it's right, part of what I have done is modified JUCE's JuceVST3EditController (see below) to subclass/implement IReaperUIEmbedInterface, and I have overriden the ::embed_message() method, but nothing is ever called. Is there any way of debugging this from REAPER?
Here's the code for:
Would be grateful for any advise/feedback from folks who have a better clue about what they're doing than me. Getting this working and publishing it for others would be stellar!
JUCE patches made:
__________________
Seasoned codemonkey
Dunno a thing about making music (here to learn!)
Last edited by gxray; 04-29-2021 at 07:20 PM.
|
|
|
04-30-2021, 07:42 AM
|
#2
|
Human being with feelings
Join Date: Nov 2020
Posts: 274
|
I've never looked at these REAPER VST3 extensions, but did you add IReaperUIEmbedInterface to your edit controller's query interface?
|
|
|
04-30-2021, 07:48 AM
|
#3
|
Human being with feelings
Join Date: Dec 2020
Location: Miami, FL USA
Posts: 394
|
Quote:
Originally Posted by robbert-vdh
I've never looked at these REAPER VST3 extensions, but did you add IReaperUIEmbedInterface to your edit controller's query interface?
|
Yeah -- the diff does not provide enough context I think, but the actual queryInterface changes are here:
https://github.com/GavinRay97/JUCE-r....cpp#L602-L667
PHP Code:
#ifdef JUCE_VST3_ENABLE_PASS_HOST_CONTEXT_TO_AUDIO_PROCESSOR_ON_INITIALIZE
#include "../../include/vendor/reaper-
DEF_CLASS_IID(IReaperUIEmbedInterface)
#endif
class JuceVST3EditController : public Vst::EditController,
public Vst::IMidiMapping,
public Vst::IUnitInfo,
public Vst::ChannelContext::IInfoListener,
public AudioProcessorListener
#ifdef JUCE_VST3_ENABLE_PASS_HOST_CONTEXT_TO_AUDIO_PROCESSOR_ON_INITIALIZE
, public IReaperUIEmbedInterface
#endif
{
public:
JuceVST3EditController (Vst::IHostApplication* host)
{
if (host != nullptr)
host->queryInterface (FUnknown::iid, (void**) &hostContext);
}
#ifdef JUCE_VST3_ENABLE_PASS_HOST_CONTEXT_TO_AUDIO_PROCESSOR_ON_INITIALIZE
Steinberg::TPtrInt embed_message(int msg, Steinberg::TPtrInt parm2, Steinberg::TPtrInt parm3) override
{
return this->audioProcessor.get()->get()->handleReaperEmbedMessage(msg, parm2, parm3);
}
#endif
//==============================================================================
static const FUID iid;
//==============================================================================
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Winconsistent-missing-override")
REFCOUNT_METHODS (ComponentBase)
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
tresult PLUGIN_API queryInterface (const TUID targetIID, void** obj) override
{
TEST_FOR_AND_RETURN_IF_VALID (targetIID, FObject)
TEST_FOR_AND_RETURN_IF_VALID (targetIID, JuceVST3EditController)
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IEditController)
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IEditController2)
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IConnectionPoint)
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IMidiMapping)
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IUnitInfo)
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::ChannelContext::IInfoListener)
TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (targetIID, IPluginBase, Vst::IEditController)
TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (targetIID, IDependent, Vst::IEditController)
TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (targetIID, FUnknown, Vst::IEditController)
#ifdef JUCE_VST3_ENABLE_PASS_HOST_CONTEXT_TO_AUDIO_PROCESSOR_ON_INITIALIZE
TEST_FOR_AND_RETURN_IF_VALID (targetIID, IReaperUIEmbedInterface)
#endif
if (doUIDsMatch (targetIID, JuceAudioProcessor::iid))
{
audioProcessor->addRef();
*obj = audioProcessor;
return kResultOk;
}
*obj = nullptr;
return kNoInterface;
}
Where the macro TEST_FOR_AND_RETURN_IF_VALID is:
https://github.com/juce-framework/JU...T3Common.h#L49
PHP Code:
#define TEST_FOR_AND_RETURN_IF_VALID(iidToTest, ClassType) \
if (doUIDsMatch (iidToTest, ClassType::iid)) \
{ \
addRef(); \
*obj = dynamic_cast<ClassType*> (this); \
return Steinberg::kResultOk; \
}
__________________
Seasoned codemonkey
Dunno a thing about making music (here to learn!)
Last edited by gxray; 04-30-2021 at 12:49 PM.
|
|
|
04-30-2021, 08:09 AM
|
#4
|
Administrator
Join Date: Mar 2007
Location: NY
Posts: 15,423
|
Quote:
Originally Posted by gxray
In "reaper_vst3_interfaces.h" and "reaper_plugin_fx_embed.h", the interface given for IReaperUIEmbedInterface is IController. But IController is a VSTGUI-specific interface, I assumed this was a typo and instead it was IEditController from VST3 SDK. Is this right or wrong?
|
You're correct, this is a typo in the documentation. The plugin's IEditController should implement IReaperUIEmbedInterface.
|
|
|
04-30-2021, 08:20 AM
|
#5
|
Administrator
Join Date: Mar 2007
Location: NY
Posts: 15,423
|
Quote:
Originally Posted by gxray
I have overriden the ::embed_message() method, but nothing is ever called
|
This is a bug on our side, sorry for the trouble! We'll fix this for the next +dev build.
|
|
|
04-30-2021, 08:40 AM
|
#6
|
Human being with feelings
Join Date: Dec 2020
Location: Miami, FL USA
Posts: 394
|
Quote:
Originally Posted by schwa
This is a bug on our side, sorry for the trouble! We'll fix this for the next +dev build.
|
Thank you Schwa -- appreciate you guys a ton!!
Will keep doing my part to keep convo going with JUCE folks and see if we can get an acceptable generic implementation merged upstream, so that all JUCE projects have optional out-of-the-box functionality for REAPER UI embedding + SDK hosting in both VST2 + VST3
<3
__________________
Seasoned codemonkey
Dunno a thing about making music (here to learn!)
|
|
|
04-30-2021, 08:56 PM
|
#7
|
Human being with feelings
Join Date: Dec 2020
Location: Miami, FL USA
Posts: 394
|
Haven't had time to test thoroughly, but the greyed-out "Show/Embed FX in TCP" option is now clickable in my plugin FX slot in 6.30 dev, and after enabling it and trying to expand the track the plugin crashed.
Which is good! It means I fucked up, but that that REAPER let me fuck up.
So it sounds like this is going to be a fun and productive weekend =)
Will continue dev efforts after brief sleep.
Once again, really appreciate you folks
__________________
Seasoned codemonkey
Dunno a thing about making music (here to learn!)
|
|
|
05-03-2021, 07:34 AM
|
#8
|
Human being with feelings
Join Date: Dec 2020
Location: Miami, FL USA
Posts: 394
|
I'm going to go off topic from original post here if that's alright
---
I'd like to ask for some basic C++ code-review/help from anyone here experienced and willing to spare it.
I have been working with JUCE devs on allowing users to implement REAPER's VST3 interfaces for TCP/MCP FX embedding and access to it's C++ API.
(So that we can get it merged upstream and all JUCE VST2/VST3 plugins can optionally choose to be REAPER-capable by default)
Got a rough version working but it was hacky (see below), then after talking to one of the JUCE dev's have been swapping it out for his implementation idea.
Problem is, I'm hitting the limits of my knowledge trying to debug why this isn't working.
- So I have modified JUCE's IEditController implementation to allow runtime registration of VST3 interfaces and lookups during it's queryInterface() method.
- The instance of the REAPER IReaperUIEmbedInterface class is getting put in here.
PHP Code:
std::string tuidToFUIDString(const TUID iid) { const auto targetFUID = FUID::fromTUID(iid); char tmpBuf[128]; targetFUID.toString(tmpBuf); return std::string(tmpBuf); }
class VST3InterfaceContainer { typedef std::string TUIDRegString; public: std::unordered_map<TUIDRegString, Steinberg::FUnknown*> vst3InterfaceMap;
template<class T> bool registerInterface(const TUID iid, T klazz) { const auto fuidStr = tuidToFUIDString(iid); //this->tuidToClassnameMap.insert_or_assign(fuidStr, std::string(typeid(T).name())); const auto result = this->vst3InterfaceMap.insert_or_assign(fuidStr, dynamic_cast<FObject*>(klazz)); return result.second; }
Steinberg::FUnknown* findInterface(const TUID iid) { const auto fuidStr = tuidToFUIDString(iid); auto klazz = this->vst3InterfaceMap.find(fuidStr); if (klazz != this->vst3InterfaceMap.end()) return klazz->second; return nullptr; } };
PHP Code:
class JuceVST3EditController : // ... bunch of VST3 and JUCE classes public VST3InterfaceContainer { tresult PLUGIN_API queryInterface (const TUID targetIID, void** obj) override { TEST_FOR_AND_RETURN_IF_VALID (targetIID, FObject) // etc..
auto klazz = this->findInterface(targetIID); if (klazz != nullptr) { klazz->addRef(); *obj = klazz; return kResultOk; }
if (doUIDsMatch (targetIID, JuceAudioProcessor::iid)) { audioProcessor->addRef(); *obj = audioProcessor; return kResultOk; }
*obj = nullptr; return kNoInterface; } }
- In the factory instance for the plugin, I've just done this to test instantiating and inserting an instance of my class into this std::unordered_map
PHP Code:
static FUnknown* createControllerInstance (Vst::IHostApplication* host) { auto editController = new JuceVST3EditController (host); const auto reaperEditController = new ReaperVST3EditController(); editController->registerInterface(ReaperVST3EditController::iid, reaperEditController); return static_cast<Vst::IEditController*>(editController); }
- And the actual implementation of the IReaperUIEmbedInterface class (ReaperVST3EditController) is:
PHP Code:
#pragma once #include <juce_core/juce_core.h> #include <juce_audio_processors/format_types/VST3_SDK/base/source/fobject.h> #include <juce_audio_processors/format_types/VST3_SDK/pluginterfaces/base/ftypes.h>
#include "../ReaperVST3InterfaceWrapper.hpp" #include "../include/vendor/reaper-sdk/sdk/reaper_plugin_fx_embed.h"
// I'm defining the same class IID as the IReaperUIEmbedInterface so that this implementation class // gets resolved by this IID during lookups DEF_CLASS_IID(IReaperUIEmbedInterface) DECLARE_CLASS_IID(ReaperVST3EditController, 0x049bf9e7, 0xbc74ead0, 0xc4101e86, 0x7f725981) class ReaperVST3EditController : public Steinberg::FObject, public IReaperUIEmbedInterface { private: // PLUGIN_API = __stdcall virtual Steinberg::uint32 PLUGIN_API addRef () override { return Steinberg::FObject::addRef (); } virtual Steinberg::uint32 PLUGIN_API release () override { return Steinberg::FObject::release (); } public: Steinberg::TPtrInt embed_message(int msg, Steinberg::TPtrInt parm2, Steinberg::TPtrInt parm3) override { DBG("[ReaperVST3EditController::embed_message] msg = " << msg << " parm2 = " << parm2 << " parm3 = " << parm3); switch (msg) { case REAPER_FXEMBED_WM_IS_SUPPORTED: return 0; } return 0; };
tresult queryInterface(const TUID _iid, void** obj) override { return Steinberg::kResultOk; };
static const FUID iid; };
DEF_CLASS_IID(ReaperVST3EditController)
================================================== ==========
Here's the problem:
- when debugging this and setting breakpoints, it DOES call the constructor of ReaperVST3EditController
- And the queryInterface() *obj gets set to the pointer to the instance of this ReaperVST3EditController
- It enables the "Show UI in TCP" that's greyed out, and draws a black box
- But the ReaperVST3EditController::embed_message() and every other function on the class is never called
Wtf is going on, how do I debug this? =/
__________________
Seasoned codemonkey
Dunno a thing about making music (here to learn!)
Last edited by gxray; 05-03-2021 at 07:43 AM.
|
|
|
05-03-2021, 07:50 AM
|
#9
|
Administrator
Join Date: Mar 2007
Location: NY
Posts: 15,423
|
If you want to post a link to a test copy of your plugin, we can let you know what it looks like from REAPER's side.
|
|
|
05-03-2021, 07:58 AM
|
#10
|
Administrator
Join Date: Mar 2007
Location: NY
Posts: 15,423
|
Quote:
Originally Posted by gxray
But the ReaperVST3EditController::embed_message() and every other function on the class is never called
|
Never called at all, or never called after the initial REAPER_FXEMBED_WM_IS_SUPPORTED query? REAPER won't call again if the initial query returns 0.
This is what the code looks like from REAPER's side. if queryInterface() is being called for IReaperUIEmbedInterface and returning properly, embed_message() should be called immediately.
Code:
IReaperUIEmbedInterface *embed_ui=NULL;
if (m_vst3->m_controller->queryInterface(IReaperUIEmbedInterface::iid,(void **)&embed_ui) == kResultTrue && embed_ui)
{
if (embed_ui->embed_message(0,0,0)) // 0=REAPER_FXEMBED_WM_IS_SUPPORTED
{
m_vst3->m_embed_ui = embed_ui;
}
else
{
embed_ui->release();
}
}
If your code is receiving the interface query from REAPER, as your screenshot/breakpoint suggests, my guess is that it's actually working properly, but you're not seeing the debug message in embed_message() for some reason.
I suppose another possibility is that your interface registration code is returning the IReaperUIEmbedInterface interface for the wrong query. You could dump the actual IID there to make sure.
Last edited by schwa; 05-03-2021 at 08:15 AM.
|
|
|
Thread Tools |
|
Display Modes |
Hybrid Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -7. The time now is 12:26 AM.
|