Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

https://github.com/osune/MidiJoystick

MidiJoystick is a MIDI client for the Jack Audio Connection Kit on Linux, which lets you use your joystick to emit MIDI commands
https://github.com/osune/MidiJoystick

gambit-scheme jack-audio-connection-kit jackaudio midi

Last synced: 3 months ago
JSON representation

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

Lists

README

        

* 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 [[http://www.jackaudio.org/][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 [[./input.conf][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 [[http://linux.die.net/man/1/jstest][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 [[./midicompendium.org][MIDI Compendium]].

** [[./CHANGELOG.org][Changelog]]

** Commandline Arguments

| 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.

** 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:

#+BEGIN_SRC lisp
((a 1) ;; bind to axis #1
((#xB0 #x02) #x01) ;; Continous Controller #1 on Channel 3
((#xB0 #x01) #x01)) ;; Continous Controller #1 on Channel 2
#+END_SRC

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.

#+BEGIN_SRC lisp
((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
#+END_SRC

Here we bind two SysEx messages (so called 'MIDI Real-Time Universal System Exclusive Messages'; more in the [[./midicompendium.org][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.org][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:

#+BEGIN_SRC lisp
((t i)
((CMD CH) PARAM BUTTON_VALUE))
#+END_SRC

An example:

#+BEGIN_SRC lisp
((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)
#+END_SRC

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:

#+BEGIN_SRC lisp
((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)
#+END_SRC

*** Examples:

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

1) Channel 3 Pitch Bend on Axis 1

#+BEGIN_SRC lisp
;; Bind axis with index 1 to Pitch-Bend on Channel 3
((a 1) ((#xE0 #x02))
#+END_SRC

2) Channel 16 Continous Controller number 1 on axis 3

#+BEGIN_SRC lisp
;; Bind axis with index 3 to Continous Controller number 1 on channel 16
((a 3) ((#xB0 #xF0) #x01))
#+END_SRC

3) Send a MIDI Real-Time Universal System Exclusive Message when button 1 is pressed

#+BEGIN_SRC lisp
((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)
#+END_SRC

*** Aditional Notes:


A configuration entry can be split to multiple lines:

#+BEGIN_SRC lisp
((t i)
((CMD CH)
PARAM))
#+END_SRC

Comments are denoted with ';'. Comments can appear between entries on their own or last in a line

#+BEGIN_SRC lisp
((t i)
; A nice comment
((CMD ;; another comment
CH) PARAM))
#+END_SRC

Remember to enclose all your entries with parantheses:

#+BEGIN_SRC lisp
( ;; <- this paranthesis is needed
((t i) ((CMD CH) PARAM))
((t i) ((CMD) PARAM))
((t i) ((CMD CH)))
) ;; <- this one too
#+END_SRC

see [[./input.conf][supplied configuration file]] for more examples of a complete config file

*** Overview Table

| 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 | |

** Implemented Midi Commands

To use Note-On/Off messages you should follow the following example configuration:

#+BEGIN_SRC lisp
;; 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
#+END_SRC

So on two inputs on the same axis following MIDI Messages are generated:

#+BEGIN_SRC
# 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
#+END_SRC

Any other use of Note-on/off is not tested, but you are free to experiment.
See the [[./input.conf][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 [[./midicompendium.org][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 [[./midicompendium.org][MIDI Compendium]]

** [[./midicompendium.org][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:
- [[http://www.jackaudio.org][Jack Audio Connection Kit]] Tested Version: jack2 1.9.10-4
- [[http://gambitscheme.org/wiki/index.php/Main_Page][Gambit]] Tested Version: 4.8.4-1

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.scm | main 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

[[./LICENSE][MIT]]