-
Notifications
You must be signed in to change notification settings - Fork 91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LV2 State Extension path mapping duplicated feature #427
Comments
yes, it probably uses the first it encounters in given m_lv2_features, as qtractor does have its own LV2_STATE__mapPath hook; it doesn't use any of the other though. do you have any specific concern on this or wish to propose a fix anyhow? |
No, its not simply a matter of lilv using the first one. It passes the array with both LV2_STATE__mapPath features to the LV2 plugin that is being saved. For my SpectMorph plugin, it would use the second one: which means that the "lilv" implementation and not your implementation gets used. I don't consider this a SpectMorph bug, because really I wouldn't expect to get the same feature passed twice, unless the LV2 spec would clarify on this. So as it stands the qtractor saving doesn't work for SpectMorph and even if I added a workaround for that (which I don't think is the right thing to do) there may be other plugins which likewise get confused here. |
Here is another piece of code that is taking the "wrong" mapPath: I think my concern is that you cannot really convince all plugin developers to agree on the one true strategy to deal with duplicated features. So it is either qtractor cannot use |
yeah you're certainly right; it all actually depends on how the lilv::add_features(() works, whether to append or prepend the lilv local map_features etc. it even might have changed across lilv releases because i'm sure this wrong doing wasn't there a few releases back. guess that it means that qtractor must have its own lilv_state_new_from_instance() and scrap the provided one; lilv should check if the caller already provides its own features (same URI) before duplicating them--but that's probably just me. thanks for the heads up. |
my take for the fix in lilv side: diff --git a/src/state.c b/src/state.c
index c8e8f14..9c284fb 100644
--- a/src/state.c
+++ b/src/state.c
@@ -378,6 +378,12 @@ add_features(const LV2_Feature* const* features,
{
size_t n_features = 0;
for (; features && features[n_features]; ++n_features) {
+ if (map && strcmp(features[n_features]->URI, LV2_STATE__mapPath) == 0)
+ map = NULL;
+ if (make && strcmp(features[n_features]->URI, LV2_STATE__makePath) == 0)
+ make = NULL;
+ if (free && strcmp(features[n_features]->URI, LV2_STATE__freePath) == 0)
+ free = NULL;
}
const LV2_Feature** ret = suppose this would solve the duplicates for good. :) what do you think? |
Yes, I think your fix is good. On Linux/macOS it should just work in any situation. On Windows, unfortunately there is this issue: lv2/lilv#14 which means that if you mix lilv path allocation with host freePath implementation (or the other way around) you're in trouble. But I think that is solvable on the host side with a two easy rules:
So yes, I think your solution is appropriate to fix the problem. |
thanks, an MR has been submitted to lilv upstream: ps. maybe you (and others) may help and up-vote the GL ticket? please? |
- rncbc/qtractor#427 Signed-off-by: Stefan Westerfeld <[email protected]>
avoids the takeover of LV2_State_{Map,Make,Free}_Path features duplicated in original implementation (lilv-0.24.22). See also: #427 https://gitlab.com/lv2/lilv/-/merge_requests/2
and here's the code that mitigates and most probably resolves to the right feature being picked up: const LV2_State_Map_Path* mapPath = nullptr;
const LV2_State_Free_Path* freePath = nullptr;
for (int i=0; features[i] != nullptr; ++i)
{
if (mapPath == nullptr
&& std::strcmp(features[i]->URI, LV2_STATE__mapPath) == 0)
mapPath = (const LV2_State_Map_Path*)features[i]->data;
else
if (freePath == nullptr
&& std::strcmp(features[i]->URI, LV2_STATE__freePath) == 0)
freePath = (const LV2_State_Free_Path*)features[i]->data;
} |
in your case this would suffice: LV2_State_Map_Path *map_path = nullptr;
#ifdef LV2_STATE__freePath
LV2_State_Free_Path *free_path = nullptr;
#endif
for (int i = 0; features[i]; i++)
{
if (!map_path && !strcmp (features[i]->URI, LV2_STATE__mapPath))
{
map_path = (LV2_State_Map_Path *)features[i]->data;
}
#ifdef LV2_STATE__freePath
else if (!free_path && !strcmp (features[i]->URI, LV2_STATE__freePath))
{
free_path = (LV2_State_Free_Path *)features[i]->data;
}
#endif
} |
eg. lilv_state_new_from_instance(), when and if already provided by the caller/host (eg. qtractor). Resolves promised qtractor method to bundle all SFZ <region> files to an archive/zip (*.qtz) session file, an old feature applicable to LV2 plugins. See also: rncbc/qtractor#427
To convert the state of an instance to a string, this code is used as a first step
If the LV2 plugin stores paths, you probably want the plugin to use the LV2_STATE__mapPath feature to translate the paths during generating the state. So you pass
nullptr
for all the dirs, but providem_lv2_features
so that the plugin uses your path translation.However,
lilv_state_new_from_instance
unconditionally adds its own LV2_STATE__mapPath feature like this:So now there are two instances of the LV2_STATE__mapPath feature, and unless there is a rule about which the plugin should use in this case (which I am not aware of), it might use the first one or the second one, which means that maybe it would use your version or not.
Not sure how to fix this; maybe it could also be fixed in lilv.
The text was updated successfully, but these errors were encountered: