Korg nanoKontrol 2 MIDI to FreePIE to vJoy

Official forum for open source FreePIE discussion and development.
Post Reply
AngryStatic
One Eyed Hopeful
Posts: 1
Joined: Tue Jul 03, 2018 9:13 pm

Korg nanoKontrol 2 MIDI to FreePIE to vJoy

Post by AngryStatic »

I've put together some code for FreePIE so you can use a Korg nanoKontrol2 as a generic joystick.

The point being that the buttons/sliders/dials won't be hard coded to keys but joystick buttons which are re assignable in the game itself.

https://github.com/gregjlinton/MIDI-to-FreePIE-to-vJoy

The horrible, horrible code that's totally inefficient is for a reason. You can comment out the parts you don't want with a #. That way you can disable sliders, buttons or whatever individually within FreePIE without having to learn actual principles of coding. Additionally you can add, subtract or change the mapping of CC# buttons to vJoy buttons directly. There's no fancy loops, counters or time outs. Brute force and ignorance.

This may require more advanced debouncing. This is beyond the scope of my skills. But it looks okay when staring at the vJoy Monitor output. I have tried this out in Descent, works like a charm. Hard as hell to control with sliders and dials...But the intent was to use this for things like Artemis Starship Bridge Simulator's Engineering console.

Share and enjoy the slider, dial, button goodness.

Code: Select all

# This is a work in progress and to hell with your warranty!
# I wanted to use a Korg nanoKontrol2 as a joystick. Why? 'Cause buttons, dials & sliders for cheaper ($80 CDN).
# This: http://www.korg.com/caen/products/computergear/nanokontrol2/
# To make this work we need to monitor the midi from the nanoKontrol2 and convert them in real time to a joystick output.
# We can do that with FreePIE (Programmable Input Emulator): http://andersmalmgren.github.io/FreePIE/
# FreePIE converts that to an output for a virtual joystick.
# For this we're using vJoy: http://vjoystick.sourceforge.net/site/
# vJoy only supports a limited number of axis which we want to use as sliders/dials and other inputs to games.
# To make this all work, we're going to have to split layout of the nanoKontrol2 into multiple virtual joysticks.
# 4 dials and 4 sliders on the left as a joystick (with some buttons?), 4 dials and 4 sliders on the right as a second joystick (with some buttons?).
# A 3rd joystick could be used for all the "transport" buttons (forward, back, play, record, next track, etc).
# All of this was coded in a brute force way because I am a noob at this.

# Install vJoy.
# Install FreePIE.
# Install Korg Kontrol Editor. https://www.korg.com/us/support/download/software/0/159/1354/
# Starting with Korg Kontrol Editor. Run it and see if you can connect to the nanoKontrol2. This should bring up a "map" of the nanoKontrol2 and the Control Channels (CC#)'s.
# Open vJoyConf. Create 2 joysticks. 1 has all the axis enables with 36 buttons. 2 has all the exis enabled with any number of buttons since they won't be used.
# Open vJoy Monitor.
# Copy/paste or open this code in/into FreePIE. Save it as a script, then press run. If it all works, you should be able to monitor the joystick outuput with vJoy's monitor program.

def update():
   diagnostics.watch(midi[0].data.channel)
   diagnostics.watch(midi[0].data.status)
   diagnostics.watch(midi[0].data.buffer[0])
   diagnostics.watch(midi[0].data.buffer[1])


# Sliders and Dials and buttons on the left side of the nanoKontrol2
# Change the value after == to the Control Channel (CC#) you want as input from the nanoKontrol2
# Change the value after vJoy[0]. you want to be the button on your virtual joystick.
# Change the value after vJoy[ for the virtual joystick you want to use [0] or [1] for example.

#slider_1
if midi[0].data.buffer[0] == 0:#CC0
	slide_1 = midi[0].data.buffer[0] == 0 and filters.mapRange(midi[0].data.buffer[1], 0, 127, -17873, 17873)
	vJoy[0].x = slide_1;
#dial_1
if midi[0].data.buffer[0] == 16:#CC16
	dial_1 = midi[0].data.buffer[0] == 16 and filters.mapRange(midi[0].data.buffer[1], 0, 127, -17873, 17873)
	vJoy[0].rx = dial_1;

#Button S1 CC#32
if (midi[0].data.buffer[0] == 32) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(14,True)  

if (midi[0].data.buffer[0] == 32) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(14,False)

#Button M1 CC#45
if (midi[0].data.buffer[0] == 48) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(13,True)  

if (midi[0].data.buffer[0] == 48) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(13,False)

#Button R1 CC#64
if (midi[0].data.buffer[0] == 64) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(12,True)  

if (midi[0].data.buffer[0] == 64) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(12,False)


#slider_2
if midi[0].data.buffer[0] == 1:#CC1	
	slide_2 = midi[0].data.buffer[0] == 1 and filters.mapRange(midi[0].data.buffer[1], 0, 127, -17873, 17873)
	vJoy[0].y = slide_2;

#dial_2
if midi[0].data.buffer[0] == 17:#CC17
	dial_2 = midi[0].data.buffer[0] == 17 and filters.mapRange(midi[0].data.buffer[1], 0, 127, -17873, 17873)
	vJoy[0].ry = dial_2;

#Button S2 CC#33
if (midi[0].data.buffer[0] == 33) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(17,True)  

if (midi[0].data.buffer[0] == 33) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(17,False)

#Button M3 CC#49
if (midi[0].data.buffer[0] == 49) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(16,True)  

if (midi[0].data.buffer[0] == 49) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(16,False)

#Button R3 CC#65
if (midi[0].data.buffer[0] == 65) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(15,True)  

if (midi[0].data.buffer[0] == 65) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(15,False)

#slider_3
if midi[0].data.buffer[0] == 2:#CC2	
	slide_3 = midi[0].data.buffer[0] == 2 and filters.mapRange(midi[0].data.buffer[1], 0, 127, -17873, 17873)
	vJoy[0].z = slide_3;
#dial_3
if midi[0].data.buffer[0] == 18:#CC18
	dial_3 = midi[0].data.buffer[0] == 18 and filters.mapRange(midi[0].data.buffer[1], 0, 127, -17873, 17873)
	vJoy[0].rz = dial_3;

#Button S3 CC#34
if (midi[0].data.buffer[0] == 34) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(20,True)  

if (midi[0].data.buffer[0] == 34) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(20,False)

#Button M3 CC#50
if (midi[0].data.buffer[0] == 50) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(19,True)  

if (midi[0].data.buffer[0] == 50) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(19,False)

#Button R3 CC#66
if (midi[0].data.buffer[0] == 66) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(18,True)  

if (midi[0].data.buffer[0] == 66) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(18,False)


#slider_4
if midi[0].data.buffer[0] == 3:#CC3	
	slide_4 = midi[0].data.buffer[0] == 3 and filters.mapRange(midi[0].data.buffer[1], 0, 127, -17873, 17873)
	vJoy[0].slider = slide_4;
#dial_4
if midi[0].data.buffer[0] == 19:#CC19
	dial_4 = midi[0].data.buffer[0] == 19 and filters.mapRange(midi[0].data.buffer[1], 0, 127, -17873, 17873)
	vJoy[0].dial = dial_4;

#Button S4 CC#35
if (midi[0].data.buffer[0] == 35) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(23,True)  

if (midi[0].data.buffer[0] == 35) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(23,False)

#Button M4 CC#51
if (midi[0].data.buffer[0] == 51) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(22,True)  

if (midi[0].data.buffer[0] == 51) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(22,False)

#Button R4 CC#67
if (midi[0].data.buffer[0] == 67) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(21,True)  

if (midi[0].data.buffer[0] == 67) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(21,False)
	
	
# Because vJoy only supports a total of 8 axis per joystick, we have to split up the slider and dials section into two halves. The second half will be on the second virtual joystick vJoy[1]. 
# Sliders and Dials and buttons on the right side of the nanoKontrol2

#slider_5
if midi[0].data.buffer[0] == 4:#CC4
	slide_1 = midi[0].data.buffer[0] == 4 and filters.mapRange(midi[0].data.buffer[1], 0, 127, -17873, 17873)
	vJoy[1].x = slide_1;
#dial_5
if midi[0].data.buffer[0] == 20:#CC20
	dial_1 = midi[0].data.buffer[0] == 20 and filters.mapRange(midi[0].data.buffer[1], 0, 127, -17873, 17873)
	vJoy[1].rx = dial_1;

# Since vJoy can handle 128 buttons, we'll keep all the mashable buttons on the nanoKontrol2 to virtual joystick 1 vJoy[0]
#Button S5 CC#36
if (midi[0].data.buffer[0] == 36) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(26,True)  

if (midi[0].data.buffer[0] == 36) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(26,False)

#Button M5 CC#52
if (midi[0].data.buffer[0] == 52) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(25,True)  

if (midi[0].data.buffer[0] == 52) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(25,False)

#Button R5 CC#66
if (midi[0].data.buffer[0] == 68) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(24,True)  

if (midi[0].data.buffer[0] == 68) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(24,False)

#slider_6
if midi[0].data.buffer[0] == 5:#CC5	
	slide_2 = midi[0].data.buffer[0] == 5 and filters.mapRange(midi[0].data.buffer[1], 0, 127, -17873, 17873)
	vJoy[1].y = slide_2;
#dial_6
if midi[0].data.buffer[0] == 21:#CC21
	dial_2 = midi[0].data.buffer[0] == 21 and filters.mapRange(midi[0].data.buffer[1], 0, 127, -17873, 17873)
	vJoy[1].ry = dial_2;

#Button S6 CC#37
if (midi[0].data.buffer[0] == 37) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(29,True)  

if (midi[0].data.buffer[0] == 37) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(29,False)

#Button M6 CC#53
if (midi[0].data.buffer[0] == 53) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(28,True)  

if (midi[0].data.buffer[0] == 53) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(28,False)

#Button R6 CC#69
if (midi[0].data.buffer[0] == 69) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(27,True)  

if (midi[0].data.buffer[0] == 69) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(27,False)

#slider_7
if midi[0].data.buffer[0] == 6:#CC6	
	slide_3 = midi[0].data.buffer[0] == 6 and filters.mapRange(midi[0].data.buffer[1], 0, 127, -17873, 17873)
	vJoy[1].z = slide_3;
#dial_7
if midi[0].data.buffer[0] == 22:#CC22
	dial_3 = midi[0].data.buffer[0] == 22 and filters.mapRange(midi[0].data.buffer[1], 0, 127, -17873, 17873)
	vJoy[1].rz = dial_3;

#Button S7 CC#38
if (midi[0].data.buffer[0] == 38) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(32,True)  

if (midi[0].data.buffer[0] == 38) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(32,False)

#Button M7 CC#54
if (midi[0].data.buffer[0] == 54) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(31,True)  

if (midi[0].data.buffer[0] == 54) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(31,False)

#Button R7 CC#70
if (midi[0].data.buffer[0] == 70) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(30,True)  

if (midi[0].data.buffer[0] == 70) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(30,False)

#slider_8
if midi[0].data.buffer[0] == 7:#CC7	
	slide_4 = midi[0].data.buffer[0] == 7 and filters.mapRange(midi[0].data.buffer[1], 0, 127, -17873, 17873)
	vJoy[1].slider = slide_4;
#dial_8
if midi[0].data.buffer[0] == 23:#CC23
	dial_4 = midi[0].data.buffer[0] == 23 and filters.mapRange(midi[0].data.buffer[1], 0, 127, -17873, 17873)
	vJoy[1].dial = dial_4;

#Button S8 CC#39
if (midi[0].data.buffer[0] == 39) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(35,True)  

if (midi[0].data.buffer[0] == 39) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(35,False)

#Button M8 CC#55
if (midi[0].data.buffer[0] == 55) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(34,True)  

if (midi[0].data.buffer[0] == 55) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(34,False)

#Button R8 CC#71
if (midi[0].data.buffer[0] == 71) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(33,True)  

if (midi[0].data.buffer[0] == 71) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(33,False)

# the Korg nanoKontrol2 includes some transport buttons as well so we'll give them some allocations on virtual joystick 1 vJoy[0] as well
# We'll leave virtual joystick button 12 ( vJoy[0].11 ) as a gap to keep the deliniation between trasnport buttons and the slider area clear. In truth, I'm too lazy to fix it now.
# Button last Track CC#58
if (midi[0].data.buffer[0] == 58) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(0,True)  

if (midi[0].data.buffer[0] == 58) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(0,False)

# Button next Track CC#59
if (midi[0].data.buffer[0] == 59) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(1,True)  

if (midi[0].data.buffer[0] == 59) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(1,False)

# Button cycle CC#46
if (midi[0].data.buffer[0] == 46) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(2,True)  

if (midi[0].data.buffer[0] == 46) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(2,False)

# Button set CC#60
if (midi[0].data.buffer[0] == 60) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(3,True)  

if (midi[0].data.buffer[0] == 60) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(3,False)

# Button Left Marker CC#61
if (midi[0].data.buffer[0] == 61) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(4,True)  

if (midi[0].data.buffer[0] == 61) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(4,False)

# Button Right Marker CC#62
if (midi[0].data.buffer[0] == 62) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(5,True)  

if (midi[0].data.buffer[0] == 62) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(5,False)

# Button Rewind CC#43
if (midi[0].data.buffer[0] == 43) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(6,True)  

if (midi[0].data.buffer[0] == 43) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(6,False)

# Button Fast Forward CC#44
if (midi[0].data.buffer[0] == 44) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(7,True)  

if (midi[0].data.buffer[0] == 44) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(7,False)

# Button Stop CC#42
if (midi[0].data.buffer[0] == 42) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(8,True)  

if (midi[0].data.buffer[0] == 42) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(8,False)

# Button Play CC#41
if (midi[0].data.buffer[0] == 41) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(9,True)  

if (midi[0].data.buffer[0] == 41) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(9,False)

# Button Record CC#45
if (midi[0].data.buffer[0] == 45) and (midi[0].data.buffer[1] > 0): 
	vJoy[0].setButton(10,True)  

if (midi[0].data.buffer[0] == 45) and (midi[0].data.buffer[1] < 127):
	vJoy[0].setButton(10,False)



if starting:
	midi[0].update += update
Post Reply

Return to “FreePIE”