refined state api and implemented in lv2 and vst3
This commit is contained in:
parent
440b49c14d
commit
5663b4389c
@ -26,16 +26,20 @@ typedef struct {
|
||||
const char * format;
|
||||
const char * (*get_bindir)(void *handle);
|
||||
const char * (*get_datadir)(void *handle);
|
||||
{{?it.product.state && it.product.state.dspCustom}}
|
||||
int (*write_state)(void *handle, const char *data, size_t length);
|
||||
{{?it.product.parameters.find(x => x.direction == "input")}}
|
||||
void (*load_parameter)(void *handle, size_t index, float value);
|
||||
{{?}}
|
||||
void (*lock_state)(void *handle);
|
||||
void (*unlock_state)(void *handle);
|
||||
{{?}}
|
||||
} plugin_callbacks;
|
||||
|
||||
{{?it.product.state && it.product.state.dspCustom}}
|
||||
typedef struct {
|
||||
void * handle;
|
||||
void (*lock)(void *handle);
|
||||
void (*unlock)(void *handle);
|
||||
int (*write)(void *handle, const char *data, size_t length);
|
||||
{{?it.product.parameters.find(x => x.direction == "input")}}
|
||||
void (*set_parameter)(void *handle, size_t index, float value);
|
||||
{{?}}
|
||||
} plugin_state_callbacks;
|
||||
{{?}}
|
||||
|
||||
typedef struct {
|
||||
void * handle;
|
||||
const char * format;
|
||||
|
@ -127,6 +127,7 @@ typedef struct {
|
||||
#ifdef DATA_STATE_DSP_CUSTOM
|
||||
LV2_URID uri_atom_Chunk;
|
||||
LV2_URID uri_state_data;
|
||||
plugin_state_callbacks state_cbs;
|
||||
LV2_State_Store_Function state_store;
|
||||
LV2_State_Handle state_handle;
|
||||
#endif
|
||||
@ -138,13 +139,25 @@ static const char * get_bundle_path_cb(void *handle) {
|
||||
}
|
||||
|
||||
#ifdef DATA_STATE_DSP_CUSTOM
|
||||
static int write_state_cb(void *handle, const char *data, size_t length) {
|
||||
static void state_lock_cb(void *handle) {
|
||||
plugin_instance * i = (plugin_instance *)handle;
|
||||
while (atomic_flag_test_and_set(&i->sync_lock_flag))
|
||||
yield();
|
||||
i->synced = 0;
|
||||
}
|
||||
|
||||
static void state_unlock_cb(void *handle) {
|
||||
plugin_instance * i = (plugin_instance *)handle;
|
||||
atomic_flag_clear(&i->sync_lock_flag);
|
||||
}
|
||||
|
||||
static int state_write_cb(void *handle, const char *data, size_t length) {
|
||||
plugin_instance * i = (plugin_instance *)handle;
|
||||
return i->state_store(i->state_handle, i->uri_state_data, data, length, i->uri_atom_Chunk, LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
|
||||
}
|
||||
|
||||
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
|
||||
static void load_parameter_cb(void *handle, size_t index, float value) {
|
||||
static void state_set_parameter_cb(void *handle, size_t index, float value) {
|
||||
plugin_instance * i = (plugin_instance *)handle;
|
||||
size_t idx = index_to_param[index] - CONTROL_INPUT_INDEX_OFFSET;
|
||||
value = adjust_param(idx, value);
|
||||
@ -152,18 +165,6 @@ static void load_parameter_cb(void *handle, size_t index, float value) {
|
||||
i->loaded = 1;
|
||||
}
|
||||
# endif
|
||||
|
||||
static void lock_state_cb(void *handle) {
|
||||
plugin_instance * i = (plugin_instance *)handle;
|
||||
while (atomic_flag_test_and_set(&i->sync_lock_flag))
|
||||
yield();
|
||||
i->synced = 0;
|
||||
}
|
||||
|
||||
static void unlock_state_cb(void *handle) {
|
||||
plugin_instance * i = (plugin_instance *)handle;
|
||||
atomic_flag_clear(&i->sync_lock_flag);
|
||||
}
|
||||
#endif
|
||||
|
||||
static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double sample_rate, const char * bundle_path, const LV2_Feature * const * features) {
|
||||
@ -207,15 +208,7 @@ static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double s
|
||||
/* .handle = */ (void *)instance,
|
||||
/* .format = */ "lv2",
|
||||
/* .get_bindir = */ get_bundle_path_cb,
|
||||
/* .get_datadir = */ get_bundle_path_cb,
|
||||
# ifdef DATA_STATE_DSP_CUSTOM
|
||||
/* .write_state = */ write_state_cb,
|
||||
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
|
||||
/* .load_parameter = */ load_parameter_cb,
|
||||
# endif
|
||||
/* .lock_state = */ lock_state_cb,
|
||||
/* .unlock_state = */ unlock_state_cb,
|
||||
# endif
|
||||
/* .get_datadir = */ get_bundle_path_cb
|
||||
};
|
||||
plugin_init(&instance->p, &cbs);
|
||||
|
||||
@ -447,7 +440,16 @@ static LV2_State_Status state_save(LV2_Handle instance, LV2_State_Store_Function
|
||||
}
|
||||
i->state_store = store;
|
||||
i->state_handle = handle;
|
||||
return plugin_state_save(&i->p) == 0 ? LV2_STATE_SUCCESS : LV2_STATE_ERR_UNKNOWN;
|
||||
plugin_state_callbacks cbs = {
|
||||
/* .handle = */ (void *)i,
|
||||
/* .lock = */ state_lock_cb,
|
||||
/* .unlock = */ state_unlock_cb,
|
||||
/* .write = */ state_write_cb,
|
||||
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
|
||||
/* .set_parameter = */ NULL
|
||||
# endif
|
||||
};
|
||||
return plugin_state_save(&i->p, &cbs) == 0 ? LV2_STATE_SUCCESS : LV2_STATE_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
static LV2_State_Status state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, uint32_t flags, const LV2_Feature * const * features) {
|
||||
@ -466,8 +468,16 @@ static LV2_State_Status state_restore(LV2_Handle instance, LV2_State_Retrieve_Fu
|
||||
lv2_log_error(&i->logger, "Cannot restore state since property <%s> could not be retrieved\n", DATA_LV2_URI "#state_data");
|
||||
return LV2_STATE_ERR_NO_PROPERTY;
|
||||
}
|
||||
plugin_state_load(&i->p, data, length);
|
||||
return LV2_STATE_SUCCESS;
|
||||
plugin_state_callbacks cbs = {
|
||||
/* .handle = */ (void *)i,
|
||||
/* .lock = */ state_lock_cb,
|
||||
/* .unlock = */ state_unlock_cb,
|
||||
/* .write = */ NULL,
|
||||
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
|
||||
/* .set_parameter = */ state_set_parameter_cb
|
||||
# endif
|
||||
};
|
||||
return plugin_state_load(&cbs, data, length) == 0 ? LV2_STATE_SUCCESS : LV2_STATE_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
static const void * extension_data(const char * uri) {
|
||||
|
@ -53,6 +53,17 @@
|
||||
#include <pmmintrin.h>
|
||||
#endif
|
||||
|
||||
#if DATA_PRODUCT_PARAMETERS_IN_N > 0
|
||||
# include <stdatomic.h>
|
||||
# if defined(_WIN32) || defined(__CYGWIN__)
|
||||
# include <processthreadsapi.h>
|
||||
# define yield SwitchToThread
|
||||
# else
|
||||
# include <sched.h>
|
||||
# define yield sched_yield
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// COM in C doc:
|
||||
// https://github.com/rubberduck-vba/Rubberduck/wiki/COM-in-plain-C
|
||||
// https://devblogs.microsoft.com/oldnewthing/20040205-00/?p=40733
|
||||
@ -229,6 +240,30 @@ static double parameterUnmapByIndex(size_t index, double v) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static int stateRead(struct Steinberg_IBStream * state, char ** data, Steinberg_int64 * length) {
|
||||
if (state->lpVtbl->seek(state, 0, Steinberg_IBStream_IStreamSeekMode_kIBSeekEnd, NULL) != Steinberg_kResultOk)
|
||||
return -1;
|
||||
if (state->lpVtbl->tell(state, length) != Steinberg_kResultOk)
|
||||
return -1;
|
||||
if (state->lpVtbl->seek(state, 0, Steinberg_IBStream_IStreamSeekMode_kIBSeekSet, NULL) != Steinberg_kResultOk)
|
||||
return -1;
|
||||
*data = *length > 0 ? malloc(*length) : NULL;
|
||||
if (*length > 0 && *data == NULL)
|
||||
return -1;
|
||||
Steinberg_int64 read = 0;
|
||||
while (read < *length) {
|
||||
Steinberg_int32 r = (*length - read) <= 0x7fffffff ? *length - read : 0x7fffffff;
|
||||
Steinberg_int32 n;
|
||||
state->lpVtbl->read(state, *data + read, *length, &n);
|
||||
if (n != r) {
|
||||
free(*data);
|
||||
return -1;
|
||||
}
|
||||
read += n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct pluginInstance {
|
||||
Steinberg_Vst_IComponentVtbl * vtblIComponent;
|
||||
Steinberg_Vst_IAudioProcessorVtbl * vtblIAudioProcessor;
|
||||
@ -239,6 +274,10 @@ typedef struct pluginInstance {
|
||||
float sampleRate;
|
||||
#if DATA_PRODUCT_PARAMETERS_IN_N > 0
|
||||
float parametersIn[DATA_PRODUCT_PARAMETERS_IN_N];
|
||||
float parametersInSync[DATA_PRODUCT_PARAMETERS_IN_N];
|
||||
atomic_flag syncLockFlag;
|
||||
char synced;
|
||||
char loaded;
|
||||
#endif
|
||||
#if DATA_PRODUCT_PARAMETERS_OUT_N > 0
|
||||
float parametersOut[DATA_PRODUCT_PARAMETERS_OUT_N];
|
||||
@ -266,16 +305,25 @@ typedef struct pluginInstance {
|
||||
char midiOutputsActive[DATA_PRODUCT_BUSES_MIDI_OUTPUT_N];
|
||||
#endif
|
||||
void * mem;
|
||||
#ifdef DATA_STATE_DSP_CUSTOM
|
||||
struct Steinberg_IBStream * state;
|
||||
#endif
|
||||
} pluginInstance;
|
||||
|
||||
static Steinberg_Vst_IComponentVtbl pluginVtblIComponent;
|
||||
static Steinberg_Vst_IAudioProcessorVtbl pluginVtblIAudioProcessor;
|
||||
|
||||
#ifdef DATA_STATE_DSP_CUSTOM
|
||||
static int pluginWriteStateCb(void *handle, const char *data, size_t length) {
|
||||
static void pluginStateLockCb(void *handle) {
|
||||
pluginInstance *p = (pluginInstance *)handle;
|
||||
while (atomic_flag_test_and_set(&p->syncLockFlag))
|
||||
yield();
|
||||
p->synced = 0;
|
||||
}
|
||||
|
||||
static void pluginStateUnlockCb(void *handle) {
|
||||
pluginInstance *p = (pluginInstance *)handle;
|
||||
atomic_flag_clear(&p->syncLockFlag);
|
||||
}
|
||||
|
||||
static int pluginStateWriteCb(void *handle, const char *data, size_t length) {
|
||||
pluginInstance *p = (pluginInstance *)handle;
|
||||
size_t written = 0;
|
||||
while (written < length) {
|
||||
@ -290,7 +338,7 @@ static int pluginWriteStateCb(void *handle, const char *data, size_t length) {
|
||||
}
|
||||
|
||||
# if DATA_PRODUCT_PARAMETERS_IN_N > 0
|
||||
static void pluginLoadParameterCb(void *handle, size_t index, float value) {
|
||||
static void pluginStateSetParameterCb(void *handle, size_t index, float value) {
|
||||
size_t i = index;
|
||||
# ifdef DATA_PARAM_LATENCY_INDEX
|
||||
if (i >= DATA_PARAM_LATENCY_INDEX)
|
||||
@ -298,11 +346,10 @@ static void pluginLoadParameterCb(void *handle, size_t index, float value) {
|
||||
# endif
|
||||
pluginInstance *p = (pluginInstance *)handle;
|
||||
size_t ii = parameterInfoToDataIndex[i];
|
||||
p->parametersIn[ii] = parameterAdjust(parameterInData + ii, value);
|
||||
plugin_set_parameter(&p->p, index, p->parametersIn[ii]);
|
||||
p->parametersInSync[ii] = parameterAdjust(parameterInData + ii, value);
|
||||
p->loaded = 1;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static Steinberg_tresult pluginQueryInterface(pluginInstance *p, const Steinberg_TUID iid, void ** obj) {
|
||||
// This seems to violate the way multiple inheritance should work in COM, but hosts like it, so what do I know...
|
||||
@ -370,18 +417,7 @@ static Steinberg_tresult pluginInitialize(void *thisInterface, struct Steinberg_
|
||||
/* .handle = */ (void *)p,
|
||||
/* .format = */ "vst3",
|
||||
/* .get_bindir = */ getBindirCb,
|
||||
/* .get_datadir = */ getDatadirCb,
|
||||
#ifdef DATA_STATE_DSP_CUSTOM
|
||||
/* .write_state = */ pluginWriteStateCb,
|
||||
# if DATA_PRODUCT_PARAMETERS_IN_N > 0
|
||||
/* .load_parameter = */ pluginLoadParameterCb
|
||||
# else
|
||||
/* .load_parameter = */ NULL
|
||||
# endif
|
||||
#else
|
||||
/* .write_state = */ NULL,
|
||||
/* .load_parameter = */ NULL
|
||||
#endif
|
||||
/* .get_datadir = */ getDatadirCb
|
||||
};
|
||||
plugin_init(&p->p, &cbs);
|
||||
#if DATA_PRODUCT_PARAMETERS_IN_N > 0
|
||||
@ -389,6 +425,11 @@ static Steinberg_tresult pluginInitialize(void *thisInterface, struct Steinberg_
|
||||
p->parametersIn[i] = parameterInData[i].def;
|
||||
plugin_set_parameter(&p->p, parameterInData[i].index, parameterInData[i].def);
|
||||
}
|
||||
for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_IN_N; i++)
|
||||
p->parametersInSync[i] = p->parametersIn[i];
|
||||
atomic_flag_clear(&p->syncLockFlag);
|
||||
p->synced = 1;
|
||||
p->loaded = 0;
|
||||
#endif
|
||||
#if DATA_PRODUCT_PARAMETERS_OUT_N > 0
|
||||
for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_OUT_N; i++)
|
||||
@ -609,75 +650,98 @@ static Steinberg_tresult pluginSetState(void* thisInterface, struct Steinberg_IB
|
||||
TRACE("plugin set state\n");
|
||||
if (state == NULL)
|
||||
return Steinberg_kResultFalse;
|
||||
#ifdef DATA_STATE_DSP_CUSTOM
|
||||
pluginInstance *p = (pluginInstance *)((char *)thisInterface - offsetof(pluginInstance, vtblIComponent));
|
||||
if (state->lpVtbl->seek(state, 0, Steinberg_IBStream_IStreamSeekMode_kIBSeekEnd, NULL) != Steinberg_kResultOk)
|
||||
return Steinberg_kResultFalse;
|
||||
|
||||
char *data;
|
||||
Steinberg_int64 length;
|
||||
if (state->lpVtbl->tell(state, &length) != Steinberg_kResultOk)
|
||||
if (stateRead(state, &data, &length) != 0)
|
||||
return Steinberg_kResultFalse;
|
||||
if (state->lpVtbl->seek(state, 0, Steinberg_IBStream_IStreamSeekMode_kIBSeekSet, NULL) != Steinberg_kResultOk)
|
||||
return Steinberg_kResultFalse;
|
||||
char *data = malloc(length);
|
||||
if (data == NULL)
|
||||
return Steinberg_kResultFalse;
|
||||
Steinberg_int64 read = 0;
|
||||
while (read < length) {
|
||||
Steinberg_int32 r = (length - read) <= 0x7fffffff ? length - read : 0x7fffffff;
|
||||
Steinberg_int32 n;
|
||||
state->lpVtbl->read(state, data + read, length, &n);
|
||||
if (n != r) {
|
||||
free(data);
|
||||
return Steinberg_kResultFalse;
|
||||
}
|
||||
read += n;
|
||||
}
|
||||
plugin_state_load(&p->p, data, length);
|
||||
free(data);
|
||||
#else
|
||||
# if DATA_PRODUCT_PARAMETERS_IN_N > 0
|
||||
|
||||
pluginInstance *p = (pluginInstance *)((char *)thisInterface - offsetof(pluginInstance, vtblIComponent));
|
||||
#ifdef DATA_STATE_DSP_CUSTOM
|
||||
plugin_state_callbacks cbs = {
|
||||
/* .handle = */ (void *)p,
|
||||
/* .lock = */ pluginStateLockCb,
|
||||
/* .unlock = */ pluginStateUnlockCb,
|
||||
/* .write = */ NULL,
|
||||
# if DATA_PRODUCT_PARAMETERS_IN_N > 0
|
||||
/* .set_parameter = */ pluginStateSetParameterCb
|
||||
# endif
|
||||
};
|
||||
int err = plugin_state_load(&cbs, data, length);
|
||||
#else
|
||||
int err = 0;
|
||||
if (length != DATA_PRODUCT_PARAMETERS_IN_N * 4) {
|
||||
if (data)
|
||||
free(data);
|
||||
return Steinberg_kResultFalse;
|
||||
}
|
||||
# if DATA_PRODUCT_PARAMETERS_IN_N > 0
|
||||
for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_IN_N; i++) {
|
||||
union { float f; uint32_t u; } v;
|
||||
Steinberg_int32 n;
|
||||
state->lpVtbl->read(state, &v, 4, &n);
|
||||
if (n != 4)
|
||||
return Steinberg_kResultFalse;
|
||||
v.u = ((uint32_t *)data)[i];
|
||||
if (IS_BIG_ENDIAN)
|
||||
v.u = SWAP_UINT32(v.u);
|
||||
p->parametersIn[i] = parameterAdjust(parameterInData + i, v.f);
|
||||
plugin_set_parameter(&p->p, parameterInData[i].index, p->parametersIn[i]);
|
||||
if (isnan(v.f)) {
|
||||
free(data);
|
||||
return Steinberg_kResultFalse;
|
||||
}
|
||||
}
|
||||
pluginStateLockCb(p);
|
||||
for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_IN_N; i++) {
|
||||
union { float f; uint32_t u; } v;
|
||||
v.u = ((uint32_t *)data)[i];
|
||||
if (IS_BIG_ENDIAN)
|
||||
v.u = SWAP_UINT32(v.u);
|
||||
pluginStateSetParameterCb(p, parameterInData[i].index, v.f);
|
||||
}
|
||||
pluginStateUnlockCb(p);
|
||||
# endif
|
||||
#endif
|
||||
return Steinberg_kResultOk;
|
||||
|
||||
if (data)
|
||||
free(data);
|
||||
return err == 0 ? Steinberg_kResultOk : Steinberg_kResultFalse;
|
||||
}
|
||||
|
||||
static Steinberg_tresult pluginGetState(void* thisInterface, struct Steinberg_IBStream* state) {
|
||||
TRACE("plugin get state\n");
|
||||
if (state == NULL)
|
||||
return Steinberg_kResultFalse;
|
||||
#ifdef DATA_STATE_DSP_CUSTOM
|
||||
|
||||
pluginInstance *p = (pluginInstance *)((char *)thisInterface - offsetof(pluginInstance, vtblIComponent));
|
||||
|
||||
p->state = state;
|
||||
if (plugin_state_save(&p->p) != 0)
|
||||
return Steinberg_kResultFalse;
|
||||
#else
|
||||
#ifdef DATA_STATE_DSP_CUSTOM
|
||||
plugin_state_callbacks cbs = {
|
||||
/* .handle = */ (void *)p,
|
||||
/* .lock = */ pluginStateLockCb,
|
||||
/* .unlock = */ pluginStateUnlockCb,
|
||||
/* .write = */ pluginStateWriteCb,
|
||||
# if DATA_PRODUCT_PARAMETERS_IN_N > 0
|
||||
pluginInstance *p = (pluginInstance *)((char *)thisInterface - offsetof(pluginInstance, vtblIComponent));
|
||||
/* .set_parameter = */ NULL
|
||||
# endif
|
||||
};
|
||||
int err = plugin_state_save(&p->p, &cbs);
|
||||
#else
|
||||
int err = 0;
|
||||
# if DATA_PRODUCT_PARAMETERS_IN_N > 0
|
||||
size_t length = DATA_PRODUCT_PARAMETERS_IN_N * 4;
|
||||
char *data = malloc(length);
|
||||
if (data == NULL)
|
||||
return Steinberg_kResultFalse;
|
||||
pluginStateLockCb(p);
|
||||
for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_IN_N; i++) {
|
||||
union { float f; uint32_t u; } v;
|
||||
v.f = p->parametersIn[i];
|
||||
v.f = p->parametersInSync[i];
|
||||
if (IS_BIG_ENDIAN)
|
||||
v.u = SWAP_UINT32(v.u);
|
||||
Steinberg_int32 n;
|
||||
state->lpVtbl->write(state, &v, 4, &n);
|
||||
if (n != 4)
|
||||
return Steinberg_kResultFalse;
|
||||
((uint32_t *)data)[i] = v.u;
|
||||
}
|
||||
pluginStateUnlockCb(p);
|
||||
err = pluginStateWriteCb(p, data, length);
|
||||
# endif
|
||||
#endif
|
||||
return Steinberg_kResultOk;
|
||||
return err == 0 ? Steinberg_kResultOk : Steinberg_kResultFalse;
|
||||
}
|
||||
|
||||
static Steinberg_Vst_IComponentVtbl pluginVtblIComponent = {
|
||||
@ -1087,6 +1151,29 @@ static void controllerGetParamDataValuePtrs(controller *ctrl, size_t index, Para
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DATA_STATE_DSP_CUSTOM
|
||||
static void controllerStateLockCb(void *handle) {
|
||||
(void)handle;
|
||||
}
|
||||
|
||||
static void controllerStateUnlockCb(void *handle) {
|
||||
(void)handle;
|
||||
}
|
||||
|
||||
# if DATA_PRODUCT_PARAMETERS_IN_N > 0
|
||||
static void controllerStateSetParameterCb(void *handle, size_t index, float value) {
|
||||
size_t i = index;
|
||||
# ifdef DATA_PARAM_LATENCY_INDEX
|
||||
if (i >= DATA_PARAM_LATENCY_INDEX)
|
||||
i--;
|
||||
# endif
|
||||
controller *c = (controller *)handle;
|
||||
size_t ii = parameterInfoToDataIndex[i];
|
||||
c->parametersIn[ii] = parameterAdjust(parameterInData + ii, value);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef DATA_UI
|
||||
|
||||
# ifdef __linux__
|
||||
@ -1354,10 +1441,6 @@ static Steinberg_tresult plugViewAttached(void* thisInterface, void* parent, Ste
|
||||
/* .set_parameter_begin = */ plugViewSetParameterBeginCb,
|
||||
/* .set_parameter = */ plugViewSetParameterCb,
|
||||
/* .set_parameter_end = */ plugViewSetParameterEndCb
|
||||
# else
|
||||
/* .set_parameter_begin = */ NULL,
|
||||
/* .set_parameter = */ NULL,
|
||||
/* .set_parameter_end = */ NULL
|
||||
# endif
|
||||
};
|
||||
v->ui = plugin_ui_create(1, parent, &cbs);
|
||||
@ -1696,68 +1779,78 @@ static Steinberg_tresult controllerSetComponentState(void* thisInterface, struct
|
||||
TRACE("controller set component state %p %p\n", thisInterface, (void *)state);
|
||||
if (state == NULL)
|
||||
return Steinberg_kResultFalse;
|
||||
#if DATA_PRODUCT_PARAMETERS_IN_N > 0
|
||||
|
||||
char *data;
|
||||
Steinberg_int64 length;
|
||||
if (stateRead(state, &data, &length) != 0)
|
||||
return Steinberg_kResultFalse;
|
||||
|
||||
controller *c = (controller *)((char *)thisInterface - offsetof(controller, vtblIEditController));
|
||||
#ifdef DATA_STATE_DSP_CUSTOM
|
||||
plugin_state_callbacks cbs = {
|
||||
/* .handle = */ (void *)c,
|
||||
/* .lock = */ controllerStateLockCb,
|
||||
/* .unlock = */ controllerStateUnlockCb,
|
||||
/* .write = */ NULL,
|
||||
# if DATA_PRODUCT_PARAMETERS_IN_N > 0
|
||||
/* .set_parameter = */ controllerStateSetParameterCb
|
||||
# endif
|
||||
};
|
||||
int err = plugin_state_load(&cbs, data, length);
|
||||
#else
|
||||
int err = 0;
|
||||
# if DATA_PRODUCT_PARAMETERS_IN_N > 0
|
||||
for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_IN_N; i++) {
|
||||
union { float f; uint32_t u; } v;
|
||||
Steinberg_int32 n;
|
||||
state->lpVtbl->read(state, &v, 4, &n);
|
||||
if (n != 4)
|
||||
v.u = ((uint32_t *)data)[i];
|
||||
if (IS_BIG_ENDIAN)
|
||||
v.u = SWAP_UINT32(v.u);
|
||||
if (isnan(v.f)) {
|
||||
free(data);
|
||||
return Steinberg_kResultFalse;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_IN_N; i++) {
|
||||
union { float f; uint32_t u; } v;
|
||||
v.u = ((uint32_t *)data)[i];
|
||||
if (IS_BIG_ENDIAN)
|
||||
v.u = SWAP_UINT32(v.u);
|
||||
c->parametersIn[i] = parameterAdjust(parameterInData + i, v.f);
|
||||
}
|
||||
|
||||
# endif
|
||||
#endif
|
||||
|
||||
if (data)
|
||||
free(data);
|
||||
if (err != 0)
|
||||
return Steinberg_kResultFalse;
|
||||
|
||||
#if (DATA_PRODUCT_PARAMETERS_IN_N > 0) && defined(DATA_UI)
|
||||
if (c->views)
|
||||
for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_IN_N; i++)
|
||||
for (size_t j = 0; j < c->viewsCount; j++)
|
||||
plugViewUpdateParameterIn(c->views[j], i);
|
||||
#endif
|
||||
|
||||
TRACE(" ok\n");
|
||||
return Steinberg_kResultTrue;
|
||||
return Steinberg_kResultOk;
|
||||
}
|
||||
|
||||
static Steinberg_tresult controllerSetState(void* thisInterface, struct Steinberg_IBStream* state) {
|
||||
// TODO: we need this implemented for Reaper, need to re-check this
|
||||
(void)thisInterface;
|
||||
(void)state;
|
||||
|
||||
TRACE("controller set state\n");
|
||||
if (state == NULL)
|
||||
return Steinberg_kResultFalse;
|
||||
#if DATA_PRODUCT_PARAMETERS_IN_N > 0
|
||||
controller *c = (controller *)((char *)thisInterface - offsetof(controller, vtblIEditController));
|
||||
for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_IN_N; i++) {
|
||||
union { float f; uint32_t u; } v;
|
||||
Steinberg_int32 n;
|
||||
state->lpVtbl->read(state, &v, 4, &n);
|
||||
if (n != 4)
|
||||
return Steinberg_kResultFalse;
|
||||
if (IS_BIG_ENDIAN)
|
||||
v.u = SWAP_UINT32(v.u);
|
||||
c->parametersIn[i] = parameterAdjust(parameterInData + i, v.f);
|
||||
# ifdef DATA_UI
|
||||
if (c->views)
|
||||
for (size_t j = 0; j < c->viewsCount; j++)
|
||||
plugViewUpdateParameterIn(c->views[j], i);
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
return Steinberg_kResultOk;
|
||||
return Steinberg_kNotImplemented;
|
||||
}
|
||||
|
||||
static Steinberg_tresult controllerGetState(void* thisInterface, struct Steinberg_IBStream* state) {
|
||||
// TODO: we need this implemented for Reaper, need to re-check this
|
||||
(void)thisInterface;
|
||||
(void)state;
|
||||
|
||||
TRACE("controller get state\n");
|
||||
if (state == NULL)
|
||||
return Steinberg_kResultFalse;
|
||||
#if DATA_PRODUCT_PARAMETERS_IN_N > 0
|
||||
controller *c = (controller *)((char *)thisInterface - offsetof(controller, vtblIEditController));
|
||||
for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_IN_N; i++) {
|
||||
union { float f; uint32_t u; } v;
|
||||
v.f = c->parametersIn[i];
|
||||
if (IS_BIG_ENDIAN)
|
||||
v.u = SWAP_UINT32(v.u);
|
||||
Steinberg_int32 n;
|
||||
state->lpVtbl->write(state, &v, 4, &n);
|
||||
if (n != 4)
|
||||
return Steinberg_kResultFalse;
|
||||
}
|
||||
#endif
|
||||
return Steinberg_kResultOk;
|
||||
return Steinberg_kNotImplemented;
|
||||
}
|
||||
|
||||
static Steinberg_int32 controllerGetParameterCount(void* thisInterface) {
|
||||
@ -1967,9 +2060,9 @@ static Steinberg_tresult controllerSetParamNormalized(void* thisInterface, Stein
|
||||
for (size_t i = 0; i < c->viewsCount; i++)
|
||||
if(c->views[i]) {
|
||||
if (parameterInfo[pi].flags & Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly)
|
||||
plugViewUpdateParameterOut(c->views[i], pi);
|
||||
plugViewUpdateParameterOut(c->views[i], parameterInfoToDataIndex[pi]);
|
||||
else
|
||||
plugViewUpdateParameterIn(c->views[i], pi);
|
||||
plugViewUpdateParameterIn(c->views[i], parameterInfoToDataIndex[pi]);
|
||||
}
|
||||
# endif
|
||||
return Steinberg_kResultTrue;
|
||||
|
@ -19,10 +19,9 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
|
||||
typedef struct plugin {
|
||||
plugin_callbacks cbs;
|
||||
|
||||
float sample_rate;
|
||||
size_t delay_line_length;
|
||||
|
||||
@ -38,8 +37,9 @@ typedef struct plugin {
|
||||
float yz1;
|
||||
} plugin;
|
||||
|
||||
static void plugin_init(plugin *instance, plugin_callbacks *cbs) {
|
||||
instance->cbs = *cbs;
|
||||
static void plugin_init(plugin *instance, const plugin_callbacks *cbs) {
|
||||
(void)instance;
|
||||
(void)cbs;
|
||||
}
|
||||
|
||||
static void plugin_fini(plugin *instance) {
|
||||
@ -139,32 +139,36 @@ static float parse_float(const uint8_t *data) {
|
||||
return v.f;
|
||||
}
|
||||
|
||||
static int plugin_state_save(plugin *instance) {
|
||||
static int plugin_state_save(plugin *instance, const plugin_state_callbacks *cbs) {
|
||||
uint8_t data[13];
|
||||
instance->cbs.lock_state(instance->cbs.handle);
|
||||
cbs->lock(cbs->handle);
|
||||
const float gain = instance->gain;
|
||||
const float delay = instance->delay;
|
||||
const float cutoff = instance->cutoff;
|
||||
const char bypass = instance->bypass;
|
||||
instance->cbs.unlock_state(instance->cbs.handle);
|
||||
cbs->unlock(cbs->handle);
|
||||
serialize_float(data, gain);
|
||||
serialize_float(data + 4, delay);
|
||||
serialize_float(data + 8, cutoff);
|
||||
data[12] = bypass ? 1 : 0;
|
||||
return instance->cbs.write_state(instance->cbs.handle, (const char *)data, 13);
|
||||
return cbs->write(cbs->handle, (const char *)data, 13);
|
||||
}
|
||||
|
||||
static void plugin_state_load(plugin *instance, const char *data, size_t length) {
|
||||
(void)length;
|
||||
static int plugin_state_load(const plugin_state_callbacks *cbs, const char *data, size_t length) {
|
||||
if (length != 13)
|
||||
return -1;
|
||||
const uint8_t *d = (const uint8_t *)data;
|
||||
const float gain = parse_float(d);
|
||||
const float delay = parse_float(d + 4);
|
||||
const float cutoff = parse_float(d + 8);
|
||||
const float bypass = d[12] ? 1.f : 0.f;
|
||||
instance->cbs.lock_state(instance->cbs.handle);
|
||||
instance->cbs.load_parameter(instance->cbs.handle, plugin_parameter_gain, gain);
|
||||
instance->cbs.load_parameter(instance->cbs.handle, plugin_parameter_delay, delay);
|
||||
instance->cbs.load_parameter(instance->cbs.handle, plugin_parameter_cutoff, cutoff);
|
||||
instance->cbs.load_parameter(instance->cbs.handle, plugin_parameter_bypass, bypass);
|
||||
instance->cbs.unlock_state(instance->cbs.handle);
|
||||
if (isnan(gain) || isnan(delay) || isnan(cutoff))
|
||||
return -1;
|
||||
cbs->lock(cbs->handle);
|
||||
cbs->set_parameter(cbs->handle, plugin_parameter_gain, gain);
|
||||
cbs->set_parameter(cbs->handle, plugin_parameter_delay, delay);
|
||||
cbs->set_parameter(cbs->handle, plugin_parameter_cutoff, cutoff);
|
||||
cbs->set_parameter(cbs->handle, plugin_parameter_bypass, bypass);
|
||||
cbs->unlock(cbs->handle);
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user