diff --git a/templates/lv2/src/lv2.c b/templates/lv2/src/lv2.c index 2d189f7..ba3ce82 100644 --- a/templates/lv2/src/lv2.c +++ b/templates/lv2/src/lv2.c @@ -93,6 +93,7 @@ static float adjust_param(size_t index, float value) { typedef struct { plugin p; + float sample_rate; #if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0 const float * x[DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N]; #endif @@ -212,7 +213,8 @@ static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double s }; plugin_init(&instance->p, &cbs); - plugin_set_sample_rate(&instance->p, sample_rate); + instance->sample_rate = (float)sample_rate; + plugin_set_sample_rate(&instance->p, instance->sample_rate); size_t req = plugin_mem_req(&instance->p); if (req != 0) { instance->mem = malloc(req); @@ -451,7 +453,7 @@ static LV2_State_Status state_save(LV2_Handle instance, LV2_State_Store_Function /* .set_parameter = */ NULL # endif }; - return plugin_state_save(&i->p, &cbs) == 0 ? LV2_STATE_SUCCESS : LV2_STATE_ERR_UNKNOWN; + return plugin_state_save(&i->p, &cbs, i->sample_rate) == 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) { @@ -479,7 +481,7 @@ static LV2_State_Status state_restore(LV2_Handle instance, LV2_State_Retrieve_Fu /* .set_parameter = */ state_set_parameter_cb # endif }; - return plugin_state_load(&cbs, data, length) == 0 ? LV2_STATE_SUCCESS : LV2_STATE_ERR_UNKNOWN; + return plugin_state_load(&cbs, i->sample_rate, data, length) == 0 ? LV2_STATE_SUCCESS : LV2_STATE_ERR_UNKNOWN; } static const void * extension_data(const char * uri) { diff --git a/templates/vst3/src/vst3.c b/templates/vst3/src/vst3.c index 8331734..4a8947e 100644 --- a/templates/vst3/src/vst3.c +++ b/templates/vst3/src/vst3.c @@ -271,7 +271,9 @@ typedef struct pluginInstance { Steinberg_uint32 refs; Steinberg_FUnknown * context; plugin p; - float sampleRate; + float lastSampleRate; + float curSampleRate; + float nextSampleRate; #if DATA_PRODUCT_PARAMETERS_IN_N > 0 float parametersIn[DATA_PRODUCT_PARAMETERS_IN_N]; float parametersInSync[DATA_PRODUCT_PARAMETERS_IN_N]; @@ -412,6 +414,9 @@ static Steinberg_tresult pluginInitialize(void *thisInterface, struct Steinberg_ if (p->context != NULL) return Steinberg_kResultFalse; p->context = context; + p->lastSampleRate = 0.f; + p->curSampleRate = 0.f; + p->nextSampleRate = 0.f; plugin_callbacks cbs = { /* .handle = */ (void *)p, @@ -628,7 +633,7 @@ static Steinberg_tresult pluginSetActive(void* thisInterface, Steinberg_TBool st p->neededBusesActive = 0; # endif #endif - plugin_set_sample_rate(&p->p, p->sampleRate); + plugin_set_sample_rate(&p->p, p->nextSampleRate); size_t req = plugin_mem_req(&p->p); if (req != 0) { p->mem = malloc(req); @@ -636,8 +641,11 @@ static Steinberg_tresult pluginSetActive(void* thisInterface, Steinberg_TBool st return Steinberg_kOutOfMemory; plugin_mem_set(&p->p, p->mem); } + p->curSampleRate = p->nextSampleRate; + p->lastSampleRate = p->nextSampleRate; plugin_reset(&p->p); - } + } else + p->curSampleRate = 0.f; return Steinberg_kResultOk; } @@ -667,7 +675,7 @@ static Steinberg_tresult pluginSetState(void* thisInterface, struct Steinberg_IB /* .set_parameter = */ pluginStateSetParameterCb # endif }; - int err = plugin_state_load(&cbs, data, length); + int err = plugin_state_load(&cbs, p->curSampleRate, data, length); #else // we need to provide a default implementation because of certain hosts (e.g. Ardour) int err = 0; @@ -723,7 +731,7 @@ static Steinberg_tresult pluginGetState(void* thisInterface, struct Steinberg_IB /* .set_parameter = */ NULL # endif }; - int err = plugin_state_save(&p->p, &cbs); + int err = plugin_state_save(&p->p, &cbs, p->lastSampleRate); #else // we need to provide a default implementation because of certain hosts (e.g. Ardour) int err = 0; @@ -855,7 +863,7 @@ static Steinberg_uint32 pluginGetLatencySamples(void* thisInterface) { static Steinberg_tresult pluginSetupProcessing(void* thisInterface, struct Steinberg_Vst_ProcessSetup* setup) { TRACE("plugin IAudioProcessor setup processing\n"); pluginInstance *p = (pluginInstance *)((char *)thisInterface - offsetof(pluginInstance, vtblIAudioProcessor)); - p->sampleRate = (float)setup->sampleRate; + p->nextSampleRate = (float)setup->sampleRate; return Steinberg_kResultOk; } @@ -1858,7 +1866,7 @@ static Steinberg_tresult controllerSetComponentState(void* thisInterface, struct /* .set_parameter = */ controllerStateSetParameterCb # endif }; - int err = plugin_state_load(&cbs, data, length); + int err = plugin_state_load(&cbs, -1.f, data, length); // -1.f means "does not apply" #else // we need to provide a default implementation because of certain hosts (e.g. Reaper) int err = 0; diff --git a/test/plugin.h b/test/plugin.h index 6ba7c33..946b062 100644 --- a/test/plugin.h +++ b/test/plugin.h @@ -138,7 +138,8 @@ static float parse_float(const uint8_t *data) { return v.f; } -static int plugin_state_save(plugin *instance, const plugin_state_callbacks *cbs) { +static int plugin_state_save(plugin *instance, const plugin_state_callbacks *cbs, float last_sample_rate) { + (void)last_sample_rate; uint8_t data[13]; cbs->lock(cbs->handle); const float gain = instance->gain; @@ -159,7 +160,8 @@ static char x_isnan(float x) { return ((v.u & 0x7f800000) == 0x7f800000) && (v.u & 0x7fffff); } -static int plugin_state_load(const plugin_state_callbacks *cbs, const char *data, size_t length) { +static int plugin_state_load(const plugin_state_callbacks *cbs, float cur_sample_rate, const char *data, size_t length) { + (void)cur_sample_rate; if (length != 13) return -1; const uint8_t *d = (const uint8_t *)data;