Interim checking, Convolution Reverb
This commit is contained in:
@@ -0,0 +1,289 @@
|
||||
// Copyright (c) 2023 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "StateInterface.hpp"
|
||||
#include "ss.hpp"
|
||||
#include "Base64.hpp"
|
||||
#include "json.hpp"
|
||||
#include <sstream>
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
LV2_State_Status StateInterface::FnStateStoreFunction(
|
||||
LV2_State_Handle handle,
|
||||
uint32_t key,
|
||||
const void *value,
|
||||
size_t size,
|
||||
uint32_t type,
|
||||
uint32_t flags)
|
||||
{
|
||||
SaveCallState *pCallState = (SaveCallState *)handle;
|
||||
|
||||
pCallState->status = pCallState->pThis->StateStoreFunction(
|
||||
pCallState,
|
||||
key,
|
||||
value,
|
||||
size,
|
||||
type,
|
||||
flags
|
||||
|
||||
);
|
||||
return pCallState->status;
|
||||
}
|
||||
|
||||
LV2_State_Status StateInterface::StateStoreFunction(
|
||||
SaveCallState *pCallState,
|
||||
uint32_t key,
|
||||
const void *value,
|
||||
size_t size,
|
||||
uint32_t type,
|
||||
uint32_t flags)
|
||||
{
|
||||
Lv2PluginState &state = pCallState->state;
|
||||
|
||||
std::string strKey = map.UridToString(key);
|
||||
Lv2PluginStateEntry& entry = state.values_[strKey];
|
||||
|
||||
std::string atomType = map.UridToString(type);
|
||||
entry.atomType_ = atomType;
|
||||
entry.flags_ = flags;
|
||||
entry.value_.resize(size);
|
||||
uint8_t *p = (uint8_t*)value;
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
entry.value_[i] = p[i];
|
||||
}
|
||||
return LV2_State_Status::LV2_STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static void CheckState(LV2_State_Status status)
|
||||
{
|
||||
const char *lv2Error = nullptr;
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case LV2_State_Status::LV2_STATE_SUCCESS:
|
||||
return;
|
||||
default:
|
||||
lv2Error = "Unknown error.";
|
||||
break;
|
||||
case LV2_State_Status::LV2_STATE_ERR_BAD_TYPE:
|
||||
lv2Error = "Invalid type.";
|
||||
break;
|
||||
case LV2_State_Status::LV2_STATE_ERR_BAD_FLAGS:
|
||||
lv2Error = "Unsupported flags.";
|
||||
break;
|
||||
case LV2_State_Status::LV2_STATE_ERR_NO_FEATURE:
|
||||
lv2Error = "Feature not supported.";
|
||||
break;
|
||||
case LV2_State_Status::LV2_STATE_ERR_NO_PROPERTY:
|
||||
lv2Error = "No such property.";
|
||||
break;
|
||||
case LV2_State_Status::LV2_STATE_ERR_NO_SPACE:
|
||||
lv2Error = "Insufficient memory.";
|
||||
break;
|
||||
}
|
||||
throw std::logic_error(lv2Error);
|
||||
}
|
||||
Lv2PluginState StateInterface::Save()
|
||||
{
|
||||
SaveCallState callState;
|
||||
callState.pThis = this;
|
||||
callState.status = LV2_State_Status::LV2_STATE_SUCCESS;
|
||||
|
||||
LV2_Feature **features = &(this->features[0]);
|
||||
LV2_Handle instanceHandle = lilv_instance_get_handle(pInstance);
|
||||
try
|
||||
{
|
||||
LV2_State_Status status =
|
||||
pluginStateInterface->save(
|
||||
instanceHandle,
|
||||
FnStateStoreFunction,
|
||||
(LV2_State_Handle)&callState,
|
||||
LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE,
|
||||
features);
|
||||
CheckState(status);
|
||||
CheckState(callState.status);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
throw std::logic_error(SS("State save failed. " << e.what()));
|
||||
}
|
||||
|
||||
return std::move(callState.state);
|
||||
}
|
||||
|
||||
void StateInterface::Restore(const Lv2PluginState &state)
|
||||
{
|
||||
RestoreCallState callState;
|
||||
callState.pThis = this;
|
||||
callState.pState = &state;
|
||||
callState.status = LV2_State_Status::LV2_STATE_SUCCESS;
|
||||
|
||||
LV2_Feature **features = &(this->features[0]);
|
||||
LV2_Handle instanceHandle = lilv_instance_get_handle(pInstance);
|
||||
try
|
||||
{
|
||||
LV2_State_Status status =
|
||||
pluginStateInterface->restore(
|
||||
instanceHandle,
|
||||
FnStateRetreiveFunction,
|
||||
(LV2_State_Handle)&callState,
|
||||
LV2_STATE_IS_POD,
|
||||
features);
|
||||
CheckState(status);
|
||||
CheckState(callState.status);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
throw std::logic_error(SS("State save failed. " << e.what()));
|
||||
}
|
||||
}
|
||||
/*static*/ const void *StateInterface::FnStateRetreiveFunction(
|
||||
LV2_State_Handle handle,
|
||||
uint32_t key,
|
||||
size_t *size,
|
||||
uint32_t *type,
|
||||
uint32_t *flags)
|
||||
{
|
||||
RestoreCallState*pCallState = (RestoreCallState*)handle;
|
||||
return pCallState->pThis->StateRetrieveFunction(
|
||||
pCallState,
|
||||
key,
|
||||
size,
|
||||
type,
|
||||
flags);
|
||||
|
||||
}
|
||||
const void *StateInterface::StateRetrieveFunction(
|
||||
RestoreCallState *pCallState,
|
||||
uint32_t key,
|
||||
size_t *size,
|
||||
uint32_t *type,
|
||||
uint32_t *flags)
|
||||
{
|
||||
std::string strKey = map.UridToString(key);
|
||||
auto & values = pCallState->pState->values_;
|
||||
auto iEntry = values.find(strKey);
|
||||
if (iEntry == values.end())
|
||||
{
|
||||
*size = 0;
|
||||
*type = urids.atom__Atom;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Lv2PluginStateEntry& entry = iEntry->second;
|
||||
*size = entry.value_.size();
|
||||
*type = map.GetUrid(entry.atomType_.c_str());
|
||||
*flags = entry.flags_;
|
||||
return (void*)&entry.value_[0];
|
||||
|
||||
}
|
||||
|
||||
void Lv2PluginState::write_json(json_writer &writer) const
|
||||
{
|
||||
writer.write(values_);
|
||||
}
|
||||
void Lv2PluginState::read_json(json_reader &reader) {
|
||||
reader.read(&values_);
|
||||
}
|
||||
|
||||
|
||||
void Lv2PluginStateEntry::write_json(json_writer &writer) const
|
||||
{
|
||||
writer.start_object();
|
||||
writer.write_member("flags",flags_);
|
||||
writer.write_raw(",");
|
||||
writer.write_member("atomType",atomType_);
|
||||
writer.write_raw(",");
|
||||
if (atomType_ == LV2_ATOM__String || atomType_ == LV2_ATOM__Path || atomType_ == LV2_ATOM__URI)
|
||||
{
|
||||
const char *p = (const char*)&(value_[0]);
|
||||
size_t size = value_.size();
|
||||
while (size > 0 && p[size-1] == '\0')
|
||||
{
|
||||
--size;
|
||||
}
|
||||
std::string value { p,size};
|
||||
writer.write_member("value",value);
|
||||
} else if (atomType_ == LV2_ATOM__Float)
|
||||
{
|
||||
if (value_.size() != sizeof(float))
|
||||
{
|
||||
throw std::logic_error("Invalid float property in LV2PluginState");
|
||||
}
|
||||
writer.write_member("value",*(float*)&(value_[0]));
|
||||
} else {
|
||||
std::string base64 = macaron::Base64::Encode(value_);
|
||||
writer.write_member("value",base64);
|
||||
}
|
||||
writer.end_object();
|
||||
}
|
||||
void Lv2PluginStateEntry::read_json(json_reader &reader)
|
||||
{
|
||||
reader.start_object();
|
||||
reader.read_member("flags",&flags_);
|
||||
reader.consume(',');
|
||||
reader.read_member("atomType",&atomType_);
|
||||
reader.consume(',');
|
||||
if (atomType_ == LV2_ATOM__String || atomType_ == LV2_ATOM__Path || atomType_ == LV2_ATOM__URI)
|
||||
{
|
||||
std::string v;
|
||||
reader.read_member("value",&v);
|
||||
value_.resize(v.length());
|
||||
for (size_t i = 0; i < v.length(); ++i)
|
||||
{
|
||||
value_[i] = (uint8_t)v[i];
|
||||
}
|
||||
} else if (atomType_ == LV2_ATOM__Float)
|
||||
{
|
||||
float v;
|
||||
reader.read_member("value",&v);
|
||||
value_.resize(sizeof(float));
|
||||
float *pVal = (float*)&(value_[0]);
|
||||
*pVal = v;
|
||||
} else {
|
||||
std::string v;
|
||||
reader.read_member("value",&v);
|
||||
value_ = macaron::Base64::Decode(v);
|
||||
}
|
||||
reader.end_object();
|
||||
}
|
||||
|
||||
StateInterface::StateInterface(IHost *host, LilvInstance *pInstance, const LV2_State_Interface *pluginStateInterface)
|
||||
: map(host->GetMapFeature()),
|
||||
pInstance(pInstance),
|
||||
pluginStateInterface(pluginStateInterface)
|
||||
{
|
||||
auto hostFeatures = host->GetLv2Features();
|
||||
while (*hostFeatures != nullptr)
|
||||
{
|
||||
features.push_back((LV2_Feature*)(*hostFeatures));
|
||||
++hostFeatures;
|
||||
}
|
||||
features.push_back(nullptr);
|
||||
}
|
||||
|
||||
std::string Lv2PluginState::ToString() const {
|
||||
std::stringstream ss;
|
||||
json_writer writer(ss);
|
||||
writer.write(*this);
|
||||
return ss.str();
|
||||
}
|
||||
Reference in New Issue
Block a user