diff --git a/src/common/serialization/vst3/attribute-list.cpp b/src/common/serialization/vst3/attribute-list.cpp index ab27863f..2e0ef421 100644 --- a/src/common/serialization/vst3/attribute-list.cpp +++ b/src/common/serialization/vst3/attribute-list.cpp @@ -29,6 +29,28 @@ IMPLEMENT_FUNKNOWN_METHODS(YaAttributeList, Steinberg::Vst::IAttributeList::iid) #pragma GCC diagnostic pop +tresult YaAttributeList::write_back( + Steinberg::Vst::IAttributeList* stream) const { + if (!stream) { + return Steinberg::kInvalidArgument; + } + + for (const auto& [key, value] : attrs_int) { + stream->setInt(key.c_str(), value); + } + for (const auto& [key, value] : attrs_float) { + stream->setFloat(key.c_str(), value); + } + for (const auto& [key, value] : attrs_string) { + stream->setString(key.c_str(), u16string_to_tchar_pointer(value)); + } + for (const auto& [key, value] : attrs_binary) { + stream->setBinary(key.c_str(), value.data(), value.size()); + } + + return Steinberg::kResultOk; +} + tresult PLUGIN_API YaAttributeList::setInt(AttrID id, int64 value) { attrs_int[id] = value; return Steinberg::kResultOk; diff --git a/src/common/serialization/vst3/attribute-list.h b/src/common/serialization/vst3/attribute-list.h index 23ab7ff2..81e43453 100644 --- a/src/common/serialization/vst3/attribute-list.h +++ b/src/common/serialization/vst3/attribute-list.h @@ -42,6 +42,13 @@ class YaAttributeList : public Steinberg::Vst::IAttributeList { DECLARE_FUNKNOWN_METHODS + /** + * Write the attribute list a host provided `IAttributeList`. This is used + * in `YaBStream::write_back` to write any preset meta data back to the host + * for hosts that support it. + */ + tresult write_back(Steinberg::Vst::IAttributeList* stream) const; + virtual tresult PLUGIN_API setInt(AttrID id, int64 value) override; virtual tresult PLUGIN_API getInt(AttrID id, int64& value) override; virtual tresult PLUGIN_API setFloat(AttrID id, double value) override; diff --git a/src/common/serialization/vst3/bstream.cpp b/src/common/serialization/vst3/bstream.cpp index 1795c20c..e93801ef 100644 --- a/src/common/serialization/vst3/bstream.cpp +++ b/src/common/serialization/vst3/bstream.cpp @@ -21,6 +21,31 @@ #include #include +/** + * These are the meta data keys used for `IStreamAttributes`. We need to keep + * track of this because `IAttributeList` has no way to just iterate over the + * stored keys. We'll read these from the host if the host supports this + * interface, and if the plugin writes an attribute with one of these keys we'll + * write the value back to the host. + * + * TODO: There's also `Steinberg::Vst::PresetAttributes::kFilePathStringType` + * This would require translating between Windows and Unix style paths, + * which we can't easily do outside of Wine. If this ends up being + * important, then we'll have to shell out to `winepath` which is not + * ideal. On the Wine side we can just use the `wine_get_dos_file_name` + * and `wine_get_unix_file_name` functions instead. Requesting this should + * also use a 1024 character buffer. + */ +const static char* stream_meta_data_keys[] = { + Steinberg::Vst::PresetAttributes::kPlugInName, + Steinberg::Vst::PresetAttributes::kPlugInCategory, + Steinberg::Vst::PresetAttributes::kInstrument, + Steinberg::Vst::PresetAttributes::kStyle, + Steinberg::Vst::PresetAttributes::kCharacter, + Steinberg::Vst::PresetAttributes::kStateType, + Steinberg::Vst::PresetAttributes::kName, + Steinberg::Vst::PresetAttributes::kFileName}; + YaBStream::YaBStream(){FUNKNOWN_CTOR} YaBStream::YaBStream(Steinberg::IBStream* stream) { @@ -61,34 +86,18 @@ YaBStream::YaBStream(Steinberg::IBStream* stream) { file_name.emplace(tchar_pointer_to_u16string(vst_string)); } - // Copy over all predefined meta data keys. `IAttributeList` does not - // offer any interface to enumerate over the stored keys. - // TODO: There's also - // `Steinberg::Vst::PresetAttributes::kFilePathStringType` - // This would require translating between Windows and Unix style - // paths, which we can't easily do outside of Wine. If this ends - // up being important, then we'll have to shell out to `winepath` - // which is not ideal. On the Wine side we can just use the - // `wine_get_dos_file_name` and `wine_get_unix_file_name` - // functions instead. Requesting this should also use a 1024 - // character buffer. attributes.emplace(); - Steinberg::IPtr stream_attributes_list = - stream_attributes->getAttributes(); - for (const auto& key : - {Steinberg::Vst::PresetAttributes::kPlugInName, - Steinberg::Vst::PresetAttributes::kPlugInCategory, - Steinberg::Vst::PresetAttributes::kInstrument, - Steinberg::Vst::PresetAttributes::kStyle, - Steinberg::Vst::PresetAttributes::kCharacter, - Steinberg::Vst::PresetAttributes::kStateType, - Steinberg::Vst::PresetAttributes::kName, - Steinberg::Vst::PresetAttributes::kFileName}) { - vst_string[0] = 0; - if (stream_attributes_list->getString(key, vst_string, - sizeof(vst_string)) == - Steinberg::kResultOk) { - attributes->setString(key, vst_string); + if (Steinberg::IPtr + stream_attributes_list = stream_attributes->getAttributes()) { + // Copy over all predefined meta data keys. `IAttributeList` does + // not offer any interface to enumerate the stored keys. + for (const auto& key : stream_meta_data_keys) { + vst_string[0] = 0; + if (stream_attributes_list->getString(key, vst_string, + sizeof(vst_string)) == + Steinberg::kResultOk) { + attributes->setString(key, vst_string); + } } } } @@ -139,6 +148,18 @@ tresult YaBStream::write_back(Steinberg::IBStream* stream) const { // back after `*::getState()`? I'd assume so, but the docs don't // mention this. If so then we need to always store whether the host // supports `IStreamAttributes`. + // Write back any attributes written by the plugin if the host supports + // preset meta data + if (Steinberg::FUnknownPtr + stream_attributes = stream; + stream_attributes && attributes) { + if (Steinberg::IPtr + stream_attributes_list = stream_attributes->getAttributes()) { + // XXX: If the host somehow preset some attributes, then we're also + // writing those back. This should not cause any issues though. + attributes->write_back(stream_attributes_list); + } + } return Steinberg::kResultOk; } diff --git a/src/common/serialization/vst3/bstream.h b/src/common/serialization/vst3/bstream.h index c449cf50..e6974d19 100644 --- a/src/common/serialization/vst3/bstream.h +++ b/src/common/serialization/vst3/bstream.h @@ -58,8 +58,8 @@ class YaBStream : public Steinberg::IBStream, DECLARE_FUNKNOWN_METHODS /** - * Write the vector buffer back to an IBStream. After writing the seek - * position will be left at the end of the stream. + * Write the vector buffer back to a host provided `IBStream`. After writing + * the seek position will be left at the end of the stream. */ tresult write_back(Steinberg::IBStream* stream) const;