obs-vst: Remove submodule in favour of direct merge 2/2

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.

This commit depends on the previous commit, which removes the submodule
separately as Git complains otherwise.

Co-authored-by: Alex Anderson <anderson.john.alexander@gmail.com>
Co-authored-by: Anton <camotank12345@gmail.com>
Co-authored-by: Blue Cat Audio <support@bluecataudio.com>
Co-authored-by: Cephas Reis <c3r1c3@nevermindonline.com>
Co-authored-by: Colin Edwards <colin@recursivepenguin.com>
Co-authored-by: Florian Zwoch <fzwoch@gmail.com>
Co-authored-by: Fogmoon <i@fogmoon.com>
Co-authored-by: Gol-D-Ace <Gol-D-Ace@users.noreply.github.com>
Co-authored-by: Igor Bochkariov <ujifgc@gmail.com>
Co-authored-by: Jesse Chappell <jesse@sonosaurus.com>
Co-authored-by: Keen <523059842@qq.com>
Co-authored-by: Kurt Kartaltepe <kkartaltepe@gmail.com>
Co-authored-by: Matt Gajownik <matt@obsproject.com>
Co-authored-by: Matt Gajownik <matt@wizardcm.com>
Co-authored-by: Richard Stanway <notr1ch@users.noreply.github.com>
Co-authored-by: Ryan Foster <RytoEX@gmail.com>
Co-authored-by: follower <github@rancidbacon.com>
Co-authored-by: gxalpha <beckmann.sebastian@outlook.de>
Co-authored-by: jp9000 <obs.jim@gmail.com>
Co-authored-by: jpark37 <jpark37@users.noreply.github.com>
Co-authored-by: mntone <sd8@live.jp>
Co-authored-by: tytan652 <tytan652@tytanium.xyz>
Co-authored-by: wangshaohui <97082645@qq.com>
Co-authored-by: wangshaohui <wang.shaohui@navercorp.com>
master
Matt Gajownik 2022-05-22 17:11:33 +10:00 committed by Ryan Foster
parent 34ff76c0e7
commit a7c3d94e4c
66 changed files with 2110 additions and 2 deletions

View File

@ -47,8 +47,7 @@ find . -type d \( \
-path ./plugins/decklink/\*/decklink-sdk -o \
-path ./plugins/enc-amf -o \
-path ./plugins/mac-syphon/syphon-framework -o \
-path ./plugins/obs-outputs/ftl-sdk -o \
-path ./plugins/obs-vst \
-path ./plugins/obs-outputs/ftl-sdk \
\) -prune -false -type f -o \
-name '*.h' -or \
-name '*.hpp' -or \

View File

@ -24,6 +24,7 @@ if(OS_WINDOWS)
add_subdirectory(obs-qsv11)
add_subdirectory(obs-text)
add_subdirectory(vlc-video)
add_subdirectory(obs-vst)
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/enc-amf/CMakeLists.txt")
add_subdirectory(enc-amf)
@ -45,6 +46,7 @@ elseif(OS_MACOS)
add_subdirectory(decklink)
add_subdirectory(vlc-video)
add_subdirectory(linux-jack)
add_subdirectory(obs-vst)
check_obs_browser()
elseif(OS_LINUX)
@ -57,6 +59,7 @@ elseif(OS_LINUX)
add_subdirectory(decklink)
add_subdirectory(vlc-video)
add_subdirectory(sndio)
add_subdirectory(obs-vst)
check_obs_browser()
elseif(OS_FREEBSD)

View File

@ -0,0 +1,88 @@
project(obs-vst)
option(ENABLE_VST "Enable building OBS with VST plugin" ON)
if(NOT ENABLE_VST)
message(STATUS "OBS: DISABLED obs-vst")
return()
endif()
option(ENABLE_VST_BUNDLED_HEADERS "Build with Bundled Headers" ON)
mark_as_advanced(ENABLE_VST_BUNDLED_HEADERS)
add_library(obs-vst MODULE)
add_library(OBS::vst ALIAS obs-vst)
find_qt(COMPONENTS Widgets)
set_target_properties(
obs-vst
PROPERTIES AUTOMOC ON
AUTOUIC ON
AUTORCC ON)
target_include_directories(
obs-vst PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR})
target_sources(
obs-vst
PRIVATE obs-vst.cpp VSTPlugin.cpp EditorWidget.cpp
headers/vst-plugin-callbacks.hpp headers/EditorWidget.h
headers/VSTPlugin.h)
target_link_libraries(obs-vst PRIVATE OBS::libobs Qt::Widgets)
target_include_directories(
obs-vst PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/headers)
target_compile_features(obs-vst PRIVATE cxx_std_17)
if(ENABLE_VST_BUNDLED_HEADERS)
message(STATUS "OBS: - obs-vst uses bundled VST headers")
target_sources(obs-vst PRIVATE vst_header/aeffectx.h)
target_include_directories(obs-vst
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/vst_header)
else()
set(VST_INCLUDE_DIR
""
CACHE PATH
"Path to Steinburg headers (e.g. C:/VST3 SDK/pluginterfaces/vst2.x)"
FORCE)
mark_as_advanced(VST_INCLUDE_DIR)
message(
WARNING
"OBS: 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."
)
target_sources(obs-vst PRIVATE ${VST_INCLUDE_DIR}/aeffectx.h)
endif()
if(OS_MACOS)
find_library(FOUNDATION Foundation)
find_library(COCOA Cocoa)
mark_as_advanced(COCOA FOUNDATION)
target_sources(obs-vst PRIVATE mac/VSTPlugin-osx.mm mac/EditorWidget-osx.mm)
target_link_libraries(obs-vst PRIVATE ${COCOA} ${FOUNDATION})
elseif(OS_WINDOWS)
target_sources(obs-vst PRIVATE win/VSTPlugin-win.cpp win/EditorWidget-win.cpp)
target_compile_definitions(obs-vst PRIVATE UNICODE _UNICODE)
elseif(OS_POSIX)
target_sources(obs-vst PRIVATE linux/VSTPlugin-linux.cpp
linux/EditorWidget-linux.cpp)
endif()
set_target_properties(obs-vst PROPERTIES FOLDER "plugins" PREFIX "")
setup_plugin_target(obs-vst)

View File

@ -0,0 +1,32 @@
/*****************************************************************************
Copyright (C) 2016-2017 by Colin Edwards.
Additional Code Copyright (C) 2016-2017 by c3r1c3 <c3r1c3@nevermindonline.com>
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 <http://www.gnu.org/licenses/>.
*****************************************************************************/
#include "headers/EditorWidget.h"
#include <QCloseEvent>
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);
}

View File

@ -0,0 +1,464 @@
/*****************************************************************************
Copyright (C) 2016-2017 by Colin Edwards.
Additional Code Copyright (C) 2016-2017 by c3r1c3 <c3r1c3@nevermindonline.com>
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 <http://www.gnu.org/licenses/>.
*****************************************************************************/
#include "headers/VSTPlugin.h"
#include <util/platform.h>
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<VSTPlugin *>(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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<float> params;
for (int i = 0; i < effect->numParams; i++) {
float parameter = effect->getParameter(effect, i);
params.push_back(parameter);
}
const char *bytes = reinterpret_cast<const char *>(&params[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<const float *>(p_chars);
const size_t size = paramData.length() / sizeof(float);
std::vector<float> 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);
}

View File

@ -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"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="فتح واجهة الإضافة"
ClosePluginInterface="إغلاق واجهة الإضافة"
VstPlugin="إضافة VST 2.x"
OpenInterfaceWhenActive="فتح الواجهة عند النشاط"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="Отваряне на интерфейса на приставката"
ClosePluginInterface="Затваряне на интерфейса на приставката"
VstPlugin="Приставка VST 2.x"
OpenInterfaceWhenActive="Отваряне на интерфейса при задействане"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="প্লাগ-ইন ইন্টারফেসের খুলুন"
ClosePluginInterface="প্লাগ-ইন ইন্টারফেস বন্ধ করুন"
VstPlugin="ভিএসটি ২.x প্লাগ-ইন"
OpenInterfaceWhenActive="সক্রিয় থাকাকালীন ইন্টারফেস খুলুন"

View File

@ -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"

View File

@ -0,0 +1,3 @@
OpenPluginInterface="Otevřít rozhraní Plug-inu"
ClosePluginInterface="Zavřít rozhraní Plug-inu"
OpenInterfaceWhenActive="Otevřít rozhraní, pokud je aktivní"

View File

@ -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"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="Pluginschnittstelle öffnen"
ClosePluginInterface="Pluginschnittstelle schließen"
VstPlugin="VST-2.x-Plugin"
OpenInterfaceWhenActive="Schnittstelle öffnen, wenn aktiv"

View File

@ -0,0 +1,3 @@
OpenPluginInterface="Άνοιγμα διεπαφής Plug-in"
ClosePluginInterface="Κλείσιμο διεπαφής Plug-in"
OpenInterfaceWhenActive="Άνοιγμα διεπαφής όταν είναι ενεργό"

View File

@ -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"

View File

@ -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"

View File

@ -0,0 +1,3 @@
OpenPluginInterface="Avatud Plug-in liides"
ClosePluginInterface="Sulgege Plug-in liides"
OpenInterfaceWhenActive="Ava liides kui aktiivne"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="Ireki pluginaren interfazea"
ClosePluginInterface="Itxi pluginaren interfazea"
VstPlugin="VST 2.x Plugina"
OpenInterfaceWhenActive="Ireki interfazea aktibatzen denean"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="بازکردن رابط افزونه"
ClosePluginInterface="بستن رابط افزونه"
VstPlugin="VST 2.x افزونه"
OpenInterfaceWhenActive="رابط کاربری باز زمانی که فعال"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="פתיחת ממשק התוספים"
ClosePluginInterface="סגירת ממשק התוספים"
VstPlugin="תוסף VST 2.x"
OpenInterfaceWhenActive="פתח ממשק כאשר פעיל"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="प्लग-इन इंटरफ़ेस खोलें"
ClosePluginInterface="प्लग-इन इंटरफ़ेस बंद करें"
VstPlugin="VST 2.x प्लग-इन"
OpenInterfaceWhenActive="सक्रिय होने पर इंटरफ़ेस खोलें"

View File

@ -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"

View File

@ -0,0 +1,3 @@
OpenPluginInterface="Buka Antarmuka Plug-in"
ClosePluginInterface="Tutup Antarmuka Plug-in"
OpenInterfaceWhenActive="Buka antarmuka ketika aktif"

View File

@ -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"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="プラグインインターフェイスを開く"
ClosePluginInterface="プラグインインターフェイスを閉じる"
VstPlugin="VST 2.x プラグイン"
OpenInterfaceWhenActive="アクティブな時にインターフェイスを開く"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="მოდულის სამართავის გახსნა"
ClosePluginInterface="მოდულის სამართავის დახურვა"
VstPlugin="VST 2.x მოდული"
OpenInterfaceWhenActive="სამართავის გახსნა ამოქმედებისას"

View File

@ -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"

View File

@ -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"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="플러그인 설정 열기"
ClosePluginInterface="플러그인 설정 닫기"
VstPlugin="VST 2.x 플러그인"
OpenInterfaceWhenActive="활성화 시 인터페이스 열기"

View File

@ -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"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="Åpne utvidelsesgrensesnittet"
ClosePluginInterface="Lukk utvidelsesgrensesnittet"
VstPlugin="VST 2.x-utvidelse"
OpenInterfaceWhenActive="Åpne grensesnittet når den er aktiv"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="Open Plugin Interface"
ClosePluginInterface="Sluit Plugin Interface"
VstPlugin="VST 2.x Plugin"
OpenInterfaceWhenActive="Open interface indien actief"

View File

@ -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"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="Abrir Interface do Plugin"
ClosePluginInterface="Fechar Interface do Plugin"
VstPlugin="Plugin VST 2.x"
OpenInterfaceWhenActive="Abrir interface quando ativo"

View File

@ -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"

View File

@ -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"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="Открыть интерфейс плагина"
ClosePluginInterface="Закрыть интерфейс плагина"
VstPlugin="Плагин VST 2.x"
OpenInterfaceWhenActive="Открыть интерфейс при активации"

View File

@ -0,0 +1,3 @@
OpenPluginInterface="Otvoriť rozhranie Plug-inu"
ClosePluginInterface="Zavrieť rozhranie Plug-inu"
OpenInterfaceWhenActive="Otvoriť rozhranie, keď je aktívny"

View File

@ -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"

View File

@ -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"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="Прикажи интерфејс за прикључак"
ClosePluginInterface="Затвори интерфејс за прикључак"
VstPlugin="VST 2.x прикључак"
OpenInterfaceWhenActive="Прикажи интерфејс када је прикључак активан"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="Eklenti Arabirimi Aç"
ClosePluginInterface="Eklenti Arabirimi Kapa"
VstPlugin="VST 2.x Eklentisi"
OpenInterfaceWhenActive="Etkinken Arabirimi Aç"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="Відкрити інтерфейс плагіна"
ClosePluginInterface="Закрити інтерфейс плагіна"
VstPlugin="Плагін VST 2.x"
OpenInterfaceWhenActive="Щоразу відкривати інтерфейс плагіна"

View File

@ -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"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="打开插件界面"
ClosePluginInterface="关闭插件界面"
VstPlugin="VST 2.x 插件"
OpenInterfaceWhenActive="活跃时打开界面"

View File

@ -0,0 +1,4 @@
OpenPluginInterface="開啟外掛程式界面"
ClosePluginInterface="關閉外掛程式介面"
VstPlugin="VST 2.x 外掛程式"
OpenInterfaceWhenActive="啟動時開啟界面"

View File

@ -0,0 +1,63 @@
/*****************************************************************************
Copyright (C) 2016-2017 by Colin Edwards.
Additional Code Copyright (C) 2016-2017 by c3r1c3 <c3r1c3@nevermindonline.com>
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 <http://www.gnu.org/licenses/>.
*****************************************************************************/
#ifndef OBS_STUDIO_EDITORDIALOG_H
#define OBS_STUDIO_EDITORDIALOG_H
#include <QWidget>
#if defined(_WIN32)
#include <QWindow>
#include <Windows.h>
#elif defined(__linux__)
#include <QWindow>
#include <xcb/xcb.h>
#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

View File

@ -0,0 +1,110 @@
/*****************************************************************************
Copyright (C) 2016-2017 by Colin Edwards.
Additional Code Copyright (C) 2016-2017 by c3r1c3 <c3r1c3@nevermindonline.com>
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 <http://www.gnu.org/licenses/>.
*****************************************************************************/
#ifndef OBS_STUDIO_VSTPLUGIN_H
#define OBS_STUDIO_VSTPLUGIN_H
#define BLOCK_SIZE 512
#include <mutex>
#include <atomic>
#include <string>
#include <QDirIterator>
#include <obs-module.h>
#include "aeffectx.h"
#include "vst-plugin-callbacks.hpp"
#include "EditorWidget.h"
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#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

View File

@ -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 <http://www.gnu.org/licenses/>.
*****************************************************************************/
#pragma once
#include "aeffectx.h"
typedef AEffect *(*vstPluginMain)(audioMasterCallback audioMaster);

View File

@ -0,0 +1,37 @@
/*****************************************************************************
Copyright (C) 2016-2017 by Colin Edwards.
Additional Code Copyright (C) 2016-2017 by c3r1c3 <c3r1c3@nevermindonline.com>
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 <http://www.gnu.org/licenses/>.
*****************************************************************************/
#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);
}

View File

@ -0,0 +1,65 @@
/*****************************************************************************
Copyright (C) 2016-2017 by Colin Edwards.
Additional Code Copyright (C) 2016-2017 by c3r1c3 <c3r1c3@nevermindonline.com>
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 <http://www.gnu.org/licenses/>.
*****************************************************************************/
#include "../headers/VSTPlugin.h"
#include <util/platform.h>
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*****************************************************************************/
#import "../headers/EditorWidget.h"
#import <Cocoa/Cocoa.h>
#include <QLayout>
#include <QWindow>
#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);
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*****************************************************************************/
#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);
}
}

332
plugins/obs-vst/obs-vst.cpp Normal file
View File

@ -0,0 +1,332 @@
/*****************************************************************************
Copyright (C) 2016-2017 by Colin Edwards.
Additional Code Copyright (C) 2016-2017 by c3r1c3 <c3r1c3@nevermindonline.com>
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 <http://www.gnu.org/licenses/>.
*****************************************************************************/
#include "headers/VSTPlugin.h"
#include <QCryptographicHash>
#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<QString>());
// 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;
}

View File

@ -0,0 +1,3 @@
Language: Cpp
SortIncludes: false
DisableFormat: true

View File

@ -0,0 +1,382 @@
/*
* aeffectx.h - simple header to allow VeSTige compilation and eventually work
*
* Copyright (c) 2006 Javier Serrano Polo <jasp00/at/users.sourceforge.net>
*
* 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 <stdint.h>
#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

View File

@ -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 <http://www.gnu.org/licenses/>.
*****************************************************************************/
#include <QGridLayout>
#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);
}
}

View File

@ -0,0 +1,91 @@
/*****************************************************************************
Copyright (C) 2016-2017 by Colin Edwards.
Additional Code Copyright (C) 2016-2017 by c3r1c3 <c3r1c3@nevermindonline.com>
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 <http://www.gnu.org/licenses/>.
*****************************************************************************/
#include "../headers/VSTPlugin.h"
#include "../headers/vst-plugin-callbacks.hpp"
#include <util/platform.h>
#include <windows.h>
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;
}
}