giant rendering overhaul and many small fixes
This commit is contained in:
@@ -42,85 +42,84 @@
|
||||
#include "ui/colorbutton.h"
|
||||
#include "ui/fontcombobox.h"
|
||||
#include "io/config.h"
|
||||
#include "playback/playback.h"
|
||||
|
||||
TimecodeEffect::TimecodeEffect(ClipPtr c, const EffectMeta* em) :
|
||||
Effect(c, em)
|
||||
Effect(c, em)
|
||||
{
|
||||
enable_always_update = true;
|
||||
enable_superimpose = true;
|
||||
enable_always_update = true;
|
||||
enable_superimpose = true;
|
||||
|
||||
EffectRow* tc_row = add_row(tr("Timecode"));
|
||||
tc_select = tc_row->add_field(EFFECT_FIELD_COMBO, "tc_selector");
|
||||
tc_select->add_combo_item(tr("Sequence"), true);
|
||||
tc_select->add_combo_item(tr("Media"), false);
|
||||
tc_select->set_combo_index(0);
|
||||
EffectRow* tc_row = add_row(tr("Timecode"));
|
||||
tc_select = tc_row->add_field(EFFECT_FIELD_COMBO, "tc_selector");
|
||||
tc_select->add_combo_item(tr("Sequence"), true);
|
||||
tc_select->add_combo_item(tr("Media"), false);
|
||||
tc_select->set_combo_index(0);
|
||||
|
||||
scale_val = add_row(tr("Scale"))->add_field(EFFECT_FIELD_DOUBLE, "scale", 2);
|
||||
scale_val->set_double_minimum_value(1);
|
||||
scale_val->set_double_default_value(100);
|
||||
scale_val->set_double_maximum_value(1000);
|
||||
scale_val = add_row(tr("Scale"))->add_field(EFFECT_FIELD_DOUBLE, "scale", 2);
|
||||
scale_val->set_double_minimum_value(1);
|
||||
scale_val->set_double_default_value(100);
|
||||
scale_val->set_double_maximum_value(1000);
|
||||
|
||||
color_val = add_row(tr("Color"))->add_field(EFFECT_FIELD_COLOR, "color", 2);
|
||||
color_val->set_color_value(Qt::white);
|
||||
color_val = add_row(tr("Color"))->add_field(EFFECT_FIELD_COLOR, "color", 2);
|
||||
color_val->set_color_value(Qt::white);
|
||||
|
||||
color_bg_val = add_row(tr("Background Color"))->add_field(EFFECT_FIELD_COLOR, "bgcolor", 2);
|
||||
color_bg_val->set_color_value(Qt::black);
|
||||
color_bg_val = add_row(tr("Background Color"))->add_field(EFFECT_FIELD_COLOR, "bgcolor", 2);
|
||||
color_bg_val->set_color_value(Qt::black);
|
||||
|
||||
bg_alpha = add_row(tr("Background Opacity"))->add_field(EFFECT_FIELD_DOUBLE, "bgalpha", 2);
|
||||
bg_alpha->set_double_minimum_value(0);
|
||||
bg_alpha->set_double_maximum_value(100);
|
||||
bg_alpha->set_double_default_value(50);
|
||||
bg_alpha = add_row(tr("Background Opacity"))->add_field(EFFECT_FIELD_DOUBLE, "bgalpha", 2);
|
||||
bg_alpha->set_double_minimum_value(0);
|
||||
bg_alpha->set_double_maximum_value(100);
|
||||
bg_alpha->set_double_default_value(50);
|
||||
|
||||
EffectRow* offset = add_row(tr("Offset"));
|
||||
offset_x_val = offset->add_field(EFFECT_FIELD_DOUBLE, "offsetx");
|
||||
offset_y_val = offset->add_field(EFFECT_FIELD_DOUBLE, "offsety");
|
||||
EffectRow* offset = add_row(tr("Offset"));
|
||||
offset_x_val = offset->add_field(EFFECT_FIELD_DOUBLE, "offsetx");
|
||||
offset_y_val = offset->add_field(EFFECT_FIELD_DOUBLE, "offsety");
|
||||
|
||||
prepend_text = add_row(tr("Prepend"))->add_field(EFFECT_FIELD_STRING, "prepend", 2);
|
||||
prepend_text = add_row(tr("Prepend"))->add_field(EFFECT_FIELD_STRING, "prepend", 2);
|
||||
}
|
||||
|
||||
|
||||
void TimecodeEffect::redraw(double timecode) {
|
||||
if (tc_select->get_combo_data(timecode).toBool()){
|
||||
display_timecode = prepend_text->get_string_value(timecode) + frame_to_timecode(olive::ActiveSequence->playhead, olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate);}
|
||||
else {
|
||||
double media_rate = parent_clip->getMediaFrameRate();
|
||||
display_timecode = prepend_text->get_string_value(timecode) + frame_to_timecode(timecode * media_rate, olive::CurrentConfig.timecode_view, media_rate);}
|
||||
img.fill(Qt::transparent);
|
||||
if (tc_select->get_combo_data(timecode).toBool()){
|
||||
display_timecode = prepend_text->get_string_value(timecode) + frame_to_timecode(olive::ActiveSequence->playhead, olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate);}
|
||||
else {
|
||||
double media_rate = parent_clip->media_frame_rate();
|
||||
display_timecode = prepend_text->get_string_value(timecode) + frame_to_timecode(timecode * media_rate, olive::CurrentConfig.timecode_view, media_rate);}
|
||||
img.fill(Qt::transparent);
|
||||
|
||||
QPainter p(&img);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
int width = img.width();
|
||||
int height = img.height();
|
||||
QPainter p(&img);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
int width = img.width();
|
||||
int height = img.height();
|
||||
|
||||
// set font
|
||||
font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias);
|
||||
font.setFamily("Helvetica");
|
||||
font.setPixelSize(qCeil(scale_val->get_double_value(timecode)*.01*(height/10)));
|
||||
p.setFont(font);
|
||||
QFontMetrics fm(font);
|
||||
// set font
|
||||
font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias);
|
||||
font.setFamily("Helvetica");
|
||||
font.setPixelSize(qCeil(scale_val->get_double_value(timecode)*.01*(height/10)));
|
||||
p.setFont(font);
|
||||
QFontMetrics fm(font);
|
||||
|
||||
QPainterPath path;
|
||||
QPainterPath path;
|
||||
|
||||
int text_x, text_y, rect_y, offset_x, offset_y;
|
||||
int text_height = fm.height();
|
||||
int text_width = fm.width(display_timecode);
|
||||
QColor background_color = color_bg_val->get_color_value(timecode);
|
||||
int alpha_val = bg_alpha->get_double_value(timecode)*2.55;
|
||||
background_color.setAlpha(alpha_val);
|
||||
int text_x, text_y, rect_y, offset_x, offset_y;
|
||||
int text_height = fm.height();
|
||||
int text_width = fm.width(display_timecode);
|
||||
QColor background_color = color_bg_val->get_color_value(timecode);
|
||||
int alpha_val = bg_alpha->get_double_value(timecode)*2.55;
|
||||
background_color.setAlpha(alpha_val);
|
||||
|
||||
offset_x = int(offset_x_val->get_double_value(timecode));
|
||||
offset_y = int(offset_y_val->get_double_value(timecode));
|
||||
offset_x = int(offset_x_val->get_double_value(timecode));
|
||||
offset_y = int(offset_y_val->get_double_value(timecode));
|
||||
|
||||
text_x = offset_x + (width/2) - (text_width/2);
|
||||
text_y = offset_y + height - height/10;
|
||||
rect_y = text_y + fm.descent() - text_height;
|
||||
text_x = offset_x + (width/2) - (text_width/2);
|
||||
text_y = offset_y + height - height/10;
|
||||
rect_y = text_y + fm.descent() - text_height;
|
||||
|
||||
path.addText(text_x, text_y, font, display_timecode);
|
||||
path.addText(text_x, text_y, font, display_timecode);
|
||||
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(background_color);
|
||||
p.drawRect(QRect(text_x-fm.descent(), rect_y, text_width+fm.descent()*2, text_height));
|
||||
p.setBrush(color_val->get_color_value(timecode));
|
||||
p.drawPath(path);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(background_color);
|
||||
p.drawRect(QRect(text_x-fm.descent(), rect_y, text_width+fm.descent()*2, text_height));
|
||||
p.setBrush(color_val->get_color_value(timecode));
|
||||
p.drawPath(path);
|
||||
}
|
||||
|
||||
+226
-226
@@ -31,7 +31,7 @@
|
||||
#include <QXmlStreamWriter>
|
||||
#include <QWindow>
|
||||
|
||||
#include "playback/audio.h"
|
||||
#include "rendering/audio.h"
|
||||
#include "mainwindow.h"
|
||||
#include "debug.h"
|
||||
|
||||
@@ -43,10 +43,10 @@
|
||||
#define CHANNEL_COUNT 2
|
||||
|
||||
struct VSTRect {
|
||||
int16_t top;
|
||||
int16_t left;
|
||||
int16_t bottom;
|
||||
int16_t right;
|
||||
int16_t top;
|
||||
int16_t left;
|
||||
int16_t bottom;
|
||||
int16_t right;
|
||||
};
|
||||
|
||||
#define effGetChunk 23
|
||||
@@ -54,44 +54,44 @@ struct VSTRect {
|
||||
|
||||
// C callbacks
|
||||
extern "C" {
|
||||
// Main host callback
|
||||
intptr_t hostCallback(AEffect* effect, int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt) {
|
||||
Q_UNUSED(value)
|
||||
// Main host callback
|
||||
intptr_t hostCallback(AEffect* effect, int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt) {
|
||||
Q_UNUSED(value)
|
||||
|
||||
switch(opcode) {
|
||||
case audioMasterAutomate:
|
||||
effect->setParameter(effect, index, opt);
|
||||
break;
|
||||
case audioMasterVersion:
|
||||
return 2400;
|
||||
case audioMasterIdle:
|
||||
effect->dispatcher(effect, effEditIdle, 0, 0, nullptr, 0);
|
||||
break;
|
||||
case audioMasterWantMidi:
|
||||
// no midi support, return 0
|
||||
break;
|
||||
case audioMasterGetSampleRate:
|
||||
return current_audio_freq();
|
||||
case audioMasterGetBlockSize:
|
||||
return BLOCK_SIZE;
|
||||
case audioMasterGetCurrentProcessLevel:
|
||||
// process level happens to be 0
|
||||
break;
|
||||
case audioMasterGetProductString:
|
||||
strcpy(static_cast<char*>(ptr), "OLIVETEAM");
|
||||
break;
|
||||
case audioMasterBeginEdit:
|
||||
// we don't really care about this
|
||||
// but we are aware of it
|
||||
break;
|
||||
case audioMasterEndEdit: // change made
|
||||
olive::MainWindow->setWindowModified(true);
|
||||
break;
|
||||
default:
|
||||
qInfo() << "Plugin requested unhandled opcode" << opcode;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
switch(opcode) {
|
||||
case audioMasterAutomate:
|
||||
effect->setParameter(effect, index, opt);
|
||||
break;
|
||||
case audioMasterVersion:
|
||||
return 2400;
|
||||
case audioMasterIdle:
|
||||
effect->dispatcher(effect, effEditIdle, 0, 0, nullptr, 0);
|
||||
break;
|
||||
case audioMasterWantMidi:
|
||||
// no midi support, return 0
|
||||
break;
|
||||
case audioMasterGetSampleRate:
|
||||
return current_audio_freq();
|
||||
case audioMasterGetBlockSize:
|
||||
return BLOCK_SIZE;
|
||||
case audioMasterGetCurrentProcessLevel:
|
||||
// process level happens to be 0
|
||||
break;
|
||||
case audioMasterGetProductString:
|
||||
strcpy(static_cast<char*>(ptr), "OLIVETEAM");
|
||||
break;
|
||||
case audioMasterBeginEdit:
|
||||
// we don't really care about this
|
||||
// but we are aware of it
|
||||
break;
|
||||
case audioMasterEndEdit: // change made
|
||||
olive::MainWindow->setWindowModified(true);
|
||||
break;
|
||||
default:
|
||||
qInfo() << "Plugin requested unhandled opcode" << opcode;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Plugin's entry point
|
||||
@@ -106,295 +106,295 @@ 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->get_filename(0, true);
|
||||
QString dll_fn = file_field->get_filename(0, true);
|
||||
|
||||
if (dll_fn.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
bundle = BundleLoad(dll_fn);
|
||||
bundle = BundleLoad(dll_fn);
|
||||
|
||||
if (bundle == NULL) {
|
||||
QMessageBox::critical(nullptr, tr("Error loading VST plugin"), tr("Failed to create VST reference"));
|
||||
return;
|
||||
}
|
||||
if (bundle == NULL) {
|
||||
QMessageBox::critical(nullptr, tr("Error loading VST plugin"), tr("Failed to create VST reference"));
|
||||
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"));
|
||||
}
|
||||
if(mainEntryPoint == NULL) {
|
||||
qCritical() << "Couldn't get a pointer to VST plugin's main()";
|
||||
BundleClose(bundle);
|
||||
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"));
|
||||
}
|
||||
if(mainEntryPoint == NULL) {
|
||||
qCritical() << "Couldn't get a pointer to VST plugin's main()";
|
||||
BundleClose(bundle);
|
||||
return;
|
||||
}
|
||||
|
||||
plugin = mainEntryPoint(hostCallback);
|
||||
if(plugin == NULL) {
|
||||
qCritical() << "Plugin's main() returns null";
|
||||
BundleClose(bundle);
|
||||
return;
|
||||
}
|
||||
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;
|
||||
modulePtr = LibLoad(dll_fn);
|
||||
if(modulePtr == nullptr) {
|
||||
QString dll_error;
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD dll_err = GetLastError();
|
||||
dll_error = QString::number(dll_err);
|
||||
DWORD dll_err = GetLastError();
|
||||
dll_error = QString::number(dll_err);
|
||||
#elif __linux__
|
||||
dll_error = dlerror();
|
||||
dll_error = dlerror();
|
||||
#endif
|
||||
qCritical() << "Failed to load VST plugin" << dll_fn << "-" << dll_error;
|
||||
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);
|
||||
QString msg_err = tr("Failed to load VST plugin \"%1\": %2").arg(dll_fn, dll_error);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (dll_err == 193) {
|
||||
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.");
|
||||
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.");
|
||||
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);
|
||||
QMessageBox::critical(nullptr, tr("Error loading VST plugin"), msg_err);
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
vstPluginFuncPtr mainEntryPoint = reinterpret_cast<vstPluginFuncPtr>(LibAddress(modulePtr, "VSTPluginMain"));
|
||||
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) {
|
||||
// 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);
|
||||
}
|
||||
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 (plugin != nullptr) {
|
||||
stopPlugin();
|
||||
#if defined(__APPLE__)
|
||||
CFBundleUnloadExecutable(bundle);
|
||||
CFRelease(bundle);
|
||||
CFBundleUnloadExecutable(bundle);
|
||||
CFRelease(bundle);
|
||||
#else
|
||||
LibClose(modulePtr);
|
||||
LibClose(modulePtr);
|
||||
#endif
|
||||
plugin = nullptr;
|
||||
}
|
||||
plugin = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool VSTHost::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) {
|
||||
qCritical() << "Plugin's magic number is bad";
|
||||
QMessageBox::critical(olive::MainWindow, tr("VST Error"), tr("Plugin's magic number is invalid"));
|
||||
return false;
|
||||
}
|
||||
// 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) {
|
||||
qCritical() << "Plugin's magic number is bad";
|
||||
QMessageBox::critical(olive::MainWindow, tr("VST Error"), tr("Plugin's magic number is invalid"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create dispatcher handle
|
||||
dispatcher = reinterpret_cast<dispatcherFuncPtr>(plugin->dispatcher);
|
||||
// Create dispatcher handle
|
||||
dispatcher = reinterpret_cast<dispatcherFuncPtr>(plugin->dispatcher);
|
||||
|
||||
// Set up plugin callback functions
|
||||
plugin->getParameter = reinterpret_cast<getParameterFuncPtr>(plugin->getParameter);
|
||||
plugin->processReplacing = reinterpret_cast<processFuncPtr>(plugin->processReplacing);
|
||||
plugin->setParameter = reinterpret_cast<setParameterFuncPtr>(plugin->setParameter);
|
||||
// Set up plugin callback functions
|
||||
plugin->getParameter = reinterpret_cast<getParameterFuncPtr>(plugin->getParameter);
|
||||
plugin->processReplacing = reinterpret_cast<processFuncPtr>(plugin->processReplacing);
|
||||
plugin->setParameter = reinterpret_cast<setParameterFuncPtr>(plugin->setParameter);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void VSTHost::startPlugin() {
|
||||
dispatcher(plugin, effOpen, 0, 0, nullptr, 0.0f);
|
||||
dispatcher(plugin, effOpen, 0, 0, nullptr, 0.0f);
|
||||
|
||||
// Set some default properties
|
||||
dispatcher(plugin, effSetSampleRate, 0, 0, nullptr, current_audio_freq());
|
||||
dispatcher(plugin, effSetBlockSize, 0, BLOCK_SIZE, nullptr, 0.0f);
|
||||
// Set some default properties
|
||||
dispatcher(plugin, effSetSampleRate, 0, 0, nullptr, current_audio_freq());
|
||||
dispatcher(plugin, effSetBlockSize, 0, BLOCK_SIZE, nullptr, 0.0f);
|
||||
|
||||
resumePlugin();
|
||||
resumePlugin();
|
||||
}
|
||||
|
||||
void VSTHost::stopPlugin() {
|
||||
suspendPlugin();
|
||||
suspendPlugin();
|
||||
|
||||
dispatcher(plugin, effClose, 0, 0, nullptr, 0);
|
||||
dispatcher(plugin, effClose, 0, 0, nullptr, 0);
|
||||
}
|
||||
|
||||
void VSTHost::resumePlugin() {
|
||||
dispatcher(plugin, effMainsChanged, 0, 1, nullptr, 0.0f);
|
||||
dispatcher(plugin, effMainsChanged, 0, 1, nullptr, 0.0f);
|
||||
}
|
||||
|
||||
void VSTHost::suspendPlugin() {
|
||||
dispatcher(plugin, effMainsChanged, 0, 0, nullptr, 0.0f);
|
||||
dispatcher(plugin, effMainsChanged, 0, 0, nullptr, 0.0f);
|
||||
}
|
||||
|
||||
bool VSTHost::canPluginDo(char *canDoString) {
|
||||
return (dispatcher(plugin, effCanDo, 0, 0, static_cast<void*>(canDoString), 0.0f) > 0);
|
||||
return (dispatcher(plugin, effCanDo, 0, 0, static_cast<void*>(canDoString), 0.0f) > 0);
|
||||
}
|
||||
|
||||
void VSTHost::processAudio(long numFrames) {
|
||||
// Always reset the output array before processing.
|
||||
for (int i=0;i<CHANNEL_COUNT;i++) {
|
||||
memset(outputs[i], 0, BLOCK_SIZE*sizeof(float));
|
||||
}
|
||||
// Always reset the output array before processing.
|
||||
for (int i=0;i<CHANNEL_COUNT;i++) {
|
||||
memset(outputs[i], 0, BLOCK_SIZE*sizeof(float));
|
||||
}
|
||||
|
||||
plugin->processReplacing(plugin, inputs, outputs, numFrames);
|
||||
plugin->processReplacing(plugin, inputs, outputs, numFrames);
|
||||
}
|
||||
|
||||
VSTHost::VSTHost(ClipPtr c, const EffectMeta *em) : Effect(c, em) {
|
||||
plugin = nullptr;
|
||||
plugin = nullptr;
|
||||
|
||||
inputs = new float* [CHANNEL_COUNT];
|
||||
outputs = new float* [CHANNEL_COUNT];
|
||||
for(int channel = 0; channel < CHANNEL_COUNT; channel++) {
|
||||
inputs[channel] = new float[BLOCK_SIZE];
|
||||
outputs[channel] = new float[BLOCK_SIZE];
|
||||
}
|
||||
inputs = new float* [CHANNEL_COUNT];
|
||||
outputs = new float* [CHANNEL_COUNT];
|
||||
for(int channel = 0; channel < CHANNEL_COUNT; channel++) {
|
||||
inputs[channel] = new float[BLOCK_SIZE];
|
||||
outputs[channel] = new float[BLOCK_SIZE];
|
||||
}
|
||||
|
||||
file_field = add_row(tr("Plugin"), true, false)->add_field(EFFECT_FIELD_FILE, "filename");
|
||||
connect(file_field, SIGNAL(changed()), this, SLOT(change_plugin()));
|
||||
file_field = add_row(tr("Plugin"), true, false)->add_field(EFFECT_FIELD_FILE, "filename");
|
||||
connect(file_field, SIGNAL(changed()), this, SLOT(change_plugin()));
|
||||
|
||||
EffectRow* interface_row = add_row(tr("Interface"), false, false);
|
||||
show_interface_btn = new QPushButton(tr("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);
|
||||
EffectRow* interface_row = add_row(tr("Interface"), false, false);
|
||||
show_interface_btn = new QPushButton(tr("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);
|
||||
|
||||
dialog = new QDialog(olive::MainWindow);
|
||||
dialog->setWindowTitle(tr("VST Plugin"));
|
||||
dialog->setAttribute(Qt::WA_NativeWindow, true);
|
||||
dialog->setWindowFlags(dialog->windowFlags() | Qt::MSWindowsFixedSizeDialogHint);
|
||||
connect(dialog, SIGNAL(finished(int)), this, SLOT(uncheck_show_button()));
|
||||
dialog = new QDialog(olive::MainWindow);
|
||||
dialog->setWindowTitle(tr("VST Plugin"));
|
||||
dialog->setAttribute(Qt::WA_NativeWindow, true);
|
||||
dialog->setWindowFlags(dialog->windowFlags() | Qt::MSWindowsFixedSizeDialogHint);
|
||||
connect(dialog, SIGNAL(finished(int)), this, SLOT(uncheck_show_button()));
|
||||
}
|
||||
|
||||
VSTHost::~VSTHost() {
|
||||
for(int channel = 0; channel < CHANNEL_COUNT; channel++) {
|
||||
delete [] inputs[channel];
|
||||
delete [] outputs[channel];
|
||||
}
|
||||
delete [] outputs;
|
||||
delete [] inputs;
|
||||
for(int channel = 0; channel < CHANNEL_COUNT; channel++) {
|
||||
delete [] inputs[channel];
|
||||
delete [] outputs[channel];
|
||||
}
|
||||
delete [] outputs;
|
||||
delete [] inputs;
|
||||
|
||||
freePlugin();
|
||||
freePlugin();
|
||||
|
||||
delete show_interface_btn;
|
||||
delete dialog;
|
||||
delete show_interface_btn;
|
||||
delete dialog;
|
||||
}
|
||||
|
||||
void VSTHost::process_audio(double, double, quint8* samples, int nb_bytes, int) {
|
||||
if (plugin != nullptr) {
|
||||
int interval = BLOCK_SIZE*4;
|
||||
for (int i=0;i<nb_bytes;i+=interval) {
|
||||
int process_size = qMin(interval, nb_bytes - i);
|
||||
int lim = i + process_size;
|
||||
if (plugin != nullptr) {
|
||||
int interval = BLOCK_SIZE*4;
|
||||
for (int i=0;i<nb_bytes;i+=interval) {
|
||||
int process_size = qMin(interval, nb_bytes - i);
|
||||
int lim = i + process_size;
|
||||
|
||||
// convert to float
|
||||
for (int j=i;j<lim;j+=4) {
|
||||
qint16 left_sample = qint16(((samples[j+1] & 0xFF) << 8) | (samples[j] & 0xFF));
|
||||
qint16 right_sample = qint16(((samples[j+3] & 0xFF) << 8) | (samples[j+2] & 0xFF));
|
||||
// convert to float
|
||||
for (int j=i;j<lim;j+=4) {
|
||||
qint16 left_sample = qint16(((samples[j+1] & 0xFF) << 8) | (samples[j] & 0xFF));
|
||||
qint16 right_sample = qint16(((samples[j+3] & 0xFF) << 8) | (samples[j+2] & 0xFF));
|
||||
|
||||
int index = (j-i)>>2;
|
||||
inputs[0][index] = float(left_sample) / float(INT16_MAX);
|
||||
inputs[1][index] = float(right_sample) / float(INT16_MAX);
|
||||
}
|
||||
int index = (j-i)>>2;
|
||||
inputs[0][index] = float(left_sample) / float(INT16_MAX);
|
||||
inputs[1][index] = float(right_sample) / float(INT16_MAX);
|
||||
}
|
||||
|
||||
// send to VST
|
||||
processAudio(process_size>>2);
|
||||
// send to VST
|
||||
processAudio(process_size>>2);
|
||||
|
||||
// convert back to int16
|
||||
for (int j=i;j<lim;j+=4) {
|
||||
int index = (j-i)>>2;
|
||||
// convert back to int16
|
||||
for (int j=i;j<lim;j+=4) {
|
||||
int index = (j-i)>>2;
|
||||
|
||||
qint16 left_sample = qint16(qRound(outputs[0][index] * INT16_MAX));
|
||||
qint16 right_sample = qint16(qRound(outputs[1][index] * INT16_MAX));
|
||||
qint16 left_sample = qint16(qRound(outputs[0][index] * INT16_MAX));
|
||||
qint16 right_sample = qint16(qRound(outputs[1][index] * INT16_MAX));
|
||||
|
||||
samples[j+3] = quint8(right_sample >> 8);
|
||||
samples[j+2] = quint8(right_sample);
|
||||
samples[j+1] = quint8(left_sample >> 8);
|
||||
samples[j] = quint8(left_sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
samples[j+3] = quint8(right_sample >> 8);
|
||||
samples[j+2] = quint8(right_sample);
|
||||
samples[j+1] = quint8(left_sample >> 8);
|
||||
samples[j] = quint8(left_sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VSTHost::custom_load(QXmlStreamReader &stream) {
|
||||
if (stream.name() == "plugindata") {
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (stream.name() == "plugindata") {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VSTHost::save(QXmlStreamWriter &stream) {
|
||||
Effect::save(stream);
|
||||
if (plugin != nullptr) {
|
||||
char* p = nullptr;
|
||||
int32_t length = int32_t(dispatcher(plugin, effGetChunk, 0, 0, &p, 0));
|
||||
data_cache = QByteArray(p, length);
|
||||
}
|
||||
if (data_cache.size() > 0) {
|
||||
stream.writeTextElement("plugindata", data_cache.toBase64());
|
||||
}
|
||||
Effect::save(stream);
|
||||
if (plugin != nullptr) {
|
||||
char* p = nullptr;
|
||||
int32_t length = int32_t(dispatcher(plugin, effGetChunk, 0, 0, &p, 0));
|
||||
data_cache = QByteArray(p, length);
|
||||
}
|
||||
if (data_cache.size() > 0) {
|
||||
stream.writeTextElement("plugindata", data_cache.toBase64());
|
||||
}
|
||||
}
|
||||
|
||||
void VSTHost::show_interface(bool show) {
|
||||
dialog->setVisible(show);
|
||||
dialog->setVisible(show);
|
||||
|
||||
if (show) {
|
||||
if (show) {
|
||||
#if defined(_WIN32)
|
||||
dispatcher(plugin, effEditOpen, 0, 0, reinterpret_cast<HWND>(dialog->windowHandle()->winId()), 0);
|
||||
dispatcher(plugin, effEditOpen, 0, 0, reinterpret_cast<HWND>(dialog->windowHandle()->winId()), 0);
|
||||
#elif defined(__APPLE__)
|
||||
dispatcher(plugin, effEditOpen, 0, 0, reinterpret_cast<NSWindow*>(dialog->windowHandle()->winId()), 0);
|
||||
dispatcher(plugin, effEditOpen, 0, 0, reinterpret_cast<NSWindow*>(dialog->windowHandle()->winId()), 0);
|
||||
#elif defined(__linux__)
|
||||
dispatcher(plugin, effEditOpen, 0, 0, reinterpret_cast<void*>(dialog->windowHandle()->winId()), 0);
|
||||
dispatcher(plugin, effEditOpen, 0, 0, reinterpret_cast<void*>(dialog->windowHandle()->winId()), 0);
|
||||
#endif
|
||||
} else {
|
||||
dispatcher(plugin, effEditClose, 0, 0, nullptr, 0);
|
||||
}
|
||||
} else {
|
||||
dispatcher(plugin, effEditClose, 0, 0, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void VSTHost::uncheck_show_button() {
|
||||
show_interface_btn->setChecked(false);
|
||||
show_interface_btn->setChecked(false);
|
||||
}
|
||||
|
||||
void VSTHost::change_plugin() {
|
||||
freePlugin();
|
||||
loadPlugin();
|
||||
if (plugin != nullptr) {
|
||||
if (configurePluginCallbacks()) {
|
||||
startPlugin();
|
||||
VSTRect* eRect = nullptr;
|
||||
plugin->dispatcher(plugin, effEditGetRect, 0, 0, &eRect, 0);
|
||||
dialog->setFixedSize(eRect->right - eRect->left, eRect->bottom - eRect->top);
|
||||
} else {
|
||||
freePlugin();
|
||||
loadPlugin();
|
||||
if (plugin != nullptr) {
|
||||
if (configurePluginCallbacks()) {
|
||||
startPlugin();
|
||||
VSTRect* eRect = nullptr;
|
||||
plugin->dispatcher(plugin, effEditGetRect, 0, 0, &eRect, 0);
|
||||
dialog->setFixedSize(eRect->right - eRect->left, eRect->bottom - eRect->top);
|
||||
} else {
|
||||
#ifdef __APPLE__
|
||||
CFBundleUnloadExecutable(bundle);
|
||||
CFRelease(bundle);
|
||||
CFBundleUnloadExecutable(bundle);
|
||||
CFRelease(bundle);
|
||||
#else
|
||||
LibClose(modulePtr);
|
||||
LibClose(modulePtr);
|
||||
#endif
|
||||
plugin = nullptr;
|
||||
}
|
||||
}
|
||||
show_interface_btn->setEnabled(plugin != nullptr);
|
||||
plugin = nullptr;
|
||||
}
|
||||
}
|
||||
show_interface_btn->setEnabled(plugin != nullptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user