Remapping Keyboard Velocity
As a musician, one of the first things I need to address is the 'feel' of my instruments. I'm sure that down the line, there will be a sweet device for this sort of transformation, but for now, we can do it entirely within Bitwig API.
Revisiting Generic Keyboard Implementation, we have host.getMidiInPort(0).createNoteInput("MIDI Keyboard");
inside init()
. This function returns an object of type NoteInput
which has the method setVelocityTranslationTable()
.
var noteInput = host.getMidiInPort(0).createNoteInput("MIDI Keyboard");
noteInput.setVelocityTranslationTable( table );
This method takes an 128 length array, or a hash table, transforming the index of the array into the values of the array as the translation being performed.
So, for example:
var table = [];
table[50] = 127;
would translate a note of velocity 50 into a velocity of 127. This way, a keyboard, like mine, which produces a narrow range of output, generally from 40 to 75, can be expanded to produce the full range of velocities accepted by software instruments. However, BitWig requires a table of 128 points to match every velocity a keyboard can produce with an appropriate transformed value, so we must start with a set of numbers to represent this transformation.
I use the worlds greatest Piano Modelling software PianoTEQ to come up with the following velocity curve.
Exported from the program, Velocity = [0, 1, 46, 50, 62, 98, 127; 0, 1, 32, 64, 96, 127, 127]
gives a nice starting place to do a linear interpolation. The first set of numbers is the input velocities, and the second set, the output. Linear interpolation is a geometry technique to find any point on a line between two points.
1 var noteInput = host.getMidiInPort(0).createNoteInput('Maschine Midi In');
2
3 inputVel = [ 0, 1, 46, 50, 62, 98, 127 ]; // x
4 transVel = [ 0, 1, 32, 64, 96, 127, 127 ]; // y
5
6 var output = [];
7 for ( slope = 0, i = 0; i < 128; i++){
8 //Y = Y1 + ( ( Y2 - Y1) ( X - X1 ) / ( X2 - X1) )
9 y = transVel[0] +
10 ( ((transVel[1] - transVel[0]) * ( i - inputVel[0] )) /
11 (inputVel[1]-inputVel[0])
12 );
13 output[i] = Math.min(Math.round(y), 127);
14 if ( inputVel[1] < i ){
15 transVel.shift();
16 inputVel.shift();
17 }
18 }
19
20 noteInput.setVelocityTranslationTable(output);
We iterate through inputVel
and transVel
by shifting each array every time the x or i
reaches the next value of inputVel
. This shift makes the operation on lines 9-13 apply again, with the new values at [0] of each array.
I would highly recommend you just copy and paste this code into your application and change as you see fit, but this is how it's done.