Delegate the plugin functionality to a class

This way we can hopefully contain all the manual memory management and
raw pointers somewhat.
This commit is contained in:
Robbert van der Helm
2020-02-06 19:01:30 +01:00
parent 3cda70ec04
commit 58d749862f
5 changed files with 177 additions and 90 deletions
+50
View File
@@ -0,0 +1,50 @@
#include "bridge.h"
#include <iostream>
// TODO: I should track down the VST2 SDK for clarification on some of the
// implementation details, such as the use of intptr_t isntead of void*
// here.
/**
* Handle an event sent by the VST host. Most of these opcodes will be passed
* through to the winelib VST host.
*/
intptr_t Bridge::dispatch(AEffect* /*plugin*/,
int32_t opcode,
int32_t /*parameter*/,
intptr_t /*value*/,
void* result,
float /*option*/) {
switch (opcode) {
case effGetEffectName:
const std::string plugin_name("Hello, world!");
std::copy(plugin_name.begin(), plugin_name.end(),
static_cast<char*>(result));
// return 1; // TODO: Why?
break;
}
// TODO: Unimplmemented
return 0;
}
void Bridge::process(AEffect* /*plugin*/,
float** /*inputs*/,
float** /*outputs*/,
int32_t /*sample_frames*/) {
// TODO: Unimplmemented
}
void Bridge::set_parameter(AEffect* /*plugin*/,
int32_t /*index*/,
float /*value*/) {
// TODO: Unimplmemented
}
float Bridge::get_parameter(AEffect* /*plugin*/, int32_t /*index*/
) {
// TODO: Unimplmemented
return 0.0f;
}
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#include <vestige/aeffect.h>
/**
* This handles the communication between the Linux native VST plugin and the
* Wine VST host. The functions below should be used as callback functions in an
* `AEffect` object.
*/
class Bridge {
public:
// The below four functions are the handlers from the VST2 API. They are
// called through proxy functions in `plugin.cpp`.
/**
* Handle an event sent by the VST host. Most of these opcodes will be
* passed through to the winelib VST host through a Unix domain socket.
*/
intptr_t dispatch(AEffect* plugin,
int32_t opcode,
int32_t parameter,
intptr_t value,
void* result,
float option);
void process(AEffect* plugin,
float** inputs,
float** outputs,
int32_t sample_frames);
void set_parameter(AEffect* plugin, int32_t index, float value);
float get_parameter(AEffect* plugin, int32_t index);
};
+94
View File
@@ -0,0 +1,94 @@
#include <vestige/aeffect.h>
#include <iostream>
#include <memory>
#include "bridge.h"
#define VST_EXPORT __attribute__((visibility("default")))
// The main entry point for VST plugins should be called `VSTPluginMain``. The
// other two exist for legacy reasons since some old hosts might still use
// them.`
extern "C" {
extern VST_EXPORT AEffect* VSTPluginMain(audioMasterCallback);
VST_EXPORT AEffect* MAIN(audioMasterCallback audioMaster) {
return VSTPluginMain(audioMaster);
}
VST_EXPORT AEffect* main_plugin(audioMasterCallback audioMaster) {
return VSTPluginMain(audioMaster);
}
}
intptr_t dispatch(AEffect*, int32_t, int32_t, intptr_t, void*, float);
void process(AEffect*, float**, float**, int32_t);
void setParameter(AEffect*, int32_t, float);
float getParameter(AEffect*, int32_t);
/**
* Retrieve the bridge instance stored in an unused pointer from a VST plugin.
* This is sadly needed as a workaround to avoid using globals since we need
* free function pointers to interface with the VST API.
*/
Bridge* get_bridge_instance(const AEffect& plugin) {
return static_cast<Bridge*>(plugin.ptr3);
}
/**
* The main VST plugin entry point. This finds the Windows VST plugin that
* should be run, executes it in our VST host inside Wine, and sets up
* communication between the two processes.
*
* This is a bit of a mess since we're interacting with an external C API. To
* keep this somewhat contained this is the only place where we're doing manual
* memory management.
*/
VST_EXPORT AEffect* VSTPluginMain(audioMasterCallback /*audioMaster*/) {
// TODO: Since we are returning raw pointers, how does cleanup work?
AEffect* plugin = new AEffect();
plugin->ptr3 = new Bridge();
plugin->dispatcher = dispatch;
plugin->process = process;
plugin->setParameter = setParameter;
plugin->getParameter = getParameter;
// // XXX: processReplacing?
// TODO: Add more and actual data
plugin->magic = kEffectMagic;
plugin->numParams = 69;
plugin->uniqueID = 69420;
return plugin;
}
// The below functions are proxy functions for the methods defined in
// `Bridge.cpp`
intptr_t dispatch(AEffect* plugin,
int32_t opcode,
int32_t parameter,
intptr_t value,
void* result,
float option) {
return get_bridge_instance(*plugin)->dispatch(plugin, opcode, parameter,
value, result, option);
}
void process(AEffect* plugin,
float** inputs,
float** outputs,
int32_t sample_frames) {
return get_bridge_instance(*plugin)->process(plugin, inputs, outputs,
sample_frames);
}
void setParameter(AEffect* plugin, int32_t index, float value) {
return get_bridge_instance(*plugin)->set_parameter(plugin, index, value);
}
float getParameter(AEffect* plugin, int32_t index) {
return get_bridge_instance(*plugin)->get_parameter(plugin, index);
}
-89
View File
@@ -1,89 +0,0 @@
#include <vestige/aeffect.h>
#include <iostream>
#define VST_EXPORT __attribute__((visibility("default")))
// The main entry point for VST plugins should be called `VSTPluginMain``. The
// other two exist for legacy reasons since some old hosts might still use
// them.`
extern "C" {
extern VST_EXPORT AEffect* VSTPluginMain(audioMasterCallback);
VST_EXPORT AEffect* MAIN(audioMasterCallback audioMaster) {
return VSTPluginMain(audioMaster);
}
VST_EXPORT AEffect* main_plugin(audioMasterCallback audioMaster) {
return VSTPluginMain(audioMaster);
}
}
intptr_t dispatch(AEffect*, int32_t, int32_t, intptr_t, void*, float);
void process(AEffect*, float**, float**, int32_t);
void setParameter(AEffect*, int32_t, float);
float getParameter(AEffect*, int32_t);
/**
* The main VST plugin entry point. This finds the Windows VST plugin that
* should be run, executes it in our VST host inside Wine, and sets up
* communication between the two processes.
*/
VST_EXPORT AEffect* VSTPluginMain(audioMasterCallback /*audioMaster*/) {
// TODO: Do something useful ehre
std::cout << "Hello, world!" << std::endl;
AEffect* effect = new AEffect();
effect->magic = kEffectMagic;
effect->dispatcher = dispatch;
effect->process = process;
// XXX: processReplacing?
effect->setParameter = setParameter;
effect->getParameter = getParameter;
effect->numParams = 69;
effect->uniqueID = 69420;
return effect;
}
// TODO: I should track down the VST2 SDK for clarification on some of the
// implementation details, such as the use of intptr_t isntead of void*
// here.
/**
* Handle an event sent by the VST host.
*
* TODO: Look up what the return value here is actually doing.
*/
intptr_t dispatch(AEffect* /*effect*/,
int32_t opcode,
int32_t /*parameter*/,
intptr_t /*value*/,
void* result,
float /*option*/) {
switch (opcode) {
case effGetEffectName:
const std::string plugin_name("Hello, world!");
std::copy(plugin_name.begin(), plugin_name.end(),
static_cast<char*>(result));
return 1; // TODO: Why?
break;
}
// TODO: Unimplmemented
return 0;
}
void process(AEffect*, float**, float**, int32_t) {
// TODO: Unimplmemented
}
void setParameter(AEffect*, int32_t, float) {
// TODO: Unimplmemented
}
float getParameter(AEffect*, int32_t) {
// TODO: Unimplmemented
return 0.0f;
}