Added VST SDK support.
This commit is contained in:
parent
a1482ec110
commit
8e09f58944
25 changed files with 850 additions and 23 deletions
|
|
@ -87,10 +87,36 @@ static void check(const char *path, xtc_plugin_format format)
|
|||
xtc_realtime_destroy(rt); xtc_graph_destroy(graph); xtc_project_destroy(p); xtc_project_destroy(loaded); unlink(document);
|
||||
printf("%s identity, buffers, stereo graph, retirement, reload and missing dependency passed.\n",xtc_plugin_format_name(format));
|
||||
}
|
||||
static void context_check(const char *path)
|
||||
{
|
||||
xtc_plugin_spec spec; xtc_plugin *plugin = NULL;
|
||||
void *handle, *symbol;
|
||||
void (*read_context)(double *, int64_t *, double *, uint32_t *) = NULL;
|
||||
float data[31] = {0}; double tempo, music; int64_t position; uint32_t flags;
|
||||
assert(xtc_plugin_probe_format(XTC_PLUGIN_VST3,path,0,48000,&spec) == XTC_OK);
|
||||
spec.tempo = 137000;
|
||||
assert(xtc_plugin_create(&spec,48000,31,&plugin) == XTC_OK);
|
||||
handle = dlopen(path,RTLD_NOW | RTLD_LOCAL); assert(handle);
|
||||
symbol = dlsym(handle,"xtc_fixture_context"); assert(symbol && sizeof(symbol) == sizeof(read_context));
|
||||
memcpy(&read_context,&symbol,sizeof(symbol));
|
||||
audio = 1; assert(xtc_plugin_process_at(plugin,data,data,31,48000) == XTC_OK); audio = 0;
|
||||
read_context(&tempo,&position,&music,&flags);
|
||||
assert(tempo == 137 && position == 48000 && music == 137.0/60.0);
|
||||
assert(flags == ((1U << 1) | (1U << 9) | (1U << 10)));
|
||||
assert(xtc_plugin_process_at(plugin,data,data,31,0) == XTC_OK);
|
||||
read_context(&tempo,&position,&music,&flags); assert(position == 0 && music == 0);
|
||||
assert(xtc_plugin_process(plugin,data,data,31) == XTC_OK);
|
||||
read_context(&tempo,&position,&music,&flags); assert(position == 31);
|
||||
assert(xtc_plugin_process_at(plugin,data,data,31,UINT64_MAX) == XTC_ERR_INVALID_ARGUMENT);
|
||||
read_context(&tempo,&position,&music,&flags); assert(position == 31);
|
||||
xtc_plugin_destroy(plugin); assert(dlclose(handle) == 0);
|
||||
puts("VST3 tempo, signed sample clock, seek and sequential context passed.");
|
||||
}
|
||||
int main(int argc,char **argv)
|
||||
{
|
||||
unsigned int i; xtc_plugin_spec spec; xtc_plugin *p = NULL; float data[1] = {1};
|
||||
assert(argc == 4);
|
||||
context_check(argv[3]);
|
||||
check(argv[1],XTC_PLUGIN_CLAP); check(argv[2],XTC_PLUGIN_VST2); check(argv[3],XTC_PLUGIN_VST3);
|
||||
for (i = 1; i < 4; ++i) assert(xtc_plugin_probe_format(XTC_PLUGIN_CLAP,argv[1],i,48000,&spec) != XTC_OK);
|
||||
assert(xtc_plugin_probe_format(XTC_PLUGIN_CLAP,argv[1],4,48000,&spec) == XTC_OK);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ from pathlib import Path
|
|||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import platform
|
||||
|
||||
binary = str(Path(sys.argv[1]).resolve())
|
||||
|
||||
|
|
@ -103,6 +104,18 @@ with tempfile.TemporaryDirectory(prefix="xtc-inspect-") as directory:
|
|||
check("--inspect", project, 2, name + " insert track 0", "missing/unreadable: 1")
|
||||
project.write_text(document.replace("XTC_PROJECT 17", "XTC_PROJECT 16").replace(chain, ""))
|
||||
check("--validate", project, 0, "metadata valid")
|
||||
# A conventional VST3 bundle is inspected without executing its fake binary.
|
||||
architecture = {"x86_64": "x86_64", "aarch64": "aarch64",
|
||||
"i386": "i386", "i686": "i386", "armv7l": "arm"}.get(platform.machine())
|
||||
if architecture:
|
||||
bundle = root / "Example.vst3"
|
||||
inner = bundle / "Contents" / (architecture + "-linux") / "Example.so"
|
||||
inner.parent.mkdir(parents=True)
|
||||
bundled = document.replace(str(module).encode().hex(), str(bundle).encode().hex())
|
||||
project.write_text(bundled)
|
||||
check("--inspect", project, 2, "VST3 insert track 0", "missing/unreadable: 1")
|
||||
inner.write_text("Not a module: metadata inspection must not execute it")
|
||||
check("--inspect", project, 0, "VST3 insert track 0", "no plugin code executed", "missing/unreadable: 0")
|
||||
for text, messages in [
|
||||
(base.replace("XTC_PROJECT 10", "XTC_PROJECT 999"), ("line 1", "999", "1..17")),
|
||||
("XTC_PROJECT 10\n", ("line 2", "APP")),
|
||||
|
|
|
|||
59
tests/integration/test_steinberg_sdk.c
Normal file
59
tests/integration/test_steinberg_sdk.c
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "xtc/xtc_plugin.h"
|
||||
#include "xtc/xtc_project.h"
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
xtc_plugin_spec gain, synth, actual;
|
||||
xtc_plugin *g = NULL, *s = NULL;
|
||||
float in[256], out[256], wet[256];
|
||||
size_t i;
|
||||
xtc_project *project = NULL, *loaded = NULL;
|
||||
uint64_t track;
|
||||
char document[] = "/tmp/xtc-sdk-project-XXXXXX";
|
||||
int fd;
|
||||
xtc_midi_event events[] = {
|
||||
{0}, {0}
|
||||
};
|
||||
assert(argc == 2 && argv[1][0] == '/');
|
||||
assert(xtc_plugin_probe(argv[1],0,48000,&gain) == XTC_OK);
|
||||
assert(gain.format == XTC_PLUGIN_VST3 && gain.inputs == 1 && !gain.instrument);
|
||||
assert(!strcmp(gain.path,argv[1]) && !strcmp(gain.label,"xtc SDK Half Gain"));
|
||||
assert(xtc_plugin_probe_format(XTC_PLUGIN_VST3,argv[1],1,48000,&synth) == XTC_OK);
|
||||
assert(synth.instrument && !synth.inputs && strcmp(synth.identifier,gain.identifier));
|
||||
assert(xtc_plugin_probe(argv[1],2,48000,&actual) == XTC_ERR_UNSUPPORTED); /* Controller, not audio. */
|
||||
assert(xtc_plugin_probe(argv[1],3,48000,&actual) == XTC_ERR_NOT_FOUND);
|
||||
assert(xtc_project_create(&project) == XTC_OK && xtc_project_create(&loaded) == XTC_OK);
|
||||
assert(xtc_project_add_track(project,"SDK Sine",&track) == XTC_OK);
|
||||
assert(xtc_project_set_instrument(project,track,&synth) == XTC_OK);
|
||||
fd = mkstemp(document); assert(fd >= 0 && close(fd) == 0);
|
||||
assert(xtc_project_save(project,document) == XTC_OK && xtc_project_load(loaded,document) == XTC_OK);
|
||||
assert(xtc_project_get_instrument(loaded,track,&actual) == XTC_OK);
|
||||
assert(!strcmp(actual.path,argv[1]) && !strcmp(actual.identifier,synth.identifier));
|
||||
assert(unlink(document) == 0); xtc_project_destroy(project); xtc_project_destroy(loaded);
|
||||
assert(xtc_plugin_create(&gain,48000,256,&g) == XTC_OK);
|
||||
assert(xtc_plugin_create(&synth,48000,256,&s) == XTC_OK);
|
||||
for (i = 0; i < 256; ++i) in[i] = i % 2 ? -.75f : .25f;
|
||||
assert(xtc_plugin_process_at(g,in,out,256,48000) == XTC_OK);
|
||||
for (i = 0; i < 256; ++i) assert(out[i] == in[i]*.5f);
|
||||
events[0].type = XTC_MIDI_NOTE_ON; events[0].offset = 13;
|
||||
events[0].channel = 3; events[0].pitch = 69; events[0].velocity = 127;
|
||||
events[1] = events[0]; events[1].type = XTC_MIDI_NOTE_OFF; events[1].offset = 200;
|
||||
assert(xtc_plugin_process_midi_at(s,events,2,out,256,0) == XTC_OK);
|
||||
for (i = 0; i <= 13; ++i) assert(out[i] == 0);
|
||||
assert(fabsf(out[40]) > .05f);
|
||||
for (i = 200; i < 256; ++i) assert(out[i] == 0);
|
||||
assert(xtc_plugin_process(g,out,wet,256) == XTC_OK);
|
||||
for (i = 0; i < 256; ++i) assert(wet[i] == out[i]*.5f && isfinite(wet[i]));
|
||||
assert(xtc_plugin_process_midi(s,NULL,0,out,256) == XTC_OK);
|
||||
for (i = 0; i < 256; ++i) assert(out[i] == 0);
|
||||
xtc_plugin_destroy(g); xtc_plugin_destroy(s);
|
||||
puts("Official SDK gain/synth: bundle discovery, identities, processing, note offsets and release passed.");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -5,6 +5,13 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
static int loaded, instances;
|
||||
static struct Steinberg_Vst_ProcessContext last_context;
|
||||
void xtc_fixture_context(double *tempo, int64_t *position, double *music, uint32_t *flags);
|
||||
void xtc_fixture_context(double *tempo, int64_t *position, double *music, uint32_t *flags)
|
||||
{
|
||||
*tempo=last_context.tempo; *position=last_context.projectTimeSamples;
|
||||
*music=last_context.projectTimeMusic; *flags=last_context.state;
|
||||
}
|
||||
static const Steinberg_TUID cid = SMTG_INLINE_UID(0x58544333,0x12345678,0x12345678,0x12345678);
|
||||
typedef struct { Steinberg_Vst_IComponent component; Steinberg_Vst_IAudioProcessor processor; unsigned int refs; int initialized, active, started; } instance;
|
||||
static instance *from_processor(void *p) { return (instance *)((char *)p - offsetof(instance,processor)); }
|
||||
|
|
@ -48,6 +55,8 @@ static Steinberg_tresult process(void *self, struct Steinberg_Vst_ProcessData *d
|
|||
{
|
||||
instance *p=from_processor(self);int32_t i;Steinberg_int32 index=-1,offset=-1;Steinberg_Vst_ParamValue value=-1;
|
||||
Steinberg_Vst_IParameterChanges *changes=data->outputParameterChanges;Steinberg_Vst_IParamValueQueue *queue;Steinberg_Vst_ParamID id=7;
|
||||
assert(data->processContext && data->processContext->sampleRate > 0);
|
||||
last_context = *data->processContext;
|
||||
assert(p->started && changes && changes->lpVtbl->getParameterCount(changes)==0);
|
||||
queue=changes->lpVtbl->addParameterData(changes,&id,&index);assert(queue && index==0);
|
||||
assert(queue->lpVtbl->getParameterId(queue)==7 && queue->lpVtbl->getPointCount(queue)==0);
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ static Steinberg_tresult process(void *self, struct Steinberg_Vst_ProcessData *d
|
|||
Steinberg_Vst_IEventList *events = data->inputEvents;
|
||||
int32_t count = events->lpVtbl->getEventCount(events);
|
||||
assert(p->started && data->numInputs == 0);
|
||||
assert(data->processContext && data->processContext->sampleRate > 0 && data->processContext->tempo > 0);
|
||||
for (i = 0; i < data->numSamples; ++i) {
|
||||
while (j < count) {
|
||||
struct Steinberg_Vst_Event event;
|
||||
|
|
|
|||
57
tests/unit/test_plugin_module_path.c
Normal file
57
tests/unit/test_plugin_module_path.c
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "../../src/plugin/module_path.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char root[] = "/tmp/xtc-module-path-XXXXXX", out[512] = "preserved", path[512];
|
||||
char bundle[512], contents[512], binary[512];
|
||||
FILE *file;
|
||||
assert(mkdtemp(root));
|
||||
assert(xtc_plugin_module_path(NULL,out) == XTC_ERR_INVALID_ARGUMENT);
|
||||
assert(xtc_plugin_module_path("relative.vst3",out) == XTC_ERR_INVALID_ARGUMENT);
|
||||
assert(xtc_plugin_module_path(root,out) == XTC_ERR_UNSUPPORTED);
|
||||
assert(!strcmp(out,"preserved"));
|
||||
snprintf(bundle,sizeof(bundle),"%s/Example.vst3",root);
|
||||
assert(mkdir(bundle,0700) == 0);
|
||||
#if defined(__x86_64__) || defined(__aarch64__) || defined(__i386__) || defined(__arm__)
|
||||
assert(xtc_plugin_module_path(bundle,out) == XTC_ERR_NOT_FOUND);
|
||||
#else
|
||||
assert(xtc_plugin_module_path(bundle,out) == XTC_ERR_UNSUPPORTED);
|
||||
assert(rmdir(bundle) == 0 && rmdir(root) == 0);
|
||||
return 0;
|
||||
#endif
|
||||
assert(!strcmp(out,"preserved"));
|
||||
snprintf(contents,sizeof(contents),"%s/Example.vst3/Contents",root);
|
||||
assert(mkdir(contents,0700) == 0);
|
||||
#if defined(__x86_64__)
|
||||
#define ARCH "x86_64-linux"
|
||||
#elif defined(__aarch64__)
|
||||
#define ARCH "aarch64-linux"
|
||||
#elif defined(__i386__)
|
||||
#define ARCH "i386-linux"
|
||||
#elif defined(__arm__)
|
||||
#define ARCH "arm-linux"
|
||||
#else
|
||||
#define ARCH "unsupported"
|
||||
#endif
|
||||
snprintf(path,sizeof(path),"%s/Example.vst3/Contents/" ARCH,root);
|
||||
assert(mkdir(path,0700) == 0);
|
||||
snprintf(binary,sizeof(binary),"%s/Example.vst3/Contents/" ARCH "/Example.so",root);
|
||||
file = fopen(binary,"wb"); assert(file); assert(fclose(file) == 0);
|
||||
assert(xtc_plugin_module_path(bundle,out) == XTC_OK && !strcmp(out,binary));
|
||||
assert(xtc_plugin_module_path(binary,out) == XTC_OK && !strcmp(out,binary));
|
||||
assert(unlink(binary) == 0);
|
||||
assert(mkfifo(binary,0600) == 0);
|
||||
strcpy(out,"preserved");
|
||||
assert(xtc_plugin_module_path(bundle,out) == XTC_ERR_UNSUPPORTED && !strcmp(out,"preserved"));
|
||||
assert(unlink(binary) == 0);
|
||||
assert(rmdir(path) == 0 && rmdir(contents) == 0 && rmdir(bundle) == 0 && rmdir(root) == 0);
|
||||
puts("Plugin binary/bundle resolution and transactional errors passed.");
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue