Repository navigation
DistrhoPluginAU: Do not treat lossy conversion as failure (#552) - #554
polluxsynth wants to merge 1 commit into
Conversation
When parsing <real> values in plist, do not bail out if the conversion is "lossy", i.e cannot be represented exactly as a float32. This will normally never happen if a preset is restored after having been previously saved by DPF, but can happen if the preset has been generated in other ways, like running an application which converts it from some other format, such as LV2.
|
This doesnt make sense, if the type is not float32 then we shouldn't give a pointer to a float. |
|
The problem that I've seen is that the numbers in the .aupreset files are written in decimal (naturally, since it is a text based format), yet there are decimal numbers which cannot be represented exactly as floats (e.g. 1.1), and in such a case CFNumberGetValue() returns false because the conversion from text to float32 is considered 'lossy', i.e. cannot be represented exactly. Thus the problem is not that the numbers are not float32's, it's a question of how exact their representation is. This has happened to me when converting .lv2 files to .aupreset files by simply copying the text values from the .lv2 file to the .aupreset file, and it seems rather fragile for the .aupreset load procedure to be picky about exact conversion of numbers when the actual difference in value would seem insignificant. At any rate, I think it would be better to perform a best effort load rather than bail out completely. Of course, a different solution is for whatever program performing the conversion to .aupreset to recalculate the numbers so that the textual representation exactly can be represented as a float32, but given that the tags for values in the .aupreset files is |
|
well floating point numbers are decimal numbers. the check above the code you changed already checks if it's a number in order to pass this line we know for sure the value is a valid number. if the conversion to float32 cant be used, we can convert to float64 instead and then do the "lossy" part ourselves. |
|
The API docs for the call: https://developer.apple.com/documentation/corefoundation/cfnumbergetvalue(_:_:_:)?language=objc
so the float32 type is the wrong one to use here. |
|
The point here is that there are decimal numbers that cannot be represented exactly as either float32 or float64 . One such value is decimal 1.1, which in binary becomes 1.00011001100110011001... with an infinitely repeating fractional part, so whatever binary form you convert it to, it will be considered 'lossy'. In fact what the documentation says is that the CFNumberGetValue() will always return a value of the desired type, but it will be an approximation if it cannot be represented exactly, either because the number is out of range, or because the conversion is 'lossy'. So while bailing out on the previous lines if the value is not a number is viable, because that would be an error in the .aupreset file, but there is no reason to bail out because of a lossy conversion - the conversion error for a 'lossy' conversion will be too small to have any impact on any sane plugin, and even if that were the case, the resulting value is still a valid float32. |
|
Any further comments on this? As I mentioned the problem is not really a lack of precision, rather it is that certain valid numbers in the aupreset files cannot be exactly represented in any binary format, because the former are written using decimal numbers. This can be a problem when converting presets from another format, rather than saving them from state. I ran into this use case when converting from LV2 to aupreset, if the LV2 files have been tweaked manually (this causes no issues when loading them), and I can't really see any problem, given that the function in question will always return a valid number. |
When parsing values in plist, do not bail out if the conversion is "lossy", i.e cannot be represented exactly as a float32. This will normally never happen if a preset is restored after having been previously saved by DPF, but can happen if the preset has been generated in other ways, like running an application which converts it from some other format, such as LV2..
Disclosure: This patch was created with the help of AI. I have found it useful for my MiMi-d plugin, where I have the factory presets in LV2 format, and convert them to .aupreset files when building the AU format version of the plugin.