2026-10-27 17:34:46 +01:00
|
|
|
#include <stdbool.h>
|
|
|
|
|
#include <vst3_c_api.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <stddef.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
static int loaded, instances;
|
|
|
|
|
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)); }
|
|
|
|
|
static Steinberg_tresult cq(void *self, const Steinberg_TUID iid, void **out)
|
|
|
|
|
{
|
|
|
|
|
instance *p = self; *out = NULL;
|
|
|
|
|
if (!memcmp(iid,Steinberg_Vst_IAudioProcessor_iid,16)) *out = &p->processor;
|
|
|
|
|
else if (!memcmp(iid,Steinberg_Vst_IComponent_iid,16) || !memcmp(iid,Steinberg_FUnknown_iid,16)) *out = &p->component;
|
|
|
|
|
if (!*out) return -1;
|
|
|
|
|
++p->refs; return 0;
|
|
|
|
|
}
|
|
|
|
|
static Steinberg_uint32 add(void *self) { return ++((instance *)self)->refs; }
|
|
|
|
|
static Steinberg_uint32 release(void *self)
|
|
|
|
|
{ instance *p = self; unsigned int refs = --p->refs; if (!refs) { assert(!p->initialized); --instances; free(p); } return refs; }
|
|
|
|
|
static Steinberg_tresult pq(void *self, const Steinberg_TUID iid, void **out) { return cq(from_processor(self),iid,out); }
|
|
|
|
|
static Steinberg_uint32 pa(void *self) { return add(from_processor(self)); }
|
|
|
|
|
static Steinberg_uint32 pr(void *self) { return release(from_processor(self)); }
|
|
|
|
|
static Steinberg_tresult init(void *self, Steinberg_FUnknown *host)
|
|
|
|
|
{ instance *p = self; assert(loaded && host && !p->initialized); if (getenv("XTC_VST3_FIXTURE_INIT")) return -1; p->initialized = 1; return 0; }
|
|
|
|
|
static Steinberg_tresult terminate(void *self) { instance *p = self; assert(p->initialized && !p->active); p->initialized = 0; return 0; }
|
|
|
|
|
static Steinberg_tresult controller(void *self, Steinberg_TUID id) { (void)self; (void)id; return -1; }
|
|
|
|
|
static Steinberg_tresult mode(void *self, Steinberg_Vst_IoMode m) { (void)self; (void)m; return 0; }
|
|
|
|
|
static Steinberg_int32 buses(void *self, Steinberg_Vst_MediaType type, Steinberg_Vst_BusDirection dir) { (void)self; (void)dir; return type == 0 ? 1 : 0; }
|
|
|
|
|
static Steinberg_tresult bus_info(void *self, Steinberg_Vst_MediaType type, Steinberg_Vst_BusDirection dir, Steinberg_int32 index, struct Steinberg_Vst_BusInfo *info)
|
|
|
|
|
{ (void)self; (void)dir; assert(type == 0 && index == 0); memset(info,0,sizeof(*info)); info->channelCount = 1; return 0; }
|
|
|
|
|
static Steinberg_tresult routing(void *self, struct Steinberg_Vst_RoutingInfo *in, struct Steinberg_Vst_RoutingInfo *out)
|
|
|
|
|
{ (void)self; (void)in; (void)out; return -1; }
|
|
|
|
|
static Steinberg_tresult activate_bus(void *self, Steinberg_Vst_MediaType type, Steinberg_Vst_BusDirection dir, Steinberg_int32 index, Steinberg_TBool state)
|
|
|
|
|
{ (void)self; (void)type; (void)dir; (void)index; (void)state; return 0; }
|
|
|
|
|
static Steinberg_tresult active(void *self, Steinberg_TBool state) { instance *p = self; assert(!p->started); p->active = state; return 0; }
|
|
|
|
|
static Steinberg_tresult state(void *self, Steinberg_IBStream *stream) { (void)self; (void)stream; return -1; }
|
|
|
|
|
static Steinberg_tresult arrangements(void *self, Steinberg_Vst_SpeakerArrangement *in, Steinberg_int32 ni, Steinberg_Vst_SpeakerArrangement *out, Steinberg_int32 no)
|
|
|
|
|
{ (void)self; return ni == 1 && no == 1 && in[0] == Steinberg_Vst_SpeakerArr_kMono && out[0] == in[0] ? 0 : -1; }
|
|
|
|
|
static Steinberg_tresult arrangement(void *self, Steinberg_Vst_BusDirection dir, Steinberg_int32 index, Steinberg_Vst_SpeakerArrangement *out)
|
|
|
|
|
{ (void)self; (void)dir; (void)index; *out = Steinberg_Vst_SpeakerArr_kMono; return 0; }
|
|
|
|
|
static Steinberg_tresult sample_size(void *self, Steinberg_int32 size) { (void)self; return size == 0 ? 0 : -1; }
|
|
|
|
|
static Steinberg_uint32 latency(void *self) { (void)self; return 0; }
|
|
|
|
|
static Steinberg_tresult setup(void *self, struct Steinberg_Vst_ProcessSetup *data) { (void)self; return data->maxSamplesPerBlock > 0 && data->sampleRate > 0 ? 0 : -1; }
|
|
|
|
|
static Steinberg_tresult processing(void *self, Steinberg_TBool value) { instance *p = from_processor(self); assert(p->active); p->started = value; return 0; }
|
|
|
|
|
static Steinberg_tresult process(void *self, struct Steinberg_Vst_ProcessData *data)
|
2026-11-06 01:50:25 +01:00
|
|
|
{
|
|
|
|
|
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(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);
|
|
|
|
|
assert(queue->lpVtbl->addPoint(queue,0,.2,&index)==0 && queue->lpVtbl->addPoint(queue,1,.8,&index)==0);
|
|
|
|
|
assert(queue->lpVtbl->getPointCount(queue)==1 && queue->lpVtbl->getPoint(queue,0,&offset,&value)==0 && offset==1 && value==.8);
|
|
|
|
|
assert(changes->lpVtbl->getParameterData(changes,0)==queue && changes->lpVtbl->getParameterData(changes,-1)==NULL);
|
|
|
|
|
for(id=8;id<71;++id)assert(changes->lpVtbl->addParameterData(changes,&id,&index));
|
|
|
|
|
assert(changes->lpVtbl->getParameterCount(changes)==64);
|
|
|
|
|
assert(changes->lpVtbl->addParameterData(changes,&id,&index)==NULL);
|
|
|
|
|
for(i=0;i<data->numSamples;++i)data->outputs[0].Steinberg_Vst_AudioBusBuffers_channelBuffers32[0][i]=data->inputs[0].Steinberg_Vst_AudioBusBuffers_channelBuffers32[0][i]*.5f;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2026-10-27 17:34:46 +01:00
|
|
|
static Steinberg_Vst_IComponentVtbl component_vtable = {cq,add,release,init,terminate,controller,mode,buses,bus_info,routing,activate_bus,active,state,state};
|
|
|
|
|
static Steinberg_Vst_IAudioProcessorVtbl processor_vtable = {pq,pa,pr,arrangements,arrangement,sample_size,latency,setup,processing,process,latency};
|
|
|
|
|
static Steinberg_tresult fq(void *self, const Steinberg_TUID iid, void **out) { (void)iid; *out = self; return 0; }
|
|
|
|
|
static Steinberg_uint32 fr(void *self) { (void)self; return 1; }
|
|
|
|
|
static Steinberg_tresult factory_info(void *self, struct Steinberg_PFactoryInfo *info) { (void)self; memset(info,0,sizeof(*info)); return 0; }
|
|
|
|
|
static Steinberg_int32 classes(void *self) { (void)self; return 1; }
|
|
|
|
|
static Steinberg_tresult class_info(void *self, Steinberg_int32 index, struct Steinberg_PClassInfo *info)
|
|
|
|
|
{ (void)self; if (index) return -1; memset(info,0,sizeof(*info)); memcpy(info->cid,cid,16); strcpy(info->category,"Audio Module Class"); strcpy(info->name,"VST3 gain"); return 0; }
|
|
|
|
|
static Steinberg_tresult create(void *self, Steinberg_FIDString id, Steinberg_FIDString iid, void **out)
|
|
|
|
|
{
|
|
|
|
|
instance *p; (void)self; *out = NULL;
|
|
|
|
|
if (memcmp(id,cid,16) || memcmp(iid,Steinberg_Vst_IComponent_iid,16)) return -1;
|
|
|
|
|
p = calloc(1,sizeof(*p)); if (!p) return -1;
|
|
|
|
|
p->component.lpVtbl = &component_vtable; p->processor.lpVtbl = &processor_vtable; p->refs = 1;
|
|
|
|
|
++instances; *out = p; return 0;
|
|
|
|
|
}
|
|
|
|
|
static Steinberg_IPluginFactoryVtbl factory_vtable = {fq,fr,fr,factory_info,classes,class_info,create};
|
|
|
|
|
static Steinberg_IPluginFactory factory = {&factory_vtable};
|
|
|
|
|
bool ModuleEntry(void *handle);
|
|
|
|
|
bool ModuleExit(void);
|
|
|
|
|
Steinberg_IPluginFactory *GetPluginFactory(void);
|
|
|
|
|
bool ModuleEntry(void *handle) { assert(handle && !loaded); loaded = 1; return true; }
|
|
|
|
|
bool ModuleExit(void) { assert(loaded && !instances); loaded = 0; return true; }
|
|
|
|
|
Steinberg_IPluginFactory *GetPluginFactory(void) { assert(loaded); return &factory; }
|