#define _POSIX_C_SOURCE 200809L #include "xtc/xtc_plugin.h" #include "xtc/xtc_project.h" #include "xtc/xtc_realtime.h" #include #include #include #include #include #include static int audio; void *__real_malloc(size_t); void *__real_calloc(size_t,size_t); void *__real_realloc(void *,size_t); void __real_free(void *); void *__real_dlopen(const char *,int); int __real_dlclose(void *); void *__wrap_malloc(size_t n) { assert(!audio); return __real_malloc(n); } void *__wrap_calloc(size_t n,size_t s) { assert(!audio); return __real_calloc(n,s); } void *__wrap_realloc(void *p,size_t n) { assert(!audio); return __real_realloc(p,n); } void __wrap_free(void *p) { assert(!audio); __real_free(p); } void *__wrap_dlopen(const char *p,int mode) { assert(!audio); return __real_dlopen(p,mode); } int __wrap_dlclose(void *p) { assert(!audio); return __real_dlclose(p); } static void render(xtc_realtime *rt) { float in[31],left[31],right[31]; size_t i; for (i = 0; i < 31; ++i) in[i] = i % 2 ? -.5f : .25f; audio = 1; assert(xtc_realtime_process_stereo(rt,in,NULL,NULL,NULL,NULL,left,right,31) == XTC_OK); audio = 0; for (i = 0; i < 31; ++i) assert(left[i] == in[i]*.5f && right[i] == left[i]); xtc_plugin_idle(); } static void check(const char *path, xtc_plugin_format format) { xtc_plugin_spec spec, actual, bad; xtc_plugin_details details; xtc_plugin *plugin = NULL, *other = NULL; xtc_project *p = NULL, *loaded = NULL; xtc_graph *graph = NULL; xtc_realtime *rt = NULL; size_t node, output, i; char document[] = "/tmp/xtc-modern-XXXXXX"; int fd = mkstemp(document); assert(fd >= 0); close(fd); assert(xtc_plugin_probe(path,0,48000,&spec) == XTC_OK && spec.format == format); assert(xtc_plugin_probe_format(format,path,0,48000,&actual) == XTC_OK); assert(!memcmp(&spec,&actual,sizeof(spec))); assert(xtc_plugin_describe(&spec,48000,&details) == XTC_OK && details.name[0]); assert(xtc_plugin_create(&spec,48000,31,&plugin) == XTC_OK); assert(xtc_plugin_create(&spec,48000,31,&other) == XTC_OK); { float data[31]; for (i = 0; i < 31; ++i) data[i] = 1; audio = 1; assert(xtc_plugin_process(plugin,data,data,31) == XTC_OK); audio = 0; for (i = 0; i < 31; ++i) assert(data[i] == .5f); audio = 1; assert(xtc_plugin_process(other,NULL,data,31) == XTC_OK); audio = 0; for (i = 0; i < 31; ++i) assert(data[i] == 0); assert(xtc_plugin_process(plugin,data,data,32) == XTC_ERR_INVALID_ARGUMENT); } xtc_plugin_idle(); xtc_plugin_destroy(plugin); xtc_plugin_destroy(other); plugin = NULL; assert(xtc_project_create(&p) == XTC_OK && xtc_project_create(&loaded) == XTC_OK); assert(xtc_graph_create(2,&graph) == XTC_OK); assert(xtc_graph_add_plugin(graph,&spec,&node) == XTC_OK && xtc_graph_add_output(graph,&output) == XTC_OK); assert(xtc_graph_connect(graph,node,output) == XTC_OK); assert(xtc_project_set_graph(p,graph) == XTC_OK); assert(xtc_project_save(p,document) == XTC_OK && xtc_project_load(loaded,document) == XTC_OK); assert(xtc_graph_get_plugin(xtc_project_graph(loaded),node,&actual) == XTC_OK); assert(!memcmp(&actual,&spec,sizeof(spec))); assert(xtc_realtime_create(48000,31,&rt) == XTC_OK); assert(xtc_realtime_submit(rt,xtc_project_graph(loaded)) == XTC_OK); render(rt); for (i = 0; i < 50; ++i) { xtc_realtime_collect(rt); assert(xtc_realtime_submit(rt,graph) == XTC_OK); render(rt); } if (format == XTC_PLUGIN_VST3) { bad = spec; strcpy(bad.identifier,"not-a-class-id"); assert(xtc_plugin_spec_validate(&bad) == XTC_ERR_INVALID_ARGUMENT); } bad = spec; bad.control_count = 1; assert(xtc_plugin_spec_validate(&bad) == XTC_ERR_UNSUPPORTED); bad = spec; ++bad.unique_id; assert(xtc_graph_replace_plugin(graph,node,&bad) == XTC_OK); xtc_realtime_collect(rt); assert(xtc_realtime_submit(rt,graph) == XTC_ERR_UNSUPPORTED); render(rt); bad = spec; strcpy(bad.path,"/missing/xtc-modern-plugin.so"); assert(xtc_graph_replace_plugin(graph,node,&bad) == XTC_OK && xtc_project_set_graph(p,graph) == XTC_OK); assert(xtc_project_save(p,document) == XTC_OK && xtc_project_load(loaded,document) == XTC_OK); assert(xtc_graph_get_plugin(xtc_project_graph(loaded),node,&actual) == XTC_OK && !strcmp(actual.path,bad.path)); assert(xtc_plugin_create(&actual,48000,31,&plugin) == XTC_ERR_NOT_FOUND && !plugin); 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)); } int main(int argc,char **argv) { unsigned int i; xtc_plugin_spec spec; xtc_plugin *p = NULL; float data[1] = {1}; assert(argc == 4); 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); assert(xtc_plugin_create(&spec,48000,1,&p) == XTC_OK); assert(xtc_plugin_process(p,data,data,1) == XTC_ERR_INVALID_STATE && data[0] == 0); xtc_plugin_destroy(p); p = NULL; assert(xtc_plugin_probe_format(XTC_PLUGIN_CLAP,argv[1],5,48000,&spec) == XTC_OK); assert(xtc_plugin_create(&spec,48000,1,&p) == XTC_OK); assert(xtc_plugin_process(p,data,data,1) == XTC_ERR_INVALID_STATE && data[0] == 0); xtc_plugin_destroy(p); assert(xtc_plugin_probe_format(XTC_PLUGIN_CLAP,argv[1],6,48000,&spec) == XTC_OK); p = NULL; data[0] = 1; assert(xtc_plugin_create(&spec,48000,1,&p) == XTC_OK); assert(xtc_plugin_process(p,data,data,1) == XTC_OK && data[0] == .5f); xtc_plugin_idle(); assert(xtc_plugin_process(p,data,data,1) == XTC_ERR_INVALID_STATE && data[0] == 0); xtc_plugin_destroy(p); assert(xtc_plugin_probe_format(XTC_PLUGIN_CLAP,argv[1],7,48000,&spec) == XTC_ERR_NOT_FOUND); assert(setenv("XTC_VST2_FIXTURE_LAYOUT","1",1) == 0); assert(xtc_plugin_probe_format(XTC_PLUGIN_VST2,argv[2],0,48000,&spec) == XTC_ERR_UNSUPPORTED); unsetenv("XTC_VST2_FIXTURE_LAYOUT"); assert(setenv("XTC_VST3_FIXTURE_INIT","1",1) == 0); assert(xtc_plugin_probe_format(XTC_PLUGIN_VST3,argv[3],0,48000,&spec) == XTC_ERR_INVALID_STATE); unsetenv("XTC_VST3_FIXTURE_INIT"); puts("Modern plugin partial initialization/start/process failures passed."); return 0; }