completed winvst frontend

This commit is contained in:
itsmattkc
2019-01-09 00:04:20 +11:00
parent b8bc25d408
commit db2815ce09
11 changed files with 228 additions and 60 deletions
+65 -39
View File
@@ -6,6 +6,7 @@
#include <QPushButton>
#include <QDialog>
#include <QMessageBox>
#include "playback/audio.h"
#include "mainwindow.h"
@@ -48,17 +49,22 @@ typedef VstInt32 (*processEventsFuncPtr)(VstEvents *events);
typedef void (*processFuncPtr)(AEffect *effect, float **inputs, float **outputs, VstInt32 sampleFrames);
void VSTHostWin::loadPlugin() {
plugin = NULL;
QString dll_fn = file_field->get_filename(0, true);
LPCWSTR dll_fn_w = reinterpret_cast<const wchar_t*>(dll_fn.utf16());
const char* vst_path = "C:\\Program Files\\VSTPlugins\\ReaPlugs\\reaeq-standalone.dll";
wchar_t win_char[200];
mbstowcs(win_char, vst_path, 200);
HMODULE modulePtr = LoadLibrary(win_char);
modulePtr = LoadLibrary(dll_fn_w);
if(modulePtr == NULL) {
DWORD dll_err = GetLastError();
dout << "[ERROR] Failed to load VST" << vst_path << "-" << dll_err;
if (dll_err == 193) dout << " Mixing 32-bit and 64-bit?";
dout << "[ERROR] Failed to load VST" << dll_fn_w << "-" << dll_err;
QString msg_err = "Failed to load VST plugin \"" + dll_fn + "\": " + QString::number(dll_err);
if (dll_err == 193) {
#ifdef _WIN64
msg_err += "\n\nNOTE: 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\nNOTE: 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
}
QMessageBox::critical(mainWindow, "Error loading VST plugin", msg_err);
return;
}
@@ -68,13 +74,14 @@ void VSTHostWin::loadPlugin() {
plugin = mainEntryPoint(hostCallback);
}
int VSTHostWin::configurePluginCallbacks() {
bool VSTHostWin::configurePluginCallbacks() {
// Check plugin's magic number
// If incorrect, then the file either was not loaded properly, is not a
// real VST plugin, or is otherwise corrupt.
if(plugin->magic != kEffectMagic) {
printf("Plugin's magic number is bad\n");
return -1;
dout << "[ERROR] Plugin's magic number is bad";
QMessageBox::critical(mainWindow, "VST Error", "Plugin's magic number is invalid");
return false;
}
// Create dispatcher handle
@@ -85,8 +92,7 @@ int VSTHostWin::configurePluginCallbacks() {
plugin->processReplacing = (processFuncPtr)plugin->processReplacing;
plugin->setParameter = (setParameterFuncPtr)plugin->setParameter;
//return plugin;
return 0;
return true;
}
void VSTHostWin::startPlugin() {
@@ -99,6 +105,12 @@ void VSTHostWin::startPlugin() {
resumePlugin();
}
void VSTHostWin::stopPlugin() {
suspendPlugin();
dispatcher(plugin, effClose, 0, 0, NULL, 0);
}
void VSTHostWin::resumePlugin() {
dispatcher(plugin, effMainsChanged, 0, 1, NULL, 0.0f);
}
@@ -125,42 +137,33 @@ void VSTHostWin::initializeIO() {
void VSTHostWin::processAudio(long numFrames) {
// Always reset the output array before processing.
silenceChannel(outputs, CHANNEL_COUNT, numFrames);
for (int i=0;i<CHANNEL_COUNT;i++) {
memset(outputs[i], 0, BLOCK_SIZE*sizeof(float));
}
plugin->processReplacing(plugin, inputs, outputs, numFrames);
}
void VSTHostWin::silenceChannel(float **channelData, int numChannels, long numFrames) {
for(int channel = 0; channel < numChannels; ++channel) {
for(long frame = 0; frame < numFrames; ++frame) {
channelData[channel][frame] = 0.0f;
}
}
}
VSTHostWin::VSTHostWin(Clip* c, const EffectMeta *em) : Effect(c, em) {
EffectRow* interface_row = add_row("Interface");
plugin = NULL;
initializeIO();
file_field = add_row("Plugin", true, false)->add_field(EFFECT_FIELD_FILE, "filename");
connect(file_field, SIGNAL(changed()), this, SLOT(change_plugin()));
EffectRow* interface_row = add_row("Interface", false, false);
show_interface_btn = new QPushButton("Show");
show_interface_btn->setCheckable(true);
show_interface_btn->setEnabled(false);
connect(show_interface_btn, SIGNAL(toggled(bool)), this, SLOT(show_interface(bool)));
interface_row->add_widget(show_interface_btn);
loadPlugin();
if (plugin != NULL) {
initializeIO();
configurePluginCallbacks();
startPlugin();
dialog = new QDialog(mainWindow);
dialog->setWindowTitle("VST Plugin");
dialog->setAttribute(Qt::WA_NativeWindow, true);
dialog->setWindowFlags(dialog->windowFlags() | Qt::MSWindowsFixedSizeDialogHint);
connect(dialog, SIGNAL(finished(int)), this, SLOT(uncheck_show_button()));
dispatcher(plugin, effEditOpen, 0, 0, reinterpret_cast<HWND>(dialog->winId()), 0);
ERect* eRect = NULL;
plugin->dispatcher(plugin, effEditGetRect, 0, 0, &eRect, 0);
dialog->setFixedWidth(eRect->right);
dialog->setFixedHeight(eRect->bottom);
}
dialog = new QDialog(mainWindow);
dialog->setWindowTitle("VST Plugin");
dialog->setAttribute(Qt::WA_NativeWindow, true);
dialog->setWindowFlags(dialog->windowFlags() | Qt::MSWindowsFixedSizeDialogHint);
connect(dialog, SIGNAL(finished(int)), this, SLOT(uncheck_show_button()));
}
void VSTHostWin::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) {
@@ -215,3 +218,26 @@ void VSTHostWin::show_interface(bool show) {
void VSTHostWin::uncheck_show_button() {
show_interface_btn->setChecked(false);
}
void VSTHostWin::change_plugin() {
if (plugin != NULL) {
stopPlugin();
FreeLibrary(modulePtr);
plugin = NULL;
}
loadPlugin();
if (plugin != NULL) {
if (configurePluginCallbacks()) {
startPlugin();
dispatcher(plugin, effEditOpen, 0, 0, reinterpret_cast<HWND>(dialog->winId()), 0);
ERect* eRect = NULL;
plugin->dispatcher(plugin, effEditGetRect, 0, 0, &eRect, 0);
dialog->setFixedWidth(eRect->right);
dialog->setFixedHeight(eRect->bottom);
} else {
FreeLibrary(modulePtr);
plugin = NULL;
}
}
show_interface_btn->setEnabled(plugin != NULL);
}
+6 -2
View File
@@ -19,22 +19,26 @@ public:
private slots:
void show_interface(bool show);
void uncheck_show_button();
void change_plugin();
private:
EffectField* file_field;
void loadPlugin();
dispatcherFuncPtr dispatcher;
AEffect* plugin;
int configurePluginCallbacks();
bool configurePluginCallbacks();
void startPlugin();
void stopPlugin();
void resumePlugin();
void suspendPlugin();
bool canPluginDo(char *canDoString);
void initializeIO();
void processAudio(long numFrames);
void silenceChannel(float **channelData, int numChannels, long numFrames);
float** inputs;
float** outputs;
QDialog* dialog;
QPushButton* show_interface_btn;
HMODULE modulePtr;
};
#endif // VSTHOSTWIN_H
+4 -2
View File
@@ -118,7 +118,8 @@ SOURCES += \
project/keyframe.cpp \
ui/rectangleselect.cpp \
dialogs/actionsearch.cpp \
effects/internal/vsthostwin.cpp
effects/internal/vsthostwin.cpp \
ui/embeddedfilechooser.cpp
HEADERS += \
mainwindow.h \
@@ -206,7 +207,8 @@ HEADERS += \
project/keyframe.h \
ui/rectangleselect.h \
dialogs/actionsearch.h \
effects/internal/vsthostwin.h
effects/internal/vsthostwin.h \
ui/embeddedfilechooser.h
FORMS +=
+20 -5
View File
@@ -313,6 +313,8 @@ Effect::Effect(Clip* c, const EffectMeta *em) :
type = EFFECT_FIELD_FONT;
} else if (comp == "STRING") {
type = EFFECT_FIELD_STRING;
} else if (comp == "FILE") {
type = EFFECT_FIELD_FILE;
}
} else if (attr.name() == "id") {
id = attr.value().toString();
@@ -405,6 +407,14 @@ Effect::Effect(Clip* c, const EffectMeta *em) :
}
}
break;
case EFFECT_FIELD_FILE:
for (int i=0;i<attributes.size();i++) {
const QXmlStreamAttribute& attr = attributes.at(i);
if (attr.name() == "filename") {
field->set_filename(attr.value().toString());
}
}
break;
}
}
}
@@ -477,7 +487,7 @@ void Effect::copy_field_keyframes(Effect* e) {
}
}
EffectRow* Effect::add_row(const QString& name, bool savable) {
EffectRow* Effect::add_row(const QString& name, bool savable, bool keyframable) {
EffectRow* row = new EffectRow(this, savable, ui_layout, name, rows.size());
rows.append(row);
return row;
@@ -586,10 +596,12 @@ QVariant load_data_from_string(int type, const QString& string) {
switch (type) {
case EFFECT_FIELD_DOUBLE: return string.toDouble();
case EFFECT_FIELD_COLOR: return QColor(string);
case EFFECT_FIELD_STRING: return string;
case EFFECT_FIELD_BOOL: return (string == "1");
case EFFECT_FIELD_COMBO: return string.toInt();
case EFFECT_FIELD_FONT: return string;
case EFFECT_FIELD_STRING:
case EFFECT_FIELD_FONT:
case EFFECT_FIELD_FILE:
return string;
}
return QVariant();
}
@@ -598,10 +610,12 @@ QString save_data_to_string(int type, const QVariant& data) {
switch (type) {
case EFFECT_FIELD_DOUBLE: return QString::number(data.toDouble());
case EFFECT_FIELD_COLOR: return data.value<QColor>().name();
case EFFECT_FIELD_STRING: return data.toString();
case EFFECT_FIELD_BOOL: return QString::number(data.toBool());
case EFFECT_FIELD_COMBO: return QString::number(data.toInt());
case EFFECT_FIELD_FONT: return data.toString();
case EFFECT_FIELD_STRING:
case EFFECT_FIELD_FONT:
case EFFECT_FIELD_FILE:
return data.toString();
}
return QString();
}
@@ -872,6 +886,7 @@ void Effect::process_shader(double timecode, GLTextureCoords&) {
glslProgram->setUniformValue(field->id.toUtf8().constData(), field->get_combo_index(timecode));
break;
case EFFECT_FIELD_FONT: break; // can you even send a string to a uniform value?
case EFFECT_FIELD_FILE: break; // can you even send a string to a uniform value?
}
}
}
+1 -1
View File
@@ -119,7 +119,7 @@ public:
QString name;
CollapsibleWidget* container;
EffectRow* add_row(const QString &name, bool savable = true);
EffectRow* add_row(const QString &name, bool savable = true, bool keyframable = true);
EffectRow* row(int i);
int row_count();
+33 -4
View File
@@ -6,6 +6,7 @@
#include "ui/checkboxex.h"
#include "ui/comboboxex.h"
#include "ui/fontcombobox.h"
#include "ui/embeddedfilechooser.h"
#include "effectrow.h"
#include "effect.h"
@@ -70,6 +71,13 @@ EffectField::EffectField(EffectRow *parent, int t, const QString &i) :
connect(fcb, SIGNAL(activated(int)), this, SLOT(ui_element_change()));
}
break;
case EFFECT_FIELD_FILE:
{
EmbeddedFileChooser* efc = new EmbeddedFileChooser();
ui_element = efc;
connect(efc, SIGNAL(changed()), this, SLOT(ui_element_change()));
}
break;
}
}
@@ -81,6 +89,7 @@ QVariant EffectField::get_previous_data() {
case EFFECT_FIELD_BOOL: return !static_cast<QCheckBox*>(ui_element)->isChecked();
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->getPreviousIndex();
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->getPreviousValue();
case EFFECT_FIELD_FILE: return static_cast<EmbeddedFileChooser*>(ui_element)->getPreviousValue();
}
return QVariant();
}
@@ -93,6 +102,7 @@ QVariant EffectField::get_current_data() {
case EFFECT_FIELD_BOOL: return static_cast<QCheckBox*>(ui_element)->isChecked();
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->currentIndex();
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->currentText();
case EFFECT_FIELD_FILE: return static_cast<EmbeddedFileChooser*>(ui_element)->getFilename();
}
return QVariant();
}
@@ -113,6 +123,7 @@ void EffectField::set_current_data(const QVariant& data) {
case EFFECT_FIELD_BOOL: return static_cast<QCheckBox*>(ui_element)->setChecked(data.toBool());
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(data.toInt());
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->setCurrentTextEx(data.toString());
case EFFECT_FIELD_FILE: return static_cast<EmbeddedFileChooser*>(ui_element)->setFilename(data.toString());
}
}
@@ -246,6 +257,12 @@ QVariant EffectField::validate_keyframe_data(double timecode, bool async) {
}
static_cast<FontCombobox*>(ui_element)->setCurrentTextEx(before_data.toString());
break;
case EFFECT_FIELD_FILE:
if (async) {
return before_data;
}
static_cast<EmbeddedFileChooser*>(ui_element)->setFilename(before_data.toString());
break;
}
}
return QVariant();
@@ -313,12 +330,12 @@ int EffectField::get_combo_index(double timecode, bool async) {
return static_cast<ComboBoxEx*>(ui_element)->currentIndex();
}
const QVariant EffectField::get_combo_data(double timecode) {
QVariant EffectField::get_combo_data(double timecode) {
validate_keyframe_data(timecode);
return static_cast<ComboBoxEx*>(ui_element)->currentData();
}
const QString EffectField::get_combo_string(double timecode) {
QString EffectField::get_combo_string(double timecode) {
validate_keyframe_data(timecode);
return static_cast<ComboBoxEx*>(ui_element)->currentText();
}
@@ -343,7 +360,7 @@ void EffectField::set_bool_value(bool b) {
return static_cast<QCheckBox*>(ui_element)->setChecked(b);
}
const QString EffectField::get_string_value(double timecode, bool async) {
QString EffectField::get_string_value(double timecode, bool async) {
if (async && hasKeyframes()) {
return validate_keyframe_data(timecode, true).toString();
}
@@ -355,7 +372,7 @@ void EffectField::set_string_value(const QString& s) {
static_cast<TextEditEx*>(ui_element)->setPlainTextEx(s);
}
const QString EffectField::get_font_name(double timecode, bool async) {
QString EffectField::get_font_name(double timecode, bool async) {
if (async && hasKeyframes()) {
return validate_keyframe_data(timecode, true).toString();
}
@@ -378,3 +395,15 @@ QColor EffectField::get_color_value(double timecode, bool async) {
void EffectField::set_color_value(QColor color) {
static_cast<ColorButton*>(ui_element)->set_color(color);
}
QString EffectField::get_filename(double timecode, bool async) {
if (async && hasKeyframes()) {
return validate_keyframe_data(timecode, true).toString();
}
validate_keyframe_data(timecode);
return static_cast<EmbeddedFileChooser*>(ui_element)->getFilename();
}
void EffectField::set_filename(const QString &s) {
static_cast<EmbeddedFileChooser*>(ui_element)->setFilename(s);
}
+8 -4
View File
@@ -7,6 +7,7 @@
#define EFFECT_FIELD_BOOL 3
#define EFFECT_FIELD_COMBO 4
#define EFFECT_FIELD_FONT 5
#define EFFECT_FIELD_FILE 6
#include <QObject>
#include <QVariant>
@@ -39,25 +40,28 @@ public:
void set_double_minimum_value(double v);
void set_double_maximum_value(double v);
const QString get_string_value(double timecode, bool async = false);
QString get_string_value(double timecode, bool async = false);
void set_string_value(const QString &s);
void add_combo_item(const QString& name, const QVariant &data);
int get_combo_index(double timecode, bool async = false);
const QVariant get_combo_data(double timecode);
const QString get_combo_string(double timecode);
QVariant get_combo_data(double timecode);
QString get_combo_string(double timecode);
void set_combo_index(int index);
void set_combo_string(const QString& s);
bool get_bool_value(double timecode, bool async = false);
void set_bool_value(bool b);
const QString get_font_name(double timecode, bool async = false);
QString get_font_name(double timecode, bool async = false);
void set_font_name(const QString& s);
QColor get_color_value(double timecode, bool async = false);
void set_color_value(QColor color);
QString get_filename(double timecode, bool async = false);
void set_filename(const QString& s);
QWidget* get_ui_element();
void set_enabled(bool e);
QVector<EffectKeyframe> keyframes;
+2 -2
View File
@@ -16,7 +16,7 @@
#include "ui/keyframenavigator.h"
#include "ui/clickablelabel.h"
EffectRow::EffectRow(Effect *parent, bool save, QGridLayout *uilayout, const QString &n, int row) :
EffectRow::EffectRow(Effect *parent, bool save, QGridLayout *uilayout, const QString &n, int row, bool keyframable) :
parent_effect(parent),
savable(save),
keyframing(false),
@@ -31,7 +31,7 @@ EffectRow::EffectRow(Effect *parent, bool save, QGridLayout *uilayout, const QSt
column_count = 1;
if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) {
if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION && keyframable) {
connect(label, SIGNAL(clicked()), this, SLOT(focus_row()));
keyframe_nav = new KeyframeNavigator();
+1 -1
View File
@@ -17,7 +17,7 @@ class ClickableLabel;
class EffectRow : public QObject {
Q_OBJECT
public:
EffectRow(Effect* parent, bool save, QGridLayout* uilayout, const QString& n, int row);
EffectRow(Effect* parent, bool save, QGridLayout* uilayout, const QString& n, int row, bool keyframable = true);
~EffectRow();
EffectField* add_field(int type, const QString &id, int colspan = 1);
void add_widget(QWidget *w);
+61
View File
@@ -0,0 +1,61 @@
#include "embeddedfilechooser.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QFileInfo>
#include <QPushButton>
#include <QFileDialog>
EmbeddedFileChooser::EmbeddedFileChooser(QWidget* parent) : QWidget(parent) {
QHBoxLayout* layout = new QHBoxLayout();
layout->setMargin(0);
setLayout(layout);
file_label = new QLabel();
update_label();
layout->addWidget(file_label);
QPushButton* browse_button = new QPushButton("...");
browse_button->setFixedWidth(25);
layout->addWidget(browse_button);
connect(browse_button, SIGNAL(clicked(bool)), this, SLOT(browse()));
}
const QString &EmbeddedFileChooser::getFilename() {
return filename;
}
const QString &EmbeddedFileChooser::getPreviousValue() {
return old_filename;
}
void EmbeddedFileChooser::setFilename(const QString &s) {
old_filename = filename;
filename = s;
update_label();
emit changed();
}
void EmbeddedFileChooser::update_label() {
QString l = "<html>File: ";
if (filename.isEmpty()) {
l += "(none)";
} else {
bool file_exists = QFileInfo::exists(filename);
if (!file_exists) l += "<font color='red'>";
QString short_fn = filename.mid(filename.lastIndexOf('/')+1);
if (short_fn.size() > 20) {
l += "..." + short_fn.right(20);
} else {
l += short_fn;
}
if (!file_exists) l += "</font>";
}
l += "</html>";
file_label->setText(l);
}
void EmbeddedFileChooser::browse() {
QString fn = QFileDialog::getOpenFileName(this);
if (!fn.isEmpty()) {
setFilename(fn);
}
}
+27
View File
@@ -0,0 +1,27 @@
#ifndef EMBEDDEDFILECHOOSER_H
#define EMBEDDEDFILECHOOSER_H
#include <QWidget>
class QLabel;
class EmbeddedFileChooser : public QWidget {
Q_OBJECT
public:
EmbeddedFileChooser(QWidget* parent = 0);
const QString& getFilename();
const QString& getPreviousValue();
void setFilename(const QString& s);
signals:
void changed();
private:
QLabel* file_label;
QString filename;
QString old_filename;
void update_label();
private slots:
void browse();
};
#endif // EMBEDDEDFILECHOOSER_H