Hi Phatline,
This may be a bit late, but what you are trying to do shouldn't be that much of a problem :)
I refactored your code a little to understand better what it should do:
int32_t value;
uint8_t note_vel = Velo_From_Note[port];
uint8_t morph_vel = beat[port].Velo_Morph[x];
uint8_t morph_offset = beat[port].Velo_Morph_Offset;
int32_t morph = ( ((vel / 127.0) * (morph_vel - 64.0)) / 64.0 ) * morph_offset;
If all input values are ints then the only operations we should worry about are divisions.
If we modify the formula so that there are no divisions anymore and we can verify that our data fits into a 32bit value we are fine.
Note that divisions by constants get optimized by more recent compilers, so unless you want to emphasize the use of a shift operation you can simply use normal * and / operators and avoid feeling like driving your brain through a meat grinder ;)
Because multiplications are associative and commutative we can write the formula like this:
int32_t morph = vel * (morph_vel - 64) * morph_offset / (127 * 64);
/* Now we multiply by 127 * 64 = 8128 and everything is integer */
int32_t morph_8128 = vel * (morph_vel - 64) * morph_offset;
let's check if that fits into our 32bit value by adding the size of every factor variable.
This works because a product of two variables with x bits fits into a variable with x+x bits
The signed int can only represent a positive 31 bit value as the MSB is used for negative values.
31 >= 8 + 8 + 8
That is valid and therefore if the variables all have 8 bits they fit into 31 (or even 24) bits.
When you add it to value, we have to have one bit in reserve because e.g. if they are both ((1<<24) - 1)
we need 25 bits for that value
value = morph + value
Your code that checks the value needs to be adjusted, too:
if (value < 0)
value = 0;
else if (value > 127 * 8128)
value = 127 * 8128;
return value / 8128;
You can reduce the time those multiplications drastically if you stick to powers of 2 but you might get away with this here ;)
Cheers, Roman