|
|
|
@@ -507,13 +507,195 @@ public: |
|
|
|
return V3_OK; |
|
|
|
} |
|
|
|
|
|
|
|
v3_result setState(v3_bstream*, void*) |
|
|
|
/* state: we pack pairs of key-value strings each separated by a null/zero byte. |
|
|
|
* states come first, and then parameters. parameters are simply converted to/from strings and floats. |
|
|
|
* the parameter symbol is used as the "key", so it is possible to reorder them or even remove and add safely. |
|
|
|
* the number of states must remain constant though. |
|
|
|
*/ |
|
|
|
v3_result setState(v3_bstream* const stream, void* arg) |
|
|
|
{ |
|
|
|
#if DISTRHO_PLUGIN_WANT_STATE |
|
|
|
// TODO |
|
|
|
#endif |
|
|
|
|
|
|
|
if (const uint32_t paramCount = fPlugin.getParameterCount()) |
|
|
|
{ |
|
|
|
char buffer[32], orig; |
|
|
|
String key, value; |
|
|
|
v3_result res; |
|
|
|
bool fillingKey = true; |
|
|
|
|
|
|
|
// temporarily set locale to "C" while converting floats |
|
|
|
const ScopedSafeLocale ssl; |
|
|
|
|
|
|
|
for (int32_t pos = 0, read;; pos += read) |
|
|
|
{ |
|
|
|
std::memset(buffer, '\xff', sizeof(buffer)); |
|
|
|
res = stream->read(arg, buffer, sizeof(buffer)-1, &read); |
|
|
|
DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res); |
|
|
|
DISTRHO_SAFE_ASSERT_INT_RETURN(read > 0, read, V3_INTERNAL_ERR); |
|
|
|
|
|
|
|
for (int32_t i = 0; i < read; ++i) |
|
|
|
{ |
|
|
|
if (buffer[i] == '\0' && pos == 0 && i == 0) |
|
|
|
continue; |
|
|
|
|
|
|
|
orig = buffer[read]; |
|
|
|
buffer[read] = '\0'; |
|
|
|
|
|
|
|
if (fillingKey) |
|
|
|
key += buffer + i; |
|
|
|
else |
|
|
|
value += buffer + i; |
|
|
|
|
|
|
|
i += std::strlen(buffer + i); |
|
|
|
buffer[read] = orig; |
|
|
|
|
|
|
|
if (buffer[i] == '\0') |
|
|
|
{ |
|
|
|
fillingKey = !fillingKey; |
|
|
|
|
|
|
|
if (value.isNotEmpty()) |
|
|
|
{ |
|
|
|
// find parameter with this symbol, and set its value |
|
|
|
for (uint32_t j=0; j<paramCount; ++j) |
|
|
|
{ |
|
|
|
if (fPlugin.isParameterOutputOrTrigger(j)) |
|
|
|
continue; |
|
|
|
if (fPlugin.getParameterSymbol(j) != key) |
|
|
|
continue; |
|
|
|
|
|
|
|
fPlugin.setParameterValue(j, std::atof(value.buffer())); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
key.clear(); |
|
|
|
value.clear(); |
|
|
|
} |
|
|
|
|
|
|
|
if (buffer[i+1] == '\0') |
|
|
|
return V3_OK; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (buffer[read] == '\0') |
|
|
|
return V3_OK; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return V3_OK; |
|
|
|
} |
|
|
|
|
|
|
|
v3_result getState(v3_bstream* const stream, void* arg) |
|
|
|
{ |
|
|
|
const uint32_t paramCount = fPlugin.getParameterCount(); |
|
|
|
#if DISTRHO_PLUGIN_WANT_STATE |
|
|
|
const uint32_t stateCount = fPlugin.getStateCount(); |
|
|
|
#else |
|
|
|
const uint32_t stateCount = 0; |
|
|
|
#endif |
|
|
|
|
|
|
|
if (stateCount == 0 && paramCount == 0) |
|
|
|
{ |
|
|
|
char buffer = '\0'; |
|
|
|
int32_t ignored; |
|
|
|
return stream->write(arg, &buffer, 1, &ignored); |
|
|
|
} |
|
|
|
|
|
|
|
String state; |
|
|
|
|
|
|
|
#if DISTRHO_PLUGIN_WANT_FULL_STATE |
|
|
|
/* |
|
|
|
// Update current state |
|
|
|
for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) |
|
|
|
{ |
|
|
|
const String& key = cit->first; |
|
|
|
fStateMap[key] = fPlugin.getState(key); |
|
|
|
} |
|
|
|
*/ |
|
|
|
#endif |
|
|
|
|
|
|
|
#if DISTRHO_PLUGIN_WANT_STATE |
|
|
|
/* |
|
|
|
for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) |
|
|
|
{ |
|
|
|
const String& key = cit->first; |
|
|
|
const String& value = cit->second; |
|
|
|
|
|
|
|
// join key and value |
|
|
|
String tmpStr; |
|
|
|
tmpStr = key; |
|
|
|
tmpStr += "\xff"; |
|
|
|
tmpStr += value; |
|
|
|
tmpStr += "\xff"; |
|
|
|
|
|
|
|
state += tmpStr; |
|
|
|
} |
|
|
|
*/ |
|
|
|
#endif |
|
|
|
|
|
|
|
if (paramCount != 0) |
|
|
|
{ |
|
|
|
// add another separator |
|
|
|
state += "\xff"; |
|
|
|
|
|
|
|
for (uint32_t i=0; i<paramCount; ++i) |
|
|
|
{ |
|
|
|
if (fPlugin.isParameterOutputOrTrigger(i)) |
|
|
|
continue; |
|
|
|
|
|
|
|
// join key and value |
|
|
|
String tmpStr; |
|
|
|
tmpStr = fPlugin.getParameterSymbol(i); |
|
|
|
tmpStr += "\xff"; |
|
|
|
tmpStr += String(fPlugin.getParameterValue(i)); |
|
|
|
tmpStr += "\xff"; |
|
|
|
|
|
|
|
state += tmpStr; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
state.replace('\xff', '\0'); |
|
|
|
|
|
|
|
// now saving state, carefully until host written bytes matches full state size |
|
|
|
const char* buffer = state.buffer(); |
|
|
|
const int32_t size = static_cast<int32_t>(state.length())+1; |
|
|
|
v3_result res; |
|
|
|
|
|
|
|
for (int32_t wrtntotal = 0, wrtn; wrtntotal < size; wrtntotal += wrtn) |
|
|
|
{ |
|
|
|
wrtn = 0; |
|
|
|
res = stream->write(arg, const_cast<char*>(buffer), size - wrtntotal, &wrtn); |
|
|
|
|
|
|
|
DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res); |
|
|
|
DISTRHO_SAFE_ASSERT_INT_RETURN(wrtn > 0, wrtn, V3_INTERNAL_ERR); |
|
|
|
} |
|
|
|
|
|
|
|
return V3_OK; |
|
|
|
} |
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------- |
|
|
|
// v3_bstream interface calls (for state support) |
|
|
|
|
|
|
|
v3_result read(void* buffer, int32_t num_bytes, int32_t* bytes_read) |
|
|
|
{ |
|
|
|
// TODO |
|
|
|
return V3_NOT_IMPLEMENTED; |
|
|
|
} |
|
|
|
|
|
|
|
v3_result getState(v3_bstream*, void*) |
|
|
|
v3_result write(void* buffer, int32_t num_bytes, int32_t* bytes_written) |
|
|
|
{ |
|
|
|
// TODO |
|
|
|
return V3_NOT_IMPLEMENTED; |
|
|
|
} |
|
|
|
|
|
|
|
v3_result seek(int64_t pos, int32_t seek_mode, int64_t* result) |
|
|
|
{ |
|
|
|
// TODO |
|
|
|
return V3_NOT_IMPLEMENTED; |
|
|
|
} |
|
|
|
|
|
|
|
v3_result tell(int64_t* pos) |
|
|
|
{ |
|
|
|
// TODO |
|
|
|
return V3_NOT_IMPLEMENTED; |
|
|
|
@@ -1302,6 +1484,102 @@ struct dpf_audio_processor : v3_audio_processor_cpp { |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------------------- |
|
|
|
// dpf_state_stream |
|
|
|
|
|
|
|
struct v3_bstream_cpp : v3_funknown { |
|
|
|
v3_bstream stream; |
|
|
|
}; |
|
|
|
|
|
|
|
struct dpf_state_stream : v3_bstream_cpp { |
|
|
|
ScopedPointer<PluginVst3>& vst3; |
|
|
|
|
|
|
|
dpf_state_stream(ScopedPointer<PluginVst3>& v) |
|
|
|
: vst3(v) |
|
|
|
{ |
|
|
|
static const uint8_t* kSupportedInterfaces[] = { |
|
|
|
v3_funknown_iid, |
|
|
|
v3_bstream_iid |
|
|
|
}; |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------ |
|
|
|
// v3_funknown |
|
|
|
|
|
|
|
query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result |
|
|
|
{ |
|
|
|
d_stdout("dpf_factory::query_interface => %p %s %p", self, tuid2str(iid), iface); |
|
|
|
*iface = NULL; |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE); |
|
|
|
|
|
|
|
for (const uint8_t* interface_iid : kSupportedInterfaces) |
|
|
|
{ |
|
|
|
if (v3_tuid_match(interface_iid, iid)) |
|
|
|
{ |
|
|
|
*iface = self; |
|
|
|
return V3_OK; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return V3_NO_INTERFACE; |
|
|
|
}; |
|
|
|
|
|
|
|
// TODO |
|
|
|
ref = []V3_API(void*) -> uint32_t { return 1; }; |
|
|
|
unref = []V3_API(void*) -> uint32_t { return 0; }; |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------ |
|
|
|
// v3_bstream |
|
|
|
|
|
|
|
stream.read = []V3_API(void* self, void* buffer, int32_t num_bytes, int32_t* bytes_read) -> v3_result |
|
|
|
{ |
|
|
|
d_stdout("dpf_state_stream::read => %p %p %i %p", self, buffer, num_bytes, bytes_read); |
|
|
|
dpf_state_stream* const stream = *(dpf_state_stream**)self; |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN(stream != nullptr, V3_NOT_INITIALISED); |
|
|
|
|
|
|
|
PluginVst3* const vst3 = stream->vst3; |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); |
|
|
|
|
|
|
|
return V3_NOT_IMPLEMENTED; |
|
|
|
}; |
|
|
|
|
|
|
|
stream.write = []V3_API(void* self, void* buffer, int32_t num_bytes, int32_t* bytes_written) -> v3_result |
|
|
|
{ |
|
|
|
d_stdout("dpf_state_stream::write => %p %p %i %p", self, buffer, num_bytes, bytes_written); |
|
|
|
dpf_state_stream* const stream = *(dpf_state_stream**)self; |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN(stream != nullptr, V3_NOT_INITIALISED); |
|
|
|
|
|
|
|
PluginVst3* const vst3 = stream->vst3; |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); |
|
|
|
|
|
|
|
return V3_NOT_IMPLEMENTED; |
|
|
|
}; |
|
|
|
|
|
|
|
stream.seek = []V3_API(void* self, int64_t pos, int32_t seek_mode, int64_t* result) -> v3_result |
|
|
|
{ |
|
|
|
d_stdout("dpf_state_stream::seek => %p %lu %i %p", self, pos, seek_mode, result); |
|
|
|
dpf_state_stream* const stream = *(dpf_state_stream**)self; |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN(stream != nullptr, V3_NOT_INITIALISED); |
|
|
|
|
|
|
|
PluginVst3* const vst3 = stream->vst3; |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); |
|
|
|
|
|
|
|
return V3_NOT_IMPLEMENTED; |
|
|
|
}; |
|
|
|
|
|
|
|
stream.tell = []V3_API(void* self, int64_t* pos) -> v3_result |
|
|
|
{ |
|
|
|
d_stdout("dpf_state_stream::tell => %p %p", self, pos); |
|
|
|
dpf_state_stream* const stream = *(dpf_state_stream**)self; |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN(stream != nullptr, V3_NOT_INITIALISED); |
|
|
|
|
|
|
|
PluginVst3* const vst3 = stream->vst3; |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); |
|
|
|
|
|
|
|
return V3_NOT_IMPLEMENTED; |
|
|
|
}; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------------------- |
|
|
|
// dpf_component |
|
|
|
|
|
|
|
@@ -1315,7 +1593,7 @@ struct dpf_component : v3_component_cpp { |
|
|
|
ScopedPointer<dpf_component>* self; |
|
|
|
ScopedPointer<dpf_audio_processor> processor; |
|
|
|
ScopedPointer<dpf_edit_controller> controller; |
|
|
|
// ScopedPointer<dpf_plugin_view> view; |
|
|
|
ScopedPointer<dpf_state_stream> stream; |
|
|
|
ScopedPointer<PluginVst3> vst3; |
|
|
|
|
|
|
|
dpf_component(ScopedPointer<dpf_component>* const s) |
|
|
|
@@ -1539,7 +1817,7 @@ struct dpf_component : v3_component_cpp { |
|
|
|
|
|
|
|
comp.get_state = []V3_API(void* self, v3_bstream** stream) -> v3_result |
|
|
|
{ |
|
|
|
d_stdout("dpf_component::get_state => %p", self); |
|
|
|
d_stdout("dpf_component::get_state => %p %p", self, stream); |
|
|
|
dpf_component* const component = *(dpf_component**)self; |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED); |
|
|
|
|
|
|
|
@@ -1706,6 +1984,8 @@ struct dpf_factory : v3_plugin_factory_cpp { |
|
|
|
return V3_NOT_IMPLEMENTED; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
DISTRHO_PREVENT_HEAP_ALLOCATION |
|
|
|
}; |
|
|
|
|
|
|
|
END_NAMESPACE_DISTRHO |
|
|
|
|