Mapping MIDI values
- KVRian
- 775 posts since 30 Nov, 2008
Raw MIDI controller changes come in as integers from 0 to 127.
If I am mapping these to a parameter in the floating point range -1 to 1, a problem arises, there is no integer value that corresponds to zero using the straightforward formula f = 2 * (i / 127) - 1 where i is the midi integer and f is the mapped floating point value.
Would it be so bad if I were to map MIDI values 63 and 64 to zero and then stretch the remaining range into -1...1 accordingly? Or alternatively, interpret 64 as zero? Either way, one end of the range has one fewer step.
How do people handle this? I have to represent zero exactly, since there could be some additional behavior at the center point.
If I am mapping these to a parameter in the floating point range -1 to 1, a problem arises, there is no integer value that corresponds to zero using the straightforward formula f = 2 * (i / 127) - 1 where i is the midi integer and f is the mapped floating point value.
Would it be so bad if I were to map MIDI values 63 and 64 to zero and then stretch the remaining range into -1...1 accordingly? Or alternatively, interpret 64 as zero? Either way, one end of the range has one fewer step.
How do people handle this? I have to represent zero exactly, since there could be some additional behavior at the center point.
My Open Source:
Beast, rippled, DSPFilters, LayerEffects, SimpleDJ
Beast, rippled, DSPFilters, LayerEffects, SimpleDJ
-
- KVRer
- 25 posts since 15 Dec, 2005 from Sacramento, CA
The idea of mapping both 63 and 64 to 0.0 isn't so bad, provided you never need to reverse the mapping. Would 0.0 indicate 63 or 64?
This is a problem with all mappings between limited sets. Designing a function that is 100% reversible requires knowledge of the specific ranges and values that both sides can take. This is even more of a problem when you're mapping MIDI to parameter values which are then mapped to control ranges, such as knob positions in your GUI. You can spend an awful lot of time tweaking every mapping for every parameter. Or you can live with the fact that you never get exactly what you want, and sometimes don't get back exactly what you started with.
Personally, though, if I really just needed a middle value (and not a range of specific values, like 1 through 10 on a knob), then I think I'd treat 0 as 1, and map the range 1..127, which has a middle at exactly 64. But that's just my preference.
This is a problem with all mappings between limited sets. Designing a function that is 100% reversible requires knowledge of the specific ranges and values that both sides can take. This is even more of a problem when you're mapping MIDI to parameter values which are then mapped to control ranges, such as knob positions in your GUI. You can spend an awful lot of time tweaking every mapping for every parameter. Or you can live with the fact that you never get exactly what you want, and sometimes don't get back exactly what you started with.
Personally, though, if I really just needed a middle value (and not a range of specific values, like 1 through 10 on a knob), then I think I'd treat 0 as 1, and map the range 1..127, which has a middle at exactly 64. But that's just my preference.
-
- KVRAF
- 2460 posts since 3 Oct, 2002 from SF CA USA NA Earth
I strongly recommend you map MIDI 64 to bipolar-normalized 0.0, MIDI 0 to bipolar-normalized -1, and MIDI 127 to bipolar-normalized +0.984375 (i.e. 63/64).
This mapping is consistent and unambiguous. The binary round numbers hit in the expected places. It doesn't change step size at the zero crossing. It behaves well when extended to 14-bit continuous controllers (where +8191/8192 = +0.99878).
Its only failing is that it can't reach exactly +1. If, for some reason, you care about that, my second best choice would be to stretch the top half of the range:
Doubling up the zero is very bad, as a slowly stepped controller will then have a jog in its response even if you do internal smoothing on the value.
This mapping is consistent and unambiguous. The binary round numbers hit in the expected places. It doesn't change step size at the zero crossing. It behaves well when extended to 14-bit continuous controllers (where +8191/8192 = +0.99878).
Its only failing is that it can't reach exactly +1. If, for some reason, you care about that, my second best choice would be to stretch the top half of the range:
Code: Select all
midi_to_bipolar(midi):
biased = midi-64
if biased < 0 return biased/64.0
else return biased/63.0- KVRian
- Topic Starter
- 775 posts since 30 Nov, 2008
LOL... it figures that my guess would turn out to be the worst choice.
Thanks for the pointers, that really helped!
Thanks for the pointers, that really helped!
My Open Source:
Beast, rippled, DSPFilters, LayerEffects, SimpleDJ
Beast, rippled, DSPFilters, LayerEffects, SimpleDJ
- KVRAF
- 2606 posts since 4 Sep, 2006 from 127.0.0.1
i faced this same issue a few years ago when i wrote my own wave file reader/writer class
so i made my choice
the closest example is 8bit signed int
it goes from -128 to +127.. i map 0.0 to 0
+1.0 to +127
-1.0 to -127
thus, i don't ever use the value -128, that's a small compromise, but i have perfect zero..
this is also perfectly reversible
so i made my choice
the closest example is 8bit signed int
it goes from -128 to +127.. i map 0.0 to 0
+1.0 to +127
-1.0 to -127
thus, i don't ever use the value -128, that's a small compromise, but i have perfect zero..
this is also perfectly reversible
It doesn't matter how it sounds..
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr
..as long as it has BASS and it's LOUD!
irc.libera.chat >>> #kvr

