diff --git a/README.md b/README.md index f555129..041e9a4 100644 --- a/README.md +++ b/README.md @@ -32,9 +32,9 @@ midizap [-h] [-k] [-o[2]] [-j *name*] [-r *rcfile*] [-d[rskmj]] midizap lets you control your favorite multimedia applications using [MIDI][]. 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 `WM_CLASS` and `WM_NAME` 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. -The midizaprc file is just an ordinary text file which you can edit to configure the program. An example.midizaprc file containing sample configurations for some applications is included in the sources. Also, in the examples directory you can find some more examples of configuration files for various purposes. +The midizaprc file is just an ordinary text file which you can edit to configure the program. The format of the configuration file is pretty straightforward, basically just a list of MIDI messages and their translations divided in sections for different applications; the language is also described in detail with lots of examples later in this manual. Moreover, an example.midizaprc file containing sample configurations for some applications is included in the sources, and you can find some more examples of configuration files for various purposes in the examples directory. -midizap provides you with a way to hook up just about any MIDI controller to your applications. MIDI controllers are readily supported by all major operating systems, and are often cheaper and more versatile than special-purpose input devices, so they're always an option to consider, especially if you already have one lying around that you'd like to put to good use again. 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. +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. 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. @@ -52,7 +52,7 @@ After installation the system-wide default configuration file will be in /etc/mi cp /etc/midizaprc ~/.midizaprc -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. (If you create new configurations which might be useful for others, please consider submitting them so that they can be included in future releases.) +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. It is also possible to specify the configuration file to be used, by invoking midizap with the `-r` option on the command line, e.g.: `midizap -r myconfig.midizaprc`. This is often used with more specialized configurations dealing with specific applications or MIDI controllers. @@ -112,7 +112,7 @@ As already mentioned, the midizap program can also be made to function as a MIDI The example.midizaprc file comes with a sample configuration in the special `[MIDI]` default section for illustration purposes. This section is only active if the program is run with the `-o` 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. -You can try it and test that it works by running `midizap -o`, firing up a MIDI synthesizer such as [FluidSynth][] or its graphical front-end [Qsynth][], and employing QjackCtl to connect its input it to midizap's output port. In the sample configuration, the notes `C4` thru `F4` in the small octave have been set up so that you can operate a little drumkit, and a binding for the volume controller (`CC7`) has been added as well. The relevant portion from the configuration entry looks as follows: +You can try it and test that it works by running `midizap -o` along with a MIDI synthesizer such as [FluidSynth][] or its graphical front-end [Qsynth][]. Use QjackCtl to connect FluidSynth's MIDI input to midizap's output port. In the sample configuration, the notes `C4` thru `F4` in the small octave have been set up so that you can operate a little drumkit, and a binding for the volume controller (`CC7`) has been added as well. The relevant portion from the configuration entry looks as follows: ~~~ [MIDI] @@ -159,12 +159,12 @@ The midizap configuration file consists of sections defining translation classes ~~~ [name] regex -<#b><0..12> # note -KP: # key pressure (aftertouch) -PC<0..127> # program change -CC<0..127> # control change -CP # channel pressure -PB # pitch bend +<#b><0..12> output # note +KP: output # key pressure (aftertouch) +PC<0..127> output # program change +CC<0..127> output # control change +CP output # channel pressure +PB output # pitch bend ~~~ The `#` 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. @@ -175,7 +175,7 @@ The translations define what output should be produced for the given MIDI input. Note messages are specified using the customary notation (note name `A..G`, optionally followed by an accidental, `#` or `b`, followed by the MIDI octave number). The same notation is used for key pressure (`KP`) messages. Note that all MIDI octaves start at the note C, so `B0` comes before `C1`. By default, `C5` denotes middle C. Enharmonic spellings are equivalent, so, e.g., `D#` and `Eb` denote exactly the same MIDI note. -We will go into most of 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 some special forms of translations which will be introduced later.) +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 some special forms of translations which will be introduced later.) ~~~ token ::= msg [ "[" number "]" ] [ "-" number ] [ incr ] @@ -209,17 +209,17 @@ Input messages can be processed in two different ways, "key mode" and "data mode - Since program changes have no parameter value associated with them, they don't really have an "on" or "off" status. But they are treated in the same key-like fashion anyway, assuming that they are "pressed" and then "released" immediately afterwards. -Also note that since an input message is only on or off in key mode, there's no step size in this mode. If the input message is followed by a step size then it is always processed in data mode. +Also note that since an input message is only on or off in key mode, there's no step size in this mode. Translations with a step size are always processed in data mode. -*Data mode* is available for all messages whose parameter value may continuously change over time, i.e., key and channel pressure, control changes, and pitch bends. In this mode, the actual *amount* of change in the value of the message (increment or decrement, a.k.a. "up" or "down") is processed rather than the on/off state. Data mode is indicated with a special suffix on the message token which indicates (1) a step size and (2) the direction of the change which the rule should apply to: increment (`+`), decrement (`-`), or both (`=`). Both parts are optional, but at least one of them must be present (otherwise the message is processed in key mode). (Data mode messages with just a step size and no increment suffix are treated specially. As these translations are somewhat esoteric and mostly used with MIDI feedback generated by the host application, we'll have a look at them later, see the *Specialized Data Translations* section near the end of the manual.) +*Data mode* is available for all messages whose parameter value may continuously change over time, i.e., key and channel pressure, control changes, and pitch bends. 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 indicates a step size and/or the direction of the value change which the rule should apply to: increment (`+`), decrement (`-`), or both (`=`). The two parts are both optional, but at least one of them must be present (otherwise the rule is interpreted as a key translation). -In the following, we only consider standard data mode messages having 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. +In the following, we concentrate on "standard" data mode messages having 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 rather specialized uses, so we'll have a look at it later in the *Advanced Features* section. -Data mode usually tracks changes in the *absolute* value of a control. However, for `CC` messages there's also an alternative mode for so-called *incremental* controllers, or *encoders* 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. In contrast, absolute-valued controllers are usually faders or knobs which are confined to a range between minimum and maximum values.) +Data mode usually tracks changes in the *absolute* value of a control. However, for `CC` messages there's also an alternative mode for so-called *incremental* controllers, or *encoders* 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. In contrast, absolute-valued controllers are usually faders or knobs which are confined to a range between minimum and maximum values. Encoders emit a special *sign bit* value indicating a *relative* 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 `<`, `>` and `~` in lieu of `-`, `+` and `=`, respectively. These suffixes are only permitted with `CC` messages. -Translations must be determined uniquely in each translation class. That is, there must at most be one translation for each MIDI token in each translation section. Note, however, that the MIDI channel is part of the token, so tokens with different MIDI channels count as different messages here. The same goes for the mode of a message (key or data), so messages can have both key and data translations associated with them (which is rarely used in practice, though). +Translations must be determined uniquely in each translation class. That is, there must be at most one translation for each MIDI token in each translation section. Note, however, that the MIDI channel is part of the token, so tokens with different MIDI channels count as different messages here. Key and (standard) data translations can also be used in concert if needed (in such a case the key translation is executed first). ## Keyboard and Mouse Translations @@ -248,7 +248,7 @@ F5 "V" XK_Left XK_Page_Up "v" G5 XK_Alt_L/D "v" XK_Alt_L/U "x" RELEASE "q" ~~~ -One pitfall for beginners is that character strings in double quotes are just a shorthand for the corresponding X key codes, ignoring case. Thus, e.g., `"abc"` actually denotes the keysym sequence `XK_a XK_b XK_c`, as does `"ABC"`. So in either case the *lowercase* string `abc` will be output. To output uppercase letters, it is always necessary to add one of the shift modifiers to the output sequence. E.g., `XK_Shift_L/D "abc"` will output `ABC` in uppercase. +One pitfall is that character strings in double quotes are just a shorthand for the corresponding X key codes, ignoring case. Thus, e.g., `"abc"` actually denotes the keysym sequence `XK_a XK_b XK_c`, as does `"ABC"`. So in either case the *lowercase* string `abc` will be output. To output uppercase letters, it is always necessary to add one of the shift modifiers to the output sequence. E.g., `XK_Shift_L/D "abc"` will output `ABC` in uppercase. Translations are handled differently depending on the input mode (cf. *Key and Data Input* above). In *key mode*, there are separate press and release sequences. The former is invoked when the input key goes "down" (i.e., when the "on" status is received), the latter when the input key goes "up" again ("off" status). More precisely, at the end of the press sequence, all down keys marked by `/D` will be released, and the last key not marked by `/D`, `/U`, or `/H` 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 `/D` will be repressed before continuing the sequence. Keycodes marked with `/H` 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: @@ -296,9 +296,9 @@ Most of the notation for MIDI messages on the left-hand side of a translation ru 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 *MIDI Output* above, you need to invoke the midizap program with the `-o` option to make MIDI output work. Otherwise, MIDI messages in the output translations will just be silently ignored. -There is one special MIDI token `CH` which can only be used on the output side. The `CH` token, which is followed by a MIDI channel number in the range 1..16, doesn't actually generate any MIDI message, but merely sets the default MIDI channel for subsequent MIDI messages in the same output sequence. This is convenient if multiple messages are output to the same MIDI channel. For instance, the sequence `C5-2 E5-2 G5-2`, which outputs a C major chord on MIDI channel 2, can also be abbreviated as `CH2 C5 E5 G5`. +There is one special MIDI token `CH` 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 `C5-2 E5-2 G5-2`, which outputs a C major chord on MIDI channel 2, can also be abbreviated as `CH2 C5 E5 G5`. -For key-mode inputs, the corresponding "on" or "off" event is generated for all MIDI messages in the output sequence, where the "on" value defaults to the maximum value (127 for controller values, 8191 for pitch bends). Thus, e.g., the following rule outputs a `CC80` message with controller value 127 each time middle C (`C5`) is pressed (and another `CC80` message with value 0 when the note is released again): +For key mode inputs, the corresponding "on" or "off" event is generated for all MIDI messages in the output sequence, where the "on" value defaults to the maximum value (127 for controller values, 8191 for pitch bends). Thus, e.g., the following rule outputs a `CC80` message with controller value 127 each time middle C (`C5`) is pressed (and another `CC80` message with value 0 when the note is released again): ~~~ C5 CC80 @@ -317,7 +317,7 @@ C2 PB[-8192] # bend down D2 PB[8191] # bend up ~~~ -There are two additional suffixes `=` and `~` for data translations which are most useful with pure MIDI translations, which is why we deferred their discussion until now. If the increment and decrement sequences for a given translation are the same, the `=` suffix can be used to indicate that this sequence should be output for *both* increments and decrements. For instance, to map the modulation wheel (`CC1`) to the volume controller (`CC7`): +Let's now have a look at data mode. There are two additional suffixes `=` and `~` for data translations which are most useful with pure MIDI translations, which is why we deferred their discussion until now. If the increment and decrement sequences for a given translation are the same, the `=` suffix can be used to indicate that this sequence should be output for *both* increments and decrements. For instance, to map the modulation wheel (`CC1`) to the volume controller (`CC7`): ~~~ CC1= CC7 @@ -361,13 +361,13 @@ The step size can also be negative, which allows you to reverse the direction of CC1= CC1[-1] ~~~ -Another possible use is to employ step sizes on *both* the left-hand and right-hand side of a rule, in order to approximate a rational scale factor: +Another possibility is to place step sizes on *both* the left-hand and right-hand side of a rule, in order to approximate a rational scale factor: ~~~ CC1[3]= CC1[2] ~~~ -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, so that the net effect is to scale the amount of change by 2/3. Note that this will only work if the input and output step sizes are reasonably small, so for most rational scale factors this method can only provide a very rough approximation. +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 amount of change by 2/3. Note that this will only work well if the input and output step sizes are reasonably small, so for most real-valued scale factors this method can only provide a very rough approximation. ## Shift State @@ -398,15 +398,17 @@ To keep things simple, only one shift status is available in the present impleme # Advanced Features -This section covers some more advanced functionality which is a bit more complicated and is used less frequently than the basic features discussed in previous sections, but will come in handy in some more specialized use cases. Specifically, we'll discuss *MIDI feedback*, which is needed to properly implement bidirectional communication with some controllers, as well as a special kind of data translations which helps implement some types of feedback, but also has its uses in "normal" processing. +This section covers some functionality which is a bit more complicated and used less frequently than the basic features discussed in previous sections, but will come in handy in some situations. Specifically, we'll discuss *MIDI feedback*, which is needed to properly implement bidirectional communication with some controllers, as well as a special kind of data translations which helps implement some types of feedback, and also has its uses in "normal" processing. ## MIDI Feedback 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 `-o2` option of midizap, or the `JACK_PORTS 2` directive in the midizaprc file, to create a second pair of MIDI input and output ports, named `midi_in2` and `midi_out2`. Use of this option also activates a second MIDI default section in the midizaprc file, labeled `[MIDI2]`, 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 `[MIDI2]` section will be the inverse of those in the `[MIDI]` section, or whatever it takes to translate the MIDI feedback from the application back to MIDI data which the controller understands. -You then wire up midizap's `midi_in` and `midi_out` ports to controller and application as before, but in addition you also connect the application back to midizap's `midi_in2` port, and the `midi_out2` 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. A full-blown example for this kind of setup can be found in examples/APCmini.midizaprc in the sources, which shows how to emulate a Mackie controller with AKAI's APCmini device, so that it readily works with DAW software such as Ardour. +You then wire up midizap's `midi_in` and `midi_out` ports to controller and application as before, but in addition you also connect the application back to midizap's `midi_in2` port, and the `midi_out2` 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. -## Specialized Data Translations +An in-depth discussion of controller feedback is beyond the scope of this manual, but we present a few useful tidbits in the context of the specialized data translations below. Also, 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. + +## Mod Translations 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 MIDI messages employed in feedback, such as time and meter displays, 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. @@ -418,19 +420,19 @@ steps ::= "[" list "]" | "[" number "]" "[" list "]" list ::= number { "," number | ":" number } ~~~ -To explain the meaning of these translations, we take the mapping of channel pressure to notes indicating buttons on the AKAI APCmini (cf. examples/APCmini.midizaprc in the sources) as a running example here. But the same works with any kind of message having a parameter value (i.e., anything but `PC`) and any kind of MIDI output. +In the following, we take the mapping of channel pressure to notes indicating buttons on the AKAI APCmini as a running example; for further details see examples/APCmini.midizaprc in the sources. These translations are useful, in particular, to decode meter messages in the Mackie protocol. But they work the same with any kind of message having a parameter value (i.e., anything but `PC`) and any kind of MIDI output, so similar rules should help with other kinds of "scrambled" MIDI data. Some other possible uses will be discussed in the following section. -In its most basic form, the translation simply looks as follows: +In its most basic form, the translation looks as follows: ~~~ CP[16] C0 ~~~ -In contrast to standard data translations, there's no increment suffix here, so the translation does *not* indicate an incremental value change of some sort. Rather, the output messages are constructed directly from the input value by some arithmetic calculations. To these ends, the step size on the left-hand side is actually being used as a *modulus* in order to decompose the input value into two separate quantities, *quotient* and *remainder*. Only the latter becomes the value of the output message, while the former is used as an *offset* to modify the output message. (Note that `CP` and `PB` 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 simply be ignored. The same goes for the `PC` message, which doesn't have a parameter value either, so that the remainder value will be ignored as well.) +In contrast to standard data translations, there's no increment suffix here, so the translation does *not* indicate an incremental value change of some sort. Rather, the output messages are constructed directly from the input value by some arithmetic calculations. To these ends, the step size on the left-hand side is actually being used as a *modulus* in order to decompose the input value into two separate quantities, *quotient* and *remainder*. Only the latter becomes the value of the output message, while the former is used as an *offset* to modify the output message. (Note that `CP` and `PB` 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 simply ignored. The `PC` message, in contrast, lacks the parameter value, so in this case the remainder value will be disregarded instead.) -In order to describe exactly how this works, let's assume an input value *v* and a modulus *k*. Mathematically, *v* is divided by *k*, yielding the offset *q* = [*v*/*k*] (i.e., *v*/*k* rounded down to the nearest integer towards zero), and the remainder *r* = *v* - *kq* of that division. E.g., with *k* = 16 and *v* = 21, we have that 16 + 5 = 21 and thus you'll get *q* = 1 and *r* = 5. (In layman's terms, 21 divided by 16 yields 1 with a remainder of 5.) The calculated offset *q* is then applied to the note itself, and the remainder *r* becomes the velocity of that note. So in the example the output would be the note `C#0` (`C0` offset by 1) with a velocity of 5. On the APCmini, this message would then light up the second button in the bottom row of the 8x8 grid in yellow. +In order to describe more precisely how this works, let's assume an input value *v* and a modulus *k*. We divide *v* by *k*, yielding the offset *q* = [*v*/*k*] (i.e., *v*/*k* rounded down to the nearest integer towards zero), and the remainder *r* = *v* - *kq* of that division. E.g., with *k* = 16 and *v* = 21, we have that 16 + 5 = 21 and thus you'll get *q* = 1 and *r* = 5 (i.e., 21 divided by 16 yields 1 with a remainder of 5). The calculated offset *q* is then applied to the note itself, and the remainder *r* becomes the velocity of that note. So in the example the output would be the note `C#0` (`C0` 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. -If all this sounds a bit esoteric, please bear with us. There is in fact an important use case for it, namely decoding meter information in the Mackie control protocol. Each meter value is sent by the host application in the form of a key pressure message whose value consists of a mixer channel index 0..7 in the "high nibble" (bits 4..6) and the corresponding meter value in the "low nibble" (bits 0..3), which is why we used 16 as the modulus in this example. +As we mentioned already, there is in fact an important use case for all this, namely decoding meter information in the Mackie protocol. There, each meter value is sent by the host application in the form of a key pressure message whose value consists of a mixer channel index 0..7 in the "high nibble" (bits 4..6) and the corresponding meter value in the "low nibble" (bits 0..3), which is why we used 16 as the modulus in this example. There are some variations of the syntax which make this kind of translation more flexible. In particular, on the right-hand side of the rule you can specify a step size if the remainder *r* needs to be scaled: @@ -438,47 +440,47 @@ There are some variations of the syntax which make this kind of translation more CP[16] C0[2] ~~~ -But in many cases the required transformations on *r* will be more complicated. Therefore it is also possible to specify a *list* of discrete velocity values instead. E.g., the APCmini uses the velocities 0, 1, 3 and 5 to denote "off" and the colors green, red and yellow, respectively, so you can map the meter value to different colors as follows: +But in many cases the required transformations on *r* will be more complicated. To accommodate these, it is also possible to specify a *list* of discrete values instead. E.g., the APCmini uses the velocities 0, 1, 3 and 5 to denote "off" and the colors green, red and yellow, respectively, so you can map the meter value to different colors as follows: ~~~ CP[16] C0[0,1,1,1,1,5,5,5,3] ~~~ -The remainder *r* will then be used as an index into the list to give the translated value. E.g., in our example 0 will be mapped to 0 (off), 1..4 to 1 (green), 5..7 to 5 (yellow), and 8 to 3 (red), which actually matches the Mackie protocol specifications. Also, the last value in the list will be used for any index which runs past the end of the list. Thus, if you receive a meter value of 10, say, which isn't in the list, the output will still be 3, since it's the last value in the list. +The remainder *r* will then be used as an index into the list to give the translated value. E.g., in our example 0 will be mapped to 0 (off), 1..4 to 1 (green), 5..7 to 5 (yellow), and 8 to 3 (red), which actually matches the Mackie protocol specifications. Also, the last value in the list will be used for any index which runs past the end of the list. E.g., if you receive a meter value of 10, which isn't in the list, the output will still be 3, since it's the last value in the list. -There are a lot of repeated values in this example. For convenience, it's possible to abbreviate these using the notation *value*`:`*count*, which also helps readability. The following denotes exactly the same list as above: +You probably noticed that there are a lot of repeated values in this example, which makes the notation a bit untidy and error-prone. As a remedy, it's possible to abbreviate repeated values as *value*`:`*count*, which also helps readability. The following denotes exactly the same list as above: ~~~ CP[16] C0[0,1:4,5:3,3] ~~~ -You can also scale the *offset* value, by adding a second step size to the left-hand side: +Furthermore, you can also scale the *offset* value, by adding a second step size to the left-hand side: ~~~ CP[16][8] C0[0,1:4,5:3,3] ~~~ -Now, a channel pressure value of 24 (denoting a meter value of 8 on the second mixer channel) will output the note `G#0` (`C0` offset by 8) with velocity 3, which on the APCmini will light up the first button in the *second* row in red. 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: +With this rule, the buttons for each mixer channel are now spread out across different *rows* rather than columns. E.g., a channel pressure value of 24 (denoting a meter value of 8 on the second mixer channel) will output the note `G#0` (`C0` offset by 8) with velocity 3, which on the APCmini will light up the first button in the second row in red. + +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: ~~~ CP[16][1,8,17,24] C0[0,1:4,5:3,3] ~~~ -You might also output several notes at once, in order to display a horizontal or vertical meter strip for each mixer channel. For instance, suppose that we'd like to use a button in the bottom row of the APCmini for the green, and the buttons in the two rows above it for the yellow and red values, respectively. You can do that as follows: +You might also output several notes at once, in order to display an entire horizontal or vertical meter *strip* instead of just a single colored button for each mixer channel. For instance: ~~~ CP[16] C0[0,1] G#0[0:5,5] E1[0:8,3] ~~~ -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, as required. For more examples, please have a look at the APCmini.midizaprc file in the sources which uses similar, but more elaborate rules to implement the meter display. +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. -While mod translations were specifically designed to help with the important case of Mackie meter feedback, this method should work with almost any other kind of "scrambled" MIDI data which packs two separate values together. There might be other special cases of MIDI data calling for different approaches, however. So, although we try to keep midizap lean and mean, we might add some more special-case data translations in the future, as the need arises. - -## Other Uses +## Other Uses of Mod Translations Mod translations work with all kinds of output, so that you can also output X11 key and mouse events along with the transformed MIDI data if needed, and the input may be any kind of message which has a parameter value. So, while mod translations are most commonly employed for MIDI feedback, they can also be used as a more capable replacement for "ordinary" data translations in various contexts. We discuss some of these use cases below and show how they're implemented. -In particular, note you can always choose the modulus large enough (> 8192 for `PB`, > 127 for other messages) so that the offset becomes zero and thus inconsequential. This is useful if you just want to employ the discrete value lists (which at present are only available in mod translations) for your mappings. These offer a great deal of flexibility, much more than can be achieved with simple step sizes. In fact, they can be used to realize *any* conceivable mapping between input and output values. For instance, here's how to map controller values to the first few Fibonacci numbers: +In particular, note you can always choose the modulus large enough (> 8192 for `PB`, > 127 for other messages) so that the offset becomes zero and thus inconsequential. This is useful if you just want to employ the discrete value lists (which are only available in mod translations) for your mappings. These offer a great deal of flexibility, much more than can be achieved with simple step sizes. In fact, they can be used to realize *any* discrete mapping between input and output values. For instance, here's how to map controller values to the first few Fibonacci numbers: ~~~ CC1[128] CC1[0,1,1,2,3,5,8,13,21,34,55,89] @@ -502,15 +504,15 @@ This will output the note with the same number as the controller value, `C0` for CC2[1] C0[127:1] ~~~ -Now we can turn notes on with `CC2` and turn them off again with `CC1`. Note the little bit of trickery there on the right-hand side. Just `[127]` would be interpreted as a simple step size, which wouldn't do us much good here since the remainder value to be scaled is always zero. Thus we need to write `[127:1]` instead to make sure that the parser recognizes this as a value list. The `[127:1]` list will map any input (including zero) to 127, which is exactly what we want here. +Now we can turn notes on with `CC2` and turn them off again with `CC1`. Note the little bit of trickery there on the right-hand side. Just `[127]` would be interpreted as a simple step size, which wouldn't do us much good here since the remainder value to be scaled is always zero. Thus we write `[127:1]` instead to make sure that the parser recognizes this as a value list. You could also use, e.g., `[127,0]`. Any list which doesn't look like a simple scale factor and maps the 0 value to 127 will do. -For the sake of a more practical example, let's have another look at MIDI feedback in the Mackie protocol. The following rule decodes the lowest digit in the time display (`CC69`) to count off time on the scene launch buttons on the AKAI 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. +For the sake of a more practical example, let's have another look at MIDI feedback in the Mackie protocol. The following rule decodes the lowest digit in the time display (`CC69`) to count off time on the scene launch buttons of the AKAI 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. ~~~ CC69[128] F7[0:49,1,0] E7[0:50,1,0] Eb7[0:51,1,0] D7[0:52,1,0] ~~~ -As you can see, mod data translations in combination with discrete value lists are really very powerful and let you implement pretty much any desired 1-1 mapping with ease. There *are* some limitations, though. In particular, mappings involving multiple different translations of the same input aren't possible right now, because translations must be unique. Also, there's no way to combine the values of several input messages into a single output message. +As you can see, mod data translations in combination with discrete value lists are really very powerful and let you implement pretty much any desired mapping with ease. There *are* some limitations, though. In particular, mappings involving multiple different translations of the same input aren't possible right now, because translations must be unique. Also, there's no way to combine the values of several input messages into a single output message. # Bugs @@ -524,7 +526,7 @@ midizap tries to keep things simple, which implies that it has its limitations. # See Also -midizap is based on a [fork][agraef/ShuttlePRO] of Eric Messick's [ShuttlePRO program][nanosyzygy/ShuttlePRO], which provides pretty much the same functionality for the Contour Design Shuttle devices. +midizap is based on a [fork][agraef/ShuttlePRO] of Eric Messick's [ShuttlePRO program][nanosyzygy/ShuttlePRO], which provides similar functionality for the Contour Design Shuttle devices. Spencer Jackson's [osc2midi][] utility makes for a great companion to midizap if you also need to convert between MIDI and [Open Sound Control][OSC]. diff --git a/midizap.1 b/midizap.1 index 69e527d..4fb5db2 100644 --- a/midizap.1 +++ b/midizap.1 @@ -74,17 +74,17 @@ 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. -An example.midizaprc file containing sample configurations for some -applications is included in the sources. -Also, in the examples directory you can find some more examples of -configuration files for various purposes. +The format of the configuration file is pretty straightforward, +basically just a list of MIDI messages and their translations divided in +sections for different applications; the language is also described in +detail with lots of examples later in this manual. +Moreover, an example.midizaprc file containing sample configurations for +some applications is included in the sources, 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. -MIDI controllers are readily supported by all major operating systems, -and are often cheaper and more versatile than special\-purpose input -devices, so they're always an option to consider, especially if you -already have one lying around that you'd like to put to good use again. 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. @@ -140,9 +140,6 @@ 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. -(If you create new configurations which might be useful for others, -please consider submitting them so that they can be included in future -releases.) .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.: @@ -308,11 +305,12 @@ 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[], -firing up a MIDI synthesizer such as +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/), and employing QjackCtl to -connect its input it to midizap's output port. +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 operate a little drumkit, and a binding for the volume controller (\f[C]CC7\f[]) has been @@ -431,12 +429,12 @@ the window class or title, and a list of translations: .nf \f[C] [name]\ regex -<#b><0..12>\ \ \ #\ note -KP:\ \ \ \ \ \ \ \ \ \ \ #\ key\ pressure\ (aftertouch) -PC<0..127>\ \ \ \ \ \ \ \ \ \ #\ program\ change -CC<0..127>\ \ \ \ \ \ \ \ \ \ #\ control\ change -CP\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ channel\ pressure -PB\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ pitch\ bend +<#b><0..12>\ output\ \ #\ note +KP:\ 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 @@ -475,9 +473,9 @@ By default, \f[C]C5\f[] denotes middle C. Enharmonic spellings are equivalent, so, e.g., \f[C]D#\f[] and \f[C]Eb\f[] denote exactly the same MIDI note. .PP -We will go into most of 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. +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 some special forms of translations @@ -584,44 +582,38 @@ afterwards. .PP Also note that since an input message is only on or off in key mode, there's no step size in this mode. -If the input message is followed by a step size then it is always -processed in data mode. +Translations with a step size are always processed in data mode. .PP \f[I]Data mode\f[] is available for all messages whose parameter value may continuously change over time, i.e., key and channel pressure, control changes, and pitch bends. -In this mode, the actual \f[I]amount\f[] of change in the value of the -message (increment or decrement, a.k.a. -\[lq]up\[rq] or \[lq]down\[rq]) is processed rather than the on/off -state. +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 -indicates (1) a step size and (2) the direction of the change which the +indicates 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[]). -Both parts are optional, but at least one of them must be present -(otherwise the message is processed in key mode). -(Data mode messages with just a step size and no increment suffix are -treated specially. -As these translations are somewhat esoteric and mostly used with MIDI -feedback generated by the host application, we'll have a look at them -later, see the \f[I]Specialized Data Translations\f[] section near the -end of the manual.) +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 only consider standard data mode messages having an -increment suffix. +In the following, we concentrate on \[lq]standard\[rq] data mode +messages having 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 rather specialized uses, so we'll have a look at it later +in the \f[I]Advanced Features\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 +These usually take the form of jog wheels or rotary encoders which can be turned endlessly in either direction. In contrast, absolute\-valued controllers are usually faders or knobs -which are confined to a range between minimum and maximum values.) +which are confined to a range between minimum and maximum values. .PP Encoders emit a special \f[I]sign bit\f[] value indicating a \f[I]relative\f[] change, where a value < 64 usually denotes an @@ -634,13 +626,12 @@ the suffixes \f[C]<\f[], \f[C]>\f[] and \f[C]~\f[] in lieu of These suffixes are only permitted with \f[C]CC\f[] messages. .PP Translations must be determined uniquely in each translation class. -That is, there must at most be one translation for each MIDI token in +That is, there must be at most one translation for each MIDI token in each translation section. Note, however, that the MIDI channel is part of the token, so tokens with different MIDI channels count as different messages here. -The same goes for the mode of a message (key or data), so messages can -have both key and data translations associated with them (which is -rarely used in practice, though). +Key and (standard) data translations can also be used in concert if +needed (in such a case the key translation is executed first). .SS Keyboard and Mouse Translations .PP The right\-hand side of a translation (i.e., everything following the @@ -699,8 +690,8 @@ G5\ XK_Alt_L/D\ "v"\ XK_Alt_L/U\ "x"\ RELEASE\ "q" \f[] .fi .PP -One pitfall for beginners is that character strings in double quotes are -just a shorthand for the corresponding X key codes, ignoring case. +One pitfall 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 @@ -841,17 +832,16 @@ silently ignored. .PP There is one special MIDI token \f[C]CH\f[] which can only be used on the output side. -The \f[C]CH\f[] token, which is followed by a MIDI channel number in the -range 1..16, doesn't actually generate any MIDI message, but merely sets +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. -This is convenient if multiple messages are output to the same MIDI -channel. +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] +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). @@ -886,6 +876,7 @@ D2\ PB[8191]\ \ #\ bend\ up \f[] .fi .PP +Let's now have a look at data mode. There are two additional suffixes \f[C]=\f[] and \f[C]~\f[] for data translations which are most useful with pure MIDI translations, which is why we deferred their discussion until now. @@ -960,7 +951,7 @@ CC1=\ CC1[\-1] \f[] .fi .PP -Another possible use is to employ step sizes on \f[I]both\f[] the +Another possibility is to place step sizes on \f[I]both\f[] the left\-hand and right\-hand side of a rule, in order to approximate a rational scale factor: .IP @@ -972,10 +963,11 @@ CC1[3]=\ CC1[2] .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, so that the net effect is to scale the amount of change by 2/3. -Note that this will only work if the input and output step sizes are -reasonably small, so for most rational scale factors this method can -only provide a very rough approximation. +doubled again, so that the net effect is to scale the amount of change +by 2/3. +Note that this will only work well if the input and output step sizes +are reasonably small, so for most real\-valued scale factors this method +can only provide a very rough approximation. .SS Shift State .PP The special \f[C]SHIFT\f[] token toggles an internal shift state, which @@ -1050,14 +1042,13 @@ faders on a device which only has a single set of faders, by assigning the shifted faders to the encoders, as shown above. .SH Advanced Features .PP -This section covers some more advanced functionality which is a bit more -complicated and is used less frequently than the basic features -discussed in previous sections, but will come in handy in some more -specialized use cases. +This section covers some functionality which is a bit more complicated +and used less frequently than the basic features discussed in previous +sections, but will come in handy in some situations. Specifically, we'll discuss \f[I]MIDI feedback\f[], which is needed to properly implement bidirectional communication with some controllers, as well as a special kind of data translations which helps implement some -types of feedback, but also has its uses in \[lq]normal\[rq] processing. +types of feedback, and also has its uses in \[lq]normal\[rq] processing. .SS MIDI Feedback .PP Some MIDI controllers need a more elaborate setup than what we've seen @@ -1082,11 +1073,16 @@ 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. -A full\-blown example for this kind of setup can be found in -examples/APCmini.midizaprc in the sources, which shows how to emulate a -Mackie controller with AKAI's APCmini device, so that it readily works -with DAW software such as Ardour. -.SS Specialized Data Translations +.PP +An in\-depth discussion of controller feedback is beyond the scope of +this manual, but we present a few useful tidbits in the context of the +specialized data translations below. +Also, 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 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 @@ -1115,14 +1111,17 @@ list\ \ ::=\ number\ {\ ","\ number\ |\ ":"\ number\ } \f[] .fi .PP -To explain the meaning of these translations, we take the mapping of -channel pressure to notes indicating buttons on the AKAI APCmini -(cf.\ examples/APCmini.midizaprc in the sources) as a running example -here. -But the same works with any kind of message having a parameter value -(i.e., anything but \f[C]PC\f[]) and any kind of MIDI output. +In the following, we take the mapping of channel pressure to notes +indicating buttons on the AKAI APCmini as a running example; for further +details see examples/APCmini.midizaprc in the sources. +These translations are useful, in particular, to decode meter messages +in the Mackie protocol. +But they work the same with any kind of message having a parameter value +(i.e., anything but \f[C]PC\f[]) and any kind of MIDI output, so similar +rules should help with other kinds of \[lq]scrambled\[rq] MIDI data. +Some other possible uses will be discussed in the following section. .PP -In its most basic form, the translation simply looks as follows: +In its most basic form, the translation looks as follows: .IP .nf \f[C] @@ -1142,35 +1141,33 @@ 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 simply be ignored. -The same goes for the \f[C]PC\f[] message, which doesn't have a -parameter value either, so that the remainder value will be ignored as -well.) +offset part of the input value will be simply ignored. +The \f[C]PC\f[] message, in contrast, lacks the parameter value, so in +this case the remainder value will be disregarded instead.) .PP -In order to describe exactly how this works, let's assume an input value -\f[I]v\f[] and a modulus \f[I]k\f[]. -Mathematically, \f[I]v\f[] is divided by \f[I]k\f[], yielding the offset -\f[I]q\f[] = [\f[I]v\f[]/\f[I]k\f[]] (i.e., \f[I]v\f[]/\f[I]k\f[] -rounded down to the nearest integer towards zero), and the remainder -\f[I]r\f[] = \f[I]v\f[] \- \f[I]kq\f[] of that division. +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 offset \f[I]q\f[] = +[\f[I]v\f[]/\f[I]k\f[]] (i.e., \f[I]v\f[]/\f[I]k\f[] rounded down to the +nearest integer towards zero), and the remainder \f[I]r\f[] = \f[I]v\f[] +\- \f[I]kq\f[] of that division. E.g., with \f[I]k\f[] = 16 and \f[I]v\f[] = 21, we have that 16 + 5 = 21 -and thus you'll get \f[I]q\f[] = 1 and \f[I]r\f[] = 5. -(In layman's terms, 21 divided by 16 yields 1 with a remainder of 5.) +and thus you'll get \f[I]q\f[] = 1 and \f[I]r\f[] = 5 (i.e., 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 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 would then light up the second button in -the bottom row of the 8x8 grid in yellow. +On the APCmini, this message will light up the second button in the +bottom row of the 8x8 grid in yellow. .PP -If all this sounds a bit esoteric, please bear with us. -There is in fact an important use case for it, namely decoding meter -information in the Mackie control protocol. -Each meter value is sent by the host application in the form of a key -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), which is why we used 16 as the -modulus in this example. +As we mentioned already, there is in fact an important use case for all +this, namely decoding meter information in the Mackie protocol. +There, each meter value is sent by the host application in the form of a +key 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), which is why we used 16 +as the modulus in this example. .PP There are some variations of the syntax which make this kind of translation more flexible. @@ -1185,8 +1182,8 @@ CP[16]\ C0[2] .PP But in many cases the required transformations on \f[I]r\f[] will be more complicated. -Therefore it is also possible to specify a \f[I]list\f[] of discrete -velocity values instead. +To accommodate these, it is also possible to specify a \f[I]list\f[] of +discrete values 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 you can map the meter value to different colors as follows: @@ -1204,11 +1201,12 @@ E.g., in our example 0 will be mapped to 0 (off), 1..4 to 1 (green), protocol specifications. Also, the last value in the list will be used for any index which runs past the end of the list. -Thus, if you receive a meter value of 10, say, which isn't in the list, -the output will still be 3, since it's the last value in the list. +E.g., if you receive a meter value of 10, which isn't in the list, the +output will still be 3, since it's the last value in the list. .PP -There are a lot of repeated values in this example. -For convenience, it's possible to abbreviate these using the notation +You probably noticed that there are a lot of repeated values in this +example, which makes the notation a bit untidy and error\-prone. +As a remedy, it's possible to abbreviate repeated values as \f[I]value\f[]\f[C]:\f[]\f[I]count\f[], which also helps readability. The following denotes exactly the same list as above: .IP @@ -1218,8 +1216,8 @@ CP[16]\ C0[0,1:4,5:3,3] \f[] .fi .PP -You can also scale the \f[I]offset\f[] value, by adding a second step -size to the left\-hand side: +Furthermore, 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] @@ -1227,10 +1225,13 @@ CP[16][8]\ C0[0,1:4,5:3,3] \f[] .fi .PP -Now, a channel pressure value of 24 (denoting a meter value of 8 on the +With this rule, the buttons for each mixer channel are now spread out +across different \f[I]rows\f[] rather than columns. +E.g., a channel pressure value of 24 (denoting a meter value of 8 on the second mixer channel) will output the note \f[C]G#0\f[] (\f[C]C0\f[] offset by 8) with velocity 3, which on the APCmini will light up the -first button in the \f[I]second\f[] row in red. +first button in the second row in red. +.PP 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: @@ -1241,12 +1242,10 @@ CP[16][1,8,17,24]\ C0[0,1:4,5:3,3] \f[] .fi .PP -You might also output several notes at once, in order to display a -horizontal or vertical meter strip for each mixer channel. -For instance, suppose that we'd like to use a button in the bottom row -of the APCmini for the green, and the buttons in the two rows above it -for the yellow and red values, respectively. -You can do that as follows: +You might also output several notes at once, in order to display an +entire horizontal or vertical meter \f[I]strip\f[] instead of just a +single colored button for each mixer channel. +For instance: .IP .nf \f[C] @@ -1256,20 +1255,8 @@ CP[16]\ C0[0,1]\ G#0[0:5,5]\ E1[0:8,3] .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, as required. -For more examples, please have a look at the APCmini.midizaprc file in -the sources which uses similar, but more elaborate rules to implement -the meter display. -.PP -While mod translations were specifically designed to help with the -important case of Mackie meter feedback, this method should work with -almost any other kind of \[lq]scrambled\[rq] MIDI data which packs two -separate values together. -There might be other special cases of MIDI data calling for different -approaches, however. -So, although we try to keep midizap lean and mean, we might add some -more special\-case data translations in the future, as the need arises. -.SS Other Uses +vertically in this example. +.SS Other Uses of Mod Translations .PP Mod translations work with all kinds of output, so that you can also output X11 key and mouse events along with the transformed MIDI data if @@ -1285,11 +1272,10 @@ In particular, note you can always choose the modulus large enough (> 8192 for \f[C]PB\f[], > 127 for other messages) so that the offset becomes zero and thus inconsequential. This is useful if you just want to employ the discrete value lists -(which at present are only available in mod translations) for your -mappings. +(which are only available in mod translations) for your mappings. These offer a great deal of flexibility, much more than can be achieved with simple step sizes. -In fact, they can be used to realize \f[I]any\f[] conceivable mapping +In fact, they can be used to realize \f[I]any\f[] discrete mapping between input and output values. For instance, here's how to map controller values to the first few Fibonacci numbers: @@ -1339,15 +1325,16 @@ Note the little bit of trickery there on the right\-hand side. Just \f[C][127]\f[] would be interpreted as a simple step size, which wouldn't do us much good here since the remainder value to be scaled is always zero. -Thus we need to write \f[C][127:1]\f[] instead to make sure that the -parser recognizes this as a value list. -The \f[C][127:1]\f[] list will map any input (including zero) to 127, -which is exactly what we want here. +Thus we write \f[C][127:1]\f[] instead to make sure that the parser +recognizes this as a value list. +You could also use, e.g., \f[C][127,0]\f[]. +Any list which doesn't look like a simple scale factor and maps the 0 +value to 127 will do. .PP For the sake of a more practical example, let's have another look at MIDI feedback in the Mackie protocol. The following rule decodes the lowest digit in the time display -(\f[C]CC69\f[]) to count off time on the scene launch buttons on the +(\f[C]CC69\f[]) to count off time on the scene launch buttons of the AKAI 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 @@ -1361,7 +1348,7 @@ CC69[128]\ F7[0:49,1,0]\ E7[0:50,1,0]\ Eb7[0:51,1,0]\ D7[0:52,1,0] .PP As you can see, mod data translations in combination with discrete value lists are really very powerful and let you implement pretty much any -desired 1\-1 mapping with ease. +desired mapping with ease. There \f[I]are\f[] some limitations, though. In particular, mappings involving multiple different translations of the same input aren't possible right now, because translations must be @@ -1403,8 +1390,7 @@ comprehensive tool like Pd (http://puredata.info/) instead. midizap is based on a fork (https://github.com/agraef/ShuttlePRO) of Eric Messick's ShuttlePRO program (https://github.com/nanosyzygy/ShuttlePRO), which provides -pretty much the same functionality for the Contour Design Shuttle -devices. +similar functionality for the Contour Design Shuttle devices. .PP Spencer Jackson's osc2midi (https://github.com/ssj71/OSC2MIDI) utility makes for a great companion to midizap if you also need to convert