100 lines
6.3 KiB
C
100 lines
6.3 KiB
C
|
|
#include <clap/clap.h>
|
||
|
|
#include <clap/ext/thread-check.h>
|
||
|
|
#include <assert.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
static int loaded, count;
|
||
|
|
static const char *features[] = {CLAP_PLUGIN_FEATURE_INSTRUMENT,NULL};
|
||
|
|
static const clap_plugin_descriptor_t descriptors[] = {
|
||
|
|
{CLAP_VERSION,"xtc.fixture.gain","CLAP gain","xtc","","","","1","",features},
|
||
|
|
{CLAP_VERSION,"xtc.fixture.stereo","Stereo","xtc","","","","1","",features},
|
||
|
|
{CLAP_VERSION,"xtc.fixture.init","Init failure","xtc","","","","1","",features},
|
||
|
|
{CLAP_VERSION,"xtc.fixture.activate","Activate failure","xtc","","","","1","",features},
|
||
|
|
{CLAP_VERSION,"xtc.fixture.start","Start failure","xtc","","","","1","",features},
|
||
|
|
{CLAP_VERSION,"xtc.fixture.process","Process failure","xtc","","","","1","",features},
|
||
|
|
{CLAP_VERSION,"xtc.fixture.restart","Restart request","xtc","","","","1","",features}
|
||
|
|
};
|
||
|
|
typedef struct { clap_plugin_t plugin; const clap_host_t *host; unsigned int index; int active, started; float level; } instance;
|
||
|
|
static bool init(const clap_plugin_t *plugin)
|
||
|
|
{ instance *p = plugin->plugin_data; assert(loaded); return p->index != 2; }
|
||
|
|
static void destroy(const clap_plugin_t *plugin)
|
||
|
|
{ instance *p = plugin->plugin_data; assert(!p->active && !p->started); --count; free(p); }
|
||
|
|
static bool activate(const clap_plugin_t *plugin, double rate, uint32_t min, uint32_t max)
|
||
|
|
{ instance *p = plugin->plugin_data; assert(rate > 0 && min && max >= min && !p->active); if (p->index == 3) return false; p->active = 1; return true; }
|
||
|
|
static void deactivate(const clap_plugin_t *plugin)
|
||
|
|
{ instance *p = plugin->plugin_data; assert(p->active && !p->started); p->active = 0; }
|
||
|
|
static bool start(const clap_plugin_t *plugin)
|
||
|
|
{
|
||
|
|
instance *p = plugin->plugin_data;
|
||
|
|
const clap_host_thread_check_t *check = p->host->get_extension(p->host,CLAP_EXT_THREAD_CHECK);
|
||
|
|
assert(p->active && !p->started && check->is_audio_thread(p->host));
|
||
|
|
if (p->index == 4) return false;
|
||
|
|
p->started = 1; return true;
|
||
|
|
}
|
||
|
|
static void stop(const clap_plugin_t *plugin)
|
||
|
|
{ instance *p = plugin->plugin_data; assert(p->started); p->started = 0; }
|
||
|
|
static void reset(const clap_plugin_t *plugin) { (void)plugin; }
|
||
|
|
static clap_process_status process(const clap_plugin_t *plugin, const clap_process_t *block)
|
||
|
|
{
|
||
|
|
instance *p = plugin->plugin_data; uint32_t i;
|
||
|
|
uint32_t j = 0, event_total = block->in_events->size(block->in_events);
|
||
|
|
assert(p->started && block->audio_inputs_count == 0 && block->audio_outputs_count == 1);
|
||
|
|
if (p->index == 5) return CLAP_PROCESS_ERROR;
|
||
|
|
for (i = 0; i < block->frames_count; ++i) {
|
||
|
|
while (j < event_total) {
|
||
|
|
const clap_event_header_t *h = block->in_events->get(block->in_events,j);
|
||
|
|
const clap_event_midi_t *m = (const clap_event_midi_t *)h;
|
||
|
|
if (h->time != i) break;
|
||
|
|
++j;
|
||
|
|
if (h->type != CLAP_EVENT_MIDI) {
|
||
|
|
const clap_event_note_t *note = (const clap_event_note_t *)h;
|
||
|
|
assert(h->type == CLAP_EVENT_NOTE_ON || h->type == CLAP_EVENT_NOTE_OFF || h->type == CLAP_EVENT_NOTE_CHOKE);
|
||
|
|
p->level = h->type == CLAP_EVENT_NOTE_ON ? (float)note->velocity : 0;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if ((m->data[0]&240) == 144) p->level = (float)m->data[2]/127;
|
||
|
|
else if ((m->data[0]&240) == 128 || ((m->data[0]&240) == 176 && m->data[1] == 120)) p->level = 0;
|
||
|
|
}
|
||
|
|
block->audio_outputs[0].data32[0][i] = p->level;
|
||
|
|
}
|
||
|
|
p->host->request_callback(p->host);
|
||
|
|
if (p->index == 6) p->host->request_restart(p->host);
|
||
|
|
return CLAP_PROCESS_CONTINUE;
|
||
|
|
}
|
||
|
|
static uint32_t port_count(const clap_plugin_t *plugin, bool input) { (void)plugin; return input ? 0 : 1; }
|
||
|
|
static bool port_get(const clap_plugin_t *plugin, uint32_t index, bool input, clap_audio_port_info_t *info)
|
||
|
|
{ instance *p = plugin->plugin_data; (void)input; if (index) return false; memset(info,0,sizeof(*info)); info->channel_count = p->index == 1 ? 2 : 1; return true; }
|
||
|
|
static uint32_t latency(const clap_plugin_t *plugin)
|
||
|
|
{ instance *p = plugin->plugin_data; assert(p->active); return 0; }
|
||
|
|
static uint32_t note_count(const clap_plugin_t *p, bool input) { (void)p; return input ? 1 : 0; }
|
||
|
|
static bool note_get(const clap_plugin_t *p, uint32_t index, bool input, clap_note_port_info_t *info)
|
||
|
|
{ (void)p; if (index || !input) return false; memset(info,0,sizeof(*info)); info->supported_dialects = info->preferred_dialect = getenv("XTC_TEST_NATIVE_NOTES") ? CLAP_NOTE_DIALECT_CLAP : CLAP_NOTE_DIALECT_MIDI; return true; }
|
||
|
|
static const void *extension(const clap_plugin_t *plugin, const char *id)
|
||
|
|
{
|
||
|
|
static const clap_plugin_audio_ports_t ports = {port_count,port_get};
|
||
|
|
static const clap_plugin_latency_t delay = {latency}; (void)plugin;
|
||
|
|
static const clap_plugin_note_ports_t notes = {note_count,note_get};
|
||
|
|
if (!strcmp(id,CLAP_EXT_NOTE_PORTS)) return ¬es;
|
||
|
|
if (!strcmp(id,CLAP_EXT_AUDIO_PORTS)) return &ports;
|
||
|
|
return !strcmp(id,CLAP_EXT_LATENCY) ? &delay : NULL;
|
||
|
|
}
|
||
|
|
static void on_main(const clap_plugin_t *plugin)
|
||
|
|
{ instance *p = plugin->plugin_data; const clap_host_thread_check_t *check = p->host->get_extension(p->host,CLAP_EXT_THREAD_CHECK); assert(check->is_main_thread(p->host)); }
|
||
|
|
static uint32_t plugin_count(const clap_plugin_factory_t *factory) { (void)factory; return 7; }
|
||
|
|
static const clap_plugin_descriptor_t *descriptor(const clap_plugin_factory_t *factory, uint32_t index)
|
||
|
|
{ (void)factory; return index < 7 ? descriptors+index : NULL; }
|
||
|
|
static const clap_plugin_t *create(const clap_plugin_factory_t *factory, const clap_host_t *host, const char *id)
|
||
|
|
{
|
||
|
|
unsigned int i; instance *p; (void)factory;
|
||
|
|
for (i = 0; i < 7 && strcmp(id,descriptors[i].id); ++i) {}
|
||
|
|
if (i == 7) return NULL;
|
||
|
|
p = calloc(1,sizeof(*p)); if (!p) return NULL;
|
||
|
|
p->host = host; p->index = i;
|
||
|
|
p->plugin = (clap_plugin_t){descriptors+i,p,init,destroy,activate,deactivate,start,stop,reset,process,extension,on_main};
|
||
|
|
++count; return &p->plugin;
|
||
|
|
}
|
||
|
|
static bool entry_init(const char *path) { (void)path; assert(!loaded); loaded = 1; return true; }
|
||
|
|
static void entry_exit(void) { assert(loaded && !count); loaded = 0; }
|
||
|
|
static const void *factory(const char *id)
|
||
|
|
{ static const clap_plugin_factory_t f = {plugin_count,descriptor,create}; return !strcmp(id,CLAP_PLUGIN_FACTORY_ID) ? &f : NULL; }
|
||
|
|
CLAP_EXPORT const clap_plugin_entry_t clap_entry = {CLAP_VERSION,entry_init,entry_exit,factory};
|