xtc/src/native/native.c

105 lines
3.3 KiB
C
Raw Normal View History

#include "xtc/xtc_native.h"
#include <math.h>
#include <stdlib.h>
struct xtc_native {
xtc_native_descriptor descriptor;
void *state;
size_t max_frames;
uint64_t next_position;
};
xtc_result xtc_native_validate(const xtc_native_descriptor *d)
{
size_t i;
if (!d)
return XTC_ERR_INVALID_ARGUMENT;
if (d->abi_version != XTC_NATIVE_ABI_VERSION || d->struct_size != sizeof(*d))
return XTC_ERR_UNSUPPORTED;
if (d->kind < XTC_NATIVE_EFFECT || d->kind > XTC_NATIVE_INSTRUMENT || !d->prepare ||
!d->reset || !d->process || !d->destroy || !d->identifier[0])
return XTC_ERR_INVALID_ARGUMENT;
for (i = 0; i < sizeof(d->identifier); ++i) {
unsigned char c = (unsigned char)d->identifier[i];
if (!c)
return XTC_OK;
if (c < 33 || c > 126)
return XTC_ERR_INVALID_ARGUMENT;
}
return XTC_ERR_INVALID_ARGUMENT;
}
xtc_result xtc_native_create(const xtc_native_descriptor *d, double rate, size_t frames,
float value, xtc_native **out)
{
xtc_native *p;
xtc_result r;
if (!out)
return XTC_ERR_INVALID_ARGUMENT;
*out = NULL;
r = xtc_native_validate(d);
if (r != XTC_OK)
return r;
if (!isfinite(rate) || rate <= 0 || rate > 768000 || !frames || frames > 65536 ||
!isfinite(value))
return XTC_ERR_INVALID_ARGUMENT;
p = calloc(1, sizeof(*p));
if (!p)
return XTC_ERR_OUT_OF_MEMORY;
p->descriptor = *d;
p->max_frames = frames;
p->next_position = UINT64_MAX;
r = d->prepare(rate, frames, value, &p->state);
if (r != XTC_OK) {
xtc_native_destroy(p);
return r;
}
p->descriptor.reset(p->state);
*out = p;
return XTC_OK;
}
void xtc_native_destroy(xtc_native *p)
{
if (p) {
p->descriptor.destroy(p->state);
free(p);
}
}
void xtc_native_reset(xtc_native *p)
{
if (p) {
p->descriptor.reset(p->state);
p->next_position = UINT64_MAX;
}
}
xtc_result xtc_native_process(xtc_native *p, const xtc_native_block *b)
{
size_t i;
xtc_result r;
if (!p || !b || !b->output || b->position > UINT64_MAX - b->frames ||
b->event_count > XTC_MIDI_MAX_EVENTS || (b->event_count && !b->events) ||
(b->event_count && p->descriptor.kind != XTC_NATIVE_INSTRUMENT))
return XTC_ERR_INVALID_ARGUMENT;
if (b->frames > p->max_frames)
return XTC_ERR_CAPACITY;
for (i = 0; i < b->event_count; ++i) {
const xtc_midi_event *e = b->events + i;
if (e->offset >= b->frames || (i && e->offset < b->events[i - 1].offset) ||
e->type < XTC_MIDI_NOTE_ON || e->type > XTC_MIDI_ALL_OFF || e->channel > 15 ||
e->pitch > 127 || e->velocity > 127 || (e->type == XTC_MIDI_NOTE_ON && !e->velocity))
return XTC_ERR_INVALID_ARGUMENT;
}
if (!b->frames)
return XTC_OK;
if (p->next_position != b->position)
p->descriptor.reset(p->state);
r = p->descriptor.process(p->state, b);
if (r != XTC_OK) {
for (i = 0; i < b->frames; ++i)
b->output[i] = 0;
xtc_native_reset(p);
return r;
}
for (i = 0; i < b->frames; ++i)
if (!isfinite(b->output[i]))
b->output[i] = 0;
p->next_position = b->position + b->frames;
return XTC_OK;
}