xtc/src/plugin/host.c

110 lines
5.8 KiB
C
Raw Normal View History

#include "modern.h"
#include <dlfcn.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct xtc_ladspa_plugin xtc_ladspa_plugin;
xtc_result xtc_ladspa_probe(const char *, unsigned int, double, xtc_plugin_spec *);
xtc_result xtc_ladspa_describe(const xtc_plugin_spec *, double, xtc_plugin_details *);
xtc_result xtc_ladspa_create(const xtc_plugin_spec *, double, size_t, xtc_ladspa_plugin **);
void xtc_ladspa_destroy(xtc_ladspa_plugin *);
xtc_result xtc_ladspa_process_at(xtc_ladspa_plugin *, const float *, float *, size_t, uint64_t);
struct xtc_plugin { xtc_ladspa_plugin *ladspa; xtc_modern *modern; uint64_t next; };
const char *xtc_plugin_format_name(xtc_plugin_format f)
{ static const char *names[] = {"LADSPA", "CLAP", "VST2", "VST3"}; return f >= 0 && f <= XTC_PLUGIN_VST3 ? names[f] : "Unknown"; }
xtc_result xtc_plugin_probe_format(xtc_plugin_format f, const char *path, unsigned int index, double rate, xtc_plugin_spec *out)
{
xtc_modern *p = NULL; xtc_result r;
if (!out || !path || path[0] != '/' || strlen(path) >= 512 || index >= 1024 || !isfinite(rate) || rate < 1 || rate > 768000)
return XTC_ERR_INVALID_ARGUMENT;
if (f == XTC_PLUGIN_LADSPA) return xtc_ladspa_probe(path,index,rate,out);
if (f < XTC_PLUGIN_CLAP || f > XTC_PLUGIN_VST3) return XTC_ERR_INVALID_ARGUMENT;
r = xtc_modern_open(f,path,index,rate,256,&p,out);
xtc_modern_destroy(p); return r;
}
xtc_result xtc_plugin_probe(const char *path, unsigned int index, double rate, xtc_plugin_spec *out)
{
void *module; xtc_plugin_format f = XTC_PLUGIN_LADSPA;
if (!path || path[0] != '/' || strlen(path) >= 512) return XTC_ERR_INVALID_ARGUMENT;
module = dlopen(path,RTLD_NOW | RTLD_LOCAL);
if (!module) return XTC_ERR_NOT_FOUND;
if (dlsym(module,"clap_entry")) f = XTC_PLUGIN_CLAP;
else if (dlsym(module,"VSTPluginMain")) f = XTC_PLUGIN_VST2;
else if (dlsym(module,"GetPluginFactory")) f = XTC_PLUGIN_VST3;
dlclose(module);
return xtc_plugin_probe_format(f,path,index,rate,out);
}
xtc_result xtc_plugin_describe(const xtc_plugin_spec *s, double rate, xtc_plugin_details *out)
{
xtc_plugin_spec actual; xtc_result r;
if (!out || xtc_plugin_spec_validate(s) != XTC_OK) return XTC_ERR_INVALID_ARGUMENT;
if (s->format == XTC_PLUGIN_LADSPA) return xtc_ladspa_describe(s,rate,out);
r = xtc_plugin_probe_format(s->format,s->path,s->index,rate,&actual);
if (r != XTC_OK) return r;
if (actual.instrument != s->instrument || actual.unique_id != s->unique_id || strcmp(actual.identifier,s->identifier) || strcmp(actual.label,s->label)) return XTC_ERR_UNSUPPORTED;
memset(out,0,sizeof(*out)); snprintf(out->name,sizeof(out->name),"%s",s->label);
snprintf(out->maker,sizeof(out->maker),"Not exposed by this adapter");
snprintf(out->copyright,sizeof(out->copyright),"See plugin license");
return XTC_OK;
}
void xtc_plugin_destroy(xtc_plugin *p)
{ if (p) { xtc_ladspa_destroy(p->ladspa); xtc_modern_destroy(p->modern); free(p); } }
xtc_result xtc_plugin_create(const xtc_plugin_spec *s, double rate, size_t frames, xtc_plugin **out)
{
xtc_plugin *p; xtc_result r; xtc_plugin_spec actual;
if (!out) return XTC_ERR_INVALID_ARGUMENT;
*out = NULL;
r = xtc_plugin_spec_validate(s); if (r != XTC_OK) return r;
if (!frames || frames > 65536 || !isfinite(rate) || rate < 1 || rate > 768000) return XTC_ERR_INVALID_ARGUMENT;
p = calloc(1,sizeof(*p)); if (!p) return XTC_ERR_OUT_OF_MEMORY;
if (s->format == XTC_PLUGIN_LADSPA) r = xtc_ladspa_create(s,rate,frames,&p->ladspa);
else {
r = xtc_modern_open(s->format,s->path,s->index,rate,frames,&p->modern,&actual);
if (r == XTC_OK && (actual.instrument != s->instrument || actual.unique_id != s->unique_id || actual.inputs != s->inputs ||
strcmp(actual.identifier,s->identifier) || strcmp(actual.label,s->label))) r = XTC_ERR_UNSUPPORTED;
}
if (r != XTC_OK) { xtc_plugin_destroy(p); return r; }
*out = p; return XTC_OK;
}
xtc_result xtc_plugin_process_at(xtc_plugin *p, const float *in, float *out, size_t frames, uint64_t position)
{
xtc_result r;
if (!p) return XTC_ERR_INVALID_ARGUMENT;
r = p->modern ? xtc_modern_process(p->modern,in,out,frames) : xtc_ladspa_process_at(p->ladspa,in,out,frames,position);
if (r == XTC_OK) p->next = position <= UINT64_MAX-frames ? position+frames : 0;
return r;
}
xtc_result xtc_plugin_process_midi(xtc_plugin *p, const xtc_midi_event *events, size_t count, float *out, size_t frames)
{ return p && p->modern ? xtc_modern_process_midi(p->modern,events,count,out,frames) : XTC_ERR_UNSUPPORTED; }
xtc_result xtc_plugin_process(xtc_plugin *p, const float *in, float *out, size_t frames)
{ return xtc_plugin_process_at(p,in,out,frames,p ? p->next : 0); }
xtc_result xtc_plugin_parameters(const xtc_plugin_spec *s, double rate, xtc_parameter_info out[XTC_PLUGIN_CONTROLS])
{
xtc_plugin_details details;
xtc_result r;
if (!out) return XTC_ERR_INVALID_ARGUMENT;
r = xtc_plugin_describe(s,rate,&details);
if (r == XTC_OK) memcpy(out,details.parameters,sizeof(details.parameters));
return r;
}
xtc_result xtc_plugin_reset(xtc_plugin_spec *s, double rate, unsigned int port)
{
xtc_plugin_details details;
xtc_plugin_spec candidate;
size_t i, count = 0;
int found = port == UINT32_MAX;
xtc_result r = xtc_plugin_describe(s,rate,&details);
if (r != XTC_OK) return r;
candidate = *s;
for (i = 0; i < s->control_count; ++i) if (port == UINT32_MAX || s->ports[i] == port) {
candidate.values[i] = details.parameters[i].default_value;
found = 1;
}
if (!found) return XTC_ERR_NOT_FOUND;
for (i = 0; i < s->point_count; ++i)
if (port != UINT32_MAX && s->points[i].port != port) candidate.points[count++] = s->points[i];
candidate.point_count = (unsigned int)count;
*s = candidate;
return XTC_OK;
}