From 1f36f92d0c702a5df7480b083fb306685af5bb53 Mon Sep 17 00:00:00 2001 From: Matt Gajownik Date: Sun, 13 Feb 2022 11:55:29 +1100 Subject: [PATCH] obs-vst: Remove submodule in favour of direct merge Please visit the submodule repo for blame history: https://github.com/obsproject/obs-vst This also replaces the obs-vst .clang-format with obs-studio's. Co-authored-by: Alex Anderson Co-authored-by: Anton Co-authored-by: Blue Cat Audio Co-authored-by: Cephas Reis Co-authored-by: Colin Edwards Co-authored-by: Florian Zwoch Co-authored-by: Fogmoon Co-authored-by: Gol-D-Ace Co-authored-by: Igor Bochkariov Co-authored-by: Jesse Chappell Co-authored-by: Keen <523059842@qq.com> Co-authored-by: Kurt Kartaltepe Co-authored-by: Matt Gajownik Co-authored-by: Matt Gajownik Co-authored-by: Richard Stanway Co-authored-by: Ryan Foster Co-authored-by: follower Co-authored-by: gxalpha Co-authored-by: jp9000 Co-authored-by: jpark37 Co-authored-by: mntone Co-authored-by: tytan652 Co-authored-by: wangshaohui <97082645@qq.com> Co-authored-by: wangshaohui --- .gitmodules | 3 - formatcode.sh | 1 - plugins/obs-vst | 1 - plugins/obs-vst/CMakeLists.txt | 84 ++++ plugins/obs-vst/EditorWidget.cpp | 32 ++ plugins/obs-vst/VSTPlugin.cpp | 464 ++++++++++++++++++ plugins/obs-vst/data/locale/an-ES.ini | 4 + plugins/obs-vst/data/locale/ar-SA.ini | 4 + plugins/obs-vst/data/locale/bg-BG.ini | 4 + plugins/obs-vst/data/locale/bn-BD.ini | 4 + plugins/obs-vst/data/locale/ca-ES.ini | 4 + plugins/obs-vst/data/locale/cs-CZ.ini | 3 + plugins/obs-vst/data/locale/da-DK.ini | 4 + plugins/obs-vst/data/locale/de-DE.ini | 4 + plugins/obs-vst/data/locale/el-GR.ini | 3 + plugins/obs-vst/data/locale/en-US.ini | 4 + plugins/obs-vst/data/locale/es-ES.ini | 4 + plugins/obs-vst/data/locale/et-EE.ini | 3 + plugins/obs-vst/data/locale/eu-ES.ini | 4 + plugins/obs-vst/data/locale/fa-IR.ini | 4 + plugins/obs-vst/data/locale/fi-FI.ini | 3 + plugins/obs-vst/data/locale/fil-PH.ini | 4 + plugins/obs-vst/data/locale/fr-FR.ini | 4 + plugins/obs-vst/data/locale/gd-GB.ini | 4 + plugins/obs-vst/data/locale/gl-ES.ini | 4 + plugins/obs-vst/data/locale/he-IL.ini | 4 + plugins/obs-vst/data/locale/hi-IN.ini | 4 + plugins/obs-vst/data/locale/hu-HU.ini | 4 + plugins/obs-vst/data/locale/id-ID.ini | 3 + plugins/obs-vst/data/locale/it-IT.ini | 4 + plugins/obs-vst/data/locale/ja-JP.ini | 4 + plugins/obs-vst/data/locale/ka-GE.ini | 4 + plugins/obs-vst/data/locale/kab-KAB.ini | 4 + plugins/obs-vst/data/locale/kmr-TR.ini | 4 + plugins/obs-vst/data/locale/ko-KR.ini | 4 + plugins/obs-vst/data/locale/ms-MY.ini | 4 + plugins/obs-vst/data/locale/nb-NO.ini | 4 + plugins/obs-vst/data/locale/nl-NL.ini | 4 + plugins/obs-vst/data/locale/pl-PL.ini | 4 + plugins/obs-vst/data/locale/pt-BR.ini | 4 + plugins/obs-vst/data/locale/pt-PT.ini | 4 + plugins/obs-vst/data/locale/ro-RO.ini | 4 + plugins/obs-vst/data/locale/ru-RU.ini | 4 + plugins/obs-vst/data/locale/sk-SK.ini | 3 + plugins/obs-vst/data/locale/sl-SI.ini | 4 + plugins/obs-vst/data/locale/sr-CS.ini | 4 + plugins/obs-vst/data/locale/sr-SP.ini | 4 + plugins/obs-vst/data/locale/sv-SE.ini | 4 + plugins/obs-vst/data/locale/szl-PL.ini | 4 + plugins/obs-vst/data/locale/tl-PH.ini | 4 + plugins/obs-vst/data/locale/tr-TR.ini | 4 + plugins/obs-vst/data/locale/uk-UA.ini | 4 + plugins/obs-vst/data/locale/vi-VN.ini | 4 + plugins/obs-vst/data/locale/zh-CN.ini | 4 + plugins/obs-vst/data/locale/zh-TW.ini | 4 + plugins/obs-vst/headers/EditorWidget.h | 63 +++ plugins/obs-vst/headers/VSTPlugin.h | 110 +++++ .../obs-vst/headers/vst-plugin-callbacks.hpp | 21 + plugins/obs-vst/linux/EditorWidget-linux.cpp | 37 ++ plugins/obs-vst/linux/VSTPlugin-linux.cpp | 65 +++ plugins/obs-vst/mac/EditorWidget-osx.mm | 62 +++ plugins/obs-vst/mac/VSTPlugin-osx.mm | 89 ++++ plugins/obs-vst/obs-vst.cpp | 332 +++++++++++++ plugins/obs-vst/vst_header/.clang-format | 3 + plugins/obs-vst/vst_header/aeffectx.h | 382 ++++++++++++++ plugins/obs-vst/win/EditorWidget-win.cpp | 77 +++ plugins/obs-vst/win/VSTPlugin-win.cpp | 91 ++++ 67 files changed, 2102 insertions(+), 5 deletions(-) delete mode 160000 plugins/obs-vst create mode 100644 plugins/obs-vst/CMakeLists.txt create mode 100644 plugins/obs-vst/EditorWidget.cpp create mode 100644 plugins/obs-vst/VSTPlugin.cpp create mode 100644 plugins/obs-vst/data/locale/an-ES.ini create mode 100644 plugins/obs-vst/data/locale/ar-SA.ini create mode 100644 plugins/obs-vst/data/locale/bg-BG.ini create mode 100644 plugins/obs-vst/data/locale/bn-BD.ini create mode 100644 plugins/obs-vst/data/locale/ca-ES.ini create mode 100644 plugins/obs-vst/data/locale/cs-CZ.ini create mode 100644 plugins/obs-vst/data/locale/da-DK.ini create mode 100644 plugins/obs-vst/data/locale/de-DE.ini create mode 100644 plugins/obs-vst/data/locale/el-GR.ini create mode 100644 plugins/obs-vst/data/locale/en-US.ini create mode 100644 plugins/obs-vst/data/locale/es-ES.ini create mode 100644 plugins/obs-vst/data/locale/et-EE.ini create mode 100644 plugins/obs-vst/data/locale/eu-ES.ini create mode 100644 plugins/obs-vst/data/locale/fa-IR.ini create mode 100644 plugins/obs-vst/data/locale/fi-FI.ini create mode 100644 plugins/obs-vst/data/locale/fil-PH.ini create mode 100644 plugins/obs-vst/data/locale/fr-FR.ini create mode 100644 plugins/obs-vst/data/locale/gd-GB.ini create mode 100644 plugins/obs-vst/data/locale/gl-ES.ini create mode 100644 plugins/obs-vst/data/locale/he-IL.ini create mode 100644 plugins/obs-vst/data/locale/hi-IN.ini create mode 100644 plugins/obs-vst/data/locale/hu-HU.ini create mode 100644 plugins/obs-vst/data/locale/id-ID.ini create mode 100644 plugins/obs-vst/data/locale/it-IT.ini create mode 100644 plugins/obs-vst/data/locale/ja-JP.ini create mode 100644 plugins/obs-vst/data/locale/ka-GE.ini create mode 100644 plugins/obs-vst/data/locale/kab-KAB.ini create mode 100644 plugins/obs-vst/data/locale/kmr-TR.ini create mode 100644 plugins/obs-vst/data/locale/ko-KR.ini create mode 100644 plugins/obs-vst/data/locale/ms-MY.ini create mode 100644 plugins/obs-vst/data/locale/nb-NO.ini create mode 100644 plugins/obs-vst/data/locale/nl-NL.ini create mode 100644 plugins/obs-vst/data/locale/pl-PL.ini create mode 100644 plugins/obs-vst/data/locale/pt-BR.ini create mode 100644 plugins/obs-vst/data/locale/pt-PT.ini create mode 100644 plugins/obs-vst/data/locale/ro-RO.ini create mode 100644 plugins/obs-vst/data/locale/ru-RU.ini create mode 100644 plugins/obs-vst/data/locale/sk-SK.ini create mode 100644 plugins/obs-vst/data/locale/sl-SI.ini create mode 100644 plugins/obs-vst/data/locale/sr-CS.ini create mode 100644 plugins/obs-vst/data/locale/sr-SP.ini create mode 100644 plugins/obs-vst/data/locale/sv-SE.ini create mode 100644 plugins/obs-vst/data/locale/szl-PL.ini create mode 100644 plugins/obs-vst/data/locale/tl-PH.ini create mode 100644 plugins/obs-vst/data/locale/tr-TR.ini create mode 100644 plugins/obs-vst/data/locale/uk-UA.ini create mode 100644 plugins/obs-vst/data/locale/vi-VN.ini create mode 100644 plugins/obs-vst/data/locale/zh-CN.ini create mode 100644 plugins/obs-vst/data/locale/zh-TW.ini create mode 100644 plugins/obs-vst/headers/EditorWidget.h create mode 100644 plugins/obs-vst/headers/VSTPlugin.h create mode 100644 plugins/obs-vst/headers/vst-plugin-callbacks.hpp create mode 100644 plugins/obs-vst/linux/EditorWidget-linux.cpp create mode 100644 plugins/obs-vst/linux/VSTPlugin-linux.cpp create mode 100644 plugins/obs-vst/mac/EditorWidget-osx.mm create mode 100644 plugins/obs-vst/mac/VSTPlugin-osx.mm create mode 100644 plugins/obs-vst/obs-vst.cpp create mode 100644 plugins/obs-vst/vst_header/.clang-format create mode 100644 plugins/obs-vst/vst_header/aeffectx.h create mode 100644 plugins/obs-vst/win/EditorWidget-win.cpp create mode 100644 plugins/obs-vst/win/VSTPlugin-win.cpp diff --git a/.gitmodules b/.gitmodules index fa1c4f10fd173f..18bee84136515e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,9 +10,6 @@ [submodule "plugins/obs-browser"] path = plugins/obs-browser url = https://github.com/obsproject/obs-browser.git -[submodule "plugins/obs-vst"] - path = plugins/obs-vst - url = https://github.com/obsproject/obs-vst.git [submodule "plugins/obs-outputs/ftl-sdk"] path = plugins/obs-outputs/ftl-sdk url = https://github.com/Mixer/ftl-sdk.git diff --git a/formatcode.sh b/formatcode.sh index 5bb867fbc64c17..b19641bf19a0f0 100755 --- a/formatcode.sh +++ b/formatcode.sh @@ -37,7 +37,6 @@ find . -type d \( -path ./deps \ -o -path ./plugins/enc-amf \ -o -path ./plugins/mac-syphon/syphon-framework \ -o -path ./plugins/obs-outputs/ftl-sdk \ --o -path ./plugins/obs-vst \ -o -path ./plugins/aja/sdk \ -o -path ./build \) -prune -type f -o -name '*.h' -or -name '*.hpp' -or -name '*.m' -or -name '*.mm' -or -name '*.c' -or -name '*.cpp' \ | xargs -L100 -P${NPROC} ${CLANG_FORMAT} -i -style=file -fallback-style=none diff --git a/plugins/obs-vst b/plugins/obs-vst deleted file mode 160000 index 8ad3f64e702ac4..00000000000000 --- a/plugins/obs-vst +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8ad3f64e702ac4f1799b209a511620eb1d096a01 diff --git a/plugins/obs-vst/CMakeLists.txt b/plugins/obs-vst/CMakeLists.txt new file mode 100644 index 00000000000000..bb88c801d226f4 --- /dev/null +++ b/plugins/obs-vst/CMakeLists.txt @@ -0,0 +1,84 @@ +if(DISABLE_UI) + message(STATUS "UI disabled,so vst plugin disabled") + return() +endif() +if(DISABLE_VST) + message(STATUS "obs-vst is disabled") + return() +endif() + +project(obs-vst) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}") + +set(CMAKE_AUTOMOC TRUE) +find_package(Qt5Widgets REQUIRED) + +option(VST_USE_BUNDLED_HEADERS "Build with Bundled Headers" ON) + +if(VST_USE_BUNDLED_HEADERS) + message(STATUS "Using the bundled VST header.") + include_directories(vst_header) + set(vst_HEADER + vst_header/aeffectx.h) +else() + set(VST_INCLUDE_DIR "" CACHE PATH + "Path to Steinburg headers (e.g. C:/VST3 SDK/pluginterfaces/vst2.x)") + + message(WARNING "You should only use the Steinburg headers for debugging or local + builds. It is illegal to distribute the Steinburg headers with anything, and + possibly against the GPL to distribute the binaries from the resultant compile.") + include_directories(${VST_INCLUDE_DIR}) + set(vst_HEADER + ${VST_INCLUDE_DIR}/aeffectx.h) +endif() + +if(APPLE) + find_library(FOUNDATION_FRAMEWORK Foundation) + find_library(COCOA_FRAMEWORK Cocoa) +endif(APPLE) + +set(obs-vst_SOURCES + obs-vst.cpp + VSTPlugin.cpp + EditorWidget.cpp) + +if(APPLE) + list(APPEND obs-vst_SOURCES + mac/VSTPlugin-osx.mm + mac/EditorWidget-osx.mm) + +elseif(WIN32) + list(APPEND obs-vst_SOURCES + win/VSTPlugin-win.cpp + win/EditorWidget-win.cpp) + +elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") + list (APPEND obs-vst_SOURCES + linux/VSTPlugin-linux.cpp + linux/EditorWidget-linux.cpp) +endif() + +list(APPEND obs-vst_HEADERS + headers/vst-plugin-callbacks.hpp + headers/EditorWidget.h + headers/VSTPlugin.h) + +add_library(obs-vst MODULE + ${obs-vst_SOURCES} + ${obs-vst_HEADERS} + ${vst-HEADER}) + +target_link_libraries(obs-vst + libobs + Qt5::Widgets) + +set_target_properties(obs-vst PROPERTIES FOLDER "plugins") + +if(APPLE) + target_link_libraries(obs-vst + ${COCOA_FRAMEWORK} + ${FOUNDATION_FRAMEWORK}) +endif(APPLE) + +install_obs_plugin_with_data(obs-vst data) diff --git a/plugins/obs-vst/EditorWidget.cpp b/plugins/obs-vst/EditorWidget.cpp new file mode 100644 index 00000000000000..c30d3ffe49b6fe --- /dev/null +++ b/plugins/obs-vst/EditorWidget.cpp @@ -0,0 +1,32 @@ +/***************************************************************************** +Copyright (C) 2016-2017 by Colin Edwards. +Additional Code Copyright (C) 2016-2017 by c3r1c3 + +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 2 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 "headers/EditorWidget.h" +#include + +EditorWidget::EditorWidget(QWidget *parent, VSTPlugin *plugin) + : QWidget(parent), plugin(plugin) +{ + setWindowFlags(this->windowFlags() |= Qt::MSWindowsFixedSizeDialogHint); +} + +void EditorWidget::closeEvent(QCloseEvent *event) +{ + plugin->onEditorClosed(); + UNUSED_PARAMETER(event); +} diff --git a/plugins/obs-vst/VSTPlugin.cpp b/plugins/obs-vst/VSTPlugin.cpp new file mode 100644 index 00000000000000..9b7757fa681fea --- /dev/null +++ b/plugins/obs-vst/VSTPlugin.cpp @@ -0,0 +1,464 @@ +/***************************************************************************** +Copyright (C) 2016-2017 by Colin Edwards. +Additional Code Copyright (C) 2016-2017 by c3r1c3 + +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 2 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 "headers/VSTPlugin.h" +#include + +intptr_t VSTPlugin::hostCallback_static(AEffect *effect, int32_t opcode, + int32_t index, intptr_t value, + void *ptr, float opt) +{ + UNUSED_PARAMETER(opt); + UNUSED_PARAMETER(ptr); + + VSTPlugin *plugin = nullptr; + if (effect && effect->user) { + plugin = static_cast(effect->user); + } + + switch (opcode) { + case audioMasterVersion: + return (intptr_t)2400; + + case audioMasterGetCurrentProcessLevel: + return 1; + + // We always replace, never accumulate + case audioMasterWillReplaceOrAccumulate: + return 1; + + case audioMasterGetSampleRate: + if (plugin) { + return (intptr_t)plugin->GetSampleRate(); + } + return 0; + + case audioMasterGetTime: + if (plugin) { + return (intptr_t)plugin->GetTimeInfo(); + } + return 0; + + // index: width, value: height + case audioMasterSizeWindow: + if (plugin && plugin->editorWidget) { + plugin->editorWidget->handleResizeRequest(index, value); + } + return 1; + + default: + return 0; + } +} + +VstTimeInfo *VSTPlugin::GetTimeInfo() +{ + mTimeInfo.nanoSeconds = os_gettime_ns() / 1000000; + return &mTimeInfo; +} + +float VSTPlugin::GetSampleRate() +{ + return mTimeInfo.sampleRate; +} + +VSTPlugin::VSTPlugin(obs_source_t *sourceContext) : sourceContext{sourceContext} +{ +} + +VSTPlugin::~VSTPlugin() +{ + unloadEffect(); + + cleanupChannelBuffers(); +} + +void VSTPlugin::createChannelBuffers(size_t count) +{ + cleanupChannelBuffers(); + + int blocksize = BLOCK_SIZE; + numChannels = (std::max)((size_t)0, count); + + if (numChannels > 0) { + inputs = (float **)malloc(sizeof(float *) * numChannels); + outputs = (float **)malloc(sizeof(float *) * numChannels); + channelrefs = (float **)malloc(sizeof(float *) * numChannels); + for (size_t channel = 0; channel < numChannels; channel++) { + inputs[channel] = + (float *)malloc(sizeof(float) * blocksize); + outputs[channel] = + (float *)malloc(sizeof(float) * blocksize); + } + } +} + +void VSTPlugin::cleanupChannelBuffers() +{ + for (size_t channel = 0; channel < numChannels; channel++) { + if (inputs && inputs[channel]) { + free(inputs[channel]); + inputs[channel] = NULL; + } + if (outputs && outputs[channel]) { + free(outputs[channel]); + outputs[channel] = NULL; + } + } + if (inputs) { + free(inputs); + inputs = NULL; + } + if (outputs) { + free(outputs); + outputs = NULL; + } + if (channelrefs) { + free(channelrefs); + channelrefs = NULL; + } + numChannels = 0; +} + +void VSTPlugin::loadEffectFromPath(std::string path) +{ + if (this->pluginPath.compare(path) != 0) { + unloadEffect(); + blog(LOG_INFO, "User selected new VST plugin: '%s'", + path.c_str()); + } + + if (!effect) { + // TODO: alert user of error if VST is not available. + + pluginPath = path; + + AEffect *effectTemp = loadEffect(); + if (!effectTemp) { + blog(LOG_WARNING, "VST Plug-in: Can't load effect!"); + return; + } + + { + std::lock_guard lock(lockEffect); + effect = effectTemp; + } + + // Check plug-in's magic number + // If incorrect, then the file either was not loaded properly, + // is not a real VST plug-in, or is otherwise corrupt. + if (effect->magic != kEffectMagic) { + blog(LOG_WARNING, "VST Plug-in's magic number is bad"); + return; + } + + int maxchans = + (std::max)(effect->numInputs, effect->numOutputs); + // sanity check + if (maxchans < 0 || maxchans > 256) { + blog(LOG_WARNING, + "VST Plug-in has invalid number of channels"); + return; + } + + createChannelBuffers(maxchans); + + // It is better to invoke this code after checking magic number + effect->dispatcher(effect, effGetEffectName, 0, 0, effectName, + 0); + effect->dispatcher(effect, effGetVendorString, 0, 0, + vendorString, 0); + + // This check logic is refer to open source project : Audacity + if ((effect->flags & effFlagsIsSynth) || + !(effect->flags & effFlagsCanReplacing)) { + blog(LOG_WARNING, + "VST Plug-in can't support replacing. '%s'", + path.c_str()); + return; + } + + // Ask the plugin to identify itself...might be needed for older plugins + effect->dispatcher(effect, effIdentify, 0, 0, nullptr, 0.0f); + + effect->dispatcher(effect, effOpen, 0, 0, nullptr, 0.0f); + + // Set some default properties + size_t sampleRate = + audio_output_get_sample_rate(obs_get_audio()); + + // Initialize time info + memset(&mTimeInfo, 0, sizeof(mTimeInfo)); + mTimeInfo.sampleRate = sampleRate; + mTimeInfo.nanoSeconds = os_gettime_ns() / 1000000; + mTimeInfo.tempo = 120.0; + mTimeInfo.timeSigNumerator = 4; + mTimeInfo.timeSigDenominator = 4; + mTimeInfo.flags = kVstTempoValid | kVstNanosValid | + kVstTransportPlaying; + + effect->dispatcher(effect, effSetSampleRate, 0, 0, nullptr, + sampleRate); + int blocksize = BLOCK_SIZE; + effect->dispatcher(effect, effSetBlockSize, 0, blocksize, + nullptr, 0.0f); + + effect->dispatcher(effect, effMainsChanged, 0, 1, nullptr, 0); + + effectReady = true; + + if (openInterfaceWhenActive) { + openEditor(); + } + } +} + +static void silenceChannel(float **channelData, size_t numChannels, + long numFrames) +{ + for (size_t channel = 0; channel < numChannels; ++channel) { + for (long frame = 0; frame < numFrames; ++frame) { + channelData[channel][frame] = 0.0f; + } + } +} + +obs_audio_data *VSTPlugin::process(struct obs_audio_data *audio) +{ + // Here we check the status firstly, + // which help avoid waiting for lock while unloadEffect() is running. + bool effectValid = (effect && effectReady && numChannels > 0); + if (!effectValid) + return audio; + + std::lock_guard lock(lockEffect); + + if (effect && effectReady && numChannels > 0) { + uint passes = (audio->frames + BLOCK_SIZE - 1) / BLOCK_SIZE; + uint extra = audio->frames % BLOCK_SIZE; + for (uint pass = 0; pass < passes; pass++) { + uint frames = pass == passes - 1 && extra ? extra + : BLOCK_SIZE; + silenceChannel(outputs, numChannels, BLOCK_SIZE); + + for (size_t d = 0; d < numChannels; d++) { + if (d < MAX_AV_PLANES && + audio->data[d] != nullptr) { + channelrefs[d] = + ((float *)audio->data[d]) + + (pass * BLOCK_SIZE); + } else { + channelrefs[d] = inputs[d]; + } + }; + + effect->processReplacing(effect, channelrefs, outputs, + frames); + + // only copy back the channels the plugin may have generated + for (size_t c = 0; c < (size_t)effect->numOutputs && + c < MAX_AV_PLANES; + c++) { + if (audio->data[c]) { + for (size_t i = 0; i < frames; i++) { + channelrefs[c][i] = + outputs[c][i]; + } + } + } + } + } + + return audio; +} + +void VSTPlugin::unloadEffect() +{ + closeEditor(); + + { + std::lock_guard lock(lockEffect); + + // Reset the status firstly to avoid VSTPlugin::process is blocked + effectReady = false; + + if (effect) { + effect->dispatcher(effect, effMainsChanged, 0, 0, + nullptr, 0); + effect->dispatcher(effect, effClose, 0, 0, nullptr, + 0.0f); + } + + effect = nullptr; + } + + unloadLibrary(); + + pluginPath = ""; +} + +bool VSTPlugin::isEditorOpen() +{ + return editorWidget ? true : false; +} + +void VSTPlugin::onEditorClosed() +{ + if (!editorWidget) + return; + + editorWidget->deleteLater(); + editorWidget = nullptr; + + if (effect && editorOpened) { + editorOpened = false; + effect->dispatcher(effect, effEditClose, 0, 0, nullptr, 0); + } +} + +void VSTPlugin::openEditor() +{ + if (effect && !editorWidget) { + // This check logic is refer to open source project : Audacity + if (!(effect->flags & effFlagsHasEditor)) { + blog(LOG_WARNING, + "VST Plug-in: Can't support edit feature. '%s'", + pluginPath.c_str()); + return; + } + + editorOpened = true; + editorWidget = new EditorWidget(nullptr, this); + editorWidget->buildEffectContainer(effect); + + if (sourceName.empty()) { + sourceName = "VST 2.x"; + } + + if (filterName.empty()) { + editorWidget->setWindowTitle(QString("%1 - %2").arg( + sourceName.c_str(), effectName)); + } else { + editorWidget->setWindowTitle( + QString("%1: %2 - %3") + .arg(sourceName.c_str(), + filterName.c_str(), effectName)); + } + editorWidget->show(); + } +} + +void VSTPlugin::closeEditor() +{ + if (editorWidget) + editorWidget->close(); +} + +std::string VSTPlugin::getEffectPath() +{ + return pluginPath; +} + +std::string VSTPlugin::getChunk() +{ + if (!effect) { + return ""; + } + + if (effect->flags & effFlagsProgramChunks) { + void *buf = nullptr; + + intptr_t chunkSize = effect->dispatcher(effect, effGetChunk, 1, + 0, &buf, 0.0); + + QByteArray data = QByteArray((char *)buf, chunkSize); + return QString(data.toBase64()).toStdString(); + } else { + std::vector params; + for (int i = 0; i < effect->numParams; i++) { + float parameter = effect->getParameter(effect, i); + params.push_back(parameter); + } + + const char *bytes = reinterpret_cast(¶ms[0]); + QByteArray data = + QByteArray(bytes, (int)(sizeof(float) * params.size())); + std::string encoded = QString(data.toBase64()).toStdString(); + return encoded; + } +} + +void VSTPlugin::setChunk(std::string data) +{ + if (!effect) { + return; + } + + if (effect->flags & effFlagsProgramChunks) { + QByteArray base64Data = + QByteArray(data.c_str(), (int)data.length()); + QByteArray chunkData = QByteArray::fromBase64(base64Data); + void *buf = nullptr; + buf = chunkData.data(); + effect->dispatcher(effect, effSetChunk, 1, chunkData.length(), + buf, 0); + } else { + QByteArray base64Data = + QByteArray(data.c_str(), (int)data.length()); + QByteArray paramData = QByteArray::fromBase64(base64Data); + + const char *p_chars = paramData.data(); + const float *p_floats = + reinterpret_cast(p_chars); + + int size = paramData.length() / sizeof(float); + + std::vector params(p_floats, p_floats + size); + + if (params.size() != (size_t)effect->numParams) { + return; + } + + for (int i = 0; i < effect->numParams; i++) { + effect->setParameter(effect, i, params[i]); + } + } +} + +void VSTPlugin::setProgram(const int programNumber) +{ + if (programNumber < effect->numPrograms) { + effect->dispatcher(effect, effSetProgram, 0, programNumber, + NULL, 0.0f); + } else { + blog(LOG_ERROR, + "Failed to load program, number was outside possible program range."); + } +} + +int VSTPlugin::getProgram() +{ + return effect->dispatcher(effect, effGetProgram, 0, 0, NULL, 0.0f); +} + +void VSTPlugin::getSourceNames() +{ + /* Only call inside the vst_filter_audio function! */ + sourceName = obs_source_get_name(obs_filter_get_parent(sourceContext)); + filterName = obs_source_get_name(sourceContext); +} diff --git a/plugins/obs-vst/data/locale/an-ES.ini b/plugins/obs-vst/data/locale/an-ES.ini new file mode 100644 index 00000000000000..5ef914462fa678 --- /dev/null +++ b/plugins/obs-vst/data/locale/an-ES.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Ubrir la interfaz d'a extensión" +ClosePluginInterface="Zarrar la interfaz d'a extension" +VstPlugin="Extensión VST 2.x" +OpenInterfaceWhenActive="Ubrir la interfaz quan siga activo" diff --git a/plugins/obs-vst/data/locale/ar-SA.ini b/plugins/obs-vst/data/locale/ar-SA.ini new file mode 100644 index 00000000000000..b2de0a96225287 --- /dev/null +++ b/plugins/obs-vst/data/locale/ar-SA.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="فتح واجهة الإضافة" +ClosePluginInterface="إغلاق واجهة الإضافة" +VstPlugin="إضافة VST 2.x" +OpenInterfaceWhenActive="فتح الواجهة عند النشاط" diff --git a/plugins/obs-vst/data/locale/bg-BG.ini b/plugins/obs-vst/data/locale/bg-BG.ini new file mode 100644 index 00000000000000..355b93790cfa5f --- /dev/null +++ b/plugins/obs-vst/data/locale/bg-BG.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Отваряне на интерфейса на приставката" +ClosePluginInterface="Затваряне на интерфейса на приставката" +VstPlugin="Приставка VST 2.x" +OpenInterfaceWhenActive="Отваряне на интерфейса при задействане" diff --git a/plugins/obs-vst/data/locale/bn-BD.ini b/plugins/obs-vst/data/locale/bn-BD.ini new file mode 100644 index 00000000000000..317eba8a3cae86 --- /dev/null +++ b/plugins/obs-vst/data/locale/bn-BD.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="প্লাগ-ইন ইন্টারফেসের খুলুন" +ClosePluginInterface="প্লাগ-ইন ইন্টারফেস বন্ধ করুন" +VstPlugin="ভিএসটি ২.x প্লাগ-ইন" +OpenInterfaceWhenActive="সক্রিয় থাকাকালীন ইন্টারফেস খুলুন" diff --git a/plugins/obs-vst/data/locale/ca-ES.ini b/plugins/obs-vst/data/locale/ca-ES.ini new file mode 100644 index 00000000000000..c711cfe46e5ac5 --- /dev/null +++ b/plugins/obs-vst/data/locale/ca-ES.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Obre l'interfície de l'extensió" +ClosePluginInterface="Tanca la interfície de l'extensió" +VstPlugin="Extensió VST 2.x" +OpenInterfaceWhenActive="Obre l'interfície quan està actiu" diff --git a/plugins/obs-vst/data/locale/cs-CZ.ini b/plugins/obs-vst/data/locale/cs-CZ.ini new file mode 100644 index 00000000000000..7a4c7dc6c74bdf --- /dev/null +++ b/plugins/obs-vst/data/locale/cs-CZ.ini @@ -0,0 +1,3 @@ +OpenPluginInterface="Otevřít rozhraní Plug-inu" +ClosePluginInterface="Zavřít rozhraní Plug-inu" +OpenInterfaceWhenActive="Otevřít rozhraní, pokud je aktivní" diff --git a/plugins/obs-vst/data/locale/da-DK.ini b/plugins/obs-vst/data/locale/da-DK.ini new file mode 100644 index 00000000000000..c6c1bd8e752f64 --- /dev/null +++ b/plugins/obs-vst/data/locale/da-DK.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Åbn plug-in grænseflade" +ClosePluginInterface="Luk plug-in grænseflade" +VstPlugin="VST 2.x plug-in" +OpenInterfaceWhenActive="Åbn grænseflade, når aktiv" diff --git a/plugins/obs-vst/data/locale/de-DE.ini b/plugins/obs-vst/data/locale/de-DE.ini new file mode 100644 index 00000000000000..dca451b3dabf80 --- /dev/null +++ b/plugins/obs-vst/data/locale/de-DE.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Pluginschnittstelle öffnen" +ClosePluginInterface="Pluginschnittstelle schließen" +VstPlugin="VST-2.x-Plugin" +OpenInterfaceWhenActive="Schnittstelle öffnen, wenn aktiv" diff --git a/plugins/obs-vst/data/locale/el-GR.ini b/plugins/obs-vst/data/locale/el-GR.ini new file mode 100644 index 00000000000000..3eec42dcb4822b --- /dev/null +++ b/plugins/obs-vst/data/locale/el-GR.ini @@ -0,0 +1,3 @@ +OpenPluginInterface="Άνοιγμα διεπαφής Plug-in" +ClosePluginInterface="Κλείσιμο διεπαφής Plug-in" +OpenInterfaceWhenActive="Άνοιγμα διεπαφής όταν είναι ενεργό" diff --git a/plugins/obs-vst/data/locale/en-US.ini b/plugins/obs-vst/data/locale/en-US.ini new file mode 100644 index 00000000000000..cd5439703956fb --- /dev/null +++ b/plugins/obs-vst/data/locale/en-US.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Open Plug-in Interface" +ClosePluginInterface="Close Plug-in Interface" +VstPlugin="VST 2.x Plug-in" +OpenInterfaceWhenActive="Open interface when active" diff --git a/plugins/obs-vst/data/locale/es-ES.ini b/plugins/obs-vst/data/locale/es-ES.ini new file mode 100644 index 00000000000000..7714aef0cdecfb --- /dev/null +++ b/plugins/obs-vst/data/locale/es-ES.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Abrir la interfaz de la extensión" +ClosePluginInterface="Cerrar la interfaz de la extensión" +VstPlugin="Extensión VST 2.x" +OpenInterfaceWhenActive="Abrir interfaz cuando está activo" diff --git a/plugins/obs-vst/data/locale/et-EE.ini b/plugins/obs-vst/data/locale/et-EE.ini new file mode 100644 index 00000000000000..21d0d425bc2445 --- /dev/null +++ b/plugins/obs-vst/data/locale/et-EE.ini @@ -0,0 +1,3 @@ +OpenPluginInterface="Avatud Plug-in liides" +ClosePluginInterface="Sulgege Plug-in liides" +OpenInterfaceWhenActive="Ava liides kui aktiivne" diff --git a/plugins/obs-vst/data/locale/eu-ES.ini b/plugins/obs-vst/data/locale/eu-ES.ini new file mode 100644 index 00000000000000..8bcd20cf7e51e5 --- /dev/null +++ b/plugins/obs-vst/data/locale/eu-ES.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Ireki pluginaren interfazea" +ClosePluginInterface="Itxi pluginaren interfazea" +VstPlugin="VST 2.x Plugina" +OpenInterfaceWhenActive="Ireki interfazea aktibatzen denean" diff --git a/plugins/obs-vst/data/locale/fa-IR.ini b/plugins/obs-vst/data/locale/fa-IR.ini new file mode 100644 index 00000000000000..eb1876dce2c8bf --- /dev/null +++ b/plugins/obs-vst/data/locale/fa-IR.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="بازکردن رابط افزونه" +ClosePluginInterface="بستن رابط افزونه" +VstPlugin="VST 2.x افزونه" +OpenInterfaceWhenActive="رابط کاربری باز زمانی که فعال" diff --git a/plugins/obs-vst/data/locale/fi-FI.ini b/plugins/obs-vst/data/locale/fi-FI.ini new file mode 100644 index 00000000000000..92b21f3522b441 --- /dev/null +++ b/plugins/obs-vst/data/locale/fi-FI.ini @@ -0,0 +1,3 @@ +OpenPluginInterface="Avaa liitännäisen käyttöliittymä" +ClosePluginInterface="Sulje liitännäisen käyttöliittymä" +OpenInterfaceWhenActive="Avaa käyttöliittymä kun aktiivinen" diff --git a/plugins/obs-vst/data/locale/fil-PH.ini b/plugins/obs-vst/data/locale/fil-PH.ini new file mode 100644 index 00000000000000..66aad64cf01525 --- /dev/null +++ b/plugins/obs-vst/data/locale/fil-PH.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Buksan ang interface at isaksak" +ClosePluginInterface="Isarado ang interface at isaksak" +VstPlugin="VST 2. x Isaksak" +OpenInterfaceWhenActive="Buksan ang interface kapag aktibo" diff --git a/plugins/obs-vst/data/locale/fr-FR.ini b/plugins/obs-vst/data/locale/fr-FR.ini new file mode 100644 index 00000000000000..6bec1f9e65dafd --- /dev/null +++ b/plugins/obs-vst/data/locale/fr-FR.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Afficher l'interface graphique du plug-in" +ClosePluginInterface="Fermer l'interface graphique du plug-in" +VstPlugin="Plug-in VST 2.x" +OpenInterfaceWhenActive="Ouvrir l'interface graphique du plug-in quand il est actif" diff --git a/plugins/obs-vst/data/locale/gd-GB.ini b/plugins/obs-vst/data/locale/gd-GB.ini new file mode 100644 index 00000000000000..4bdf0fdf86e59e --- /dev/null +++ b/plugins/obs-vst/data/locale/gd-GB.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Fosgail eadar-aghaidh a’ phlugain" +ClosePluginInterface="Dùin eadar-aghaidh a’ phlugain" +VstPlugin="Plugan VST 2.x" +OpenInterfaceWhenActive="Fosgail an eadar-aghaidh nuair a bhios e gnìomhach" diff --git a/plugins/obs-vst/data/locale/gl-ES.ini b/plugins/obs-vst/data/locale/gl-ES.ini new file mode 100644 index 00000000000000..6adccbcf160bc9 --- /dev/null +++ b/plugins/obs-vst/data/locale/gl-ES.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Abrir a interface do engadido" +ClosePluginInterface="Pechar a interface do engadido" +VstPlugin="Engadido VST 2.x" +OpenInterfaceWhenActive="Abrir a interface cando estea activo" diff --git a/plugins/obs-vst/data/locale/he-IL.ini b/plugins/obs-vst/data/locale/he-IL.ini new file mode 100644 index 00000000000000..27306e2d1f3670 --- /dev/null +++ b/plugins/obs-vst/data/locale/he-IL.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="פתיחת ממשק התוספים" +ClosePluginInterface="סגירת ממשק התוספים" +VstPlugin="תוסף VST 2.x" +OpenInterfaceWhenActive="פתח ממשק כאשר פעיל" diff --git a/plugins/obs-vst/data/locale/hi-IN.ini b/plugins/obs-vst/data/locale/hi-IN.ini new file mode 100644 index 00000000000000..24c728ac17a3eb --- /dev/null +++ b/plugins/obs-vst/data/locale/hi-IN.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="प्लग-इन इंटरफ़ेस खोलें" +ClosePluginInterface="प्लग-इन इंटरफ़ेस बंद करें" +VstPlugin="VST 2.x प्लग-इन" +OpenInterfaceWhenActive="सक्रिय होने पर इंटरफ़ेस खोलें" diff --git a/plugins/obs-vst/data/locale/hu-HU.ini b/plugins/obs-vst/data/locale/hu-HU.ini new file mode 100644 index 00000000000000..9c81773c66d4a0 --- /dev/null +++ b/plugins/obs-vst/data/locale/hu-HU.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Bővítmény interfész megnyitása" +ClosePluginInterface="Bővítmény interfész bezárása" +VstPlugin="VST 2.x Bővítmény" +OpenInterfaceWhenActive="Interfész megnyitása, amikor aktív" diff --git a/plugins/obs-vst/data/locale/id-ID.ini b/plugins/obs-vst/data/locale/id-ID.ini new file mode 100644 index 00000000000000..9e8b99a876898e --- /dev/null +++ b/plugins/obs-vst/data/locale/id-ID.ini @@ -0,0 +1,3 @@ +OpenPluginInterface="Buka Antarmuka Plug-in" +ClosePluginInterface="Tutup Antarmuka Plug-in" +OpenInterfaceWhenActive="Buka antarmuka ketika aktif" diff --git a/plugins/obs-vst/data/locale/it-IT.ini b/plugins/obs-vst/data/locale/it-IT.ini new file mode 100644 index 00000000000000..4a10f0ecbc7272 --- /dev/null +++ b/plugins/obs-vst/data/locale/it-IT.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Apri l'interfaccia del plugin" +ClosePluginInterface="Chiudi l'interfaccia del plugin" +VstPlugin="Plugin VST 2.x" +OpenInterfaceWhenActive="Apri l'interfaccia quando attivo" diff --git a/plugins/obs-vst/data/locale/ja-JP.ini b/plugins/obs-vst/data/locale/ja-JP.ini new file mode 100644 index 00000000000000..84a5d90c89e8d6 --- /dev/null +++ b/plugins/obs-vst/data/locale/ja-JP.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="プラグインインターフェイスを開く" +ClosePluginInterface="プラグインインターフェイスを閉じる" +VstPlugin="VST 2.x プラグイン" +OpenInterfaceWhenActive="アクティブな時にインターフェイスを開く" diff --git a/plugins/obs-vst/data/locale/ka-GE.ini b/plugins/obs-vst/data/locale/ka-GE.ini new file mode 100644 index 00000000000000..e1b5d1a1cbcf4a --- /dev/null +++ b/plugins/obs-vst/data/locale/ka-GE.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="მოდულის სამართავის გახსნა" +ClosePluginInterface="მოდულის სამართავის დახურვა" +VstPlugin="VST 2.x მოდული" +OpenInterfaceWhenActive="სამართავის გახსნა ამოქმედებისას" diff --git a/plugins/obs-vst/data/locale/kab-KAB.ini b/plugins/obs-vst/data/locale/kab-KAB.ini new file mode 100644 index 00000000000000..afdd6d8818c187 --- /dev/null +++ b/plugins/obs-vst/data/locale/kab-KAB.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Ldi agrudem n usiɣzef" +ClosePluginInterface="Mdel agrudem n usiɣzef" +VstPlugin="Asiɣzef VST 2.x" +OpenInterfaceWhenActive="Ldi agrudemp ticki yermed" diff --git a/plugins/obs-vst/data/locale/kmr-TR.ini b/plugins/obs-vst/data/locale/kmr-TR.ini new file mode 100644 index 00000000000000..3b33e8bddf6ddc --- /dev/null +++ b/plugins/obs-vst/data/locale/kmr-TR.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Navrûya pêvekê veke" +ClosePluginInterface="Navrûya pêvekê bigire" +VstPlugin="Pêveka VST 2.x" +OpenInterfaceWhenActive="Dema çalak be navrûyê veke" diff --git a/plugins/obs-vst/data/locale/ko-KR.ini b/plugins/obs-vst/data/locale/ko-KR.ini new file mode 100644 index 00000000000000..30a18025ba9d82 --- /dev/null +++ b/plugins/obs-vst/data/locale/ko-KR.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="플러그인 설정 열기" +ClosePluginInterface="플러그인 설정 닫기" +VstPlugin="VST 2.x 플러그인" +OpenInterfaceWhenActive="활성화 시 인터페이스 열기" diff --git a/plugins/obs-vst/data/locale/ms-MY.ini b/plugins/obs-vst/data/locale/ms-MY.ini new file mode 100644 index 00000000000000..0ba86ffced0f54 --- /dev/null +++ b/plugins/obs-vst/data/locale/ms-MY.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Buka Antara Muka Pemalam" +ClosePluginInterface="Tutup Antara Muka Pemalam" +VstPlugin="Pemalam VST 2.x" +OpenInterfaceWhenActive="Buka antara muka bila aktif" diff --git a/plugins/obs-vst/data/locale/nb-NO.ini b/plugins/obs-vst/data/locale/nb-NO.ini new file mode 100644 index 00000000000000..bed64e8823c6aa --- /dev/null +++ b/plugins/obs-vst/data/locale/nb-NO.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Åpne utvidelsesgrensesnittet" +ClosePluginInterface="Lukk utvidelsesgrensesnittet" +VstPlugin="VST 2.x-utvidelse" +OpenInterfaceWhenActive="Åpne grensesnittet når den er aktiv" diff --git a/plugins/obs-vst/data/locale/nl-NL.ini b/plugins/obs-vst/data/locale/nl-NL.ini new file mode 100644 index 00000000000000..21f33dcfa0e10f --- /dev/null +++ b/plugins/obs-vst/data/locale/nl-NL.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Open Plugin Interface" +ClosePluginInterface="Sluit Plugin Interface" +VstPlugin="VST 2.x Plugin" +OpenInterfaceWhenActive="Open interface indien actief" diff --git a/plugins/obs-vst/data/locale/pl-PL.ini b/plugins/obs-vst/data/locale/pl-PL.ini new file mode 100644 index 00000000000000..c02b0dc999578f --- /dev/null +++ b/plugins/obs-vst/data/locale/pl-PL.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Otwórz panel wtyczki" +ClosePluginInterface="Zamknij panel wtyczki" +VstPlugin="Wtyczka VST 2.x" +OpenInterfaceWhenActive="Otwórz panel, gdy wtyczka aktywna" diff --git a/plugins/obs-vst/data/locale/pt-BR.ini b/plugins/obs-vst/data/locale/pt-BR.ini new file mode 100644 index 00000000000000..7daecab443e8d6 --- /dev/null +++ b/plugins/obs-vst/data/locale/pt-BR.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Abrir Interface do Plugin" +ClosePluginInterface="Fechar Interface do Plugin" +VstPlugin="Plugin VST 2.x" +OpenInterfaceWhenActive="Abrir interface quando ativo" diff --git a/plugins/obs-vst/data/locale/pt-PT.ini b/plugins/obs-vst/data/locale/pt-PT.ini new file mode 100644 index 00000000000000..f1a791d08b48fd --- /dev/null +++ b/plugins/obs-vst/data/locale/pt-PT.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Abrir interface da extensão" +ClosePluginInterface="Fechar interface da extensão" +VstPlugin="Extensão VST 2.x" +OpenInterfaceWhenActive="Abrir interface quando ativo" diff --git a/plugins/obs-vst/data/locale/ro-RO.ini b/plugins/obs-vst/data/locale/ro-RO.ini new file mode 100644 index 00000000000000..9bde952976f0d6 --- /dev/null +++ b/plugins/obs-vst/data/locale/ro-RO.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Deschide interfața pluginului" +ClosePluginInterface="Închide interfața pluginului" +VstPlugin="Plug-in VST 2.x" +OpenInterfaceWhenActive="Deschide interfața pluginului când este activ" diff --git a/plugins/obs-vst/data/locale/ru-RU.ini b/plugins/obs-vst/data/locale/ru-RU.ini new file mode 100644 index 00000000000000..04d2f75e1f6ae2 --- /dev/null +++ b/plugins/obs-vst/data/locale/ru-RU.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Открыть интерфейс плагина" +ClosePluginInterface="Закрыть интерфейс плагина" +VstPlugin="Плагин VST 2.x" +OpenInterfaceWhenActive="Открыть интерфейс при активации" diff --git a/plugins/obs-vst/data/locale/sk-SK.ini b/plugins/obs-vst/data/locale/sk-SK.ini new file mode 100644 index 00000000000000..db080d5bd54e55 --- /dev/null +++ b/plugins/obs-vst/data/locale/sk-SK.ini @@ -0,0 +1,3 @@ +OpenPluginInterface="Otvoriť rozhranie Plug-inu" +ClosePluginInterface="Zavrieť rozhranie Plug-inu" +OpenInterfaceWhenActive="Otvoriť rozhranie, keď je aktívny" diff --git a/plugins/obs-vst/data/locale/sl-SI.ini b/plugins/obs-vst/data/locale/sl-SI.ini new file mode 100644 index 00000000000000..32cf67067b36a9 --- /dev/null +++ b/plugins/obs-vst/data/locale/sl-SI.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Odpri vmesnik vtičnikov" +ClosePluginInterface="Zapri vmesnik vtičnikov" +VstPlugin="Vtičnik VST 2.x" +OpenInterfaceWhenActive="Odpri vmesnik, ko je dejaven" diff --git a/plugins/obs-vst/data/locale/sr-CS.ini b/plugins/obs-vst/data/locale/sr-CS.ini new file mode 100644 index 00000000000000..034fb4c43c6488 --- /dev/null +++ b/plugins/obs-vst/data/locale/sr-CS.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Prikaži interfejs za priključak" +ClosePluginInterface="Zatvori interfejs za priključak" +VstPlugin="VST 2.x priključak" +OpenInterfaceWhenActive="Prikaži interfejs kada je priključak aktivan" diff --git a/plugins/obs-vst/data/locale/sr-SP.ini b/plugins/obs-vst/data/locale/sr-SP.ini new file mode 100644 index 00000000000000..f898084b6543f9 --- /dev/null +++ b/plugins/obs-vst/data/locale/sr-SP.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Прикажи интерфејс за прикључак" +ClosePluginInterface="Затвори интерфејс за прикључак" +VstPlugin="VST 2.x прикључак" +OpenInterfaceWhenActive="Прикажи интерфејс када је прикључак активан" diff --git a/plugins/obs-vst/data/locale/sv-SE.ini b/plugins/obs-vst/data/locale/sv-SE.ini new file mode 100644 index 00000000000000..ee644482a97fc7 --- /dev/null +++ b/plugins/obs-vst/data/locale/sv-SE.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Öppna tilläggets gränssnitt" +ClosePluginInterface="Stäng tilläggets gränssnitt" +VstPlugin="VST 2.x-tillägg" +OpenInterfaceWhenActive="Öppna gränssnitt vid aktiv" diff --git a/plugins/obs-vst/data/locale/szl-PL.ini b/plugins/obs-vst/data/locale/szl-PL.ini new file mode 100644 index 00000000000000..08b6847cf0eb49 --- /dev/null +++ b/plugins/obs-vst/data/locale/szl-PL.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Ôtwōrz panel pluginu" +ClosePluginInterface="Zawrzij panel pluginu" +VstPlugin="Plugin VST 2.x" +OpenInterfaceWhenActive="Ôtwōrz panel, kej plugin je aktywny" diff --git a/plugins/obs-vst/data/locale/tl-PH.ini b/plugins/obs-vst/data/locale/tl-PH.ini new file mode 100644 index 00000000000000..4fa8df64ea12bf --- /dev/null +++ b/plugins/obs-vst/data/locale/tl-PH.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="I-open ang Plug-in na Interface" +ClosePluginInterface="I-close ang Plug-in na Interface" +VstPlugin="VST 2.x na Plug-in" +OpenInterfaceWhenActive="I-open ang interface kung itoy aktibo" diff --git a/plugins/obs-vst/data/locale/tr-TR.ini b/plugins/obs-vst/data/locale/tr-TR.ini new file mode 100644 index 00000000000000..5db96fb52efa44 --- /dev/null +++ b/plugins/obs-vst/data/locale/tr-TR.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Eklenti Arabirimi Aç" +ClosePluginInterface="Eklenti Arabirimi Kapa" +VstPlugin="VST 2.x Eklentisi" +OpenInterfaceWhenActive="Etkinken Arabirimi Aç" diff --git a/plugins/obs-vst/data/locale/uk-UA.ini b/plugins/obs-vst/data/locale/uk-UA.ini new file mode 100644 index 00000000000000..cf37f47cb9ed3d --- /dev/null +++ b/plugins/obs-vst/data/locale/uk-UA.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Відкрити інтерфейс плагіна" +ClosePluginInterface="Закрити інтерфейс плагіна" +VstPlugin="Плагін VST 2.x" +OpenInterfaceWhenActive="Щоразу відкривати інтерфейс плагіна" diff --git a/plugins/obs-vst/data/locale/vi-VN.ini b/plugins/obs-vst/data/locale/vi-VN.ini new file mode 100644 index 00000000000000..750773381d31ae --- /dev/null +++ b/plugins/obs-vst/data/locale/vi-VN.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="Mở giao diện bổ trợ" +ClosePluginInterface="Đóng giao diện bổ trợ" +VstPlugin="Bổ trợ VST 2.x" +OpenInterfaceWhenActive="Mở giao diện khi hoạt động" diff --git a/plugins/obs-vst/data/locale/zh-CN.ini b/plugins/obs-vst/data/locale/zh-CN.ini new file mode 100644 index 00000000000000..f3c2e33839f430 --- /dev/null +++ b/plugins/obs-vst/data/locale/zh-CN.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="打开插件界面" +ClosePluginInterface="关闭插件界面" +VstPlugin="VST 2.x 插件" +OpenInterfaceWhenActive="活跃时打开界面" diff --git a/plugins/obs-vst/data/locale/zh-TW.ini b/plugins/obs-vst/data/locale/zh-TW.ini new file mode 100644 index 00000000000000..1254e1a25de839 --- /dev/null +++ b/plugins/obs-vst/data/locale/zh-TW.ini @@ -0,0 +1,4 @@ +OpenPluginInterface="開啟外掛程式界面" +ClosePluginInterface="關閉外掛程式介面" +VstPlugin="VST 2.x 外掛程式" +OpenInterfaceWhenActive="啟動時開啟界面" diff --git a/plugins/obs-vst/headers/EditorWidget.h b/plugins/obs-vst/headers/EditorWidget.h new file mode 100644 index 00000000000000..ce14b584a21078 --- /dev/null +++ b/plugins/obs-vst/headers/EditorWidget.h @@ -0,0 +1,63 @@ +/***************************************************************************** +Copyright (C) 2016-2017 by Colin Edwards. +Additional Code Copyright (C) 2016-2017 by c3r1c3 + +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 2 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 OBS_STUDIO_EDITORDIALOG_H +#define OBS_STUDIO_EDITORDIALOG_H + +#include + +#if defined(_WIN32) +#include +#include +#elif defined(__linux__) +#include +#include +#endif + +#include "aeffectx.h" +#include "VSTPlugin.h" + +class VSTPlugin; + +class VstRect { + +public: + short top; + short left; + short bottom; + short right; +}; + +class EditorWidget : public QWidget { + + VSTPlugin *plugin; + +#if defined(__APPLE__) + QWidget *cocoaViewContainer = NULL; +#elif defined(_WIN32) + HWND windowHandle = NULL; +#endif + +public: + EditorWidget(QWidget *parent, VSTPlugin *plugin); + void buildEffectContainer(AEffect *effect); + void closeEvent(QCloseEvent *event) override; + void handleResizeRequest(int width, int height); +}; + +#endif // OBS_STUDIO_EDITORDIALOG_H diff --git a/plugins/obs-vst/headers/VSTPlugin.h b/plugins/obs-vst/headers/VSTPlugin.h new file mode 100644 index 00000000000000..f9b08890b809a2 --- /dev/null +++ b/plugins/obs-vst/headers/VSTPlugin.h @@ -0,0 +1,110 @@ +/***************************************************************************** +Copyright (C) 2016-2017 by Colin Edwards. +Additional Code Copyright (C) 2016-2017 by c3r1c3 + +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 2 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 OBS_STUDIO_VSTPLUGIN_H +#define OBS_STUDIO_VSTPLUGIN_H + +#define BLOCK_SIZE 512 + +#include +#include +#include +#include +#include +#include "aeffectx.h" +#include "vst-plugin-callbacks.hpp" +#include "EditorWidget.h" + +#ifdef __APPLE__ +#include +#endif + +class EditorWidget; + +class VSTPlugin : public QObject { + Q_OBJECT + + /* Because effect is always changed in UI thread, so lockEffect is only necessary for these situations: + 1. access effect object outside of UI thread; + 2. close/delete effect object any where. */ + std::recursive_mutex lockEffect; + AEffect *effect = nullptr; + obs_source_t *sourceContext; + std::string pluginPath; + + float **inputs = nullptr; + float **outputs = nullptr; + float **channelrefs = nullptr; + size_t numChannels = 0; + void createChannelBuffers(size_t count); + void cleanupChannelBuffers(); + + EditorWidget *editorWidget = nullptr; + bool editorOpened = false; + + AEffect *loadEffect(); + + std::atomic_bool effectReady = false; + + std::string sourceName; + std::string filterName; + char effectName[64]; + // Remove below... or comment out + char vendorString[64]; + + VstTimeInfo mTimeInfo; + +#ifdef __APPLE__ + CFBundleRef bundle = NULL; +#elif WIN32 + HINSTANCE dllHandle = nullptr; +#elif __linux__ + void *soHandle = nullptr; +#endif + + void unloadLibrary(); + + static intptr_t hostCallback_static(AEffect *effect, int32_t opcode, + int32_t index, intptr_t value, + void *ptr, float opt); + VstTimeInfo *GetTimeInfo(); + float GetSampleRate(); + +public: + VSTPlugin(obs_source_t *sourceContext); + ~VSTPlugin(); + void loadEffectFromPath(std::string path); + void unloadEffect(); + std::string getEffectPath(); + std::string getChunk(); + void setChunk(std::string data); + void setProgram(const int programNumber); + int getProgram(); + void getSourceNames(); + obs_audio_data *process(struct obs_audio_data *audio); + bool openInterfaceWhenActive = false; + + bool isEditorOpen(); + void onEditorClosed(); + +public slots: + void openEditor(); + void closeEditor(); +}; + +#endif // OBS_STUDIO_VSTPLUGIN_H diff --git a/plugins/obs-vst/headers/vst-plugin-callbacks.hpp b/plugins/obs-vst/headers/vst-plugin-callbacks.hpp new file mode 100644 index 00000000000000..4d33015743d860 --- /dev/null +++ b/plugins/obs-vst/headers/vst-plugin-callbacks.hpp @@ -0,0 +1,21 @@ +/***************************************************************************** +Copyright (C) 2016-2017 by Colin Edwards. + +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 2 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 . +*****************************************************************************/ +#pragma once + +#include "aeffectx.h" + +typedef AEffect *(*vstPluginMain)(audioMasterCallback audioMaster); \ No newline at end of file diff --git a/plugins/obs-vst/linux/EditorWidget-linux.cpp b/plugins/obs-vst/linux/EditorWidget-linux.cpp new file mode 100644 index 00000000000000..08a6d8a3efc4eb --- /dev/null +++ b/plugins/obs-vst/linux/EditorWidget-linux.cpp @@ -0,0 +1,37 @@ +/***************************************************************************** +Copyright (C) 2016-2017 by Colin Edwards. +Additional Code Copyright (C) 2016-2017 by c3r1c3 + +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 2 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 "../headers/EditorWidget.h" + +void EditorWidget::buildEffectContainer(AEffect *effect) +{ + WId id = winId(); + effect->dispatcher(effect, effEditOpen, 0, 0, (void *)id, 0); + VstRect *vstRect = nullptr; + effect->dispatcher(effect, effEditGetRect, 0, 0, &vstRect, 0); + + if (vstRect) { + setFixedSize(vstRect->right - vstRect->left, + vstRect->bottom - vstRect->top); + } +} + +void EditorWidget::handleResizeRequest(int width, int height) +{ + setFixedSize(width, height); +} diff --git a/plugins/obs-vst/linux/VSTPlugin-linux.cpp b/plugins/obs-vst/linux/VSTPlugin-linux.cpp new file mode 100644 index 00000000000000..259945caada796 --- /dev/null +++ b/plugins/obs-vst/linux/VSTPlugin-linux.cpp @@ -0,0 +1,65 @@ +/***************************************************************************** +Copyright (C) 2016-2017 by Colin Edwards. +Additional Code Copyright (C) 2016-2017 by c3r1c3 + +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 2 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 "../headers/VSTPlugin.h" + +#include + +AEffect *VSTPlugin::loadEffect() +{ + AEffect *plugin = nullptr; + + soHandle = os_dlopen(pluginPath.c_str()); + if (soHandle == nullptr) { + blog(LOG_WARNING, + "Failed trying to load VST from '%s'," + "error %d\n", + pluginPath.c_str(), errno); + return nullptr; + } + + vstPluginMain mainEntryPoint; + + mainEntryPoint = (vstPluginMain)os_dlsym(soHandle, "VSTPluginMain"); + + if (mainEntryPoint == nullptr) { + mainEntryPoint = + (vstPluginMain)os_dlsym(soHandle, "VstPluginMain()"); + } + + if (mainEntryPoint == nullptr) { + mainEntryPoint = (vstPluginMain)os_dlsym(soHandle, "main"); + } + + if (mainEntryPoint == nullptr) { + blog(LOG_WARNING, "Couldn't get a pointer to plug-in's main()"); + return nullptr; + } + + // Instantiate the plug-in + plugin = mainEntryPoint(hostCallback_static); + plugin->user = this; + return plugin; +} + +void VSTPlugin::unloadLibrary() +{ + if (soHandle) { + os_dlclose(soHandle); + soHandle = nullptr; + } +} diff --git a/plugins/obs-vst/mac/EditorWidget-osx.mm b/plugins/obs-vst/mac/EditorWidget-osx.mm new file mode 100644 index 00000000000000..9ed0eb121be67b --- /dev/null +++ b/plugins/obs-vst/mac/EditorWidget-osx.mm @@ -0,0 +1,62 @@ +/***************************************************************************** +Copyright (C) 2016-2017 by Colin Edwards. + +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 2 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 . +*****************************************************************************/ +#import "../headers/EditorWidget.h" +#import +#include +#include + +#import "../headers/VSTPlugin.h" + +void EditorWidget::buildEffectContainer(AEffect *effect) +{ + NSView *view = + [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300)]; + cocoaViewContainer = + QWidget::createWindowContainer(QWindow::fromWinId(WId(view))); + cocoaViewContainer->move(0, 0); + cocoaViewContainer->resize(300, 300); + cocoaViewContainer->show(); + + QGridLayout *hblParams = new QGridLayout(); + hblParams->setContentsMargins(0, 0, 0, 0); + hblParams->setSpacing(0); + hblParams->addWidget(cocoaViewContainer); + + VstRect *vstRect = nullptr; + effect->dispatcher(effect, effEditGetRect, 0, 0, &vstRect, 0); + if (vstRect) { + NSRect frame = NSMakeRect(vstRect->left, vstRect->top, + vstRect->right, vstRect->bottom); + + [view setFrame:frame]; + + cocoaViewContainer->resize(vstRect->right - vstRect->left, + vstRect->bottom - vstRect->top); + + setFixedSize(vstRect->right - vstRect->left, + vstRect->bottom - vstRect->top); + } + + effect->dispatcher(effect, effEditOpen, 0, 0, view, 0); + + setLayout(hblParams); +} + +void EditorWidget::handleResizeRequest(int width, int height) +{ + setFixedSize(width, height); +} diff --git a/plugins/obs-vst/mac/VSTPlugin-osx.mm b/plugins/obs-vst/mac/VSTPlugin-osx.mm new file mode 100644 index 00000000000000..032e9e0955afd6 --- /dev/null +++ b/plugins/obs-vst/mac/VSTPlugin-osx.mm @@ -0,0 +1,89 @@ +/***************************************************************************** +Copyright (C) 2016-2017 by Colin Edwards. + +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 2 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 "../headers/VSTPlugin.h" + +AEffect *VSTPlugin::loadEffect() +{ + AEffect *newEffect = NULL; + + // Create a path to the bundle + CFStringRef pluginPathStringRef = CFStringCreateWithCString( + NULL, pluginPath.c_str(), kCFStringEncodingUTF8); + CFURLRef bundleUrl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, + pluginPathStringRef, + kCFURLPOSIXPathStyle, + true); + + if (bundleUrl == NULL) { + blog(LOG_WARNING, + "Couldn't make URL reference for VST plug-in"); + return NULL; + } + + // Open the bundle + bundle = CFBundleCreate(kCFAllocatorDefault, bundleUrl); + if (bundle == NULL) { + blog(LOG_WARNING, "Couldn't create VST bundle reference."); + CFRelease(pluginPathStringRef); + CFRelease(bundleUrl); + return NULL; + } + + vstPluginMain mainEntryPoint = NULL; + mainEntryPoint = (vstPluginMain)CFBundleGetFunctionPointerForName( + bundle, CFSTR("VSTPluginMain")); + + // VST plugins previous to the 2.4 SDK used main_macho for the + // entry point name. + if (mainEntryPoint == NULL) { + mainEntryPoint = + (vstPluginMain)CFBundleGetFunctionPointerForName( + bundle, CFSTR("main_macho")); + } + + if (mainEntryPoint == NULL) { + blog(LOG_WARNING, "Couldn't get a pointer to plug-in's main()"); + CFBundleUnloadExecutable(bundle); + CFRelease(bundle); + return NULL; + } + + newEffect = mainEntryPoint(hostCallback_static); + if (newEffect == NULL) { + blog(LOG_WARNING, "VST Plug-in's main() returns null."); + CFBundleUnloadExecutable(bundle); + CFRelease(bundle); + return NULL; + } + + newEffect->user = this; + + // Clean up + CFRelease(pluginPathStringRef); + CFRelease(bundleUrl); + + return newEffect; +} + +void VSTPlugin::unloadLibrary() +{ + if (bundle) { + CFBundleUnloadExecutable(bundle); + CFRelease(bundle); + } +} \ No newline at end of file diff --git a/plugins/obs-vst/obs-vst.cpp b/plugins/obs-vst/obs-vst.cpp new file mode 100644 index 00000000000000..590610cfdc26d4 --- /dev/null +++ b/plugins/obs-vst/obs-vst.cpp @@ -0,0 +1,332 @@ +/***************************************************************************** +Copyright (C) 2016-2017 by Colin Edwards. +Additional Code Copyright (C) 2016-2017 by c3r1c3 + +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 2 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 "headers/VSTPlugin.h" +#include + +#define OPEN_VST_SETTINGS "open_vst_settings" +#define CLOSE_VST_SETTINGS "close_vst_settings" +#define OPEN_WHEN_ACTIVE_VST_SETTINGS "open_when_active_vst_settings" + +#define PLUG_IN_NAME obs_module_text("VstPlugin") +#define OPEN_VST_TEXT obs_module_text("OpenPluginInterface") +#define CLOSE_VST_TEXT obs_module_text("ClosePluginInterface") +#define OPEN_WHEN_ACTIVE_VST_TEXT obs_module_text("OpenInterfaceWhenActive") + +OBS_DECLARE_MODULE() +OBS_MODULE_USE_DEFAULT_LOCALE("obs-vst", "en-US") +MODULE_EXPORT const char *obs_module_description(void) +{ + return "VST 2.x Plug-in filter"; +} + +static bool open_editor_button_clicked(obs_properties_t *props, + obs_property_t *property, void *data) +{ + VSTPlugin *vstPlugin = (VSTPlugin *)data; + + QMetaObject::invokeMethod(vstPlugin, "openEditor"); + + obs_property_set_visible(obs_properties_get(props, OPEN_VST_SETTINGS), + false); + obs_property_set_visible(obs_properties_get(props, CLOSE_VST_SETTINGS), + true); + + UNUSED_PARAMETER(props); + UNUSED_PARAMETER(property); + UNUSED_PARAMETER(data); + + return true; +} + +static bool close_editor_button_clicked(obs_properties_t *props, + obs_property_t *property, void *data) +{ + VSTPlugin *vstPlugin = (VSTPlugin *)data; + + QMetaObject::invokeMethod(vstPlugin, "closeEditor"); + + obs_property_set_visible(obs_properties_get(props, OPEN_VST_SETTINGS), + true); + obs_property_set_visible(obs_properties_get(props, CLOSE_VST_SETTINGS), + false); + + UNUSED_PARAMETER(property); + + return true; +} + +std::string getFileMD5(const char *file) +{ + QFile f(file); + if (f.open(QFile::ReadOnly)) { + QCryptographicHash hash(QCryptographicHash::Md5); + if (hash.addData(&f)) + return std::string(hash.result().toHex()); + } + + return std::string(); +} + +static const char *vst_name(void *unused) +{ + UNUSED_PARAMETER(unused); + return PLUG_IN_NAME; +} + +static void vst_destroy(void *data) +{ + VSTPlugin *vstPlugin = (VSTPlugin *)data; + QMetaObject::invokeMethod(vstPlugin, "closeEditor"); + vstPlugin->deleteLater(); +} + +static void vst_update(void *data, obs_data_t *settings) +{ + VSTPlugin *vstPlugin = (VSTPlugin *)data; + + vstPlugin->openInterfaceWhenActive = + obs_data_get_bool(settings, OPEN_WHEN_ACTIVE_VST_SETTINGS); + + const char *path = obs_data_get_string(settings, "plugin_path"); + + if (strcmp(path, "") == 0) { + vstPlugin->unloadEffect(); + return; + } + vstPlugin->loadEffectFromPath(std::string(path)); + + std::string hash = getFileMD5(path); + const char *chunkHash = obs_data_get_string(settings, "chunk_hash"); + const char *chunkData = obs_data_get_string(settings, "chunk_data"); + + bool chunkHashesMatch = chunkHash && strlen(chunkHash) > 0 && + hash.compare(chunkHash) == 0; + if (chunkData && strlen(chunkData) > 0 && + (chunkHashesMatch || !chunkHash || strlen(chunkHash) == 0)) { + vstPlugin->setChunk(std::string(chunkData)); + } +} + +static void *vst_create(obs_data_t *settings, obs_source_t *filter) +{ + VSTPlugin *vstPlugin = new VSTPlugin(filter); + vst_update(vstPlugin, settings); + + return vstPlugin; +} + +static void vst_save(void *data, obs_data_t *settings) +{ + VSTPlugin *vstPlugin = (VSTPlugin *)data; + obs_data_set_string(settings, "chunk_data", + vstPlugin->getChunk().c_str()); + obs_data_set_string( + settings, "chunk_hash", + getFileMD5(vstPlugin->getEffectPath().c_str()).c_str()); +} + +static struct obs_audio_data *vst_filter_audio(void *data, + struct obs_audio_data *audio) +{ + VSTPlugin *vstPlugin = (VSTPlugin *)data; + vstPlugin->process(audio); + + /* + * OBS can only guarantee getting the filter source's parent and own name + * in this call, so we grab it and return the results for processing + * by the EditorWidget. + */ + vstPlugin->getSourceNames(); + + return audio; +} + +static void fill_out_plugins(obs_property_t *list) +{ + QStringList dir_list; + +#ifdef __APPLE__ + dir_list << "/Library/Audio/Plug-Ins/VST/" + << "~/Library/Audio/Plug-ins/VST/"; +#elif WIN32 +#ifndef _WIN64 + HANDLE hProcess = GetCurrentProcess(); + + BOOL isWow64; + IsWow64Process(hProcess, &isWow64); + + if (!isWow64) { +#endif + dir_list << qEnvironmentVariable("ProgramFiles") + + "/Steinberg/VstPlugins/" + << qEnvironmentVariable("CommonProgramFiles") + + "/Steinberg/Shared Components/" + << qEnvironmentVariable("CommonProgramFiles") + "/VST2" + << qEnvironmentVariable("CommonProgramFiles") + + "/Steinberg/VST2" + << qEnvironmentVariable("CommonProgramFiles") + + "/VSTPlugins/" + << qEnvironmentVariable("ProgramFiles") + + "/VSTPlugins/"; +#ifndef _WIN64 + } else { + dir_list << qEnvironmentVariable("ProgramFiles(x86)") + + "/Steinberg/VstPlugins/" + << qEnvironmentVariable("CommonProgramFiles(x86)") + + "/Steinberg/Shared Components/" + << qEnvironmentVariable("CommonProgramFiles(x86)") + + "/VST2" + << qEnvironmentVariable("CommonProgramFiles(x86)") + + "/VSTPlugins/" + << qEnvironmentVariable("ProgramFiles(x86)") + + "/VSTPlugins/"; + } +#endif +#elif __linux__ + // If the user has set the VST_PATH environmental + // variable, then use it. Else default to a list + // of common locations. + QString vstPathEnv(getenv("VST_PATH")); + if (!vstPathEnv.isNull()) { + dir_list.append(vstPathEnv.split(":")); + } else { + QString home(getenv("HOME")); + // Choose the most common locations + // clang-format off + dir_list << "/usr/lib/vst/" + << "/usr/lib/lxvst/" + << "/usr/lib/linux_vst/" + << "/usr/lib64/vst/" + << "/usr/lib64/lxvst/" + << "/usr/lib64/linux_vst/" + << "/usr/local/lib/vst/" + << "/usr/local/lib/lxvst/" + << "/usr/local/lib/linux_vst/" + << "/usr/local/lib64/vst/" + << "/usr/local/lib64/lxvst/" + << "/usr/local/lib64/linux_vst/" + << home + "/.vst/" + << home + "/.lxvst/"; + // clang-format on + } +#endif + + QStringList filters; + +#ifdef __APPLE__ + filters << "*.vst"; +#elif WIN32 + filters << "*.dll"; +#elif __linux__ + filters << "*.so" + << "*.o"; +#endif + + QStringList vst_list; + + // Read all plugins into a list... + for (int a = 0; a < dir_list.size(); ++a) { + QDir search_dir(dir_list[a]); + search_dir.setNameFilters(filters); + QDirIterator it(search_dir, QDirIterator::Subdirectories); + while (it.hasNext()) { + QString path = it.next(); + QString name = it.fileName(); + +#ifdef __APPLE__ + name.remove(".vst", Qt::CaseInsensitive); +#elif WIN32 + name.remove(".dll", Qt::CaseInsensitive); +#elif __linux__ + name.remove(".so", Qt::CaseInsensitive); + name.remove(".o", Qt::CaseInsensitive); +#endif + + name.append("=").append(path); + vst_list << name; + } + } + + // Now sort list alphabetically (still case-sensitive though). + std::stable_sort(vst_list.begin(), vst_list.end(), + std::less()); + + // Now add said list to the plug-in list of OBS + obs_property_list_add_string(list, "{Please select a plug-in}", + nullptr); + for (int b = 0; b < vst_list.size(); ++b) { + QString vst_sorted = vst_list[b]; + obs_property_list_add_string( + list, + vst_sorted.left(vst_sorted.indexOf('=')) + .toStdString() + .c_str(), + vst_sorted.mid(vst_sorted.indexOf('=') + 1) + .toStdString() + .c_str()); + } +} + +static obs_properties_t *vst_properties(void *data) +{ + VSTPlugin *vstPlugin = (VSTPlugin *)data; + obs_properties_t *props = obs_properties_create(); + obs_property_t *list = obs_properties_add_list(props, "plugin_path", + PLUG_IN_NAME, + OBS_COMBO_TYPE_LIST, + OBS_COMBO_FORMAT_STRING); + + fill_out_plugins(list); + + obs_properties_add_button(props, OPEN_VST_SETTINGS, OPEN_VST_TEXT, + open_editor_button_clicked); + obs_properties_add_button(props, CLOSE_VST_SETTINGS, CLOSE_VST_TEXT, + close_editor_button_clicked); + + if (vstPlugin->isEditorOpen()) { + obs_property_set_visible( + obs_properties_get(props, OPEN_VST_SETTINGS), false); + } else { + obs_property_set_visible( + obs_properties_get(props, CLOSE_VST_SETTINGS), false); + } + + obs_properties_add_bool(props, OPEN_WHEN_ACTIVE_VST_SETTINGS, + OPEN_WHEN_ACTIVE_VST_TEXT); + + return props; +} + +bool obs_module_load(void) +{ + struct obs_source_info vst_filter = {}; + vst_filter.id = "vst_filter"; + vst_filter.type = OBS_SOURCE_TYPE_FILTER; + vst_filter.output_flags = OBS_SOURCE_AUDIO; + vst_filter.get_name = vst_name; + vst_filter.create = vst_create; + vst_filter.destroy = vst_destroy; + vst_filter.update = vst_update; + vst_filter.filter_audio = vst_filter_audio; + vst_filter.get_properties = vst_properties; + vst_filter.save = vst_save; + + obs_register_source(&vst_filter); + return true; +} diff --git a/plugins/obs-vst/vst_header/.clang-format b/plugins/obs-vst/vst_header/.clang-format new file mode 100644 index 00000000000000..6420a46881e054 --- /dev/null +++ b/plugins/obs-vst/vst_header/.clang-format @@ -0,0 +1,3 @@ +Language: Cpp +SortIncludes: false +DisableFormat: true diff --git a/plugins/obs-vst/vst_header/aeffectx.h b/plugins/obs-vst/vst_header/aeffectx.h new file mode 100644 index 00000000000000..18f0f644d5c80f --- /dev/null +++ b/plugins/obs-vst/vst_header/aeffectx.h @@ -0,0 +1,382 @@ +/* + * aeffectx.h - simple header to allow VeSTige compilation and eventually work + * + * Copyright (c) 2006 Javier Serrano Polo + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * 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 2 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 (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#include + +#ifndef _AEFFECTX_H +#define _AEFFECTX_H + +#define CCONST(a, b, c, d)( ( ( (int) a ) << 24 ) | \ + ( ( (int) b ) << 16 ) | \ + ( ( (int) c ) << 8 ) | \ + ( ( (int) d ) << 0 ) ) + + +const int audioMasterAutomate = 0; +const int audioMasterVersion = 1; +const int audioMasterCurrentId = 2; +const int audioMasterIdle = 3; +const int audioMasterPinConnected = 4; +// unsupported? 5 +const int audioMasterWantMidi = 6; +const int audioMasterGetTime = 7; +const int audioMasterProcessEvents = 8; +const int audioMasterSetTime = 9; +const int audioMasterTempoAt = 10; +const int audioMasterGetNumAutomatableParameters = 11; +const int audioMasterGetParameterQuantization = 12; +const int audioMasterIOChanged = 13; +const int audioMasterNeedIdle = 14; +const int audioMasterSizeWindow = 15; +const int audioMasterGetSampleRate = 16; +const int audioMasterGetBlockSize = 17; +const int audioMasterGetInputLatency = 18; +const int audioMasterGetOutputLatency = 19; +const int audioMasterGetPreviousPlug = 20; +const int audioMasterGetNextPlug = 21; +const int audioMasterWillReplaceOrAccumulate = 22; +const int audioMasterGetCurrentProcessLevel = 23; +const int audioMasterGetAutomationState = 24; +const int audioMasterOfflineStart = 25; +const int audioMasterOfflineRead = 26; +const int audioMasterOfflineWrite = 27; +const int audioMasterOfflineGetCurrentPass = 28; +const int audioMasterOfflineGetCurrentMetaPass = 29; +const int audioMasterSetOutputSampleRate = 30; +// unsupported? 31 +const int audioMasterGetSpeakerArrangement = 31; // deprecated in 2.4? +const int audioMasterGetVendorString = 32; +const int audioMasterGetProductString = 33; +const int audioMasterGetVendorVersion = 34; +const int audioMasterVendorSpecific = 35; +const int audioMasterSetIcon = 36; +const int audioMasterCanDo = 37; +const int audioMasterGetLanguage = 38; +const int audioMasterOpenWindow = 39; +const int audioMasterCloseWindow = 40; +const int audioMasterGetDirectory = 41; +const int audioMasterUpdateDisplay = 42; +const int audioMasterBeginEdit = 43; +const int audioMasterEndEdit = 44; +const int audioMasterOpenFileSelector = 45; +const int audioMasterCloseFileSelector = 46; // currently unused +const int audioMasterEditFile = 47; // currently unused +const int audioMasterGetChunkFile = 48; // currently unused +const int audioMasterGetInputSpeakerArrangement = 49; // currently unused + +const int effFlagsHasEditor = 1; +const int effFlagsCanReplacing = 1 << 4; // very likely +const int effFlagsProgramChunks = 1 << 5; // from Ardour +const int effFlagsIsSynth = 1 << 8; // currently unused + +const int effOpen = 0; +const int effClose = 1; // currently unused +const int effSetProgram = 2; // currently unused +const int effGetProgram = 3; // currently unused +// The next one was gleaned from http://www.kvraudio.com/forum/viewtopic.php?p=1905347 +const int effSetProgramName = 4; +const int effGetProgramName = 5; // currently unused +// The next two were gleaned from http://www.kvraudio.com/forum/viewtopic.php?p=1905347 +const int effGetParamLabel = 6; +const int effGetParamDisplay = 7; +const int effGetParamName = 8; // currently unused +const int effSetSampleRate = 10; +const int effSetBlockSize = 11; +const int effMainsChanged = 12; +const int effEditGetRect = 13; +const int effEditOpen = 14; +const int effEditClose = 15; +const int effEditIdle = 19; +const int effEditTop = 20; +const int effIdentify = 22; // from http://www.asseca.org/vst-24-specs/efIdentify.html +const int effGetChunk = 23; // from Ardour +const int effSetChunk = 24; // from Ardour +const int effProcessEvents = 25; +// The next one was gleaned from http://www.asseca.org/vst-24-specs/efCanBeAutomated.html +const int effCanBeAutomated = 26; +// The next one was gleaned from http://www.kvraudio.com/forum/viewtopic.php?p=1905347 +const int effGetProgramNameIndexed = 29; +// The next one was gleaned from http://www.asseca.org/vst-24-specs/efGetPlugCategory.html +const int effGetPlugCategory = 35; +const int effGetEffectName = 45; +const int effGetParameterProperties = 56; // missing +const int effGetVendorString = 47; +const int effGetProductString = 48; +const int effGetVendorVersion = 49; +const int effCanDo = 51; // currently unused +// The next one was gleaned from http://www.asseca.org/vst-24-specs/efIdle.html +const int effIdle = 53; +const int effGetVstVersion = 58; // currently unused +// The next one was gleaned from http://www.asseca.org/vst-24-specs/efBeginSetProgram.html +const int effBeginSetProgram = 67; +// The next one was gleaned from http://www.asseca.org/vst-24-specs/efEndSetProgram.html +const int effEndSetProgram = 68; +// The next one was gleaned from http://www.asseca.org/vst-24-specs/efShellGetNextPlugin.html +const int effShellGetNextPlugin = 70; +// The next one was gleaned from http://www.asseca.org/vst-24-specs/efBeginLoadBank.html +const int effBeginLoadBank = 75; +// The next one was gleaned from http://www.asseca.org/vst-24-specs/efBeginLoadProgram.html +const int effBeginLoadProgram = 76; + +// The next two were gleaned from http://www.kvraudio.com/forum/printview.php?t=143587&start=0 +const int effStartProcess = 71; +const int effStopProcess = 72; + +const int kEffectMagic = CCONST( 'V', 's', 't', 'P' ); +const int kVstLangEnglish = 1; +const int kVstMidiType = 1; + +const int kVstNanosValid = 1 << 8; +const int kVstPpqPosValid = 1 << 9; +const int kVstTempoValid = 1 << 10; +const int kVstBarsValid = 1 << 11; +const int kVstCyclePosValid = 1 << 12; +const int kVstTimeSigValid = 1 << 13; +// from Ardour +const int kVstSmpteValid = 1 << 14; +// from Ardour +const int kVstClockValid = 1 << 15; + +const int kVstTransportPlaying = 1 << 1; +const int kVstTransportCycleActive = 1 << 2; +const int kVstTransportChanged = 1; + + +class RemoteVstPlugin; + + +class VstMidiEvent +{ + public: + // 00 + int type; + // 04 + int byteSize; + // 08 + int deltaFrames; + // 0c? + int flags; + // 10? + int noteLength; + // 14? + int noteOffset; + // 18 + char midiData[4]; + // 1c? + char detune; + // 1d? + char noteOffVelocity; + // 1e? + char reserved1; + // 1f? + char reserved2; +}; + + +class VstEvent +{ + char dump[sizeof( VstMidiEvent )]; +}; + + +class VstEvents +{ + public: + // 00 + int numEvents; + // 04 + void *reserved; + // 08 + VstEvent* events[1]; +}; + + +// Not finished, neither really used +class VstParameterProperties +{ + public: + /* + float stepFloat; + char label[64]; + int flags; + int minInteger; + int maxInteger; + int stepInteger; + char shortLabel[8]; + int category; + char categoryLabel[24]; + char empty[128]; + */ + + float stepFloat; + float smallStepFloat; + float largeStepFloat; + char label[64]; + unsigned int flags; + unsigned int minInteger; + unsigned int maxInteger; + unsigned int stepInteger; + unsigned int largeStepInteger; + char shortLabel[8]; + unsigned short displayIndex; + unsigned short category; + unsigned short numParametersInCategory; + unsigned short reserved; + char categoryLabel[24]; + char future[16]; +}; + + +class AEffect +{ + public: + // Never use virtual functions!!! + // 00-03 + int magic; + // dispatcher 04-07 + intptr_t (* dispatcher)( AEffect * , int , int , intptr_t, void * , float ); + // process, quite sure 08-0b + void (* process)( AEffect * , float * * , float * * , int ); + // setParameter 0c-0f + void (* setParameter)( AEffect * , int , float ); + // getParameter 10-13 + float (* getParameter)( AEffect * , int ); + // programs 14-17 + int numPrograms; + // Params 18-1b + int numParams; + // Input 1c-1f + int numInputs; + // Output 20-23 + int numOutputs; + // flags 24-27 + int flags; + // Fill somewhere 28-2b + void * ptr1; + void * ptr2; + int initialDelay; + // Zeroes 34-37 38-3b + int empty3a; + int empty3b; + // 1.0f 3c-3f + float unkown_float; + // An object? pointer 40-43 + void *ptr3; + // Zeroes 44-47 + void *user; + // Id 48-4b + int32_t uniqueID; + int32_t version; + // processReplacing 50-53 + void (* processReplacing)( AEffect * , float * * , float * * , int ); +}; + +typedef intptr_t (* audioMasterCallback)( AEffect * , int32_t, int32_t, + intptr_t, void * , float ); + +class VstTimeInfo +{ + public: + // 00 + double samplePos; + // 08 + double sampleRate; + // 10 + double nanoSeconds; + // 18 + double ppqPos; + // 20? + double tempo; + // 28 + double barStartPos; + // 30? + double cycleStartPos; + // 38? + double cycleEndPos; + // 40? + int timeSigNumerator; + // 44? + int timeSigDenominator; + // unconfirmed 48 4c 50 + char empty3[4 + 4 + 4]; + // 54 + int flags; +}; + +// from http://www.asseca.org/vst-24-specs/efGetParameterProperties.html +enum VstParameterFlags +{ + // parameter is a switch (on/off) + kVstParameterIsSwitch = 1 << 0, + + // minInteger, maxInteger valid + kVstParameterUsesIntegerMinMax = 1 << 1, + + // stepFloat, smallStepFloat, largeStepFloat valid + kVstParameterUsesFloatStep = 1 << 2, + + // stepInteger, largeStepInteger valid + kVstParameterUsesIntStep = 1 << 3, + + // displayIndex valid + kVstParameterSupportsDisplayIndex = 1 << 4, + + // category, etc. valid + kVstParameterSupportsDisplayCategory = 1 << 5, + + // set if parameter value can ramp up/down + kVstParameterCanRamp = 1 << 6 +}; + +// from http://www.asseca.org/vst-24-specs/efBeginLoadProgram.html +struct VstPatchChunkInfo +{ + int32_t version; // Format Version (should be 1) + int32_t pluginUniqueID; // UniqueID of the plug-in + int32_t pluginVersion; // Plug-in Version + int32_t numElements; // Number of Programs (Bank) or + // Parameters (Program) + char future[48]; // Reserved for future use +}; + +// from http://www.asseca.org/vst-24-specs/efGetPlugCategory.html +enum VstPlugCategory +{ + kPlugCategUnknown = 0, // 0=Unknown, category not implemented + kPlugCategEffect, // 1=Simple Effect + kPlugCategSynth, // 2=VST Instrument (Synths, samplers,...) + kPlugCategAnalysis, // 3=Scope, Tuner, ... + kPlugCategMastering, // 4=Dynamics, ... + kPlugCategSpacializer, // 5=Panners, ... + kPlugCategRoomFx, // 6=Delays and Reverbs + kPlugSurroundFx, // 7=Dedicated surround processor + kPlugCategRestoration, // 8=Denoiser, ... + kPlugCategOfflineProcess, // 9=Offline Process + kPlugCategShell, // 10=Plug-in is container of other + // plug-ins @see effShellGetNextPlugin() + kPlugCategGenerator, // 11=ToneGenerator, ... + kPlugCategMaxCount // 12=Marker to count the categories +}; + +#endif \ No newline at end of file diff --git a/plugins/obs-vst/win/EditorWidget-win.cpp b/plugins/obs-vst/win/EditorWidget-win.cpp new file mode 100644 index 00000000000000..d32b72f5c51ed4 --- /dev/null +++ b/plugins/obs-vst/win/EditorWidget-win.cpp @@ -0,0 +1,77 @@ +/***************************************************************************** +Copyright (C) 2016-2017 by Colin Edwards. + +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 2 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 +#include "../headers/EditorWidget.h" + +void EditorWidget::buildEffectContainer(AEffect *effect) +{ + WNDCLASSEXW wcex{sizeof(wcex)}; + + wcex.lpfnWndProc = DefWindowProcW; + wcex.hInstance = GetModuleHandleW(nullptr); + wcex.lpszClassName = L"Minimal VST host - Guest VST Window Frame"; + RegisterClassExW(&wcex); + + const auto style = WS_CAPTION | WS_THICKFRAME | WS_OVERLAPPEDWINDOW; + windowHandle = CreateWindowW(wcex.lpszClassName, TEXT(""), style, 0, 0, + 0, 0, nullptr, nullptr, nullptr, nullptr); + + // set pointer to vst effect for window long + LONG_PTR wndPtr = (LONG_PTR)effect; + SetWindowLongPtr(windowHandle, -21 /*GWLP_USERDATA*/, wndPtr); + + QWidget *widget = QWidget::createWindowContainer( + QWindow::fromWinId((WId)windowHandle), nullptr); + widget->move(0, 0); + QGridLayout *layout = new QGridLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + setLayout(layout); + layout->addWidget(widget); + + effect->dispatcher(effect, effEditOpen, 0, 0, windowHandle, 0); + + VstRect *vstRect = nullptr; + effect->dispatcher(effect, effEditGetRect, 0, 0, &vstRect, 0); + if (vstRect) { + widget->resize(vstRect->right - vstRect->left, + vstRect->bottom - vstRect->top); + resize(vstRect->right - vstRect->left, + vstRect->bottom - vstRect->top); + } else { + widget->resize(300, 300); + } +} + +void EditorWidget::handleResizeRequest(int, int) +{ + // Some plugins can't resize automatically (like SPAN by Voxengo), + // so we must resize window manually + + // get pointer to vst effect from window long + LONG_PTR wndPtr = (LONG_PTR)GetWindowLongPtrW(windowHandle, + -21 /*GWLP_USERDATA*/); + AEffect *effect = (AEffect *)(wndPtr); + VstRect *rec = nullptr; + + effect->dispatcher(effect, effEditGetRect, 0, 0, &rec, 0); + + if (rec) { + resize(rec->right - rec->left, rec->bottom - rec->top); + } +} diff --git a/plugins/obs-vst/win/VSTPlugin-win.cpp b/plugins/obs-vst/win/VSTPlugin-win.cpp new file mode 100644 index 00000000000000..d8cf0566c215a4 --- /dev/null +++ b/plugins/obs-vst/win/VSTPlugin-win.cpp @@ -0,0 +1,91 @@ +/***************************************************************************** +Copyright (C) 2016-2017 by Colin Edwards. +Additional Code Copyright (C) 2016-2017 by c3r1c3 + +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 2 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 "../headers/VSTPlugin.h" +#include "../headers/vst-plugin-callbacks.hpp" + +#include +#include + +AEffect *VSTPlugin::loadEffect() +{ + AEffect *plugin = nullptr; + + wchar_t *wpath; + os_utf8_to_wcs_ptr(pluginPath.c_str(), 0, &wpath); + dllHandle = LoadLibraryW(wpath); + bfree(wpath); + if (dllHandle == nullptr) { + + DWORD errorCode = GetLastError(); + + // Display the error message and exit the process + if (errorCode == ERROR_BAD_EXE_FORMAT) { + blog(LOG_WARNING, "Could not open library, " + "wrong architecture."); + } else { + blog(LOG_WARNING, + "Failed trying to load VST from '%s'" + ", error %d\n", + pluginPath.c_str(), GetLastError()); + } + return nullptr; + } + + vstPluginMain mainEntryPoint = + (vstPluginMain)GetProcAddress(dllHandle, "VSTPluginMain"); + + if (mainEntryPoint == nullptr) { + mainEntryPoint = (vstPluginMain)GetProcAddress( + dllHandle, "VstPluginMain()"); + } + + if (mainEntryPoint == nullptr) { + mainEntryPoint = + (vstPluginMain)GetProcAddress(dllHandle, "main"); + } + + if (mainEntryPoint == nullptr) { + blog(LOG_WARNING, "Couldn't get a pointer to plug-in's main()"); + return nullptr; + } + + // Instantiate the plug-in + try { + plugin = mainEntryPoint(hostCallback_static); + } catch (...) { + blog(LOG_WARNING, "VST plugin initialization failed"); + return nullptr; + } + + if (plugin == nullptr) { + blog(LOG_WARNING, "Couldn't create instance for '%s'", + pluginPath.c_str()); + return nullptr; + } + + plugin->user = this; + return plugin; +} + +void VSTPlugin::unloadLibrary() +{ + if (dllHandle) { + FreeLibrary(dllHandle); + dllHandle = nullptr; + } +}