MidiJoystick is a client for the Jack Audio Connection Kit on Linux (and maybe other unixlikes) which lets you use your joystick as a midicontroller.
All inputs are freely configurable and multiple MIDI Messages can be bound to the same input.
All types of Midi Messages are supported, excluding Note-On (0x90) and Note-Off (0x80).
See supplied configuration file for an example configuration for a XBOX 360 Controller.
MidiJoystick uses a configuration file to read your input mapping, syntax is described further down. You’ll need to know the index of each of your inputs (axes and buttons) which you can test with the program jstest.
On start ‘midijoystick’ will parse your configuration file, telling you about problematic lines.
If not supplied as commandline arguments, Midijoystick will default to following files:
input file | path |
---|---|
joystick | /dev/input/js0 |
configuration | ./input.conf |
If you need help on MIDI see the included MIDI Compendium.
- added Note-On/Off messages are supported
- added deadzone commandline argument for axes
- added usage commandline argument
- added verbose commandline argument
flag | comment | default |
---|---|---|
-j | path to joystick | /dev/input/js0 |
-c | path to configuration file | ./input.conf |
-d | integer denoting deadzone radius for axes | no deadzone |
-v | if given prints midi messages | - |
-h | prints usage information |
You may want to use ‘-d 3000’ or a similar value, when your axes don’t emit a zero value when released.
A Configuration entry:
((t i) ((CMD [CH]) [PARAM*])+)
(brackets denote optional elements; a ‘+’ denotes one or more of the preceeding list/element; a * denotes zero or more of the preceedint list/elemnt;)
In the configuration you can use numbers of the base 10 or of the base 16. As MIDI is a byte oriented protocol it’s easier to use base 16 (hexadecimal) numbers.
NOTE: In the configuration file you have to write hexadecimal numbers with the prefix '#x' instead of the common prefix '0x'.
So instead of writing '0xE0' you would write '#xE0'.
A entry is consists of two parts on the toplevel:
- One Inputidentifier
- One or more Commandbindings
The Inputidentifier tells the program which joystick inputs should emit a MIDI message.
(t i)
A Inputidentifier consists of a token t
and an index i
.
The token t
specifies if the input is a axis or a button, the index i
specifies the index of the axis or button.
Allowed values for token t
are ‘a’ for axis and ‘b’ for button.
Allowed values for index i
are any positive integers.
To determine the index of any axis or button please use the unix tool ‘jstest’.
Commandbindings tell the program which MIDI messages should be emitted when a input (specified by the Inputidentifier) is recognized.
((CMD [CH]) [PARAM+])
A Commandbinding consists of two parts:
- The MIDI Command
CMD
and a MIDI ChannelCH
. The later is ignored (therefor optional) if the MIDI Command is a SysEx (CMD := 0xF0) message. Channels are counted from zero. - A list of zero or more integers
PARAM
, which are supplied as aditional parameters for the MIDI CommandCMD
.
Allowed values for CMD
are contained in this list: [0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0]
Allowed values for PARAM
are in the range of 0x00 - 0x7F.
So a Commandbinding can be viewed as a template, it represents quite closely the real MIDI message on the byte level. It’s a template cause dependeing,
on the specified CMD
, the joystick input is appended to or insert into the byte stream.
To bind multiple Commandbindings to one Inputidentifier you just add more Commandbindings to your entry.
See this example how you can bind two different messages to one axis:
((a 1) ;; bind to axis #1
((#xB0 #x02) #x01) ;; Continous Controller #1 on Channel 3
((#xB0 #x01) #x01)) ;; Continous Controller #1 on Channel 2
Here we bind the input from axis number 1 to two Continous Controller with the ID 1. One for Channel 3 and one for Channel 2.
((b 7) ;; bind to button #7
((#xF0) #x7F #x7F #x06 #x02 #xF7) ;; Send SysEx to send MMC Start
((#xF0) #x7F #x7F #x06 #x01 #xF7)) ;; Send SysEx to send MMC Stop
Here we bind two SysEx messages (so called ‘MIDI Real-Time Universal System Exclusive Messages’; more in the Midicompendium) to the button number 7.
There is one difference how buttons and axis act when multiple Commands are bound to one input:
Axis: All Commands are send when a input is recogniced. They are issued in the order in which they are specified. This should be semi-simultan.
Buttons: When a button is pressed the first MIDI Command is issued, on the second press the second Command is issued, and so on. If the last Command in the list is send, the next press will issue the first Command again. A endless cycle…
In the example above that would mean:
first press: Send SysEx to send MMC Start is issued
second press: Send SysEx to send MMC Stop is issued
third press: Send SysEx to send MMC Start is issued
Here are some examples how a configuration entry can look like:
- Channel 3 Pitch Bend on Axis 1
;; Bind axis with index 1 to Pitch-Bend on Channel 3
((a 1) ((#xE0 #x02))
- Channel 16 Continous Controller number 1 on axis 3
;; Bind axis with index 3 to Continous Controller number 1 on channel 16
((a 3) ((#xB0 #xF0) #x01))
- Send a MIDI Real-Time Universal System Exclusive Message when button 1 is pressed
((b 1) ;; Bind to input 'Button with index 1'
((#xF0) ;; denote that this is a System Exclusive Message
#x7F #x7F #x06 #02 #xF7)) ;; the SysEx Message which will be send (here: MIDI Machine Control to start playing)
A configuration entry can be split to multiple lines:
((t i)
((CMD CH)
PARAM))
Comments are denoted with ‘;’. Comments can appear between entries on their own or last in a line
((t i)
; A nice comment
((CMD ;; another comment
CH) PARAM))
Remember to enclose all your entries with parantheses:
( ;; <- this paranthesis is needed
((t i) ((CMD CH) PARAM))
((t i) ((CMD) PARAM))
((t i) ((CMD CH)))
) ;; <- this one too
see supplied configuration file for more examples of a complete config file
token | note | values |
---|---|---|
t | specifies input type: a for axis; b buttons | [ab] |
i | specifies index of the input type | [0-9]+ |
CMD | Midi command identifier as two digit hex number (see table below) | #x[89a-fA-F]0 |
CH | Midi channel for the command as a two digit hex number (0x00 - > 0x0F) so 0x00 is Channel 1 | #x0[0-9a-fA-F] |
PARAM | optional parameter as a two digit hex number (0x00 -> 0x7F), no default if omitted command; Meaning of PARAM is special to CMD -> see table below | [0-7][0-9a-fA-F] |
; | indicates a Comment |
To use Note-On/Off messages you should follow the following example configuration:
;; bind note-off and note-on to axis 1 for channel 1
((a 1)
(#x80 #x00) ; first send note-off, the value for note off is the last read value from axis 1
(#x90 #x00)) ; then send note-on, the value for note on is the current read value from axis 2
So on two inputs on the same axis following MIDI Messages are generated:
# First Input: we start off with a 'last-value' of 0x00 which translates to MIDI note 64 0: 80 40 7f note off (channel 0): pitch 64, velocity 127 1: 90 40 7f note on (channel 0): pitch 64, velocity 127 # Second Input: Last played note gets muted (compare msg 2 vs 1), new note sounds until next input 2: 80 40 7f note off (channel 0): pitch 64, velocity 127 3: 90 45 7f note on (channel 0): pitch 69, velocity 127
Any other use of Note-on/off is not tested, but you are free to experiment. See the example configuration, where a button is bound to CC 0x7B which mutes all sounding notes of a Channel.
Command | Meaning | joystick read value | config | comment |
---|---|---|---|---|
0x80 | Note-Off | - | - | note value is the value of the event bevore |
0x90 | Note-On | Note value | ||
0xB0 | Continous Controller (CC) | controller value | CC ID | see table of CC IDs in the MIDI Compendium |
0xC0 | Patch Change | not used | patch number | |
0xD0 | Channel Pressure | pressure amount | not used | |
0xE0 | Pitch Bend | bend amount | not used | |
0xF0 | SysEx Messages | not used | the SysEx Message which should be send |
For further information see the included MIDI Compendium
- TODO Support System Realtime Messages (Start, Stop, Reset )
- TODO allow to configure midi value emitted when button is pressed (instead of hardcoded 0x7F)
- TODO maybe find a way to configure buttons as mod keys for axis events (e.g. axis mapped to Pitch Bend, hold a button and axis now emits CC )
$ make all
will build:
- midijoystick: main program
Dependencies:
The joystick api maps axes values to a int16_t (positive and negative) range. While midi data bytes range from 0x00 to 0x7F. So we’re mapping the axis values to uint16_t and then to the midi data range (0x00 - 0x7F), thus the real axis value of 0x00 is a midi value of 0x40. A real axis value of 0x00 occures when the axis controler is at center position.
Buttons emit midi values of 0x7F when pressed and no signal when released, so their usefullness is subpar as for example mapping a button to Note-on would make not much sense.
file(s) | comments |
---|---|
midijoystick.scm | main program |
joystick.{c,h} | for talking with the joystick device file |
midijack.{c,h} | for talking with jackaudio server |