#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> PluginHandles; TSharedPtr TryLoadHandle(FString Path) { if (TSharedPtr* Handle = PluginHandles.Find(Path)) return *Handle; void* DllHandle = FPlatformProcess::GetDllHandle(*Path); if (!DllHandle) return nullptr; TSharedPtr& NewHandle = PluginHandles.Add(Path, MakeShared()); NewHandle->Path = Path; NewHandle->Handle = DllHandle; return NewHandle; } typedef AEffect* (*VSTPluginEntryProc)(audioMasterCallback AudioMaster); TMap 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(Effect->user); // if (const TSharedPtr 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(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(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); }