2048 has no significance, other than I thought it looks about straight there, you could raise it much higher, it will just trend towards a straight line but never quite get there.
I used a ti-89 emulator and solve() to do this math to solve for y and it spit out this, which is correct. I became dependent on this in school, which was bad and 'cheating', but hey it works, I wouldn't have solved this without it.
s = 127
q = sqrt(s^2 + s^2)
w = sqrt(r^2 - (q/2)^2)*(-s/q)
y = (-sqrt(4*r^2-s^2-4*s*(w-x)-4*(w^2-2*w*x+x^2))-s+2*w)/2 god i hope I retyped that right, it copy and pastes funny out of desmos
Either way you can see that painfully long solution working in all of it's glory in desmos if I did type it wrong.
where x is the number between 0 and 127 you would like to compress and r is a number between 127-2048+ that represents how much you would like the returning y variable to be compressed.
https://www.desmos.com/calculator/hhpynxmgfp
That is a LOT of math to do every time you want to compress a midi number, so I would suggest creating some lookup tables with this math to translate with if you don't need fast response from different r values. If it were me, I would figure it out in processing, have it spit out the tables to serial, and copy and paste that into the arduino code.
edit:
http://codepen.io/ohnoitsaninja/pen/MprbvJ
Here is a javascript version with a working demo. You could copy and paste into arduino, switch the vars to floats and it would work.
Code:
var s = 127;
var s2 = s*s;
var r2 = r*r;
var q = sqrt(s2 + s2);
var s4 = 4*s;
var w = sqrt(r2 - (q/2)*(q/2)) *(-s/q);
var w2 = w*w;
var p = 4*r2-s2;
var k = -s+2*w;
var white = color(255);
for (var x = 0; x < 128;x++){
var y = -((sqrt(p-s4*(w-x)-4*(w2-2*w*x+x*x)))+k)/2;
set(200+x, 200-y, white);
}
http://codepen.io/ohnoitsaninja/pen/xqpVJz/?editors=0010
Here is a different attempt trying to average between two circles, wrong, not symmetric and couldn't get it to work.