108 lines
5.5 KiB
C
108 lines
5.5 KiB
C
#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.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.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(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;
|
|
}
|