The question is in the title, really. I'd like it be able to convert an inlet value (int32) to a floating-point number in the range 0 > 1, then convert that back to an int32 in the correct range.
Sorry if it's a naive question.
a|x
The question is in the title, really. I'd like it be able to convert an inlet value (int32) to a floating-point number in the range 0 > 1, then convert that back to an int32 in the correct range.
Sorry if it's a naive question.
a|x
Can you please give an example you want to do this ?
Knowing that :
are you sure you need this ?
In C, with float to int32 conversion, you will loose the fractional part.
But maybe I did not understand the question.
Something like this works:
float in1f = inlet_inlet1*(float)(1.0f/(1<<27));
float out1f = in1f*in1f; // example : square function
outlet_outlet1 = (int)(out1f*(float)(1<<27));
Hi JeromeB,
thanks for getting back to me so quickly.
I have two things I want to use this for:
I thought the exp/pow part might be more easily achieved in floating-point, but it would require converting all variables to fp in the 0 > 1 range, hence my question.
I hope this makes sense. I'm used to working with floating-point values, but unfamiliar with fixed-point mathematics (and it's confusing the hell out of me, currently)...
a|x
Thank you, that's great!
I was aware of the 1/n method, but was wondering if there was a more efficient way to do it, avoiding division (which I vaguely understand is expensive).
This is what I had in mind.
a|x
Not sure how smart the compiler is, the compiler can do fixed-float conversion to a single instruction
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/CHDJAEDB.html
Square should be fast, square root too, but I expect a powf(x,y) call to be expensive.
Do you think it would be cheaper to do some kind of fixed-point lookup-table based approximation of the top and bottom curves, then lerp between them?
a|x
A lookup table will be slower than a square, both in fixed or floating point.
For square root there is a cpu instruction for float, taking 14 cycles rather than one. For fixed point this does not exist.
I'd suggest to interpolate betweeny=2*x-x*x
andy=x*x
avoiding a square root, but perhaps close enough
so y=a*(2*x-x*x)+(1-a)(x*x)
or the equivalenty=2*a*(x-x*x)+x*x
Apparently, there's a builtin Cortex M4 floating point square root function.
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/CHDHHAJF.html
so I guess
(float)sqrt = __VSQRT(in);
would work.
I'd quite like to make the curves more extreme (i.e. cube/cube root), but I can't work out if there's a way of approximating a cube root without division, as you've done with square root.
a|x
i thought with the compiler options we are using , you should be able to use math.h functions for these things... no?
(-mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mthumb )
fyi: math/sqrt uses
float aif = ai;
aif *= (1<<27);
aif = _VSQRTF(air);
also for:
float in1f = inlet_inlet1*(float)(1.0f/(1<<27));
id assume the compiler will replace 1/ (1 << 27) with a constant, so there wont be a division on execution just the multiplication.
or am i expecting too much of compilers ?
EDIT: Im interested in this, as Ive been messing with the same thing today, also for looking a envelopes with adjustable curves. I do like @johannes solution... but yeah, would be nice to have more extreme curves.
Interesting. I Might just leave this to you, then, I'm sure you'll make a better job.
One thing that did occur to me is that if you were to add a trigger outlet to, for example, an AD envelope object, so it sent out a pulse when the envelope moved from Attack to Decay phase, you could then use that in combination with the linear > exp interpolation object above and a multiplexer to have adjustable curves for the A and D stages of the envelope.
Even better, the envelope could send out an int value indicating the current envelope stage.
An envelope with integrated adjustable curves for each section would be neater, of course..
a|x
he, he... I think we have been on a very similar thought train today, spooky really...
basically, after doing the cycle ad object, Id thought about enhancing it,
and this led me to looking at the manuals for make noise function and maths as inspiration...
so was looking at implementing these
yes, the function, has an EOR (end of rise) outlet, which is as you say a trigger at the end of the attack phase.
it also has a exp/lin knob which has exp to lin curve effect on the rise/fall.
and thats, what caught my eye here... as you were basically after the same thing.
@johannes , so when I started to look at this, I started looking at CMSIS (arm_math) for some interesting functions... but I noticed if I called arm_sqrt_f32, that it doesnt resolve sqrtf()... ok, i assume this is because we don't link in against the math lib... but actually it should not be trying to use sqrtf, it should be using _sqrtf , because we have an fpu, but this seems to mean that __ FPU _PRESENT should be defined. Ive no familiarity with CMSIS... but should we be defining this to ensure when CMSIS is used, its 'optimised' for fpu... ok, noticed FPUPRESENT is defined, different issue
Good we're thinking along the same lines.
Cool. I think what we both want is a log to exp control (with linear in the middle), though, which is quite rare in the synth hardware world, but nonetheless quite cool, particularly for percussion sounds. Having seperate curve controls for both rising and falling segments will be really handy too, I'm sure.
a|x
I made a "workbench patch" to measure cpu cycles consumed by various operations.
My observations so far:
VCVT
instruction saves cycles compared to "plain" c conversion.powf()
is very expensivef>0?f:-f
is worse than fabs(f)
fsinf(f)
is not very unreasonable at 71 cycles/callThe workbench patch is in axoloti-contrib/patches/jt/devel/float_workbench.axp
Feel free to extend it, or question my observations.
For more extreme curves, let me suggesty=a*(x^3) + (1-a)*(1-(1-x)^3)
ory=a*(x^4) + (1-a)*(1-(1-x)^4)
None of these will give you a vertical asymptote at x=0 like sqrt.
But all of them will give you a horizontal n-the degree continuity at x=1 (when a=1), that is a potentially desirable property for an attack curve.
That's what I thought : I did not understand !
Your int32 inlet is a fixed point number, not an integer, ok.
I think, you found the two best people to answer your question !
@JeromeB Hehe... Yep, fell on my feet, there...
I was under the impression that the inlets internally are integers, but are represented outside the object as fixed-point fractional numbers. I've been making that assumption so far, anyway, and it seems to have worked out ok...
a|x
@johannes the reason sqrtf is not being converted to VSQRTF is because you need to set
-fno-math-errno
basically because the std maths functions set errno, which the VSQRTF (etc) would not, so are not 100% compatible, so you have to tell the compiler you dont need this...
I think we should do this for both the firmware and patch... any possible issues you can think of?