AronaSlate/Source/AronaCore/PluginHost/VST2PluginHost.cpp

286 lines
6.9 KiB
C++

#include "VST2PluginHost.h"
#include "Singleton/PortAudioAPI.h"
#include "Mixer/MixerTrack.h"
#include "HAL/PlatformProcess.h"
// #include "Widget/WindowManager.h"
DEFINE_LOG_CATEGORY(LogVST2PluginHost);
static TMap<FString, TSharedPtr<FVST2PluginHandle>> PluginHandles;
TSharedPtr<FVST2PluginHandle> TryLoadHandle(FString Path)
{
if (TSharedPtr<FVST2PluginHandle>* Handle = PluginHandles.Find(Path))
return *Handle;
void* DllHandle = FPlatformProcess::GetDllHandle(*Path);
if (!DllHandle)
return nullptr;
TSharedPtr<FVST2PluginHandle>& NewHandle = PluginHandles.Add(Path, MakeShared<FVST2PluginHandle>());
NewHandle->Path = Path;
NewHandle->Handle = DllHandle;
return NewHandle;
}
typedef AEffect* (*VSTPluginEntryProc)(audioMasterCallback AudioMaster);
TMap<FName, bool> CanDoMap =
{
{"sendVstEvents", true},
{"sendVstMidiEvent", true},
{"sendVstTimeInfo", true},
{"receiveVstEvents", false},
{"receiveVstMidiEvent", false},
{"receiveVstTimeInfo", false},
{"offline", false},
{"reportConnectionChanges", false},
{"acceptIOChanges", true},
{"sizeWindow", true},
{"asyncProcessing", true},
{"supplyIdle", true},
{"supportShell", false},
{"openFileSelector", false},
{"editFile", false},
{"closeFileSelector", false},
{"NIMKPIVendorSpecificCallbacks", false},
};
bool VstHostCanDo(const char* CanDo)
{
const FName CanDoName = FName(UTF8_TO_TCHAR(CanDo));
const bool* Find = CanDoMap.Find(CanDoName);
check(Find)
if (Find)
return *Find;
return false;
}
VstIntPtr MasterCallback(AEffect* Effect, VstInt32 OpCode, VstInt32 Index, VstIntPtr Value, void* Ptr, float Opt)
{
switch (OpCode)
{
case audioMasterAutomate:
return 1;
case audioMasterVersion:
return kVstVersion; // 返回插件版本号
case audioMasterWantMidi:
return 1;
case audioMasterGetSampleRate:
return FPortAudioAPI::Get().SampleRate; // 返回采样率
case audioMasterGetCurrentProcessLevel:
return kVstProcessLevelRealtime; // 返回当前处理级别
case audioMasterGetBlockSize:
return FPortAudioAPI::Get().BlockSize; // 返回块大小
case audioMasterSizeWindow:
{
// 设置插件窗口大小
// FVST2PluginHost* Host = static_cast<FVST2PluginHost*>(Effect->user);
// if (const TSharedPtr<SWindow> Window = FWindowManager::Get().FindPluginEditor(Host))
// Window->Resize(FVector2D(Index, Value));
return 1;
}
case audioMasterGetTime:
return (VstIntPtr)&VST2::VSTTimeInfo;
case audioMasterIdle:
UE_LOG(LogTemp, Log, TEXT("Plugin Idle"));
return 1;
case audioMasterNeedIdle:
UE_LOG(LogTemp, Log, TEXT("Plugin Need Idle"));
return 1;
case audioMasterGetVendorString:
{
const char* Ptr1 = (const char*)Ptr;
Ptr1 = "Arona";
return 1;
}
case audioMasterGetProductString:
{
const char* Ptr1 = (const char*)Ptr;
Ptr1 = "Arona";
return 1;
}
case audioMasterGetVendorVersion:
return 1000;
case audioMasterCanDo:
{
const char* Ptr1 = (const char*)Ptr;
return VstHostCanDo(Ptr1) ? 1 : 0;
}
case audioMasterUpdateDisplay:
return 1;
case audioMasterBeginEdit:
{
UE_LOG(LogTemp, Log, TEXT("Want Begin Edit"));
return 1;
}
case audioMasterEndEdit:
{
UE_LOG(LogTemp, Log, TEXT("Want End Edit"));
return 1;
}
case audioMasterVendorSpecific:
return 0;
case audioMasterProcessEvents:
// TODO
{
VstEvents* Events = (VstEvents*)Ptr;
Events->events[0]->type;
FVST2PluginHost* Host = static_cast<FVST2PluginHost*>(Effect->user);
}
return 1;
default:
ensureMsgf(0, TEXT("No Implement OpCode: %d"), OpCode);
}
return 1;
}
FVST2PluginHandle::~FVST2PluginHandle()
{
FPlatformProcess::FreeDllHandle(Handle);
}
FVST2PluginHost::FVST2PluginHost()
{
Handle = nullptr;
Effect = nullptr;
}
FVST2PluginHost::~FVST2PluginHost()
{
UE_LOG(LogVST2PluginHost, Log, TEXT("VST2Plugin Destroyed: %s"), *Name);
if (Effect)
Dispatch(effClose);
Effect = nullptr;
Handle.Reset();
MidiEventsToSend.freeEvents();
}
bool FVST2PluginHost::Load(const FString& Path)
{
Handle = TryLoadHandle(Path);
if (!Handle.IsValid())
{
UE_LOG(LogVST2PluginHost, Error, TEXT("加载插件失败 %s: 无法加载库文件"), *Path);
return false;
}
VSTPluginEntryProc PluginEntryProc = static_cast<VSTPluginEntryProc>(FPlatformProcess::GetDllExport(Handle->Handle, TEXT("VSTPluginMain")));
if (!PluginEntryProc)
{
UE_LOG(LogVST2PluginHost, Error, TEXT("加载插件失败 %s: 没有找到函数入口"), *Path);
return false;
}
Effect = PluginEntryProc(&MasterCallback);
check(Effect->magic == kEffectMagic)
Effect->user = this;
char Buf[256];
Dispatch(effGetEffectName, 0, 0, Buf);
Name = UTF8_TO_TCHAR(Buf);
Dispatch(effGetVendorString, 0, 0, Buf);
Vendor = FName(UTF8_TO_TCHAR(Buf));
UpdateSampleRate(FPortAudioAPI::Get().SampleRate);
UpdateBlockSize(FPortAudioAPI::Get().BlockSize);
ChannelInterface = new FChannelInterface(Effect->numInputs, Effect->numOutputs);
Dispatch(effOpen);
SetEnabled(true);
return true;
}
void FVST2PluginHost::SetEnabled(bool bEnabled)
{
EnableState = bEnabled;
Dispatch(effMainsChanged, 0, bEnabled);
}
bool FVST2PluginHost::IsEnabled()
{
return EnableState;
}
void FVST2PluginHost::UpdateBlockSize(int32 BlockSize)
{
Dispatch(effSetBlockSize, 0, BlockSize);
}
void FVST2PluginHost::UpdateSampleRate(float SampleRate)
{
Dispatch(effSetSampleRate, 0, 0, nullptr, SampleRate);
}
void FVST2PluginHost::Process(int32 NumSamples)
{
MidiEventsToSend.clear();
MidiEventsToSend.ensureSize(1);
for (const auto metadata : IncomingMidi)
MidiEventsToSend.addEvent(metadata->message.getRawData(), metadata->message.getRawDataSize(), FMath::Clamp(metadata->message.getTimeStamp(), 0, NumSamples - 1));
Dispatch(effProcessEvents, 0, 0, MidiEventsToSend.events);
IncomingMidi.clear();
Effect->processReplacing(Effect, ChannelInterface->GetInputHeader(), ChannelInterface->GetOutputHeader(), NumSamples);
}
void FVST2PluginHost::UpdateChannelNodeName()
{
VstPinProperties PinProperties;
for (int i = 0; i < Effect->numInputs; ++i)
{
if (Dispatch(effGetInputProperties, i, 0, &PinProperties) == 1)
{
ChannelInterface->SetInputChannelNodeName(i / 2, i, UTF8_TO_TCHAR(PinProperties.label));
}
}
for (int i = 0; i < Effect->numOutputs; ++i)
{
if (Dispatch(effGetOutputProperties, i, 0, &PinProperties) == 1)
{
ChannelInterface->SetOutputChannelNodeName(i / 2, i, UTF8_TO_TCHAR(PinProperties.label));
}
}
}
void FVST2PluginHost::OpenEditor(void* WindowHandle)
{
if (!HasEditor())
return;
Dispatch(effEditOpen, 0, 0, WindowHandle);
}
void FVST2PluginHost::CloseEditor()
{
Dispatch(effEditClose);
}
void FVST2PluginHost::IdleEditor()
{
Dispatch(effEditIdle);
}
bool FVST2PluginHost::HasEditor()
{
return Effect->flags & effFlagsHasEditor;
}
FVector2D FVST2PluginHost::GetEditorSize()
{
ERect* EditorRect = nullptr;
Dispatch(effEditGetRect, 0, 0, &EditorRect);
return FVector2D(EditorRect->right - EditorRect->left, EditorRect->bottom - EditorRect->top);
}