Dear all,
sorry for stirring things up!
I am currently implementing a program for scanning soundfonts for
optimizations, and one possible optimization is to use a modulator
instead of a manual value list. To adapt a modulator to a value list,
one must have a good understanding of the possibilities for tweaking the
transfer function.
Most things in the soundfont specification are quite clear, but some are
"underspecified".
The first topic is how the range of a controller is originally mapped
onto the range from zero to one.
My naive assumption is that most transforms happen on the unit interval
from zero to one and that the minimum value maps to zero and the maximum
value maps to one.
However, if you read the specification for the standard modulator for
channel pressure, it says that the value 0 is mapped to 0 (good!) and
the value 127 is mapped to 127/128 (instead of 1??).
Even better is the default modulator for velocity to attenuation: a
value of 0 does not exist (I understand the reason for that), so 1 is
mapped to the maximum 127/128 (again not to 1) and 127 is mapped to
1/127 (since the domain is now one value shorter).
A 14-bit controller should have the same problem in principle, but
16383/16384 is an acceptable "one" for me...
Well, you cannot argue with a specification, and there may have been
valid hardware-based reasons for that definition caused by the original
soundcards. But it is quirky nontheless.
The second topic are the curves for "convex" and "concave". It is
already mentioned in the FluidSynth code that the definition in the spec
is not helpful at all. For concave, the formula
output = log(sqrt(value^2)/(max value)^2)
is used which yields nonsensical values, regardless of whether these are
the original controller values or whether they have already been
transformed onto the interval [0..1].
But even the implementation in FluidSynth does not help me. It reads:
return ((i == 0)
? 0
: ((i == FLUID_VEL_CB_SIZE - 1)
? 1
: ((-200.0L * 2 / FLUID_PEAK_ATTENUATION) *
gcem::log(((FLUID_VEL_CB_SIZE - 1) - i) / (FLUID_VEL_CB_SIZE - 1.0L)) /
GCEM_LOG_10)
));
At least someone dares to return 0 and 1 for the left and right interval
ends! But in between, I am not convinced how this fits into the original
logic shown in the images, especially the scaling with -something/log10
looks suspicious. Great, there is a log function as in the original
specification, but in my opinion log ruins everything ;-)
When I looked at the concave and convex pictures, I thought that they
really look like circle quadrants (where typically x² + y² = 1) which
could lead to the following functions:
concave: y = 1 - sqrt(1- x²)
convex: y = sqrt(1 - (1 - x²))
So we have the squares and square roots already mentioned in the
specification function; hence this could therefore be a viable approach.
The big advantage of a circle segment is that it is symmetrical, which
is definitely not the case with a logarithm function.
I can understand that this may be considered an esoteric discussion, as
we are mostly talking about minimal differences in modulation values.
But I would like to have a solid mathematical foundation for my algorithms.
Can anyone help me here?
Best regards,
Prof. Spock
_______________________________________________
fluid-dev mailing list
fluid-dev@nongnu.org
https://lists.nongnu.org/mailman/listinfo/fluid-dev