diff --git a/effects/effectloaders.cpp b/effects/effectloaders.cpp index b30938f43..fd012a227 100644 --- a/effects/effectloaders.cpp +++ b/effects/effectloaders.cpp @@ -25,12 +25,11 @@ #include "global/path.h" #include "panels/panels.h" #include "panels/effectcontrols.h" -#include "global/crossplatformlib.h" #include "global/config.h" #include #include - +#include #include #ifndef NOFREI0R @@ -206,15 +205,19 @@ void EffectInit::StartLoading() { void load_frei0r_effects_worker(const QString& dir, EffectMeta& em, QVector& loaded_names) { QDir search_dir(dir); if (search_dir.exists()) { - QList entry_list = search_dir.entryList(LibFilter(), QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); + QList entry_list = search_dir.entryList(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); for (int j=0;j(LibAddress(effect, "f0r_get_plugin_info")); + + QString path_without_extension = search_dir.filePath(QFileInfo(entry_list.at(j)).baseName()); + + QLibrary effect; + effect.setFileName(path_without_extension); + if (effect.load()) { + f0rGetPluginInfo get_info_func = reinterpret_cast(effect.resolve("f0r_get_plugin_info")); if (get_info_func != nullptr) { f0r_plugin_info_t info; get_info_func(&info); @@ -231,11 +234,9 @@ void load_frei0r_effects_worker(const QString& dir, EffectMeta& em, QVectorpath).filePath(em->filename); - handle = LibLoad(dll_fn); - if(handle == nullptr) { + handle.setFileName(dll_fn); + + + if (!handle.load()) { QString dll_error; #ifdef _WIN32 @@ -75,18 +77,18 @@ Frei0rEffect::Frei0rEffect(Clip* c, const EffectMeta *em) : return; } - f0rInitFunc init = reinterpret_cast(LibAddress(handle, "f0r_init")); + f0rInitFunc init = reinterpret_cast(handle.resolve("f0r_init")); init(); construct_module(); f0r_plugin_info_t info; - f0rGetPluginInfo info_func = reinterpret_cast(LibAddress(handle, "f0r_get_plugin_info")); + f0rGetPluginInfo info_func = reinterpret_cast(handle.resolve("f0r_get_plugin_info")); info_func(&info); param_count = info.num_params; - get_param_info = reinterpret_cast(LibAddress(handle, "f0r_get_param_info")); + get_param_info = reinterpret_cast(handle.resolve("f0r_get_param_info")); for (int i=0;i(LibAddress(handle, "f0r_deinit")); + if (handle.isLoaded()) { + f0rDeinitFunc deinit = reinterpret_cast(handle.resolve("f0r_deinit")); deinit(); - LibClose(handle); + handle.unload(); } } void Frei0rEffect::process_image(double timecode, uint8_t *input, uint8_t *output, int) { - f0rUpdateFunc update_func = reinterpret_cast(LibAddress(handle, "f0r_update")); + f0rUpdateFunc update_func = reinterpret_cast(handle.resolve("f0r_update")); for (int i=0;i(LibAddress(handle, "f0r_set_param_value")); + f0rSetParamValue set_param = reinterpret_cast(handle.resolve("f0r_set_param_value")); switch (param_info.type) { case F0R_PARAM_BOOL: { @@ -197,7 +199,7 @@ void Frei0rEffect::refresh() { void Frei0rEffect::destruct_module() { if (open) { - f0rDestructFunc destruct = reinterpret_cast(LibAddress(handle, "f0r_destruct")); + f0rDestructFunc destruct = reinterpret_cast(handle.resolve("f0r_destruct")); destruct(instance); open = false; @@ -205,7 +207,7 @@ void Frei0rEffect::destruct_module() { } void Frei0rEffect::construct_module() { - f0rConstructFunc construct = reinterpret_cast(LibAddress(handle, "f0r_construct")); + f0rConstructFunc construct = reinterpret_cast(handle.resolve("f0r_construct")); instance = construct(parent_clip->media_width(), parent_clip->media_height()); open = true; diff --git a/effects/internal/frei0reffect.h b/effects/internal/frei0reffect.h index 6f7356b28..b309a15cd 100644 --- a/effects/internal/frei0reffect.h +++ b/effects/internal/frei0reffect.h @@ -23,6 +23,7 @@ #ifndef NOFREI0R +#include #include #include "effects/effect.h" @@ -41,7 +42,7 @@ public: virtual void refresh(); private: - ModulePtr handle; + QLibrary handle; f0r_instance_t instance; int param_count; f0rGetParamInfo get_param_info; diff --git a/effects/internal/vsthost.cpp b/effects/internal/vsthost.cpp index de723af8b..09ed8b593 100644 --- a/effects/internal/vsthost.cpp +++ b/effects/internal/vsthost.cpp @@ -34,7 +34,14 @@ #include "global/global.h" #include "global/debug.h" -#ifdef __linux__ +// Load libraries for retrieving the native window handle. Used for VST plugins that have a separate window +// dedicated to controls. +#if defined(_WIN32) +#include +#elif defined(__APPLE__) +#include +class NSWindow; +#elif defined(__linux__) #include #endif @@ -105,95 +112,53 @@ typedef int32_t (*processEventsFuncPtr)(VstEvents *events); typedef void (*processFuncPtr)(AEffect *effect, float **inputs, float **outputs, int32_t sampleFrames); void VSTHost::loadPlugin() { + QString dll_fn = file_field->GetFileAt(0); if (dll_fn.isEmpty()) { return; } -#if defined(__APPLE__) - bundle = BundleLoad(dll_fn); + // Try to load the plugin + modulePtr.setFileName(dll_fn); + if (!modulePtr.load()) { - if (bundle == NULL) { - QMessageBox::critical(nullptr, tr("Error loading VST plugin"), tr("Failed to create VST reference")); + // Show an error if the plugin fails to load + + qCritical() << "Failed to load VST plugin" << dll_fn << "-" << modulePtr.errorString(); + QMessageBox::critical(olive::MainWindow, + tr("Error loading VST plugin"), + tr("Failed to load VST plugin \"%1\": %2").arg(dll_fn, modulePtr.errorString())); return; + } - vstPluginFuncPtr mainEntryPoint = NULL; - mainEntryPoint = (vstPluginFuncPtr)CFBundleGetFunctionPointerForName(bundle, CFSTR("VSTPluginMain")); - // VST plugins previous to the 2.4 SDK used main_macho for the entry point name - if(mainEntryPoint == NULL) { - mainEntryPoint = (vstPluginFuncPtr)CFBundleGetFunctionPointerForName(bundle, CFSTR("main_macho")); + // Try to find the VST entry point (first using VSTPluginMain() ) + vstPluginFuncPtr mainEntryPoint = reinterpret_cast(modulePtr.resolve("VSTPluginMain")); + + if (mainEntryPoint == nullptr) { + // If there's no VSTPluginMain(), the plugin may use main() instead + mainEntryPoint = reinterpret_cast(modulePtr.resolve("main")); } - if(mainEntryPoint == NULL) { - qCritical() << "Couldn't get a pointer to VST plugin's main()"; - BundleClose(bundle); + + if (mainEntryPoint == nullptr) { + QMessageBox::critical(olive::MainWindow, + tr("Error loading VST plugin"), + tr("Failed to locate entry point for dynamic library.")); + modulePtr.unload(); return; } + // Instantiate the plugin plugin = mainEntryPoint(hostCallback); - if(plugin == NULL) { - qCritical() << "Plugin's main() returns null"; - BundleClose(bundle); - return; - } -#else - modulePtr = LibLoad(dll_fn); - if(modulePtr == nullptr) { - QString dll_error; -#ifdef _WIN32 - DWORD dll_err = GetLastError(); - dll_error = QString::number(dll_err); -#elif defined(__linux__) || defined(__HAIKU__) - dll_error = dlerror(); -#endif - qCritical() << "Failed to load VST plugin" << dll_fn << "-" << dll_error; - - QString msg_err = tr("Failed to load VST plugin \"%1\": %2").arg(dll_fn, dll_error); - -#ifdef _WIN32 - if (dll_err == 193) { -#ifdef _WIN64 - msg_err += "\n\n" + tr("NOTE: You can't load 32-bit VST plugins into a 64-bit build of Olive. Please find a 64-bit version of this plugin or switch to a 32-bit build of Olive."); -#elif _WIN32 - msg_err += "\n\n" + tr("NOTE: You can't load 64-bit VST plugins into a 32-bit build of Olive. Please find a 32-bit version of this plugin or switch to a 64-bit build of Olive."); -#endif - } -#endif - - QMessageBox::critical(nullptr, tr("Error loading VST plugin"), msg_err); - - return; - } - - vstPluginFuncPtr mainEntryPoint = reinterpret_cast(LibAddress(modulePtr, "VSTPluginMain")); - - if (mainEntryPoint == nullptr) { - // if there's no VSTPluginMain(), fallback to main() - mainEntryPoint = reinterpret_cast(LibAddress(modulePtr, "main")); - } - - if (mainEntryPoint == nullptr) { - QMessageBox::critical(nullptr, tr("Error loading VST plugin"), tr("Failed to locate entry point for dynamic library.")); - LibClose(modulePtr); - } else { - // Instantiate the plugin - plugin = mainEntryPoint(hostCallback); - } -#endif } void VSTHost::freePlugin() { if (plugin != nullptr) { stopPlugin(); data_cache.clear(); -#if defined(__APPLE__) - CFBundleUnloadExecutable(bundle); - CFRelease(bundle); -#else - LibClose(modulePtr); -#endif + modulePtr.unload(); plugin = nullptr; } } @@ -406,13 +371,10 @@ void VSTHost::change_plugin() { dialog->setFixedSize(eRect->right - eRect->left, eRect->bottom - eRect->top); } else { -#ifdef __APPLE__ - CFBundleUnloadExecutable(bundle); - CFRelease(bundle); -#else - LibClose(modulePtr); -#endif + + modulePtr.unload(); plugin = nullptr; + } } show_interface_btn->SetEnabled(plugin != nullptr); diff --git a/effects/internal/vsthost.h b/effects/internal/vsthost.h index 8bc117201..1d64548ef 100644 --- a/effects/internal/vsthost.h +++ b/effects/internal/vsthost.h @@ -21,17 +21,16 @@ #ifndef VSTHOSTWIN_H #define VSTHOSTWIN_H +#include +#include + #include "effects/effect.h" - #include "global/crossplatformlib.h" - #include "include/vestige.h" // Plugin's dispatcher function typedef intptr_t (*dispatcherFuncPtr)(AEffect *effect, int32_t opCode, int32_t index, int32_t value, void *ptr, float opt); -#include - class VSTHost : public Effect { Q_OBJECT public: @@ -68,11 +67,7 @@ private: void send_data_cache_to_plugin(); -#if defined(__APPLE__) - CFBundleRef bundle; -#else - ModulePtr modulePtr; -#endif + QLibrary modulePtr; }; #endif // VSTHOSTWIN_H diff --git a/global/crossplatformlib.cpp b/global/crossplatformlib.cpp deleted file mode 100644 index f5b7d486b..000000000 --- a/global/crossplatformlib.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#include "crossplatformlib.h" - -#include - -ModulePtr LibLoad(const QString &filename) { -#ifdef _WIN32 - LPCWSTR dll_fn_w = reinterpret_cast(filename.utf16()); - return LoadLibrary(dll_fn_w); -#elif defined(__linux__) || defined(__APPLE__) || defined(__HAIKU__) - return dlopen(filename.toUtf8(), RTLD_LAZY); -#else - qWarning() << "Olive doesn't know how to open dynamic libraries on this platform, external libraries will not be functional"; - return nullptr; -#endif -} - -QStringList LibFilter() { -#ifdef _WIN32 - return QStringList("*.dll"); -#elif defined(__linux__) || defined(__APPLE__) || defined(__HAIKU__) - return {"*.so", "*.dylib"}; -#endif -} - -#ifdef __APPLE__ -CFBundleRef BundleLoad(const QString &filename) { - CFStringRef bundle_str = CFStringCreateWithCString(NULL, filename.toUtf8(), kCFStringEncodingUTF8); - CFURLRef bundle_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, bundle_str, kCFURLPOSIXPathStyle, true); - CFBundleRef bundle = NULL; - if (bundle_url != NULL) { - bundle = CFBundleCreate(kCFAllocatorDefault, bundle_url); - } else { - qCritical() << "Failed to create VST URL"; - } - CFRelease(bundle_url); - CFRelease(bundle_str); - return bundle; -} - -void BundleClose(CFBundleRef bundle) { - CFBundleUnloadExecutable(bundle); - CFRelease(bundle); -} -#endif diff --git a/global/crossplatformlib.h b/global/crossplatformlib.h deleted file mode 100644 index bd1935a7d..000000000 --- a/global/crossplatformlib.h +++ /dev/null @@ -1,49 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#ifndef CROSSPLATFORMLIB_H -#define CROSSPLATFORMLIB_H - -#include - -#ifdef _WIN32 - #include - #define LibAddress GetProcAddress - #define LibClose FreeModule - #define ModulePtr HMODULE -#elif defined(__linux__) || defined(__APPLE__) || defined(__HAIKU__) - #include - #define LibAddress dlsym - #define LibClose dlclose - #define ModulePtr void* -#endif - -ModulePtr LibLoad(const QString& filename); -QStringList LibFilter(); - -#ifdef __APPLE__ -#include -class NSWindow; - -CFBundleRef BundleLoad(const QString& filename); -void BundleClose(CFBundleRef bundle); -#endif - -#endif // CROSSPLATFORMLIB_H diff --git a/olive.pro b/olive.pro index e86586c3f..5e338de17 100644 --- a/olive.pro +++ b/olive.pro @@ -135,7 +135,6 @@ SOURCES += \ project/projectfilter.cpp \ effects/internal/frei0reffect.cpp \ effects/effectloaders.cpp \ - global/crossplatformlib.cpp \ effects/internal/vsthost.cpp \ ui/flowlayout.cpp \ dialogs/proxydialog.cpp \ @@ -262,7 +261,6 @@ HEADERS += \ project/projectfilter.h \ effects/internal/frei0reffect.h \ effects/effectloaders.h \ - global/crossplatformlib.h \ effects/internal/vsthost.h \ ui/flowlayout.h \ dialogs/proxydialog.h \ @@ -338,9 +336,6 @@ unix:!mac { CONFIG += link_pkgconfig PKGCONFIG += libavutil libavformat libavcodec libavfilter libswscale libswresample } -unix:!mac:!haiku { - LIBS += -ldl -} RESOURCES += \ icons/icons.qrc \