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
parent
34ff76c0e7
commit
a7c3d94e4c
|
@ -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 \
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
|
@ -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);
|
||||
}
|
|
@ -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 *>(¶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<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);
|
||||
}
|
|
@ -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"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="فتح واجهة الإضافة"
|
||||
ClosePluginInterface="إغلاق واجهة الإضافة"
|
||||
VstPlugin="إضافة VST 2.x"
|
||||
OpenInterfaceWhenActive="فتح الواجهة عند النشاط"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="Отваряне на интерфейса на приставката"
|
||||
ClosePluginInterface="Затваряне на интерфейса на приставката"
|
||||
VstPlugin="Приставка VST 2.x"
|
||||
OpenInterfaceWhenActive="Отваряне на интерфейса при задействане"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="প্লাগ-ইন ইন্টারফেসের খুলুন"
|
||||
ClosePluginInterface="প্লাগ-ইন ইন্টারফেস বন্ধ করুন"
|
||||
VstPlugin="ভিএসটি ২.x প্লাগ-ইন"
|
||||
OpenInterfaceWhenActive="সক্রিয় থাকাকালীন ইন্টারফেস খুলুন"
|
|
@ -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"
|
|
@ -0,0 +1,3 @@
|
|||
OpenPluginInterface="Otevřít rozhraní Plug-inu"
|
||||
ClosePluginInterface="Zavřít rozhraní Plug-inu"
|
||||
OpenInterfaceWhenActive="Otevřít rozhraní, pokud je aktivní"
|
|
@ -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"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="Pluginschnittstelle öffnen"
|
||||
ClosePluginInterface="Pluginschnittstelle schließen"
|
||||
VstPlugin="VST-2.x-Plugin"
|
||||
OpenInterfaceWhenActive="Schnittstelle öffnen, wenn aktiv"
|
|
@ -0,0 +1,3 @@
|
|||
OpenPluginInterface="Άνοιγμα διεπαφής Plug-in"
|
||||
ClosePluginInterface="Κλείσιμο διεπαφής Plug-in"
|
||||
OpenInterfaceWhenActive="Άνοιγμα διεπαφής όταν είναι ενεργό"
|
|
@ -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"
|
|
@ -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"
|
|
@ -0,0 +1,3 @@
|
|||
OpenPluginInterface="Avatud Plug-in liides"
|
||||
ClosePluginInterface="Sulgege Plug-in liides"
|
||||
OpenInterfaceWhenActive="Ava liides kui aktiivne"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="Ireki pluginaren interfazea"
|
||||
ClosePluginInterface="Itxi pluginaren interfazea"
|
||||
VstPlugin="VST 2.x Plugina"
|
||||
OpenInterfaceWhenActive="Ireki interfazea aktibatzen denean"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="بازکردن رابط افزونه"
|
||||
ClosePluginInterface="بستن رابط افزونه"
|
||||
VstPlugin="VST 2.x افزونه"
|
||||
OpenInterfaceWhenActive="رابط کاربری باز زمانی که فعال"
|
|
@ -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"
|
|
@ -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"
|
|
@ -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"
|
|
@ -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"
|
|
@ -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"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="פתיחת ממשק התוספים"
|
||||
ClosePluginInterface="סגירת ממשק התוספים"
|
||||
VstPlugin="תוסף VST 2.x"
|
||||
OpenInterfaceWhenActive="פתח ממשק כאשר פעיל"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="प्लग-इन इंटरफ़ेस खोलें"
|
||||
ClosePluginInterface="प्लग-इन इंटरफ़ेस बंद करें"
|
||||
VstPlugin="VST 2.x प्लग-इन"
|
||||
OpenInterfaceWhenActive="सक्रिय होने पर इंटरफ़ेस खोलें"
|
|
@ -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"
|
|
@ -0,0 +1,3 @@
|
|||
OpenPluginInterface="Buka Antarmuka Plug-in"
|
||||
ClosePluginInterface="Tutup Antarmuka Plug-in"
|
||||
OpenInterfaceWhenActive="Buka antarmuka ketika aktif"
|
|
@ -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"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="プラグインインターフェイスを開く"
|
||||
ClosePluginInterface="プラグインインターフェイスを閉じる"
|
||||
VstPlugin="VST 2.x プラグイン"
|
||||
OpenInterfaceWhenActive="アクティブな時にインターフェイスを開く"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="მოდულის სამართავის გახსნა"
|
||||
ClosePluginInterface="მოდულის სამართავის დახურვა"
|
||||
VstPlugin="VST 2.x მოდული"
|
||||
OpenInterfaceWhenActive="სამართავის გახსნა ამოქმედებისას"
|
|
@ -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"
|
|
@ -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"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="플러그인 설정 열기"
|
||||
ClosePluginInterface="플러그인 설정 닫기"
|
||||
VstPlugin="VST 2.x 플러그인"
|
||||
OpenInterfaceWhenActive="활성화 시 인터페이스 열기"
|
|
@ -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"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="Åpne utvidelsesgrensesnittet"
|
||||
ClosePluginInterface="Lukk utvidelsesgrensesnittet"
|
||||
VstPlugin="VST 2.x-utvidelse"
|
||||
OpenInterfaceWhenActive="Åpne grensesnittet når den er aktiv"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="Open Plugin Interface"
|
||||
ClosePluginInterface="Sluit Plugin Interface"
|
||||
VstPlugin="VST 2.x Plugin"
|
||||
OpenInterfaceWhenActive="Open interface indien actief"
|
|
@ -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"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="Abrir Interface do Plugin"
|
||||
ClosePluginInterface="Fechar Interface do Plugin"
|
||||
VstPlugin="Plugin VST 2.x"
|
||||
OpenInterfaceWhenActive="Abrir interface quando ativo"
|
|
@ -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"
|
|
@ -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"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="Открыть интерфейс плагина"
|
||||
ClosePluginInterface="Закрыть интерфейс плагина"
|
||||
VstPlugin="Плагин VST 2.x"
|
||||
OpenInterfaceWhenActive="Открыть интерфейс при активации"
|
|
@ -0,0 +1,3 @@
|
|||
OpenPluginInterface="Otvoriť rozhranie Plug-inu"
|
||||
ClosePluginInterface="Zavrieť rozhranie Plug-inu"
|
||||
OpenInterfaceWhenActive="Otvoriť rozhranie, keď je aktívny"
|
|
@ -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"
|
|
@ -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"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="Прикажи интерфејс за прикључак"
|
||||
ClosePluginInterface="Затвори интерфејс за прикључак"
|
||||
VstPlugin="VST 2.x прикључак"
|
||||
OpenInterfaceWhenActive="Прикажи интерфејс када је прикључак активан"
|
|
@ -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"
|
|
@ -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"
|
|
@ -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"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="Eklenti Arabirimi Aç"
|
||||
ClosePluginInterface="Eklenti Arabirimi Kapa"
|
||||
VstPlugin="VST 2.x Eklentisi"
|
||||
OpenInterfaceWhenActive="Etkinken Arabirimi Aç"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="Відкрити інтерфейс плагіна"
|
||||
ClosePluginInterface="Закрити інтерфейс плагіна"
|
||||
VstPlugin="Плагін VST 2.x"
|
||||
OpenInterfaceWhenActive="Щоразу відкривати інтерфейс плагіна"
|
|
@ -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"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="打开插件界面"
|
||||
ClosePluginInterface="关闭插件界面"
|
||||
VstPlugin="VST 2.x 插件"
|
||||
OpenInterfaceWhenActive="活跃时打开界面"
|
|
@ -0,0 +1,4 @@
|
|||
OpenPluginInterface="開啟外掛程式界面"
|
||||
ClosePluginInterface="關閉外掛程式介面"
|
||||
VstPlugin="VST 2.x 外掛程式"
|
||||
OpenInterfaceWhenActive="啟動時開啟界面"
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
Language: Cpp
|
||||
SortIncludes: false
|
||||
DisableFormat: true
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue