4

I would like to create a simple FX VST3 host in Delphi, to pass samples to a plugin and get the effected audio.

The code below works until the point where the editor window should appear, but it crashes with a $18 address AV error in the plugin DLL, so seems there is a missing object.

What is missing for the editor window to appear - and generally how to use an FX VST3 plugin?

type
THostApplication = class (TInterfacedObject, IHostApplication, IPlugFrame)
  function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  // Gets host application name.
  function GetName(name: PString128): TResult; stdcall;
  // Create host object (e.g. Vst::IMessage).
  function CreateInstance(cid: TUID; iid: TUID; var obj: pointer): TResult; stdcall;
  // Called to inform the host about the resize of a given view.
  function ResizeView(view: IPlugView; newSize: PViewRect): TResult; stdcall;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
    DLLHandle: THandle;
    PluginInit: TPluginInitExit;
    PluginExit: TPluginInitExit;
    PluginFactoryCall: TGetPluginFactory;
    PluginFactoryCallResult: Pointer;
    PluginFactory: IPluginFactory;
    FactoryInfo: TPFactoryInfo;
    ClassInfo: TPClassInfo;
    Component: IComponent;
    PluginInstance: Pointer;
    AudioProcessor: IAudioProcessor;
    Error: Cardinal;
    HostApplication: THostApplication;
    EditController: IEditController;
    cp_comp: IConnectionPoint;
    cp_edit: IConnectionPoint;
    PlugView: IPlugView;
    PanelHandle: HWND;
    ProcessSetup: TProcessSetup;
    SpeakerArrangement: TSpeakerArrangement;
begin

Set8087CW($133F);

DLLHandle := LoadLibrary(PChar('ReLife.vst3'));

PluginInit := GetProcAddress(DLLHandle, PAnsiChar('InitDLL'));
PluginExit := GetProcAddress(DLLHandle, PAnsiChar('ExitDLL'));
if Assigned(PluginInit) then begin
    PluginInit;
end;

PluginFactoryCall := GetProcAddress(DLLHandle, PAnsiChar('GetPluginFactory'));
PluginFactoryCallResult := PluginFactoryCall;
PluginFactory := IPluginFactory(PluginFactoryCallResult);
PluginFactory.GetFactoryInfo(FactoryInfo);
PluginFactory.GetClassInfo(0, ClassInfo);
PluginFactory.CreateInstance(PANSIChar(@ClassInfo.cid), PANSIChar(@UID_IComponent), PluginInstance);
Component := IComponent(PluginInstance);
Component.SetIoMode(kSimple);
HostApplication := THostApplication.Create;
Error := Component.Initialize(HostApplication);

PluginFactory.CreateInstance(PANSIChar(@ClassInfo.cid), PANSIChar(@UID_IAudioProcessor), PluginInstance);
AudioProcessor := IAudioProcessor(PluginInstance);

ProcessSetup.processMode := kRealtime;
ProcessSetup.symbolicSampleSize := kSample32;
ProcessSetup.maxSamplesPerBlock := 1024;
ProcessSetup.sampleRate := 44100;

SpeakerArrangement := 3;

AudioProcessor.SetBusArrangements(@SpeakerArrangement, 2, @SpeakerArrangement, 2);

AudioProcessor.SetupProcessing(ProcessSetup);
AudioProcessor.SetProcessing(1);

PluginFactory.CreateInstance(PANSIChar(@ClassInfo.cid), PANSIChar(@UID_IEditController), PluginInstance);
EditController := IEditController(PluginInstance);
Error := EditController.Initialize(HostApplication);

//Component.QueryInterface(UID_IConnectionPoint, cp_comp);
//EditController.QueryInterface(UID_IConnectionPoint, cp_edit);
//cp_comp.Connect(cp_edit);
//cp_edit.Connect(cp_comp);

PlugView := IPlugView(EditController.CreateView(PANSIChar(kEditor)));
PlugView.SetFrame(HostApplication);
PanelHandle := Panel1.Handle;
PlugView.Attached(Pointer(PanelHandle), kPlatformTypeHWND);

end;

function THostApplication.CreateInstance(cid, iid: TUID; var obj: pointer): TResult;
begin
    //* Don't know what to put here?
    Result := 0;
end;

function THostApplication.GetName(name: PString128): TResult;
begin
    Result := 0;
end;

function THostApplication.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
    if (IID = UID_IPlugFrame)
    OR (IID = UID_FUnknown)
    then begin
        Pointer(Obj) := Self;
        Result := kResultTrue;
    end else begin
        Result := inherited;
    end;
end;

function THostApplication.ResizeView(view: IPlugView; newSize: PViewRect): TResult;
begin
    //* TODO
    Result := 0;
end;

EDIT: Found this code:

// connect the 2 components
Vst::IConnectionPoint* iConnectionPointComponent = nullPtr;
Vst::IConnectionPoint* iConnectionPointController = nullPtr;

processorComponent->queryInterface (Vst::IConnectionPoint::iid, (void**)&iConnectionPointComponent);
editController->queryInterface (Vst::IConnectionPoint::iid, (void**)&iConnectionPointController);

if (iConnectionPointComponent && iConnectionPointController)
{
    iConnectionPointComponent->connect (iConnectionPointController);
    iConnectionPointController->connect (iConnectionPointComponent);
}

// synchronize controller to component by using setComponentState
MemoryStream stream; // defined in "public.sdk/source/common/memorystream.h"
stream.setByteOrder (kLittleEndian);
if (processorComponent->getState (&stream) == kResultTrue)
{
    stream.rewind ();
    editController->setComponentState (&stream);
}

// now processorComponent and editController parts are connected and synchronized...:-)

}

But when I try this in Delphi it returns a 'kNoInterface' $80004002 'E_NOINTERFACE' in 'HRes'.

    HRes := Component.QueryInterface(UID_IConnectionPoint, cp_comp);
    Showmessage(IntToStr(HRes));
    HRes := EditController.QueryInterface(UID_IConnectionPoint, cp_edit);
    Showmessage(IntToStr(HRes));
    Res := cp_comp.Connect(cp_edit);
    Showmessage(IntToStr(Res));
    cp_edit.Connect(cp_comp);

So I'm pretty much stuck now. Anybody any ideas?

3delite
  • 65
  • 1
  • 5
  • Get the VST3 SDK and read the docs. https://developer.steinberg.help/display/VST/VST+3+Links – obiwanjacobi Nov 20 '21 at 05:10
  • Thank you, I already downloaded and studied the SDK examples and example source codes I could find on the net for 2 days now, that's how I got this far with the code in the opening post. There must be something simple missing from the code but could not yet figure out what that is. – 3delite Nov 20 '21 at 08:49
  • The SDK does contain host samples (C++). Perhaps those could give you a hint? – obiwanjacobi Nov 20 '21 at 13:25
  • I edited the opening post. Thank you! – 3delite Nov 20 '21 at 19:59

0 Answers0