midizap/midizap.1

2185 lines
84 KiB
Groff

.\" Automatically generated by Pandoc 2.2.3.2
.\"
.TH "midizap" "1" "" "" ""
.hy
.SH Name
.PP
midizap \[en] control your multimedia applications with MIDI
.SH Synopsis
.PP
midizap [\-hkns] [\-d[rskmj]] [\-j \f[I]name\f[]] [\-o[\f[I]n\f[]]]
[\-P[\f[I]prio\f[]]] [\-r \f[I]rcfile\f[]]
.SH Options
.TP
.B \-h
Print a short help message and exit.
.RS
.RE
.TP
.B \-d[rskmj]
Enable various debugging options: r = regex (print matched translation
sections), s = strokes (print the parsed configuration file in a
human\-readable format), k = keys (print executed translations), m =
midi (MIDI monitor, print all recognizable MIDI input), j = jack
(additional Jack debugging output).
Just \f[C]\-d\f[] enables all debugging options.
See Section \f[I]Basic Usage\f[].
.RS
.RE
.TP
.B \-j \f[I]name\f[]
Set the Jack client name.
This overrides the corresponding directive in the configuration file.
Default: \[lq]midizap\[rq].
See Section \f[I]Jack\-Related Options\f[].
.RS
.RE
.TP
.B \-k
Keep track of key (on/off) status of MIDI notes and control switches.
This isn't generally recommended, but may occasionally be useful to deal
with quirky controllers sending note\- or control\-ons without
corresponding off messages.
.RS
.RE
.TP
.B \-n
No automatic feedback.
By default, midizap keeps track of controller feedback from the second
input port if it is enabled (\f[C]\-o2\f[]).
This option lets you disable this feature if the second port is being
used for other purposes.
See Section \f[I]Automatic Feedback\f[].
.RS
.RE
.TP
.B \-o[\f[I]n\f[]]
Enable MIDI output and set the number of output ports \f[I]n\f[] (1 by
default).
Use \f[I]n\f[] = 2 for a second pair of MIDI ports, e.g., for controller
feedback, or \f[I]n\f[] = 0 to disable MIDI output.
This overrides the corresponding directive in the configuration file.
See Section \f[I]Jack\-Related Options\f[].
.RS
.RE
.TP
.B \-P[\f[I]prio\f[]]
Run with the given real\-time priority (default: 90).
See Section \f[I]Jack\-Related Options\f[].
.RS
.RE
.TP
.B \-r \f[I]rcfile\f[]
Set the configuration file name.
Default: taken from the MIDIZAP_CONFIG_FILE environment variable if it
exists, or ~/.midizaprc if it exists, /etc/midizaprc otherwise.
See Section \f[I]Configuration File\f[].
.RS
.RE
.TP
.B \-s
Pass through system messages from MIDI input to output.
See Section \f[I]MIDI Output\f[].
.RS
.RE
.SH Description
.PP
midizap lets you control your multimedia applications using
MIDI (https://www.midi.org/).
To these ends, it translates Jack MIDI input into X keystrokes, mouse
button presses, scroll wheel events, and, as an option, MIDI output.
It does this by matching the \f[C]WM_CLASS\f[] and \f[C]WM_NAME\f[]
properties of the window that has the keyboard focus against the regular
expressions for each application section in its configuration
(midizaprc) file.
If a regex matches, the corresponding set of translations is used.
If a matching section cannot be found, or if it doesn't define a
suitable translation, the program falls back to a set of translations in
a default section at the end of the file, if available.
.PP
The midizaprc file is just an ordinary text file which you can edit to
configure the program.
The configuration language is fairly straightforward, basically the file
is just a list of MIDI messages (denoted with familiar human\-readable
mnemonics, no hex numbers!) and their translations, which is divided
into sections for different applications.
An example.midizaprc file containing sample configurations for some
applications is included in the sources to get you started, and you can
find some more examples of configuration files for various purposes in
the examples directory.
.PP
midizap provides you with a way to hook up just about any MIDI
controller to your applications.
Even if your target application already supports MIDI, midizap's MIDI
output option will be useful if your controller can't work directly with
the application because of protocol incompatibilities.
In particular, you can use midizap to turn pretty much any MIDI
controller with enough faders and buttons into a Mackie\-compatible
mixing device ready to be used with most DAW (digital audio workstation)
programs.
Another common use case is video editing software, which rarely offers
built\-in MIDI support.
midizap allows you to map the faders, encoders and buttons of your MIDI
controller to keyboard commands of your video editor for cutting,
marking, playback, scrolling, zooming, etc.
.PP
In other words, as long as the target application can be controlled with
simple keyboard shortcuts and/or MIDI commands, chances are that midizap
can make it work (at least to some extent) with your controller.
.SH Installation
.PP
First, make sure that you have the required dependencies installed.
The program needs a few X11 libraries and Jack.
And of course you need GNU make and gcc (the GNU C compiler).
On Ubuntu and other Debian\-based systems you should be able to get
everything that's needed by running this command:
.IP
.nf
\f[C]
sudo\ apt\ install\ build\-essential\ libx11\-dev\ libxtst\-dev\ libjack\-dev
\f[]
.fi
.PP
Then just run \f[C]make\f[] and \f[C]sudo\ make\ install\f[].
This installs the example.midizaprc file as /etc/midizaprc, and the
midizap program and the manual page in the default install location.
Usually this will be under /usr/local, but the installation prefix can
be changed with the \f[C]prefix\f[] variable in the Makefile.
Also, package maintainers can use the \f[C]DESTDIR\f[] variable to
install into a staging directory for packaging purposes.
.SH Configuration File
.PP
After installation the system\-wide default configuration file will be
in /etc/midizaprc, where the program will be able to find it.
We recommend copying this file to your home directory, renaming it to
\&.midizaprc:
.IP
.nf
\f[C]
cp\ /etc/midizaprc\ ~/.midizaprc
\f[]
.fi
.PP
The ~/.midizaprc file, if it exists, takes priority over /etc/midizaprc,
so it becomes your personal default midizap configuration.
The midizaprc file included in the distribution is really just an
example; you're expected to edit this file to adjust the bindings for
the MIDI controllers and the applications that you use.
.PP
It is also possible to specify the configuration file to be used, by
invoking midizap with the \f[C]\-r\f[] option on the command line, e.g.:
\f[C]midizap\ \-r\ myconfig.midizaprc\f[].
This is often used with more specialized configurations dealing with
specific applications or MIDI controllers.
.PP
The program automatically reloads the midizaprc file whenever it notices
that the file has been changed.
Thus you can edit the file while the program keeps running, and have the
changes take effect immediately without having to restart the program.
When working on new translations, you may want to run the program in a
terminal, and employ some or all of the debugging options explained
below to see exactly how your translations are being processed.
.SH Basic Usage
.PP
The midizap program is a command line application, so you typically run
it from the terminal.
However, it is also possible to launch it from your Jack session manager
(see \f[I]Jack\-Related Options\f[] below) or from your desktop
environment's startup files once you've set up everything to your
liking.
.PP
Try \f[C]midizap\ \-h\f[] for a brief summary of the available options
with which the program can be invoked.
.PP
midizap uses Jack (http://jackaudio.org/) for doing all its MIDI input
and output, so you need to be able to run Jack and connect the Jack MIDI
inputs and outputs of the program.
We recommend using a Jack front\-end and patchbay program like
QjackCtl (https://qjackctl.sourceforge.io/) for this purpose.
In QjackCtl's setup, make sure that you have selected \f[C]seq\f[] as
the MIDI driver.
This exposes the ALSA sequencer ports of your MIDI hardware and other
non\-Jack ALSA MIDI applications as Jack MIDI ports, so that they can
easily be connected to midizap.
(We're assuming that you're using Jack1 here.
Jack2 works in a very similar way, but may require some more fiddling;
in particular, you may have to use
a2jmidid (http://repo.or.cz/a2jmidid.git) as a separate ALSA\-Jack MIDI
bridge in order to have the ALSA MIDI devices show properly as Jack MIDI
devices.)
.PP
Having that set up, start Jack, make sure that your MIDI controller is
connected, and try running \f[C]midizap\f[] from the command line
(without any arguments).
In QjackCtl, open the Connections dialog and activate the second tab
named \[lq]MIDI\[rq], which shows all available Jack MIDI inputs and
outputs.
On the right side of the MIDI tab, you should now see a client named
\f[C]midizap\f[] with one MIDI input port named \f[C]midi_in\f[].
That's the one you need to connect to your MIDI controller, whose output
port should be visible under the \f[C]alsa_midi\f[] client on the left
side of the dialog.
.PP
To test the waters, you can hook up just about any MIDI keyboard and
give it a try with the default section in the distributed midizaprc
file, which contains some basic translations for mouse and cursor key
emulation.
Here is the relevant excerpt from that section:
.IP
.nf
\f[C]
[Default]
\ C5\ \ \ \ XK_Button_1
\ D5\ \ \ \ XK_Button_2
\ E5\ \ \ \ XK_Button_3
\ F5\ \ \ \ XK_Left
\ G5\ \ \ \ XK_Up
\ A5\ \ \ \ XK_Down
\ B5\ \ \ \ XK_Right
\ CC1+\ \ XK_Scroll_Up
\ CC1\-\ \ XK_Scroll_Down
\f[]
.fi
.PP
We refer to Section \f[I]Translation Syntax\f[] below for a discussion
of the syntax being used here, but it should be fairly obvious that
these translations map the white keys of the middle octave (MIDI notes
\f[C]C5\f[] thru \f[C]B5\f[]) to some mouse buttons and cursor commands.
Switch the keyboard focus to some window with text in it, such as a
terminal or an editor window.
Pressing the keys C, D and E should click the mouse buttons, while F
thru B should perform various cursor movements.
Also, moving the modulation wheel (\f[C]CC1\f[]) on your keyboard should
scroll the window contents up and down.
.PP
One useful feature is that you can invoke the program with various
debugging options to get more verbose output as the program recognizes
events from the device and translates them to corresponding mouse
actions or key presses.
E.g., try running \f[C]midizap\ \-drk\f[] to have the program print the
recognized configuration sections and translations as they are executed.
Now press some of the keys and move the modulation wheel.
You should see something like:
.IP
.nf
\f[C]
$\ midizap\ \-drk
Loading\ configuration:\ /home/user/.midizaprc
translation:\ Default\ for\ emacs\@hostname\ (class\ emacs)
CC1\-1\-:\ XK_Scroll_Down/D\ XK_Scroll_Down/U\
CC1\-1\-:\ XK_Scroll_Down/D\ XK_Scroll_Down/U\
G5\-1[D]:\ XK_Up/D\
G5\-1[U]:\ XK_Up/U\
A5\-1[D]:\ XK_Down/D\
A5\-1[U]:\ XK_Down/U\
\f[]
.fi
.PP
The debugging options will be very helpful when you start developing
your own bindings.
The \f[C]\-d\f[] option can be combined with various option characters
to choose exactly which kinds of debugging output you want; \f[C]r\f[]
(\[lq]regex\[rq]) prints the matched translation section (if any) along
with the window name and class of the focused window; \f[C]s\f[]
(\[lq]strokes\[rq]) prints the parsed contents of the configuration file
in a human\-readable form whenever the file is loaded; \f[C]k\f[]
(\[lq]keys\[rq]) shows the recognized translations as the program
executes them, in the same format as \f[C]s\f[]; \f[C]m\f[]
(\[lq]MIDI\[rq]) prints \f[I]any\f[] MIDI input, so that you can figure
out which MIDI tokens to use for configuring the translations for your
controller; and \f[C]j\f[] adds some debugging output from the Jack
driver.
You can also just use \f[C]\-d\f[] to enable all debugging output.
(Most of these options are also available as directives in the midizaprc
file, these are listed in the comments at the beginning of
example.midizaprc.)
.PP
Most of the other translations in the distributed midizaprc file assume
a Mackie\-like device with standard playback controls and a jog wheel.
There are also a few more generic examples, like the one above, which
will work with almost any kind of MIDI keyboard.
The examples are mostly for illustrative and testing purposes, though,
to help you get started.
You will want to edit them and add translations for your own controllers
and favorite applications.
.SH MIDI Output
.PP
As already mentioned, the midizap program can also be made to function
as a MIDI mapper which translates MIDI input to MIDI output.
MIDI output is enabled by running the program as \f[C]midizap\ \-o\f[].
This equips the Jack client with an additional MIDI output port named
\f[C]midi_out\f[] (visible on the left side of QjackCtl's Connection
window).
.PP
The example.midizaprc file comes with a sample configuration in the
special \f[C][MIDI]\f[] default section for illustration purposes.
This section is only active if the program is run with the \f[C]\-o\f[]
option.
It allows MIDI output to be sent to any connected applications, no
matter which window currently has the keyboard focus.
This is probably the most common way to use this feature, but of course
it is also possible to have application\-specific MIDI translations, in
the same way as with X11 key bindings.
In fact, you can freely mix mouse actions, key presses and MIDI messages
in all translations.
.PP
You can try it and test that it works by running \f[C]midizap\ \-o\f[]
along with a MIDI synthesizer such as
FluidSynth (http://www.fluidsynth.org/) or its graphical front\-end
Qsynth (https://qsynth.sourceforge.io/).
Use QjackCtl to connect FluidSynth's MIDI input to midizap's output
port.
In the sample configuration, the notes \f[C]C4\f[] thru \f[C]F4\f[] in
the small octave have been set up so that you can use them to operate a
little drumkit, and a binding for the volume controller (\f[C]CC7\f[])
has been added as well.
The relevant portion from the configuration entry looks as follows:
.IP
.nf
\f[C]
[MIDI]
\ C4\ \ \ \ C3\-10
\ D4\ \ \ \ C#3\-10
\ E4\ \ \ \ D3\-10
\ F4\ \ \ \ D#3\-10
\ CC7=\ \ CC7\-10
\f[]
.fi
.PP
Note the \f[C]\-10\f[] suffix on the output messages in the above
example, which indicates that output goes to MIDI channel 10.
In midizaprc syntax, MIDI channels are 1\-based, so they are numbered
1..16, and 10 denotes the GM (General MIDI) drum channel.
E.g., the input note \f[C]C4\f[] is mapped to \f[C]C3\-10\f[], the note
C in the third MIDI octave, which on channel 10 will produce the sound
of a bass drum, at least on GM compatible synthesizers like Fluidsynth.
The binding for the volume controller (\f[C]CC7\f[]) at the end of the
entry sends volume changes to the same drum channel (\f[C]CC7\-10\f[]),
so that you can use the volume control on your keyboard to change the
volume on the drum channel.
.PP
Besides MIDI notes and control change (\f[C]CC\f[]) messages, the
midizap program also recognizes key and channel pressure (\f[C]KP\f[],
\f[C]CP\f[]), program change (\f[C]PC\f[]), and pitch bend (\f[C]PB\f[])
messages, which should cover most common use cases.
These are discussed in more detail in the \f[I]Translation Syntax\f[]
section below.
In addition, while midizap cannot translate system messages such as
system exclusive, it can pass them through if you specify the
\f[C]\-s\f[] option on the command line, or the special
\f[C]SYSTEM_PASSTHROUGH\f[] directive in the configuration file.
.SH Jack\-Related Options
.PP
There are some additional directives (and corresponding command line
options) to set midizap's Jack client name and the number of input and
output ports it uses.
(If both the command line options and directives in the midizaprc file
are used, the former take priority, so that it's always possible to
override the configuration settings from the command line.)
.PP
Firstly, there's the \f[C]\-j\f[] option and the \f[C]JACK_NAME\f[]
directive which change the Jack client name from the default
(\f[C]midizap\f[]) to whatever you want it to be.
To use this option, simply invoke midizap as
\f[C]midizap\ \-j\ client\-name\f[], or put the following directive into
your midizaprc file:
.IP
.nf
\f[C]
JACK_NAME\ "client\-name"
\f[]
.fi
.PP
This option is useful, in particular, if you're running multiple
instances of midizap with different configurations for different
controllers and/or target applications, and you want to have the
corresponding Jack clients named appropriately, so that they can be
identified more easily when wiring them up.
If you're using a persistent MIDI patchbay, such as the one available in
QjackCtl, you can then have the right connections automatically set up
for you whenever you launch midizap with that specific configuration.
.PP
Secondly, we've already seen the \f[C]\-o\f[] option which is used to
equip the Jack client with an additional output port.
This can also be achieved with the \f[C]JACK_PORTS\f[] directive in the
midizaprc file, as follows:
.IP
.nf
\f[C]
JACK_PORTS\ 1
\f[]
.fi
.PP
The given number of output ports must be 0, 1 or 2.
Zero means that MIDI output is disabled (which is the default anyway, so
you don't have to specify it explicitly).
You may want to use \f[C]JACK_PORTS\ 1\f[] if the configuration is
primarily aimed at doing MIDI translations, so you'd like to have MIDI
output enabled by default.
\f[C]JACK_PORTS\ 2\f[] or the \f[C]\-o2\f[] option indicates that
\f[I]two\f[] pairs of input and output ports are to be created (the
second port is typically used to deal with controller feedback from the
application, see the \f[I]MIDI Feedback\f[] section for details).
.PP
\f[B]NOTE:\f[] If you notice bad latency or jitter in MIDI output, you
should try running midizap with real\-time priorities.
Jack itself usually does that anyway, but midizap's main thread won't
unless you run it with the \f[C]\-P\f[] option (\f[C]midizap\ \-P\f[],
or \f[C]midizap\ \-P80\f[] if you also want to specify the priority; the
default is 90).
Using this option, midizap should be able to get down to MIDI latencies
in the 1 msec ballpark which should be good enough for most purposes
(YMMV, though).
.PP
Last but not least, midizap also supports \f[I]Jack session
management\f[], which makes it possible to record the options the
program was invoked with, along with all the MIDI connections.
This feature can be used with any Jack session management software.
QjackCtl has its own built\-in Jack session manager which is available
in its Session dialog.
To use this, launch midizap and any other Jack applications you want to
have in the session, use QjackCtl to set up all the connections as
needed, and then hit the \[lq]Save\[rq] button in the Session dialog to
have the session recorded.
(The \[lq]Save and Quit\[rq] option does the same, but also asks midizap
and other Jack session clients to quit afterwards.) Now, at any later
time you can rerun the recorded session with the \[lq]Load\[rq] button
in the same dialog.
Also, your most recent sessions are available in the \[lq]Recent\[rq]
menu from where they can be launched quickly.
.SH Translation Syntax
.PP
The midizap configuration file consists of sections defining translation
classes.
Each section generally looks like this, specifying the name of a
translation class, optionally a regular expression to be matched against
the window class or title, and a list of translations:
.IP
.nf
\f[C]
[name]\ regex
<A..G><#b><0..12>\ output\ \ #\ note
KP:<note>\ output\ \ \ \ \ \ \ \ \ \ #\ key\ pressure\ (aftertouch)
PC<0..127>\ output\ \ \ \ \ \ \ \ \ #\ program\ change
CC<0..127>\ output\ \ \ \ \ \ \ \ \ #\ control\ change
CP\ output\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ channel\ pressure
PB\ output\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ pitch\ bend
\f[]
.fi
.PP
The \f[C]#\f[] character at the beginning of a line and after whitespace
is special; it indicates that the rest of the line is a comment, which
is skipped by the parser.
Empty lines and lines containing nothing but whitespace are also
ignored.
.PP
Lines beginning with a \f[C][\f[]\f[I]name\f[]\f[C]]\f[] header are also
special.
Each such line introduces a translation class \f[I]name\f[], which may
be followed by a basic regular expression \f[I]regex\f[] (see the
regex(7) manual page) to be matched against window class and title.
Note that \f[I]everything\f[] following the
\f[C][\f[]\f[I]name\f[]\f[C]]\f[] header on the same line is taken
verbatim; the \f[I]regex\f[] part is the entire rest of the line,
ignoring leading and trailing whitespace, but including embedded
whitespace and \f[C]#\f[] characters (so you can't place a comment on
such lines).
.PP
To find a set of eligible translations, midizap matches class and title
of the window with the keyboard focus against each section, in the order
in which they are listed in the configuration file.
For each section, midizap first tries to match the window class (the
\f[C]WM_CLASS\f[] property), then the window title (the \f[C]WM_NAME\f[]
property).
The first section which matches determines the translations to be used
for that window.
An empty \f[I]regex\f[] for the last class will always match, allowing
default translations.
If a translation cannot be found in the matched section, it will be
loaded from the default section if possible.
In addition, there are two special default sections labeled
\f[C][MIDI]\f[] and \f[C][MIDI2]\f[] which are used specifically for
MIDI translations, please see the \f[I]MIDI Output\f[] and \f[I]MIDI
Feedback\f[] sections for details.
If these sections are present, they should precede the main default
section.
All other sections, including the main default section, can be named any
way you like; the given \f[I]name\f[] is only used for debugging output
and diagnostics, and needn't be unique.
.PP
This means that when you start writing a section for a new application,
the first thing you'll have to do is determine its window class and
title, so that you can figure out a regular expression to use in the
corresponding section header.
The easiest way to do this is to run midizap with the \f[C]\-dr\f[]
option.
Make sure that your controller is hooked up to midizap, click on the
window and wiggle any control on your device.
You'll get a message like the following, telling you both the title and
the class name of the window (as well as the name of the translation
class if the window is already recognized):
.IP
.nf
\f[C]
translation:\ Default\ for\ mysession\ \-\ Ardour\ (class\ ardour_ardour)
\f[]
.fi
.PP
Here, the class name is \[lq]ardour_ardour\[rq] and the window title
\[lq]mysession \- Ardour\[rq].
Either can be used for the regular expression, but the class name
usually provides the more specific clues for identifying an application.
So we might write:
.IP
.nf
\f[C]
[Ardour]\ ^ardour_ardour$
\f[]
.fi
.PP
The header is followed by a list of translations which define what
output should be produced for the given MIDI input.
Each translation must be on a line by itself.
The left\-hand side (first token) of the translation denotes the MIDI
message to be translated.
The corresponding right\-hand side (the rest of the line) is a sequence
of zero or more tokens, separated by whitespace, indicating MIDI and X11
keyboard and mouse events to be output.
The output sequence may be empty, or just the special token \f[C]NOP\f[]
(which doesn't produce any output), to indicate that the translation
outputs nothing at all; this suppresses the default translation for this
input.
Translation classes may be empty as well (i.e., not provide any
translations), in which case \f[I]only\f[] the default translations are
active, even if a later non\-default section matches the same window.
.PP
\f[B]NOTE:\f[] Translations may be listed in any order, but they
\f[I]must be determined uniquely\f[], i.e., each input message may be
bound to at most one output sequence in each translation class.
Otherwise, the parser will print an error message, and the extra
translations will be ignored.
This restriction makes it easier to detect inconsistencies, and it also
ensures that midizap's operation is completely \f[I]deterministic\f[].
That is, for each input sequence on a given window the program will
always generate exactly the same output sequence.
.PP
Example:
.IP
.nf
\f[C]
[Terminal]\ ^.*\-terminal.*\\|konsole\\|xterm$\
\ F5\ \ \ \ XK_Up
\ F#5\ \ \ "pwd"
\ G5\ \ \ \ XK_Down
\ G#5\ \ \ "ls"
\ A5\ \ \ \ XK_Return
\f[]
.fi
.PP
This binds a few keys in the middle octave to the Up, Down and Return
keys as well as some frequently used shell commands, in a section named
\f[C]Terminal\f[] which matches some common types of terminal windows by
their class names.
The bindings in this translation class will let you operate the shell
from your MIDI keyboard when the keyboard focus is on a terminal window.
.SS MIDI Message Notation
.PP
There's no real standard for symbolic designations of MIDI messages, but
we hope that most users will find midizap's notation easy to understand
and remember.
Notes are specified using a format which musicians will find familiar: a
note name \f[C]A\f[], \f[C]B\f[], \&..., \f[C]G\f[] is followed by an
(optional) accidental (\f[C]#\f[] or \f[C]b\f[]), and a (mandatory) MIDI
octave number.
Note that all MIDI octaves start at the note C, so \f[C]B0\f[] comes
before \f[C]C1\f[].
By default, \f[C]C5\f[] denotes middle C (you can change this if you
want, see \f[I]Octave Numbering\f[] below).
Enharmonic spellings are equivalent, so, e.g., \f[C]D#5\f[] and
\f[C]Eb5\f[] denote exactly the same MIDI note.
.PP
The other messages are denoted using short mnemonics:
\f[C]KP:\f[]\f[I]note\f[] (aftertouch a.k.a.\ key pressure for the given
note); \f[C]CC\f[]\f[I]n\f[] (control change for the given controller
number); \f[C]PC\f[]\f[I]n\f[] (program change for the given program
number); \f[C]CP\f[] (channel pressure); and \f[C]PB\f[] (pitch bend).
We will go into the other syntactic bits and pieces of MIDI message
designations later, but it's good to have the following grammar in EBNF
notation handy for reference.
(To keep things simple, the grammar is somewhat abridged, but it covers
all the frequently used notation.
There is some additional syntax for special forms of translations which
will be introduced later.)
.IP
.nf
\f[C]
token\ ::=\ msg\ [\ "["\ number\ "]"\ ]\ [\ "\-"\ number\ ]\ [\ flag\ ]
msg\ \ \ ::=\ (\ note\ |\ other\ )\ [\ number\ ]
note\ \ ::=\ (\ "A"\ |\ ...\ |\ "G"\ )\ [\ "#"\ |\ "b"\ ]
other\ ::=\ "CH"\ |\ "PB"\ |\ "PC"\ |\ "CC"\ |\ "CP"\ |\ "KP:"\ note
flag\ \ ::=\ "\-"\ |\ "+"\ |\ "="\ |\ "<"\ |\ ">"\ |\ "~"
\f[]
.fi
.PP
Case is ignored here, so \f[C]CC\f[], \f[C]cc\f[] or even \f[C]Cc\f[]
are considered to be exactly the same token by the parser, although by
convention we usually write them in uppercase.
Numbers are always integers in decimal.
The meaning of the \f[C]msg\f[] number depends on the context (octave
number for notes and key pressure, controller or program number in the
range 0..127 for other messages, MIDI channel number in the range 1..16
for the special \f[C]CH\f[] token).
This can optionally be followed by a number in brackets, denoting a
nonzero step size.
Also optionally, a suffix with a third number (after the dash) denotes
the MIDI channel in the range 1..16; otherwise the default MIDI channel
is used (which is always 1 on the left\-hand side, but can be set on the
right\-hand side with the \f[C]CH\f[] token).
The optional \[lq]increment\[rq] flag at the end of a token indicates a
\[lq]data\[rq] translation which responds to incremental (up/down) value
changes rather than key presses, cf.\ \f[I]Key and Data Translations\f[]
below.
.SS Octave Numbering
.PP
A note on the octave numbers in MIDI note designations is in order here.
There are various different standards for numbering octaves, and
different programs use different standards, which can be rather
confusing.
E.g., there's the ASA (Acoustical Society of America) standard where
middle C is C4, also known as \[lq]scientific\[rq] or \[lq]American
standard\[rq] pitch notation.
At least two other standards exist specifically for MIDI octave
numbering, one in which middle C is C3 (so the lowest MIDI octave starts
at C\-2), and zero\-based octave numbers, which start at C0 and have
middle C at C5.
There's not really a single \[lq]best\[rq] standard here, but the latter
seems intuitive to mathematically inclined and computer\-savvy people,
and is also what is used by default in the midizaprc file.
.PP
However, you may want to change this, e.g., if you're working with
documentation or MIDI monitoring software which uses a different
numbering scheme.
To do this, just specify the desired offset for the lowest MIDI octave
with the special \f[C]MIDI_OCTAVE\f[] directive in the configuration
file.
For instance:
.IP
.nf
\f[C]
MIDI_OCTAVE\ \-1\ #\ ASA\ pitches\ (middle\ C\ is\ C4)
\f[]
.fi
.PP
Note that this transposes \f[I]all\f[] existing notes in translations
following the directive, so if you add this option to an existing
configuration, you probably have to edit the note messages in it
accordingly.
.SS Key and Data Translations
.PP
Translations come in two flavors or \[lq]modes\[rq], \f[I]key
translations\f[] and \f[I]data translations\f[], which differ in the way
the extra data payload of the input message, called the \f[I]parameter
value\f[] (or just \f[I]value\f[] for short), is processed.
The parameter value depends on the type of MIDI message.
Program changes (\f[C]PC\f[]) have no value at all.
For notes, as well as key and channel pressure messages (\f[C]CP\f[],
\f[C]KP\f[]), it is a velocity value; for control changes (\f[C]CC\f[]),
a controller value; and for pitch bend messages (\f[C]PB\f[]), a pitch
bend value.
The latter is a 14 bit value composed of the two data bytes in the
message, which is considered as a signed quantity in the range
\-8192..8191, where 0 denotes the center value.
In all other cases, the parameter value consists of a single data byte,
which denotes an unsigned 7 bit quantity in the range 0..127.
.PP
Note that since translations must be determined uniquely in each
translation class, you can't have both key \f[I]and\f[] data
translations for the same input in the same section; it's either one or
the other.
.PP
\f[I]Key mode\f[] is the default mode and is available for all message
types.
In this mode, MIDI messages are considered as keys which can be
\[lq]pressed\[rq] (\[lq]on\[rq]) or \[lq]released\[rq] (\[lq]off\[rq]).
Any nonzero data value means \[lq]pressed\[rq], zero \[lq]released\[rq].
Two special cases need to be considered here:
.IP \[bu] 2
For pitch bends, any positive \f[I]or\f[] negative value means
\[lq]pressed\[rq], while 0 (the center value) means \[lq]released\[rq].
.IP \[bu] 2
Since program changes have no parameter value associated with them, they
don't really have an \[lq]on\[rq] or \[lq]off\[rq] status.
But they are treated in the same key\-like fashion anyway, assuming that
they are \[lq]pressed\[rq] and then \[lq]released\[rq] immediately
afterwards.
.PP
\f[I]Data mode\f[] is available for all messages with a parameter value,
i.e., anything but \f[C]PC\f[].
In this mode, the actual value of the message is processed rather than
just the on/off state.
Data mode is indicated with a special suffix on the message token which
denotes a step size and/or the direction of the value change which the
rule should apply to: increment (\f[C]+\f[]), decrement (\f[C]\-\f[]),
or both (\f[C]=\f[]).
The two parts are both optional, but at least one of them must be
present (otherwise the rule is interpreted as a key translation).
.PP
In the following, we concentrate on \f[I]incremental\f[] data mode
messages, i.e., the kind which has an increment suffix.
In this case, the optional step size in brackets indicates the amount of
change required to trigger the translation, so its effect is to
downscale the amount of change in the input value.
The variant without an increment suffix is more complicated and mostly
intended for more specialized uses, so we'll have a look at it later in
the \f[I]Mod Translations\f[] section.
.PP
Data mode usually tracks changes in the \f[I]absolute\f[] value of a
control.
However, for \f[C]CC\f[] messages there's also an alternative mode for
so\-called \f[I]incremental\f[] controllers, or \f[I]encoders\f[] for
short, which can found on some DAW controllers.
These usually take the form of jog wheels or rotary encoders which can
be turned endlessly in either direction.
Encoders emit a special \f[I]sign bit\f[] value indicating a
\f[I]relative\f[] change, where a value < 64 usually denotes an
increment (representing clockwise rotation), and a value > 64 a
decrement (counter\-clockwise rotation).
The actual amount of change is in the lower 6 bits of the value.
In the message syntax, these kinds of controls are indicated by using
the suffixes \f[C]<\f[], \f[C]>\f[] and \f[C]~\f[] in lieu of
\f[C]\-\f[], \f[C]+\f[] and \f[C]=\f[], respectively.
These flags are only permitted with \f[C]CC\f[] messages.
.SS Keyboard and Mouse Events
.PP
Keyboard and mouse output consists of X key codes with optional up/down
indicators, or strings of printable characters enclosed in double
quotes.
The syntax of these items, as well as the special \f[C]RELEASE\f[] and
\f[C]SHIFT\f[] tokens which will be discussed later, are described by
the following grammar:
.IP
.nf
\f[C]
token\ \ \ ::=\ "RELEASE"\ |\ "SHIFT"\ [\ number\ ]\ |
\ \ \ \ \ \ \ \ \ \ \ \ keycode\ [\ "/"\ keyflag\ ]\ |\ string
keycode\ ::=\ "XK_Button_1"\ |\ "XK_Button_2"\ |\ "XK_Button_3"\ |
\ \ \ \ \ \ \ \ \ \ \ \ "XK_Scroll_Up"\ |\ "XK_Scroll_Down"\ |
\ \ \ \ \ \ \ \ \ \ \ \ "XK_..."\ (X\ keysyms,\ see\ /usr/include/X11/keysymdef.h)
keyflag\ ::=\ "U"\ |\ "D"\ |\ "H"
string\ \ ::=\ \[aq]"\[aq]\ {\ character\ }\ \[aq]"\[aq]
\f[]
.fi
.PP
Here, case \f[I]is\f[] significant (except in character strings, see the
remarks below), so the special \f[C]RELEASE\f[] and \f[C]SHIFT\f[]
tokens must be in all caps, and the \f[C]XK\f[] symbols need to be
written in mixed case exactly as they appear in the
/usr/include/X11/keysymdef.h file.
Besides the key codes from the keysymdef.h file, there are also some
special additional key codes to denote mouse button and scroll wheel
events (\f[C]XK_Button_1\f[], \f[C]XK_Scroll_Up\f[], etc.).
.PP
Any keycode can be followed by an optional \f[C]/D\f[], \f[C]/U\f[], or
\f[C]/H\f[] flag, indicating that the key is just going down (without
being released), going up, or going down and being held until the
\[lq]off\[rq] event is received.
So, in general, modifier key codes will be followed by \f[C]/D\f[], and
precede the keycodes they are intended to modify.
If a sequence requires different sets of modifiers for different
keycodes, \f[C]/U\f[] can be used to release a modifier that was
previously pressed with \f[C]/D\f[].
Sequences may also have separate press and release sequences, separated
by the special word \f[C]RELEASE\f[].
Examples:
.IP
.nf
\f[C]
C5\ "qwer"
D5\ XK_Right
E5\ XK_Alt_L/D\ XK_Right
F5\ "V"\ XK_Left\ XK_Page_Up\ "v"
G5\ XK_Alt_L/D\ "v"\ XK_Alt_L/U\ "x"\ RELEASE\ "q"
\f[]
.fi
.PP
Translations are handled differently depending on the input mode
(cf.\ \f[I]Key and Data Translations\f[] above).
In \f[I]key mode\f[], there are separate press and release sequences.
The former is invoked when the input key goes \[lq]down\[rq] (i.e., when
the \[lq]on\[rq] status is received), the latter when the input key goes
\[lq]up\[rq] again (\[lq]off\[rq] status).
More precisely, at the end of the press sequence, all down keys marked
by \f[C]/D\f[] will be released, and the last key not marked by
\f[C]/D\f[], \f[C]/U\f[], or \f[C]/H\f[] will remain pressed.
The release sequence will begin by releasing the last held key.
If keys are to be pressed as part of the release sequence, then any keys
marked with \f[C]/D\f[] will be repressed before continuing the
sequence.
Keycodes marked with \f[C]/H\f[] remain held between the press and
release sequences.
For instance, let's take a look at one of the more conspicuous
translations in the example above:
.IP
.nf
\f[C]
G5\ XK_Alt_L/D\ "v"\ XK_Alt_L/U\ "x"\ RELEASE\ "q"
\f[]
.fi
.PP
This translation has the following meaning: When the \f[C]G5\f[] key is
pressed on the MIDI keyboard, the key sequence \f[C]Alt+v\ x\f[] is
initiated, keeping the \f[C]x\f[] key pressed (so it may start
auto\-repeating after a while).
The program then sits there waiting (possibly executing other
translations) until you release the \f[C]G5\f[] key again, at which
point the \f[C]x\f[] key is released and the \f[C]q\f[] key is pressed
(and released).
.PP
One pitfall here is that character strings in double quotes are just a
shorthand for the corresponding X key codes, ignoring case.
Thus, e.g., \f[C]"abc"\f[] actually denotes the keysym sequence
\f[C]XK_a\ XK_b\ XK_c\f[], as does \f[C]"ABC"\f[].
So in either case the \f[I]lowercase\f[] string \f[C]abc\f[] will be
output.
To output uppercase letters, it is always necessary to add one of the
shift modifiers to the output sequence.
E.g., \f[C]XK_Shift_L/D\ "abc"\f[] will output \f[C]ABC\f[] in
uppercase.
.PP
In \f[I]data mode\f[] only a single sequence is output whenever the
message value changes.
So there's no separate \[lq]release\[rq] sequence, and at the end of the
sequence, \f[I]all\f[] down keys will be released.
Instead, data mode distinguishes between \f[I]increments\f[] and
\f[I]decrements\f[] of the input value and outputs the corresponding
sequence for each unit change.
For instance, the following translations move the cursor left or right
whenever the volume controller (\f[C]CC7\f[]) decreases and increases,
respectively.
Also, the number of times one of these keys is output corresponds to the
actual change in the value.
Thus, if in the example \f[C]CC7\f[] increases by 4, say, the program
will press (and release) \f[C]XK_Right\f[] four times in close
succession, moving the cursor in the focused window four positions to
the right.
.IP
.nf
\f[C]
CC7\-\ XK_Left
CC7+\ XK_Right
\f[]
.fi
.PP
Incremental \f[C]CC\f[] messages are treated in an analogous fashion,
but in this case the increment or decrement is determined directly by
the input message.
One example for this type of controller is the big jog wheel
(\f[C]CC60\f[]) on some Mackie devices, which can be processed as
follows (using \f[C]<\f[] and \f[C]>\f[] in lieu of \f[C]\-\f[] and
\f[C]+\f[] as the increment flag of the \f[C]CC\f[] message):
.IP
.nf
\f[C]
CC60<\ XK_Left
CC60>\ XK_Right
\f[]
.fi
.PP
The corresponding \[lq]bidirectional\[rq] translations, which are
indicated with the \f[C]=\f[] and \f[C]~\f[] flags, are mostly used with
MIDI output; the same goes for the special \f[C]SHIFT\f[] token.
Thus we'll discuss these in later sections, see \f[I]MIDI Events\f[] and
\f[I]Shift State\f[] below.
.PP
In data mode, input messages can also have a \f[I]step size\f[]
associated with them, which has the effect of downscaling changes in the
parameter value.
The default step size is 1 (no scaling).
To change it, the desired step size is written in brackets immediately
after the message token and before the increment flag.
A step size \f[I]k\f[] indicates that the translation is executed
whenever the input value has changed by \f[I]k\f[] units.
For instance, to slow down the cursor movement in the example above by a
factor of 4:
.IP
.nf
\f[C]
CC7[4]\-\ XK_Left
CC7[4]+\ XK_Right
\f[]
.fi
.PP
The same goes for incremental \f[C]CC\f[] messages:
.IP
.nf
\f[C]
CC60[4]<\ XK_Left
CC60[4]>\ XK_Right
\f[]
.fi
.PP
Note that since there's no persistent absolute controller state in this
case, this simply scales down the actual increment value in the message
itself.
.SS MIDI Events
.PP
Most of the notation for MIDI messages on the left\-hand side of a
translation rule also carry over to the output side.
The only real difference is that the increment flags \f[C]+\-=<>\f[]
aren't permitted here, as they are only used to determine the input mode
(key or data) of the entire translation.
The \f[C]~\f[] flag \f[I]is\f[] allowed, however, to indicate output in
bit\-sign encoder format in data translations, see below.
Step sizes are permitted as well on the output side, in \f[I]both\f[]
key and data translations.
Their meaning depends on the kind of translation, however.
In key translations, they denote the (nonzero) value to be used for the
\[lq]on\[rq] state in the press sequence; in data translations, they
indicate the amount of change for each unit input change (which has the
effect of \f[I]upscaling\f[] the value change).
.PP
The output sequence can involve as many MIDI messages as you want, and
these can be combined freely with keyboard and mouse events in any
order.
However, as already discussed in Section \f[I]MIDI Output\f[] above, you
also need to invoke the midizap program with the \f[C]\-o\f[] option to
make MIDI output work.
Otherwise, MIDI messages in the output translations will just be
silently ignored.
.PP
There is one special MIDI token \f[C]CH\f[] which can only be used on
the output side.
It is always followed by a MIDI channel number in the range 1..16.
This token doesn't actually generate any MIDI message, but merely sets
the default MIDI channel for subsequent MIDI messages in the same output
sequence, which is convenient if multiple messages are output to the
same MIDI channel.
For instance, the sequence \f[C]C5\-2\ E5\-2\ G5\-2\f[], which outputs a
C major chord on MIDI channel 2, can also be abbreviated as
\f[C]CH2\ C5\ E5\ G5\f[].
.PP
For key mode inputs, the corresponding \[lq]on\[rq] or \[lq]off\[rq]
event is generated for all MIDI messages in the output sequence, where
the \[lq]on\[rq] value defaults to the maximum value (127 for controller
values, 8191 for pitch bends).
Thus, e.g., the following rule outputs a \f[C]CC64\f[] (hold pedal)
message with controller value 127 each time \f[C]C3\f[] is pressed (and
another \f[C]CC64\f[] message with value 0 when the note is released
again):
.IP
.nf
\f[C]
C3\ CC64\ #\ hold\ pedal\ on/off
\f[]
.fi
.PP
The value for the \[lq]on\[rq] state can also be denoted explicitly with
a step size:
.IP
.nf
\f[C]
C3\ CC64[64]\ #\ hold\ pedal\ with\ an\ "on"\ value\ of\ 64
\f[]
.fi
.PP
For pitch bends, the step size can also be negative.
For instance, the following rules assign two keys to bend down and up by
the maximum amount possible:
.IP
.nf
\f[C]
C2\ PB[\-8192]\ #\ bend\ down
D2\ PB[8191]\ \ #\ bend\ up
\f[]
.fi
.PP
Rules similar to the ones above may be useful if your MIDI keyboard
doesn't have a hold pedal or pitch bend wheel, as they let you set aside
some keys to emulate those functions.
.PP
Let's now have a look at data mode.
There are two additional flags \f[C]=\f[] and \f[C]~\f[] for data
translations which are most useful with MIDI output, which is why we
deferred their discussion until now.
In pure MIDI translations not involving any key or mouse output, the
increment and decrement sequences are usually identical, in which case
the \f[C]=\f[] suffix can be used to indicate that the output is to be
used for \f[I]both\f[] increments and decrements.
For instance, to map the modulation wheel (\f[C]CC1\f[]) to the volume
controller (\f[C]CC7\f[]):
.IP
.nf
\f[C]
CC1=\ CC7
\f[]
.fi
.PP
Which is more convenient to write, but is really just a shorthand for
the two separate translations:
.IP
.nf
\f[C]
CC1+\ CC7
CC1\-\ CC7
\f[]
.fi
.PP
The same goes for \f[C]<\f[], \f[C]>\f[] and \f[C]~\f[] with sign\-bit
encoders:
.IP
.nf
\f[C]
CC60~\ CC7
\f[]
.fi
.PP
Which is equivalent to:
.IP
.nf
\f[C]
CC60<\ CC7
CC60>\ CC7
\f[]
.fi
.PP
The \f[C]~\f[] flag can be used to denote encoders in output messages,
too.
E.g., to translate a standard (absolute) MIDI controller to an
incremental encoder value, you might use a rule like:
.IP
.nf
\f[C]
CC48=\ CC16~
\f[]
.fi
.PP
Step sizes work on the right\-hand side of data translations as well.
You might use these to scale up value changes, e.g., when translating
from control changes to pitch bends:
.IP
.nf
\f[C]
CC1=\ PB[128]
\f[]
.fi
.PP
The step size can also be negative, which allows you to reverse the
direction of a controller if needed.
E.g., the following will output values going down from 127 to 0 as input
values go up from 0 to 127:
.IP
.nf
\f[C]
CC1=\ CC1[\-1]
\f[]
.fi
.PP
Note that you can also place step sizes on \f[I]both\f[] the left\-hand
and right\-hand side of a rule, in order to approximate a rational
scaling factor:
.IP
.nf
\f[C]
CC1[3]=\ CC1[2]
\f[]
.fi
.PP
The above translation will only be triggered when the input value
changes by 3 units, and the change in the output value will then be
doubled again, so that the net effect is to scale the input value by
2/3.
(Note that for most ratios this will only give a rough approximation;
the method works best if the input and output step sizes are reasonably
small.)
.PP
\f[B]NOTE:\f[] All data translations we've seen so far handle
\f[I]incremental\f[] value changes.
In order to be able to detect these changes and, in the case of MIDI
output, change the output values accordingly, midizap has to keep track
of all the current parameter values of all messages on all MIDI
channels, for both input and output.
This is easy enough, but midizap usually has no way of knowing the
\f[I]actual\f[] state of your controllers and MIDI applications, so when
the program starts up, it simply assumes all these values to be zero.
This means that midizap's \[lq]shadow\[rq] values of controllers, pitch
bends etc.\ may initially well be out of sync with your input devices
and applications, and you may have to wiggle a control in order to
\[lq]calibrate\[rq] it.
(This becomes most apparent when using negative step sizes, as in the
translation \f[C]CC1=\ CC1[\-1]\f[] from above.
In this case, you will first have to move the control all the way up and
then down again to get it working properly.) There are some ways to
alleviate these issues, however.
In particular, midizap can utilize controller feedback from the
application, please check the \f[I]MIDI Feedback\f[] section below for
details.
Also, encoders need no calibration as they represent incremental changes
anyway, and there's an alternative form of data translation, to be
discussed in Section \f[I]Mod Translations\f[], which always works with
absolute values and thus needs no calibration either.
.SS Shift State
.PP
Like the \f[C]CH\f[] token, the special \f[C]SHIFT\f[] token doesn't
generate any output by itself; it merely toggles an internal shift state
which can then be tested by other translations to generate alternative
output sequences.
The \f[C]^\f[] prefix denotes a rule which is active only in shifted
state, while unprefixed rules are active in \f[I]both\f[] shifted and
unshifted state.
Also, a prefixed rule \f[I]always\f[] overrides an unprefixed one (no
matter in which order they appear in the configuration file), so if you
specify both, the former will be used in shifted, the latter in
unshifted state.
That is, unprefixed rules act as defaults which can be overridden by
prefixed ones.
.PP
Many DAW controllers have some designated shift keys which can be used
for this purpose, but the following will actually work with any
key\-style MIDI message.
E.g., to bind the shift key on an AKAI APCmini controller (\f[C]D8\f[]):
.IP
.nf
\f[C]
D8\ SHIFT
\f[]
.fi
.PP
This rule doesn't have a prefix, so it is used to turn shift state both
on and off, giving a \[lq]Caps Lock\[rq]\-style of toggle key.
If you'd rather have an ordinary shift key which turns on shift state
when pressed and immediately turns it off when released again, you can
do that as follows:
.IP
.nf
\f[C]
D8\ SHIFT\ RELEASE\ SHIFT
\f[]
.fi
.PP
Note that in either case \f[C]SHIFT\f[] works as a toggle, which turns
shift status on when it is currently off, and turns it off again when it
is on.
.PP
Having set up the translation for the shift key itself, we can now
assign, depending on the shift state, different functions to buttons and
faders.
Here's a typical example which maps a control change to either
Mackie\-style fader values encoded as pitch bends, or incremental
encoder values:
.IP
.nf
\f[C]
\ CC48=\ PB[128]\ \ #\ default:\ translate\ to\ pitch\ bend
^CC48=\ CC16~\ \ \ \ #\ shifted:\ translate\ to\ encoder
\f[]
.fi
.PP
It's also possible to explicitly denote a rule which is active
\f[I]only\f[] in unshifted state.
Unshifted state is specified with the \f[C]0^\f[] (zero\-caret) prefix,
so you can write:
.IP
.nf
\f[C]
0^CC56=\ PB[128]\-9\ #\ unshifted:\ translate\ to\ pitch\ bend
\f[]
.fi
.PP
The syntax is a bit awkward, but the case arises rarely (usually, you'll
just write an unprefixed rule instead).
.PP
midizap actually supports up to four different shift states, which are
denoted \f[C]SHIFT1\f[] to \f[C]SHIFT4\f[], with the corresponding
prefixes being \f[C]1^\f[] to \f[C]4^\f[].
Unprefixed rules are enabled by default in all of these.
The \f[C]SHIFT\f[] token and \f[C]^\f[] prefix we've seen above are in
fact just shortcuts for \f[C]SHIFT1\f[] and \f[C]1^\f[], respectively.
So our first example above is equivalent to:
.IP
.nf
\f[C]
D8\ SHIFT1\ RELEASE\ SHIFT1
CC48=\ PB[128]
1^CC48=\ CC16~
\f[]
.fi
.PP
We might add another shift key and use it to assign yet another function
to the same input message:
.IP
.nf
\f[C]
F7\ SHIFT2\ RELEASE\ SHIFT2
2^CC48\-\ XK_Left
2^CC48+\ XK_Right
\f[]
.fi
.PP
Another way to look at this is that translations are organized in
\f[I]layers\f[].
Layer 0 contains the unshifted translations, layer 1 to 4 the
translations prefixed with the corresponding shift level.
Unprefixed translations are available in all of these layers, unless
they are overriden by translations specifically assigned to one of the
layers.
To keep things simple, only one layer can be active at any one time; if
you press more than one shift key without releasing them, the last one
wins.
.PP
Also note that the status of internal shift keys is \f[I]only\f[]
available to the midizap program; the host application never gets to see
them.
If your host software does its own handling of shift keys, it's usually
more convenient to simply pass those keys on to the application.
However, \f[C]SHIFT\f[] comes in handy if your controller doesn't have
enough buttons and faders, since it makes it possible to multiply the
amount of controls available on the device.
For instance, you can emulate a Mackie controller with both encoders and
faders on a device which only has a single set of faders, simply by
assigning the shifted faders to the encoders, as shown in the first
example above.
.SH MIDI Feedback
.PP
Some MIDI controllers need a more elaborate setup than what we've seen
so far, because they have motor faders, LEDs, etc., requiring feedback
from the application.
To accommodate these, you can use the \f[C]\-o2\f[] option of midizap,
or the \f[C]JACK_PORTS\ 2\f[] directive in the midizaprc file, to create
a second pair of MIDI input and output ports, named \f[C]midi_in2\f[]
and \f[C]midi_out2\f[].
Use of this option also activates a second MIDI default section in the
midizaprc file, labeled \f[C][MIDI2]\f[], which is used exclusively for
translating MIDI input from the second input port and sending the
resulting MIDI output to the second output port.
Typically, the translations in the \f[C][MIDI2]\f[] section will be the
inverse of those in the \f[C][MIDI]\f[] section, or whatever it takes to
translate the MIDI feedback from the application back to MIDI data which
the controller understands.
.PP
You then wire up midizap's \f[C]midi_in\f[] and \f[C]midi_out\f[] ports
to controller and application as before, but in addition you also
connect the application back to midizap's \f[C]midi_in2\f[] port, and
the \f[C]midi_out2\f[] port to the controller.
This reverse path is what is needed to translate the feedback from the
application and send it back to the controller.
(The \f[C]\-s\f[] option a.k.a.\ \f[C]SYSTEM_PASSTHROUGH\f[] directive
also works on the feedback port, passing through all system messages
from the second input port to the second output port unchanged.)
.PP
The distribution includes a full\-blown example of this kind of setup
for your perusal, please check examples/APCmini.midizaprc in the
sources.
It shows how to emulate a Mackie controller with AKAI's APCmini device,
so that it readily works with DAW software such as Ardour.
.SS Automatic Feedback
.PP
If done right, MIDI feedback will usually eliminate the problem of
controls being out of sync with the application.
midizap has some built\-in logic to help with this.
Specifically, the current state of controls communicated by the host
application via the \f[C]midi_in2\f[] port will be recorded, so that
subsequent MIDI output for incremental data translations will use the
proper values for determining the required relative changes.
(The same goes for the reverse path, recording the values from
\f[C]midi_in\f[] so that data translations feeding back to the
controller will work correctly.)
.PP
We refer to this as \f[I]automatic feedback\f[].
Some devices may provide you with sign\-bit encoders which don't need
any kind of feedback for themselves.
In this case the automatic feedback will be all that's needed to keep
controller and application in sync, and you don't even have to write any
translation rules for the feedback; just enabling the second port and
hooking it up to the application will be enough.
Other controllers may provide faders with motors or LEDs on them,
however, in which case additional translation rules for the feedback
will be needed.
.PP
\f[B]NOTE:\f[] Automatic feedback is enabled automatically whenever you
create a second pair of ports using \f[C]\-o2\f[].
If you're using the second pair for more esoteric purposes, you may want
to disable this feature, which can be done with the \f[C]\-n\f[] option
or the \f[C]NO_FEEDBACK\f[] directive in the configuration file.
Use this option \f[I]only\f[] if feedback isn't needed with your
application.
.SS Direct Feedback
.PP
Translations can also provide feedback themselves.
To these ends, any MIDI message on the right\-hand side of a translation
can be prefixed with the \f[C]!\f[] character.
This outputs the message as usual, but flips the output ports, so that
the message will go to port 2 in a forward translation destined for port
1, and vice versa to port 1 in a feedback translation (in the
\f[C][MIDI2]\f[] section) destined for port 2.
.PP
We call this \f[I]direct feedback\f[].
For instance, suppose that on our MIDI controller we have a fader taking
the form of a touchstrip \f[C]CC1\f[] that has some LEDs for conveying
its current value.
We might like to translate that message to a \f[C]CC7\f[] message for
the application, while also providing feedback to the controller.
The following translation will do this:
.IP
.nf
\f[C]
CC1=\ CC7\ !CC1
\f[]
.fi
.PP
Now, whenever you touch that fader, the corresponding value will be sent
as \f[C]CC7\f[] to the application, while the same value is sent back as
\f[C]CC1\f[] to the controller (which presumably will light the
appropriate LEDs on the fader).
.PP
Another example are internal shift buttons (cf.\ \f[I]Shift State\f[]
above).
The host application never gets to see these, so chances are that we'll
have to provide suitable feedback ourselves in order to light the
buttons.
E.g., the following should usually turn on the LED of the button when
pressed, and turn it off again when released:
.IP
.nf
\f[C]
D8\ SHIFT\ !D8\ RELEASE\ SHIFT\ !D8
\f[]
.fi
.PP
This will work for simple cases involving only a single shift key whose
state always matches the button state.
However, for more complicated setups possibly involving multiple shift
keys, it's better to use the \f[C]^\f[] prefix instead:
.IP
.nf
\f[C]
D8\ SHIFT\ ^D8\ RELEASE\ SHIFT\ ^D8
\f[]
.fi
.PP
This variation of direct feedback is tailored to shift keys, and it
\f[I]only\f[] works with key translations.
It also operates under the following two assumptions:
.IP \[bu] 2
Feedback messages come \f[I]after\f[] the corresponding \f[C]SHIFT\f[]
token in the translation, so that midizap knows which shift state the
message belongs to.
.IP \[bu] 2
The shift keys can be turned off by sending them a zero parameter value.
.PP
Under these conditions it is possible to employ the machinery built into
midizap which makes handling direct feedback for shift keys much easier.
In particular, midizap ensures that the feedback message reflects the
\f[I]shift\f[] (rather than the button) state, which is needed to make
\[lq]Caps Lock\[rq]\-style toggle keys like the following work
correctly:
.IP
.nf
\f[C]
D8\ SHIFT\ ^D8
\f[]
.fi
.PP
This turns the key on when pushed, and toggles it off again when pushed
a second time.
Note that you can't get this behavior with the basic direct feedback
facility, since there's no way to keep track of the required status
information across different translations.
Moreover, midizap also maintains the current status of all shift keys
and automatically turns them off when switching from one shift status to
another, so that the proper key will be lit even if you use multiple
shift keys in your configuration.
.PP
midizap still has a few more tricks up its sleeves which are useful when
dealing with controller feedback, but they require the use of a special
kind of data translation, the mod translations.
These are a separate topic in their own right, so we'll introduce them
in the next section.
.SH Mod Translations
.PP
Most of the time, MIDI feedback uses just the standard kinds of MIDI
messages readily supported by midizap, such as note messages which make
buttons light up in different colors, or control change messages which
set the positions of motor faders.
However, there are some encodings of feedback messages which combine
different bits of information in a single message, making them difficult
or even impossible to translate using the simple kinds of rules we've
seen so far.
midizap offers a special variation of data mode to help decoding such
messages.
We call them \f[I]mod translations\f[] (a.k.a.\ \[lq]modulus\[rq] or
\[lq]modifier\[rq] translations), because they involve operations with
integer moduli which enable you to both calculate output from input
values in a direct fashion, \f[I]and\f[] modify the output messages
themselves along the way.
.PP
One important task, which we'll use as a running example below, is the
decoding of meter (RMS level) data in the Mackie protocol.
There, each meter value is represented as a channel pressure message
whose value consists of a mixer channel index 0..7 in the \[lq]high
nibble\[rq] (bits 4..6) and the corresponding meter value in the
\[lq]low nibble\[rq] (bits 0..3).
We will show how to map these values to notes indicating buttons on the
AKAI APCmini (please check examples/APCmini.midizaprc in the sources for
details about this device).
Mod translations aren't limited to this specific use case, however;
similar rules will apply to other kinds of \[lq]scrambled\[rq] MIDI
data.
.PP
In its simplest form, the translation looks as follows:
.IP
.nf
\f[C]
CP[16]\ C0
\f[]
.fi
.PP
In contrast to standard data translations, there's no increment flag
here, so the translation does \f[I]not\f[] indicate an incremental
change of the input value.
Instead, mod translations always work with \f[I]absolute\f[] values, and
the step size on the left\-hand side is treated as a \f[I]modulus\f[] to
decompose the input value into two separate quantities,
\f[I]quotient\f[] and \f[I]remainder\f[].
Only the latter becomes the value of the output message, while the
former is used as an \f[I]offset\f[] to modify the output message.
(Note that \f[C]CP\f[] and \f[C]PB\f[] messages don't have a modifiable
offset, so if you use these on the output side of a mod translation, the
offset part of the input value will be ignored.
\f[C]PC\f[] messages, on the other hand, lack the parameter value, so in
this case the remainder value will be disregarded instead.)
.PP
In order to describe more precisely how this works, let's assume an
input value \f[I]v\f[] and a modulus \f[I]k\f[].
We divide \f[I]v\f[] by \f[I]k\f[], yielding the quotient (offset)
\f[I]q\f[] = \f[I]v\f[] div \f[I]k\f[] and the remainder (value)
\f[I]r\f[] = \f[I]v\f[] mod \f[I]k\f[].
E.g., with \f[I]k\f[] = 16 and \f[I]v\f[] = 21, you'll get \f[I]q\f[] =
1 and \f[I]r\f[] = 5 (21 divided by 16 yields 1 with a remainder of 5).
The calculated offset \f[I]q\f[] is then applied to the note itself, and
the remainder \f[I]r\f[] becomes the velocity of that note.
So in the example above the output would be the note \f[C]C#0\f[]
(\f[C]C0\f[] offset by 1) with a velocity of 5.
On the APCmini, this message will light up the second button in the
bottom row of the 8x8 grid in yellow.
.PP
This transformation is surprisingly versatile, and there are some
extensions of the MIDI syntax which make it even more flexible.
These extensions are only available in mod translations.
They are described by the following grammar rules (please also refer to
Section \f[I]MIDI Message Notation\f[] for the rest of the grammar rules
for the MIDI syntax):
.IP
.nf
\f[C]
token\ ::=\ msg\ [\ mod\ ]\ [\ steps\ ]\ [\ "\-"\ number]\ [\ flag\ ]
mod\ \ \ ::=\ "["\ [\ number\ ]\ "]"
steps\ ::=\ "["\ number\ "]"\ |\ "{"\ list\ "}"
list\ \ ::=\ number\ {\ ","\ number\ |\ ":"\ number\ |\ "\-"\ number\ }
flag\ \ ::=\ "\[aq]"\ |\ "?"\ |\ "\[aq]?"\ |\ "?\[aq]"
\f[]
.fi
.PP
There are a couple of new elements in the syntax: an empty modulus
bracket \f[C][]\f[], the transposition flag \f[C]\[aq]\f[], the change
flag \f[C]?\f[], and lists of numbers enclosed in curly braces.
They have the following meaning:
.IP \[bu] 2
The \f[I]empty modulus\f[] bracket, denoted \f[C][]\f[] on the
left\-hand side of a mod translation, indicates a default modulus large
enough (16384 for \f[C]PB\f[], 128 for other messages) so that the
offset \f[I]q\f[] always becomes zero and the translation passes on the
entire input value as is.
.IP \[bu] 2
The \f[I]transposition\f[] flag, denoted with the \f[C]\[aq]\f[]
(apostrophe) suffix on an output message, reverses the roles of
\f[I]q\f[] and \f[I]r\f[], so that the remainder becomes the offset and
the quotient the value of the output message.
.IP \[bu] 2
The \f[I]change\f[] flag, denoted with the \f[C]?\f[] suffix on an
output message, only outputs the message if there are any changes in
offset or value.
.IP \[bu] 2
\f[I]Value lists\f[], denoted as lists of numbers separated by commas
and enclosed in curly braces, provide a way to describe \f[I]discrete
mappings\f[] of input to output values.
The input value is used as an index into the list to give the
corresponding output value, and the last value in the list will be used
for any index which runs past the end of the list.
There are also some convenient shortcuts which let you construct these
lists more easily: repetition \f[I]a\f[]\f[C]:\f[]\f[I]b\f[] (denoting
\f[I]b\f[] consecutive \f[I]a\f[]'s) and enumeration
\f[I]a\f[]\f[C]\-\f[]\f[I]b\f[] (denoting
\f[I]a\f[]\f[C],\f[]\f[I]a\f[]±1\f[C],\f[]\&...\f[C],\f[]\f[I]b\f[],
which ramps either up or down depending on whether
\f[I]a\f[]<=\f[I]b\f[] or \f[I]a\f[]>\f[I]b\f[], respectively).
.PP
These are often used in concert.
We will introduce value lists in a moment, and cover the other options
in due course.
.PP
\f[B]NOTE:\f[] In the context of mod translations, pitch bend values are
interpreted as \f[I]unsigned\f[] quantities in the range 0..16383 (with
8192 denoting the center value), which corresponds to the way they are
actually encoded in MIDI.
This makes the modular arithmetic work consistently across all types of
MIDI messages, and also facilitates conversions between the different
types of absolute parameter values.
Normally you shouldn't have to worry about this, but the change in
representation needs to be taken into account when transforming pitch
bend values with value lists.
.PP
Let's return to our example.
As usual in data translations, you can also specify a step size on the
right\-hand side to upscale the output value (which is the remainder
\f[I]r\f[] here):
.IP
.nf
\f[C]
CP[16]\ C0[2]
\f[]
.fi
.PP
More complicated transformations can be specified as value lists
instead.
E.g., the APCmini uses the velocities 0, 1, 3 and 5 to denote
\[lq]off\[rq] and the colors green, red and yellow, respectively, so we
can map the meter values to different colors as follows:
.IP
.nf
\f[C]
CP[16]\ C0{0,1,1,1,1,1,1,1,1,5,5,5,3}
\f[]
.fi
.PP
Using the shorthand for repetitions, this can be written more succinctly
(which also helps readability):
.IP
.nf
\f[C]
CP[16]\ C0{0,1:8,5:3,3}
\f[]
.fi
.PP
Thus 0 will be mapped to 0 (off), 1..8 to 1 (green), 9..11 to 5
(yellow), and 12 or more to 3 (red).
(These values appear to be in line with the MCP feedback spit out by
Ardour, and what little technical documentation about the Mackie
protocol is available on the web.
Your mileage may vary, though, so you may have to experiment with these
values to make this rule work with your DAW.)
.PP
The quotient here is the mixer channel index in the high\-nibble of the
\f[C]CP\f[] message, which will be used as an offset for the \f[C]C0\f[]
note on the right, so the above rule shows the meters as a single row of
colored buttons at the bottom of the 8x8 grid on the APCmini (first
value on \f[C]C0\f[], second value on \f[C]C#0\f[], etc.).
To get a different layout, you can also scale the \f[I]offset\f[] value,
by adding a second step size to the left\-hand side:
.IP
.nf
\f[C]
CP[16][8]\ C0{0,1:8,5:3,3}
\f[]
.fi
.PP
With this rule, the buttons are now in the first \f[I]column\f[] of the
grid (first value on \f[C]C0\f[], second value on \f[C]G#0\f[], etc.).
Instead of a single step size, it's also possible to specify a list of
discrete offset values, so that you can achieve any regular or irregular
output pattern that you want.
E.g., the following rule places every other meter value in the second
row:
.IP
.nf
\f[C]
CP[16]{0,9,2,11,4,13,6,15}\ C0{0,1:8,5:3,3}
\f[]
.fi
.PP
You might also output several notes at once, in order to display a
horizontal or vertical meter \f[I]strip\f[] instead of just a single
colored button for each value.
For instance:
.IP
.nf
\f[C]
CP[16]\ C0{0,1}\ G#0{0:8,5}\ E1{0:11,3}
\f[]
.fi
.PP
Note that each of the output notes will be offset by the same amount, so
that the green, yellow and red buttons will always be lined up
vertically in this example.
(The APCmini.midizaprc example actually uses a very similar scheme
mapping the meter values to the five topmost button rows.)
.PP
Another example from the Mackie protocol is time feedback.
The following rule (also from the APCmini.midizaprc example) decodes the
least significant digit of the beat number in the time display
(\f[C]CC69\f[]) to count off time on some of the scene launch buttons of
the APCmini.
Note that the digits are actually encoded in ASCII, hence the copious
amount of initial zeros in the value lists below with which we skip over
all the non\-digit characters at the beginning of the ASCII table.
.IP
.nf
\f[C]
CC69[]\ F7{0:49,1,0}\ E7{0:50,1,0}\ Eb7{0:51,1,0}\ D7{0:52,1,0}
\f[]
.fi
.PP
Also note the use of an empty modulus bracket on the left\-hand side,
which means that we always have a zero offset here and thus the output
notes aren't modified in this example.
.SS Basic Mod Translations
.PP
While mod translations are often employed for MIDI feedback, they can
also be used as an alternative to \[lq]ordinary\[rq] (incremental) data
translations in various contexts.
We discuss some of these use cases below and show how they're
implemented.
.PP
For more basic uses we often want to simply pass on (and possibly
transform) the input value \f[I]without\f[] using an offset, so we
employ a default modulus in most of the following examples to ensure
that the offset becomes zero and thus inconsequential.
We also call such translations \f[I]basic\f[] mod translations.
They are useful, in particular, if we want to simply preserve the
parameter value in a data translation.
For instance:
.IP
.nf
\f[C]
CC1[]\ C5
\f[]
.fi
.PP
This translates the \f[C]CC1\f[] (modulation wheel) controller to a
\f[C]C5\f[] (middle C) note message in such a way that the controller
value becomes the velocity of the note.
Note that this is different from both the key translation
\f[C]CC1\ C5\f[] (which only preserves the \[lq]on\[rq]/\[lq]off\[rq]
status but looses the actual parameter value) and the incremental data
translation \f[C]CC1=\ C5\f[] (which usually preserves the value, but
executes the translation in a step\-wise fashion).
A mod translation always maps messages in a single step, which
reproduces leaps in the input values on the output side (and, as a side
effect, also reduces the amount of data traffic compared to incremental
data translations).
While key and incremental data translations are tailored to key and
mouse output, for pure MIDI bindings like the one above a basic mod
translation is often preferable.
.PP
You also need to use a mod translation if your binding involves discrete
value lists, because these are not available in other kinds of
translations.
Value lists can represent \f[I]any\f[] discrete mapping from input to
output values, and thus offer much more flexibility than simple step
sizes.
For instance, here's how to map controller values to the first few
Fibonacci numbers:
.IP
.nf
\f[C]
CC1[]\ CC1{0,1,1,2,3,5,8,13,21,34,55,89}
\f[]
.fi
.PP
Value lists offer some conveniences to facilitate their use,
\f[I]repetitions\f[] (which we've already discussed above) and
\f[I]enumerations\f[].
Enumerations are used to denote an ascending or descending range of
values.
E.g., to reverse the values of a controller you may write:
.IP
.nf
\f[C]
CC1[]\ CC1{127\-0}
\f[]
.fi
.PP
The values in a list may be in any order, and you can throw in any
combination of singleton values, enumerations and repetitions.
For instance:
.IP
.nf
\f[C]
CC1[]\ CC1{0:2\-5,7:5\-0}
\f[]
.fi
.PP
The value list in this example starts with two zeros, then ramps up to 5
followed by five 7s, before finally fading back to 0.
It goes without saying that this is much easier to read and also much
less error\-prone to write than
\f[C]{0,0,1,2,3,4,5,7,7,7,7,7,6,5,4,3,2,1,0}\f[].
.PP
Values in lists may also be negative.
In general, if mapping any input value using a value list results in an
output value that is out of range for the type of MIDI message at hand,
the message will be silently ignored.
We can use this, e.g., to suppress note\-off messages in the output:
.IP
.nf
\f[C]
C0[]\ C0{\-1,1\-127}
\f[]
.fi
.PP
This rule will translate a zero velocity to \-1, which isn't in the
valid range, so the output message will be dropped.
For all other velocities, the input message will be output unchanged,
because the \f[C]1\-127\f[] enumeration maps the positive velocities to
themselves.
If you'd rather output a key\-style fixed velocity for the note\-ons
instead, you can do that as follows:
.IP
.nf
\f[C]
C0[]\ C0{\-1,127}
\f[]
.fi
.PP
This translation may look a bit odd, but can be useful at times if the
application interprets note inputs, e.g., as radio or toggle buttons,
and may get confused by note\-off messages.
Note that it's impossible to do this kind of mapping with key or
incremental data translations, because these don't allow you to suppress
the note\-off messages.
.PP
Last but not least, you can also use a modulus of 1 to cancel the
\f[I]remainder\f[] instead, if you want to use the input value solely as
an offset.
For instance, here's how you can map controller values to note
\f[I]numbers\f[] (rather than velocities):
.IP
.nf
\f[C]
CC1[1]\ C0
\f[]
.fi
.PP
This outputs the note with the same number as the controller value,
\f[C]C0\f[] for value 0, \f[C]C#0\f[] for value 1, \f[C]D0\f[] for value
2, etc.
In fact, this is just a basic mod translation in disguise, because
employing the \f[C]\[aq]\f[] flag on the output message to transpose
quotient and remainder, we can also write it as:
.IP
.nf
\f[C]
CC1[]\ C0\[aq]
\f[]
.fi
.PP
Note that the quotient, which becomes the velocity of the output note,
will always be zero here, so the above translation turns all notes off.
To get a nonzero velocity, you specify it in a value list:
.IP
.nf
\f[C]
CC2[]\ C0{127}\[aq]
\f[]
.fi
.SS Extracting Sub\-Values
.PP
Another important idiom is the following, which extracts the low nibble
from a controller value.
To these ends, we use a modulus of 16 and force the offset value to
zero:
.IP
.nf
\f[C]
CC1[16]{0}\ CC1
\f[]
.fi
.PP
Extracting the \f[I]high\f[] nibble is just as easy (this is another
case where the transposition flag comes in handy):
.IP
.nf
\f[C]
CC1[16]{0}\ CC2\[aq]
\f[]
.fi
.PP
Note that this works because the output mapping \f[C]{0}\f[] (which
forces the offset to 0) is in fact applied \f[I]after\f[] the
transposition.
Thus the quotient becomes the value of the \f[C]CC2\f[] message, while
the remainder is canceled out and becomes a zero offset.
You can also output \f[I]both\f[] the low and high nibbles at the same
time that way:
.IP
.nf
\f[C]
CC1[16]{0}\ CC1\ CC2\[aq]
\f[]
.fi
.PP
Using similar rules, you can extract almost any part of an input value,
down to every single bit if needed (see the \f[I]Macro Translations\f[]
section below for another example).
.SS Detecting Changes
.PP
Let's have another look at the high\-nibble extraction rule from above:
.IP
.nf
\f[C]
CC1[16]{0}\ CC2\[aq]
\f[]
.fi
.PP
Note that if the input value changes gradually then many output values
will be identical.
E.g., if the input values are 0, 10, 19, 32, 64 then the first four high
nibbles are all zero, so the output will be 0, 0, 0, 0, 1, with the zero
value repeated four times.
If this is not desired, you can add the \f[C]?\f[] flag to indicate that
the message should be output only if the value has changed:
.IP
.nf
\f[C]
CC1[16]{0}\ CC2\[aq]?
\f[]
.fi
.PP
Now, repeated values are suppressed, so with the same inputs the output
will be just 0, 1.
Note that we used the \f[C]?\f[] flag in combination with transposition
and the offset forced to zero here, but of course it will work for any
kind of change (offset or value, transposed or not).
Also note that change detection always considers the
\[lq]post\-transform\[rq] values as they would be output, i.e., changes
are detected \f[I]after\f[] transposition and all mappings of input and
output values have been performed.
.PP
Change detection is often useful when input values are projected, as in
the above example, but also in many other situations in which you simply
want to prevent repeated values.
For instance, suppose that we'd like to turn the modulation wheel
(\f[C]CC1\f[]) into a kind of on/off switch.
Using a basic mod translation with a value list and change detection,
this can be done quite easily:
.IP
.nf
\f[C]
CC1[]\ CC1{0,127}?
\f[]
.fi
.PP
This emits a single 127 value as soon as the input value becomes
nonzero, and a single 0 value when it drops to zero again.
Note that without the \f[C]?\f[] flag, the 127 value might be repeated
any number of times while you keep turning the modulation wheel, which
isn't the behavior we want here.
.SS Macro Translations
.PP
There are some situations in which it is hard or even impossible to
construct a translation in a single step, but it may become much easier
if we can recursively invoke other translations.
midizap allows you to do this by \[lq]calling\[rq] the mod translation
for a MIDI message on the right\-hand side of a translation.
This is done by prefixing the message to be expanded with the \f[C]$\f[]
character:
.IP
.nf
\f[C]
CC0[]\ $CC1
\f[]
.fi
.PP
Note that you can \f[I]only\f[] call mod translations this way, so the
message to be expanded (\f[C]CC1\f[] in this example) must be bound in a
mod translation somewhere; otherwise you'll get a warning about the
message being undefined and no output will be generated.
On the other hand, the translation \f[I]containing\f[] the call may also
be a key or incremental data translation instead, so we might just as
well have written, e.g.:
.IP
.nf
\f[C]
CC0=\ $CC1
\f[]
.fi
.PP
Before we proceed, let's introduce a few terms which will make it easier
to talk about these things.
We refer to a mod translation being called in this manner as a
\f[I]macro translation\f[], and we also call the left\-hand side of the
translation a \f[I]macro\f[], and the invocation of a macro using the
dollar symbol a \f[I]macro call\f[].
.PP
To continue our example, let's define the \f[C]CC1\f[] macro so that it
outputs just a single note message:
.IP
.nf
\f[C]
CC0[]\ $CC1\ \ #1
CC1[]\ C5\ \ \ \ #2
\f[]
.fi
.PP
On a conceptual level, the macro expansion process works pretty much
like the production rules of a grammar, with the \[lq]dollar\[rq] tokens
playing the role of the nonterminals.
Thus, with the definitions above a \f[C]CC0\f[] message will be
processed as follows:
.IP \[bu] 2
Rule #1 is applied, constructing the output sequence with the
\f[C]CC1\f[] message as usual.
.IP \[bu] 2
Instead of outputting the resulting \f[C]CC1\f[] message directly, the
program now looks for a mod translation of that message which can be
applied recursively.
.IP \[bu] 2
Rule #2 is applied, yielding a \f[C]C5\f[] message which is substituted
for the \f[C]$CC1\f[] token in rule #1.
.PP
Unsurprisingly, the end result is a \f[C]C5\f[] message with the same
velocity as the value of the \f[C]CC1\f[] message, which in turn comes
from the original \f[C]CC0\f[] message being translated.
.PP
Of course, we could also just have written \f[C]CC0[]\ C5\f[] here and
be done with it.
So let's try something slightly more complicated which really
\f[I]needs\f[] recursive translations to work.
For instance, suppose that we'd like to output \f[I]two\f[] messages
instead: the note message \f[C]C5\f[] as before, followed by a
\f[C]CC1\f[] message with just the low nibble of the controller value.
Now each of these translations is easy to define:
.IP
.nf
\f[C]
CC0[]\ C5
CC0[16]{0}\ CC1
\f[]
.fi
.PP
But we can't just put these two rules into the same section, because
we're not allowed to bind \f[C]CC0\f[] in two different translations at
once (if you try this, the parser will complain and just ignore the
second rule).
And the single rule \f[C]CC0[16]{0}\ C5\ CC1\f[] won't work either,
because it only passes the low nibble to the \f[C]C5\f[] message.
However, using a macro call we can massage those rules into an eligible
form:
.IP
.nf
\f[C]
CC0[]\ C5\ $CC1
CC1[16]{0}\ CC1
\f[]
.fi
.PP
This does exactly what we set out to do, and the transformation of the
original rules we applied here is actually quite straightforward.
In the same vein, we can combine as many different mod translations as
we like, even if they involve different moduli and offset
transformations.
.PP
If you know C, you will have realized by now that macro translations
work pretty much like parameter\-less macros in the C programming
language.
The same caveats apply here, too.
Specifically, you usually do \f[I]not\f[] want to have a macro invoke
itself (either directly or indirectly), because that will almost
certainly lead to infinite recursion.
E.g.:
.IP
.nf
\f[C]
CC0[128]\ $CC1
CC1[128]\ $CC0\ #\ don\[aq]t\ do\ this!
\f[]
.fi
.PP
midizap \f[I]will\f[] catch such mishaps after a few iterations, but
it's better to avoid them in the first place.
We mention in passing that in theory, recursive macro calls in
conjunction with value lists and change detection make the configuration
language Turing\-complete.
However, there's a quite stringent limit on the number of recursive
calls, and there are no variables and no iteration constructs, so these
facilities aren't really intended for general\-purpose programming.
.PP
But there's still a lot of fun to be had with macros despite their
limitations.
Here's another instructive example which spits out the individual bits
of a controller value, using the approach that we discussed earlier in
the context of nibble extraction.
Input comes from \f[C]CC7\f[] in the example, and bit #\f[I]i\f[] of the
controller value becomes \f[C]CC\f[]\f[I]i\f[] in the output, where
\f[I]i\f[] runs from 0 to 6.
Note that each of these rules uses a successively smaller power of 2 as
modulus and passes on the remainder to the next rule, while
transposition is used to extract and output the topmost bit in the
quotient.
.IP
.nf
\f[C]
CC7[64]{0}\ $CC6\ CC6\[aq]
CC6[32]{0}\ $CC5\ CC5\[aq]
CC5[16]{0}\ $CC4\ CC4\[aq]
CC4[8]{0}\ \ $CC3\ CC3\[aq]
CC3[4]{0}\ \ $CC2\ CC2\[aq]
CC2[2]{0}\ \ CC0\ \ CC1\[aq]
\f[]
.fi
.PP
You may want to run this example with debugging enabled to see what
exactly is going on there.
.PP
The \[lq]naming\[rq] of macros is another issue worth discussing here.
In principle, any message which can occur on the left\-hand side of a
mod translation (i.e., everything but \f[C]PC\f[]) can also be used as a
macro.
Unfortunately, in general you can't be sure which messages might show up
in \f[I]real\f[] MIDI input.
For instance, in the example above the macro translations for
\f[C]CC2\f[] to \f[C]CC6\f[] might also be triggered by real MIDI input
instead of macro calls.
While this may be useful at times, e.g., for testing purposes, it is
most likely going to confuse unsuspecting end users.
As a remedy, midizap also provides a special kind of \f[I]macro
event\f[], denoted \f[C]M0\f[] to \f[C]M127\f[], using the following
syntax:
.IP
.nf
\f[C]
msg\ \ \ ::=\ "M"\ number
\f[]
.fi
.PP
These \[lq]synthetic\[rq] messages work exactly like \f[C]CC\f[]
messages, but they are guaranteed to never occur as real input, and they
can \f[I]only\f[] be used in macro calls and on the left\-hand side of
mod translations.
We can rewrite the previous example using macro events as follows:
.IP
.nf
\f[C]
CC7[64]{0}\ $M6\ CC6\[aq]
M6[32]{0}\ \ $M5\ CC5\[aq]
M5[16]{0}\ \ $M4\ CC4\[aq]
M4[8]{0}\ \ \ $M3\ CC3\[aq]
M3[4]{0}\ \ \ $M2\ CC2\[aq]
M2[2]{0}\ \ \ CC0\ \ CC1\[aq]
\f[]
.fi
.PP
Let's conclude with another, slightly more practical example for the use
of macros, which turns the pitch wheel of a MIDI keyboard into a simple
kind of \[lq]shuttle control\[rq].
To illustrate how this works, let's emit an \f[C]XK_Left\f[] key event
when the pitch wheel is pushed down, and an \f[C]XK_Right\f[] event when
it's pushed up.
This can be done as follows:
.IP
.nf
\f[C]
PB[]\ $M0{0:8192,1,2}?
M0[]\ $M1{1,\-1}\ $M2{\-1:2,1,\-1}
M1[]\ XK_Left
M2[]\ XK_Right
\f[]
.fi
.PP
Note that the \f[C]M0\f[] macro will be invoked with a value of 0, 1 and
2 if the pitch wheel is down, centered, and up, respectively.
The value lists in the definition of \f[C]M0\f[] are then used to filter
these values and call the appropriate macro which handles the key output
(\f[C]M1\f[] for value 0, \f[C]M2\f[] for value 2).
It's easy to adjust the \f[C]M1\f[] and \f[C]M2\f[] macros for other
purposes.
E.g., we might output the keyboard shortcuts for \[lq]Rewind\[rq] and
\[lq]Fast Forward\[rq] of a video editor like Kdenlive, or the
corresponding MIDI messages of a Mackie controller:
.IP
.nf
\f[C]
M1[]\ G7[127]\ \ #\ Rew
M2[]\ G#7[127]\ #\ FFwd
\f[]
.fi
.SH Bugs
.PP
There probably are some.
Please submit bug reports and pull requests at the midizap git
repository (https://github.com/agraef/midizap).
Contributions are also welcome.
In particular, we're looking for interesting configurations to be
included in the distribution.
.PP
The names of some of the debugging options are rather idiosyncratic.
midizap inherited them from Eric Messick's ShuttlePRO program, and we
decided to keep them for backward compatibility.
.PP
midizap tries to keep things simple, which implies that it has its
limitations.
In particular, midizap lacks support for translating system messages and
some more interesting ways of mapping, filtering and recombining MIDI
data right now.
There are other, more powerful utilities which do these things, but they
are also more complicated and usually require programming skills.
Fortunately, midizap often does the job reasonably well for simple
mapping tasks (and even some rather complicated ones, such as the
APCmini Mackie emulation included in the distribution).
But if things start getting too fiddly then you should consider using a
more comprehensive tool with real programming capabilities such as
Pd (http://puredata.info/) instead.
.PP
midizap has only been tested on Linux so far, and its keyboard and mouse
support is tailored to X11, i.e., it's pretty much tied to Unix/X11
systems right now.
Native Mac or Windows support certainly seems possible, but it's not
going to happen until someone who's in the know about suitable Mac and
Windows replacements for the X11 XTest extension, comes along and ports
it over.
.SH See Also
.PP
midizap is based on a fork (https://github.com/agraef/ShuttlePRO) of
Eric Messick's ShuttlePRO
program (https://github.com/nanosyzygy/ShuttlePRO), which provides
similar functionality for the Contour Design Shuttle devices.
.PP
Spencer Jackson's osc2midi utility (https://github.com/ssj71/OSC2MIDI)
makes for a great companion to midizap if you also need to convert
between MIDI and Open Sound Control (http://opensoundcontrol.org/).
.PP
The Bome MIDI Translator (https://www.bome.com/products/miditranslator)
seems to be a popular MIDI and keystroke mapping tool for Mac and
Windows.
It is proprietary software and isn't available for Linux, but it should
be worth a look if you need a midizap alternative which runs on these
systems.
.SH Authors, License and Credits
.PP
midizap is free and open source software licensed under the GPLv3,
please see the LICENSE file in the distribution for details.
.PP
Copyright 2013 Eric Messick (FixedImagePhoto.com/Contact)
.PD 0
.P
.PD
Copyright 2018 Albert Graef (<aggraef@gmail.com>)
.PP
This is a version of Eric Messick's ShuttlePRO program which has been
redesigned to work with Jack MIDI instead of the Contour Design Shuttle
devices.
ShuttlePRO was written in 2013 by Eric Messick, based on earlier code by
Trammell Hudson and Arendt David.
The MIDI support was added by Albert Gräf.
All the key and mouse translation features of the original program still
work as before, but it goes without saying that the configuration
language and the translation code have undergone some substantial
changes to accommodate the MIDI input and output facilities.
The Jack MIDI backend is based on code from Spencer Jackson's osc2midi
utility, and on the simple_session_client.c example available in the
Jack git repository.