Skip to content

MidiJoystick is a MIDI client for the Jack Audio Connection Kit on Linux, which lets you use your joystick to emit MIDI commands

License

Notifications You must be signed in to change notification settings

osune/MidiJoystick

Repository files navigation

MidiJoystick (VERSION 1.1.0)

WARNING: THIS IS NOT COMPATIBLE WITH GAMBIT 4.2.X But feel free to hack away anyways.

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.

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 filepath
joystick/dev/input/js0
configuration./input.conf

If you need help on MIDI see the included MIDI Compendium.

Commandline Arguments

flagcommentdefault
-jpath to joystick/dev/input/js0
-cpath to configuration file./input.conf
-dinteger denoting deadzone radius for axesno deadzone
-vif given prints midi messages-
-hprints usage information

You may want to use ‘-d 3000’ or a similar value, when your axes don’t emit a zero value when released.

Configuration Syntax

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:

  1. One Inputidentifier
  2. One or more Commandbindings

Inputidentifier:

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:

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:

  1. The MIDI Command CMD and a MIDI Channel CH. The later is ignored (therefor optional) if the MIDI Command is a SysEx (CMD := 0xF0) message. Channels are counted from zero.
  2. A list of zero or more integers PARAM, which are supplied as aditional parameters for the MIDI Command CMD.

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.

Bind multiple Commandbindings to one Inputidentifier

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

Buttons:

Since version 1.1.0 you can specify a value which gets emitted when a button is pressed. This means on all supported MIDI messages (CC, Note-On/Off, Pitch Bend) a button press can emit another value then 0x7F. This change allows to play one defined note, using CCs which act more like a switch (see Midicompendium) or applying a defined Pitch Bend value.

Take note that no bound checking is done. The values you supply must be in the range [0x00, 0x7F] ([0x0000, 0x3FFF] for Pitch Bend).

The format for this new configuration feature is:

((t i)
  ((CMD CH) PARAM BUTTON_VALUE))

An example:

((b 5)  ;; bind button 5
 ((#xB0 #x04) #x40 #x7F)    ;; CC 0x40 (Damper/Sustain) on Channel 5 with the value 0x7F (ON)
 ((#xB0 #x04) #x40 #x00))  ;; CC 0x40 (Damper/Sustain) on Channel 5 with the value 0x00 (OFF)

As you can see the rules for buttons as explained above still apply: You have to supply two lines with different `BUTTON_VALUE` to toggle between two states.

If you ommit `BUTTON_VALUE` a value of 0x7F is used. Which means you can write the example above as:

((b 5)  ;; bind button 5
 ((#xB0 #x04) #x40)    ;; CC 0x40 (Damper/Sustain) on Channel 5 with the _implicit_ value 0x7F (ON)
 ((#xB0 #x04) #x40 #x00))  ;; CC 0x40 (Damper/Sustain) on Channel 5 with the value 0x00 (OFF)

Examples:

Here are some examples how a configuration entry can look like:

  1. Channel 3 Pitch Bend on Axis 1
;; Bind axis with index 1 to Pitch-Bend on Channel 3
((a 1) ((#xE0 #x02))
  1. 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))
  1. 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)

Aditional Notes:

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

Overview Table

tokennotevalues
tspecifies input type: a for axis; b buttons[ab]
ispecifies index of the input type[0-9]+
CMDMidi command identifier as two digit hex number (see table below)#x[89a-fA-F]0
CHMidi channel for the command as a two digit hex number (0x00 - > 0x0F) so 0x00 is Channel 1#x0[0-9a-fA-F]
PARAMoptional 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

Implemented Midi Commands

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.

CommandMeaningjoystick read valueconfigcomment
0x80Note-Off--note value is the value of the event bevore
0x90Note-OnNote value
0xB0Continous Controller (CC)controller valueCC IDsee table of CC IDs in the MIDI Compendium
0xC0Patch Changenot usedpatch number
0xD0Channel Pressurepressure amountnot used
0xE0Pitch Bendbend amountnot used
0xF0SysEx Messagesnot usedthe SysEx Message which should be send

For further information see the included MIDI Compendium

TODOs

  • TODO Support System Realtime Messages (Start, Stop, Reset )
  • TODO allow to configure midi value emitted when button is pressed (instead of hardcoded 0x7F) fixed in 1.1.0
  • 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 )

How to build

$ make all

will build:

  • midijoystick: main program

Dependencies:

Tested Version numbers taken from the Arch Linux Packages.

Additional Notes

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.

Source Code Map

file(s)comments
midijoystick.scmmain program
glue.{c,h}glue.c gets included into midijoystick.scm it holds some helper functions
joystick.{c,h}for talking with the joystick device file
midijack.{c,h}for talking with jackaudio server

License

MIT

About

MidiJoystick is a MIDI client for the Jack Audio Connection Kit on Linux, which lets you use your joystick to emit MIDI commands

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published