merged with master
This commit is contained in:
+3
-2
@@ -85,9 +85,7 @@ EffectPtr Effect::Create(Clip* c, const EffectMeta* em) {
|
||||
case EFFECT_INTERNAL_SHAKE: return std::make_shared<ShakeEffect>(c, em);
|
||||
case EFFECT_INTERNAL_CORNERPIN: return std::make_shared<CornerPinEffect>(c, em);
|
||||
case EFFECT_INTERNAL_FILLLEFTRIGHT: return std::make_shared<FillLeftRightEffect>(c, em);
|
||||
#ifndef NOVST
|
||||
case EFFECT_INTERNAL_VST: return std::make_shared<VSTHost>(c, em);
|
||||
#endif
|
||||
case EFFECT_INTERNAL_RICHTEXT: return std::make_shared<RichTextEffect>(c, em);
|
||||
}
|
||||
} else if (!em->filename.isEmpty()) {
|
||||
@@ -597,6 +595,9 @@ void Effect::load(QXmlStreamReader& stream) {
|
||||
field->keyframes.append(key);
|
||||
}
|
||||
}
|
||||
|
||||
field->Changed();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "global/path.h"
|
||||
#include "panels/panels.h"
|
||||
#include "panels/effectcontrols.h"
|
||||
#include "global/crossplatformlib.h"
|
||||
#include "global/config.h"
|
||||
|
||||
QMutex olive::effects_loaded;
|
||||
@@ -55,11 +54,9 @@ void load_internal_effects() {
|
||||
em.internal = EFFECT_INTERNAL_PAN;
|
||||
olive::effects.append(em);
|
||||
|
||||
#ifndef NOVST
|
||||
em.name = "VST Plugin 2.x";
|
||||
em.internal = EFFECT_INTERNAL_VST;
|
||||
olive::effects.append(em);
|
||||
#endif
|
||||
|
||||
em.name = "Tone";
|
||||
em.internal = EFFECT_INTERNAL_TONE;
|
||||
|
||||
@@ -60,11 +60,6 @@ bool EffectRow::IsKeyframing() {
|
||||
}
|
||||
|
||||
void EffectRow::SetKeyframingInternal(bool b) {
|
||||
// No need to run this function if the keyframing state isn't actually changing.
|
||||
if (b == keyframing_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetParentEffect()->meta->type != EFFECT_TYPE_TRANSITION) {
|
||||
keyframing_ = b;
|
||||
emit KeyframingSetChanged(keyframing_);
|
||||
@@ -127,7 +122,6 @@ void EffectRow::SetKeyframingEnabled(bool enabled) {
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
SetKeyframingInternal(true);
|
||||
|
||||
}
|
||||
|
||||
@@ -32,18 +32,67 @@ class BoolField : public EffectField
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* @brief See Effect::Effect().
|
||||
*/
|
||||
BoolField(EffectRow* parent, const QString& id);
|
||||
|
||||
/**
|
||||
* @brief Get the boolean value at a given timecode
|
||||
*
|
||||
* A convenience function, equivalent to GetValueAt(timecode).toBool()
|
||||
*
|
||||
* @param timecode
|
||||
*
|
||||
* The timecode to retrieve the value at
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* The boolean value at this timecode
|
||||
*/
|
||||
bool GetBoolAt(double timecode);
|
||||
|
||||
/**
|
||||
* @brief See EffectField::CreateWidget()
|
||||
*/
|
||||
virtual QWidget* CreateWidget(QWidget *existing = nullptr) override;
|
||||
|
||||
/**
|
||||
* @brief See EffectField::UpdateWidgetValue()
|
||||
*/
|
||||
virtual void UpdateWidgetValue(QWidget* widget, double timecode) override;
|
||||
|
||||
/**
|
||||
* @brief See EffectField::ConvertStringToValue()
|
||||
*/
|
||||
virtual QVariant ConvertStringToValue(const QString& s) override;
|
||||
|
||||
/**
|
||||
* @brief See EffectField::ConvertValueToString()
|
||||
*/
|
||||
virtual QString ConvertValueToString(const QVariant& v) override;
|
||||
signals:
|
||||
/**
|
||||
* @brief Emitted whenever the UI widget's boolean value has changed
|
||||
*
|
||||
* For any QCheckBox created through this field's CreateWidget() function, this signal is emitted any time the
|
||||
* checkbox value changes (either through user intervention or keyframing). It is mostly useful for
|
||||
* enabling/disabling/changing other UI elements based on the checked
|
||||
* state of this field's value (e.g. enabling other fields if this field is checked).
|
||||
*
|
||||
* It is NOT a reliable signal that the value has changed at all, as it is only emitted if a widget (created
|
||||
* from CreateWidget() ) is currently active.
|
||||
*/
|
||||
void Toggled(bool);
|
||||
private slots:
|
||||
/**
|
||||
* @brief Internal function connected to any QWidget made from CreateWidget() to update the value based on user input
|
||||
*
|
||||
* @param b
|
||||
*
|
||||
* The current checked state of the QWidget (QCheckBox in this case). Automatically set when this slot is connected
|
||||
* to the QCheckBox::toggled() signal.
|
||||
*/
|
||||
void UpdateFromWidget(bool b);
|
||||
};
|
||||
|
||||
|
||||
@@ -23,26 +23,86 @@
|
||||
|
||||
#include "../effectfield.h"
|
||||
|
||||
/**
|
||||
* @brief The ButtonField class
|
||||
*
|
||||
* A UI-type EffectField. This field is largely an EffectField wrapper around a QPushButton and provides no data that's
|
||||
* usable in the Effect. It's primarily useful for other UI functions (e.g. showing/hiding a dialog or other UI
|
||||
* elements). This field is not exposed to the external shader API as it requires raw C++ code to connect it to other
|
||||
* elements.
|
||||
*
|
||||
* As with all widgets created from EffectField::CreateWidget(), you should never interface with the resulting widget
|
||||
* directly (apart from adding it to a layout and deleting it when it's unnecessary). All signals/slots should pass
|
||||
* through ButtonField instead to keep consistency with every layer involved.
|
||||
*/
|
||||
class ButtonField : public EffectField
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* @brief See Effect::Effect().
|
||||
*/
|
||||
ButtonField(EffectRow* parent, const QString& string);
|
||||
|
||||
/**
|
||||
* @brief Set whether this pushbutton is checkable
|
||||
*
|
||||
* This function is mainly a wrapper around QPushButton::setCheckable().
|
||||
*
|
||||
* "Checkable" means the button can be toggled between a state of being "normal" and being "pressed". In checkable
|
||||
* mode this field still cannot be used as a value in an Effect. Instead use BoolField (which uses a QCheckBox
|
||||
* representation) for passing values to the Effect that can only be true or false.
|
||||
*
|
||||
* @param c
|
||||
*
|
||||
* TRUE if this button should be checkable or not.
|
||||
*/
|
||||
void SetCheckable(bool c);
|
||||
|
||||
/**
|
||||
* @brief See EffectField::CreateWidget()
|
||||
*/
|
||||
virtual QWidget* CreateWidget(QWidget *existing = nullptr) override;
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief A slot for when a widget's (created and connected from CreateWidget() ) checked state is changed
|
||||
*
|
||||
* @param c
|
||||
*
|
||||
* The current checked state (automatically filled by the QPushButton::toggled() signal)
|
||||
*/
|
||||
void SetChecked(bool c);
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief A signal emitted whenever the field's internal checked state is changed
|
||||
*
|
||||
* Primarily used to set any connected widget's checked state to be consistent with the field's.
|
||||
*/
|
||||
void CheckedChanged(bool);
|
||||
|
||||
/**
|
||||
* @brief A signal emitted whenever the checked state of a connected widget changes
|
||||
*
|
||||
* Any widgets associated with this field will emit this signal when their checked state changes.
|
||||
*/
|
||||
void Toggled(bool);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Internal button text string passed to widgets created by CreateWidget()
|
||||
*/
|
||||
bool checkable_;
|
||||
|
||||
/**
|
||||
* @brief Internal checked value passed to and from widgets created by CreateWidget()
|
||||
*/
|
||||
bool checked_;
|
||||
|
||||
/**
|
||||
* @brief Internal button text string passed to widgets created by CreateWidget()
|
||||
*/
|
||||
QString button_text_;
|
||||
};
|
||||
|
||||
|
||||
@@ -20,12 +20,15 @@
|
||||
|
||||
#include "filefield.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include "ui/embeddedfilechooser.h"
|
||||
|
||||
FileField::FileField(EffectRow* parent, const QString &id) :
|
||||
EffectField(parent, id, EFFECT_FIELD_FILE)
|
||||
{
|
||||
|
||||
// Set default value to an empty string
|
||||
SetValueAt(0, "");
|
||||
}
|
||||
|
||||
QString FileField::GetFileAt(double timecode)
|
||||
@@ -43,6 +46,15 @@ QWidget *FileField::CreateWidget(QWidget *existing)
|
||||
return efc;
|
||||
}
|
||||
|
||||
void FileField::UpdateWidgetValue(QWidget *widget, double timecode)
|
||||
{
|
||||
EmbeddedFileChooser* efc = static_cast<EmbeddedFileChooser*>(widget);
|
||||
|
||||
efc->blockSignals(true);
|
||||
efc->setFilename(GetFileAt(timecode));
|
||||
efc->blockSignals(false);
|
||||
}
|
||||
|
||||
void FileField::UpdateFromWidget(const QString &s)
|
||||
{
|
||||
KeyframeDataChange* kdc = new KeyframeDataChange(this);
|
||||
|
||||
@@ -32,6 +32,7 @@ public:
|
||||
QString GetFileAt(double timecode);
|
||||
|
||||
virtual QWidget* CreateWidget(QWidget *existing = nullptr) override;
|
||||
virtual void UpdateWidgetValue(QWidget *widget, double timecode) override;
|
||||
private slots:
|
||||
void UpdateFromWidget(const QString &s);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2019 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "frei0reffect.h"
|
||||
|
||||
#ifndef NOFREI0R
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QDir>
|
||||
|
||||
#include "timeline/clip.h"
|
||||
|
||||
typedef f0r_instance_t (*f0rConstructFunc)(unsigned int width, unsigned int height);
|
||||
typedef int (*f0rInitFunc) ();
|
||||
typedef void (*f0rDeinitFunc) ();
|
||||
typedef void (*f0rUpdateFunc) (f0r_instance_t instance,
|
||||
double time, const uint32_t* inframe, uint32_t* outframe);
|
||||
typedef void (*f0rDestructFunc)(f0r_instance_t instance);
|
||||
typedef void (*f0rGetPluginInfo)(f0r_plugin_info_t* info);
|
||||
typedef void (*f0rSetParamValue) (f0r_instance_t instance,
|
||||
f0r_param_t param, int param_index);
|
||||
|
||||
Frei0rEffect::Frei0rEffect(Clip* c, const EffectMeta *em) :
|
||||
Effect(c, em),
|
||||
open(false)
|
||||
{
|
||||
SetFlags(ImageFlag);
|
||||
|
||||
// Windows DLL loading routine
|
||||
QString dll_fn = QDir(em->path).filePath(em->filename);
|
||||
|
||||
handle.setFileName(dll_fn);
|
||||
|
||||
|
||||
if (!handle.load()) {
|
||||
QString dll_error = handle.errorString();
|
||||
QMessageBox::critical(nullptr, tr("Error loading Frei0r plugin"),
|
||||
tr("Failed to load Frei0r plugin \"%1\": %2").arg(dll_fn, dll_error));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
f0rInitFunc init = reinterpret_cast<f0rInitFunc>(handle.resolve("f0r_init"));
|
||||
init();
|
||||
|
||||
construct_module();
|
||||
|
||||
f0r_plugin_info_t info;
|
||||
f0rGetPluginInfo info_func = reinterpret_cast<f0rGetPluginInfo>(handle.resolve("f0r_get_plugin_info"));
|
||||
info_func(&info);
|
||||
|
||||
param_count = info.num_params;
|
||||
|
||||
get_param_info = reinterpret_cast<f0rGetParamInfo>(handle.resolve("f0r_get_param_info"));
|
||||
for (int i=0;i<param_count;i++) {
|
||||
f0r_param_info_t param_info;
|
||||
get_param_info(¶m_info, i);
|
||||
|
||||
if (param_info.type >= 0 && param_info.type <= F0R_PARAM_STRING) {
|
||||
EffectRow* row = new EffectRow(this, param_info.name);
|
||||
switch (param_info.type) {
|
||||
case F0R_PARAM_BOOL:
|
||||
new BoolField(row, QString::number(i));
|
||||
break;
|
||||
case F0R_PARAM_DOUBLE:
|
||||
{
|
||||
DoubleField* f = new DoubleField(row, QString::number(i));
|
||||
f->SetMinimum(0);
|
||||
f->SetMaximum(100);
|
||||
}
|
||||
break;
|
||||
case F0R_PARAM_COLOR:
|
||||
new ColorField(row, QString::number(i));
|
||||
break;
|
||||
case F0R_PARAM_POSITION:
|
||||
{
|
||||
DoubleField* fx = new DoubleField(row, QString("%1X").arg(QString::number(i)));
|
||||
fx->SetMinimum(0);
|
||||
fx->SetMaximum(100);
|
||||
DoubleField* fy = new DoubleField(row, QString("%1Y").arg(QString::number(i)));
|
||||
fy->SetMinimum(0);
|
||||
fy->SetMaximum(100);
|
||||
}
|
||||
break;
|
||||
case F0R_PARAM_STRING:
|
||||
new StringField(row, QString::number(i), false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Frei0rEffect::~Frei0rEffect() {
|
||||
if (handle.isLoaded()) {
|
||||
f0rDeinitFunc deinit = reinterpret_cast<f0rDeinitFunc>(handle.resolve("f0r_deinit"));
|
||||
deinit();
|
||||
|
||||
handle.unload();
|
||||
}
|
||||
}
|
||||
|
||||
void Frei0rEffect::process_image(double timecode, uint8_t *input, uint8_t *output, int) {
|
||||
f0rUpdateFunc update_func = reinterpret_cast<f0rUpdateFunc>(handle.resolve("f0r_update"));
|
||||
|
||||
for (int i=0;i<param_count;i++) {
|
||||
EffectRow* param_row = row(i);
|
||||
|
||||
f0r_param_info_t param_info;
|
||||
get_param_info(¶m_info, i);
|
||||
|
||||
f0rSetParamValue set_param = reinterpret_cast<f0rSetParamValue>(handle.resolve("f0r_set_param_value"));
|
||||
switch (param_info.type) {
|
||||
case F0R_PARAM_BOOL:
|
||||
{
|
||||
double b = param_row->Field(0)->GetValueAt(timecode).toBool();
|
||||
set_param(instance, &b, i);
|
||||
}
|
||||
break;
|
||||
case F0R_PARAM_DOUBLE:
|
||||
{
|
||||
double d = param_row->Field(0)->GetValueAt(timecode).toDouble()*0.01;
|
||||
set_param(instance, &d, i);
|
||||
}
|
||||
break;
|
||||
case F0R_PARAM_COLOR:
|
||||
{
|
||||
QColor qcolor = param_row->Field(0)->GetValueAt(timecode).value<QColor>();
|
||||
|
||||
f0r_param_color fcolor;
|
||||
fcolor.r = float(qcolor.redF());
|
||||
fcolor.g = float(qcolor.greenF());
|
||||
fcolor.b = float(qcolor.blueF());
|
||||
|
||||
set_param(instance, &fcolor, i);
|
||||
}
|
||||
break;
|
||||
case F0R_PARAM_POSITION:
|
||||
{
|
||||
f0r_param_position pos;
|
||||
pos.x = param_row->Field(0)->GetValueAt(timecode).toDouble();
|
||||
pos.y = param_row->Field(1)->GetValueAt(timecode).toDouble();
|
||||
set_param(instance, &pos, i);
|
||||
}
|
||||
break;
|
||||
case F0R_PARAM_STRING:
|
||||
{
|
||||
QByteArray bytes = param_row->Field(0)->GetValueAt(timecode).toString().toUtf8();
|
||||
char* byte_data = bytes.data();
|
||||
set_param(instance, &byte_data, i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
update_func(instance, timecode, reinterpret_cast<uint32_t*>(input), reinterpret_cast<uint32_t*>(output));
|
||||
}
|
||||
|
||||
void Frei0rEffect::refresh() {
|
||||
destruct_module();
|
||||
construct_module();
|
||||
}
|
||||
|
||||
void Frei0rEffect::destruct_module() {
|
||||
if (open) {
|
||||
f0rDestructFunc destruct = reinterpret_cast<f0rDestructFunc>(handle.resolve("f0r_destruct"));
|
||||
destruct(instance);
|
||||
|
||||
open = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Frei0rEffect::construct_module() {
|
||||
f0rConstructFunc construct = reinterpret_cast<f0rConstructFunc>(handle.resolve("f0r_construct"));
|
||||
instance = construct(parent_clip->media_width(), parent_clip->media_height());
|
||||
|
||||
open = true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,55 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2019 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef FREI0REFFECT_H
|
||||
#define FREI0REFFECT_H
|
||||
|
||||
#ifndef NOFREI0R
|
||||
|
||||
#include <QLibrary>
|
||||
#include <frei0r.h>
|
||||
|
||||
#include "effects/effect.h"
|
||||
|
||||
typedef void (*f0rGetParamInfo)(f0r_param_info_t * info,
|
||||
int param_index );
|
||||
|
||||
class Frei0rEffect : public Effect {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Frei0rEffect(Clip* c, const EffectMeta* em);
|
||||
~Frei0rEffect();
|
||||
|
||||
virtual void process_image(double timecode, uint8_t* input, uint8_t* output, int size);
|
||||
|
||||
virtual void refresh();
|
||||
private:
|
||||
QLibrary handle;
|
||||
f0r_instance_t instance;
|
||||
int param_count;
|
||||
f0rGetParamInfo get_param_info;
|
||||
void destruct_module();
|
||||
void construct_module();
|
||||
bool open;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // FREI0REFFECT_H
|
||||
@@ -34,7 +34,14 @@
|
||||
#include "global/global.h"
|
||||
#include "global/debug.h"
|
||||
|
||||
#ifdef __linux__
|
||||
// Load libraries for retrieving the native window handle. Used for VST plugins that have a separate window
|
||||
// dedicated to controls.
|
||||
#if defined(Q_OS_WIN)
|
||||
#include <Windows.h>
|
||||
#elif defined(Q_OS_MACOS)
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
class NSWindow;
|
||||
#elif defined(Q_OS_LINUX)
|
||||
#include <X11/X.h>
|
||||
#endif
|
||||
|
||||
@@ -105,94 +112,53 @@ typedef int32_t (*processEventsFuncPtr)(VstEvents *events);
|
||||
typedef void (*processFuncPtr)(AEffect *effect, float **inputs, float **outputs, int32_t sampleFrames);
|
||||
|
||||
void VSTHost::loadPlugin() {
|
||||
|
||||
QString dll_fn = file_field->GetFileAt(0);
|
||||
|
||||
if (dll_fn.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
bundle = BundleLoad(dll_fn);
|
||||
// Try to load the plugin
|
||||
modulePtr.setFileName(dll_fn);
|
||||
if (!modulePtr.load()) {
|
||||
|
||||
if (bundle == NULL) {
|
||||
QMessageBox::critical(nullptr, tr("Error loading VST plugin"), tr("Failed to create VST reference"));
|
||||
// Show an error if the plugin fails to load
|
||||
|
||||
qCritical() << "Failed to load VST plugin" << dll_fn << "-" << modulePtr.errorString();
|
||||
QMessageBox::critical(olive::MainWindow,
|
||||
tr("Error loading VST plugin"),
|
||||
tr("Failed to load VST plugin \"%1\": %2").arg(dll_fn, modulePtr.errorString()));
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
vstPluginFuncPtr mainEntryPoint = NULL;
|
||||
mainEntryPoint = (vstPluginFuncPtr)CFBundleGetFunctionPointerForName(bundle, CFSTR("VSTPluginMain"));
|
||||
// VST plugins previous to the 2.4 SDK used main_macho for the entry point name
|
||||
if(mainEntryPoint == NULL) {
|
||||
mainEntryPoint = (vstPluginFuncPtr)CFBundleGetFunctionPointerForName(bundle, CFSTR("main_macho"));
|
||||
// Try to find the VST entry point (first using VSTPluginMain() )
|
||||
vstPluginFuncPtr mainEntryPoint = reinterpret_cast<vstPluginFuncPtr>(modulePtr.resolve("VSTPluginMain"));
|
||||
|
||||
if (mainEntryPoint == nullptr) {
|
||||
// If there's no VSTPluginMain(), the plugin may use main() instead
|
||||
mainEntryPoint = reinterpret_cast<vstPluginFuncPtr>(modulePtr.resolve("main"));
|
||||
}
|
||||
if(mainEntryPoint == NULL) {
|
||||
qCritical() << "Couldn't get a pointer to VST plugin's main()";
|
||||
BundleClose(bundle);
|
||||
|
||||
if (mainEntryPoint == nullptr) {
|
||||
QMessageBox::critical(olive::MainWindow,
|
||||
tr("Error loading VST plugin"),
|
||||
tr("Failed to locate entry point for dynamic library."));
|
||||
modulePtr.unload();
|
||||
return;
|
||||
}
|
||||
|
||||
// Instantiate the plugin
|
||||
plugin = mainEntryPoint(hostCallback);
|
||||
if(plugin == NULL) {
|
||||
qCritical() << "Plugin's main() returns null";
|
||||
BundleClose(bundle);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
modulePtr = LibLoad(dll_fn);
|
||||
if(modulePtr == nullptr) {
|
||||
QString dll_error;
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD dll_err = GetLastError();
|
||||
dll_error = QString::number(dll_err);
|
||||
#elif defined(__linux__) || defined(__HAIKU__)
|
||||
dll_error = dlerror();
|
||||
#endif
|
||||
qCritical() << "Failed to load VST plugin" << dll_fn << "-" << dll_error;
|
||||
|
||||
QString msg_err = tr("Failed to load VST plugin \"%1\": %2").arg(dll_fn, dll_error);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (dll_err == 193) {
|
||||
#ifdef _WIN64
|
||||
msg_err += "\n\n" + tr("NOTE: You can't load 32-bit VST plugins into a 64-bit build of Olive. Please find a 64-bit version of this plugin or switch to a 32-bit build of Olive.");
|
||||
#elif _WIN32
|
||||
msg_err += "\n\n" + tr("NOTE: You can't load 64-bit VST plugins into a 32-bit build of Olive. Please find a 32-bit version of this plugin or switch to a 64-bit build of Olive.");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
QMessageBox::critical(nullptr, tr("Error loading VST plugin"), msg_err);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
vstPluginFuncPtr mainEntryPoint = reinterpret_cast<vstPluginFuncPtr>(LibAddress(modulePtr, "VSTPluginMain"));
|
||||
|
||||
if (mainEntryPoint == nullptr) {
|
||||
// if there's no VSTPluginMain(), fallback to main()
|
||||
mainEntryPoint = reinterpret_cast<vstPluginFuncPtr>(LibAddress(modulePtr, "main"));
|
||||
}
|
||||
|
||||
if (mainEntryPoint == nullptr) {
|
||||
QMessageBox::critical(nullptr, tr("Error loading VST plugin"), tr("Failed to locate entry point for dynamic library."));
|
||||
LibClose(modulePtr);
|
||||
} else {
|
||||
// Instantiate the plugin
|
||||
plugin = mainEntryPoint(hostCallback);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void VSTHost::freePlugin() {
|
||||
if (plugin != nullptr) {
|
||||
stopPlugin();
|
||||
#if defined(__APPLE__)
|
||||
CFBundleUnloadExecutable(bundle);
|
||||
CFRelease(bundle);
|
||||
#else
|
||||
LibClose(modulePtr);
|
||||
#endif
|
||||
data_cache.clear();
|
||||
modulePtr.unload();
|
||||
plugin = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -266,6 +232,11 @@ void VSTHost::CreateDialogIfNull()
|
||||
}
|
||||
}
|
||||
|
||||
void VSTHost::send_data_cache_to_plugin()
|
||||
{
|
||||
dispatcher(plugin, effSetChunk, 0, int32_t(data_cache.size()), static_cast<void*>(data_cache.data()), 0);
|
||||
}
|
||||
|
||||
VSTHost::VSTHost(Clip* c, const EffectMeta *em) :
|
||||
Effect(c, em),
|
||||
plugin(nullptr),
|
||||
@@ -282,7 +253,7 @@ VSTHost::VSTHost(Clip* c, const EffectMeta *em) :
|
||||
|
||||
EffectRow* file_row = new EffectRow(this, tr("Plugin"), true, false);
|
||||
file_field = new FileField(file_row, "filename");
|
||||
connect(file_field, SIGNAL(Changed()), this, SLOT(change_plugin()));
|
||||
connect(file_field, SIGNAL(Changed()), this, SLOT(change_plugin()), Qt::QueuedConnection);
|
||||
|
||||
EffectRow* interface_row = new EffectRow(this, tr("Interface"), false, false);
|
||||
|
||||
@@ -344,7 +315,7 @@ void VSTHost::custom_load(QXmlStreamReader &stream) {
|
||||
stream.readNext();
|
||||
data_cache = QByteArray::fromBase64(stream.text().toUtf8());
|
||||
if (plugin != nullptr) {
|
||||
dispatcher(plugin, effSetChunk, 0, int32_t(data_cache.size()), static_cast<void*>(data_cache.data()), 0);
|
||||
send_data_cache_to_plugin();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -366,11 +337,11 @@ void VSTHost::show_interface(bool show) {
|
||||
dialog->setVisible(show);
|
||||
|
||||
if (show) {
|
||||
#if defined(_WIN32)
|
||||
#if defined(Q_OS_WIN)
|
||||
dispatcher(plugin, effEditOpen, 0, 0, reinterpret_cast<HWND>(dialog->windowHandle()->winId()), 0);
|
||||
#elif defined(__APPLE__)
|
||||
#elif defined(Q_OS_MACOS)
|
||||
dispatcher(plugin, effEditOpen, 0, 0, reinterpret_cast<NSWindow*>(dialog->windowHandle()->winId()), 0);
|
||||
#elif defined(__linux__) || defined(__HAIKU__)
|
||||
#elif defined(Q_OS_LINUX) || defined(__HAIKU__)
|
||||
dispatcher(plugin, effEditOpen, 0, 0, reinterpret_cast<void*>(dialog->windowHandle()->winId()), 0);
|
||||
#endif
|
||||
} else {
|
||||
@@ -392,17 +363,18 @@ void VSTHost::change_plugin() {
|
||||
VSTRect* eRect = nullptr;
|
||||
plugin->dispatcher(plugin, effEditGetRect, 0, 0, &eRect, 0);
|
||||
|
||||
if (!data_cache.isEmpty()) {
|
||||
send_data_cache_to_plugin();
|
||||
}
|
||||
|
||||
CreateDialogIfNull();
|
||||
dialog->setFixedSize(eRect->right - eRect->left, eRect->bottom - eRect->top);
|
||||
|
||||
} else {
|
||||
#ifdef __APPLE__
|
||||
CFBundleUnloadExecutable(bundle);
|
||||
CFRelease(bundle);
|
||||
#else
|
||||
LibClose(modulePtr);
|
||||
#endif
|
||||
|
||||
modulePtr.unload();
|
||||
plugin = nullptr;
|
||||
|
||||
}
|
||||
}
|
||||
show_interface_btn->SetEnabled(plugin != nullptr);
|
||||
|
||||
@@ -21,19 +21,15 @@
|
||||
#ifndef VSTHOSTWIN_H
|
||||
#define VSTHOSTWIN_H
|
||||
|
||||
#ifndef NOVST
|
||||
#include <QDialog>
|
||||
#include <QLibrary>
|
||||
|
||||
#include "effects/effect.h"
|
||||
|
||||
#include "global/crossplatformlib.h"
|
||||
|
||||
#include "include/vestige.h"
|
||||
|
||||
// Plugin's dispatcher function
|
||||
typedef intptr_t (*dispatcherFuncPtr)(AEffect *effect, int32_t opCode, int32_t index, int32_t value, void *ptr, float opt);
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class VSTHost : public Effect {
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -68,13 +64,9 @@ private:
|
||||
QDialog* dialog;
|
||||
QByteArray data_cache;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
CFBundleRef bundle;
|
||||
#else
|
||||
ModulePtr modulePtr;
|
||||
#endif
|
||||
void send_data_cache_to_plugin();
|
||||
|
||||
QLibrary modulePtr;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // VSTHOSTWIN_H
|
||||
|
||||
Reference in New Issue
Block a user