Text changes.

master 0.1
Albert Graef 2018-08-31 10:12:23 +02:00
parent 8f5182a217
commit 12767f07c2
2 changed files with 159 additions and 122 deletions

View File

@ -174,7 +174,15 @@ 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. 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.
Each `[name] regex` line introduces the list of MIDI message translations for the named translation class. The name is only used for debugging output and diagnostics, and needn't be unique. When focus is on a window whose class or title matches the regular expression `regex`, the corresponding translations are in effect. An empty regex for the last class will always match, allowing default translations. Any output sequences not bound in a matched section will be loaded from the default section if they are bound there. Each `[name] regex` line introduces the list of MIDI message translations for the named translation class. E.g., the following header might be used to begin a new section for the Kdenlive video editor:
~~~
[Kdenlive] ^kdenlive$
~~~
Please refer to regex(7) for an explanation of the regular expression syntax. The regex above will match `kdenlive` and nothing else, because we tied the match to beginning and end with the `^` and `$` anchors.
When focus is on a window whose class or title matches the (basic) regular expression `regex`, the corresponding translations are in effect. An empty regex for the last class will always match, allowing default translations. Any output sequences not bound in a matched section will be loaded from the default section if they are bound there. In addition, there are two special default sections labeled `[MIDI]` and `[MIDI2]` which are used specifically for MIDI translations, please see the *MIDI Output* and *MIDI Feedback* 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 name is only used for debugging output and diagnostics, and needn't be unique.
The translations 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 one or more tokens, separated by whitespace, indicating either MIDI messages or X11 keyboard and mouse events to be output. The translations 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 one or more tokens, separated by whitespace, indicating either MIDI messages or X11 keyboard and mouse events to be output.
@ -184,9 +192,7 @@ The translations define what output should be produced for the given MIDI input.
Note messages are specified using a human-readable format which should look familiar (to musicians at least): a note name `A..G` is followed by an (optional) accidental (`#` or `b`), and a (mandatory) MIDI octave number. Note that all MIDI octaves start at the note C, so `B0` comes before `C1`. By default, `C5` denotes middle C (you can change this if you want, see *Octave Numbering* below). Enharmonic spellings are equivalent, so, e.g., `D#` and `Eb` denote exactly the same MIDI note. Note messages are specified using a human-readable format which should look familiar (to musicians at least): a note name `A..G` is followed by an (optional) accidental (`#` or `b`), and a (mandatory) MIDI octave number. Note that all MIDI octaves start at the note C, so `B0` comes before `C1`. By default, `C5` denotes middle C (you can change this if you want, see *Octave Numbering* below). Enharmonic spellings are equivalent, so, e.g., `D#` and `Eb` denote exactly the same MIDI note.
The other messages are denoted using short mnemonics: `KP` (aftertouch a.k.a. key pressure; followed by `:` and a note designation); `CC` (control change, followed by a controller number); `PC` (program change, followed by a program number); `CP` and `PB` (channel pressure and pitch bend; these don't have a numeric suffix, as they apply to the entire MIDI channel). The other messages are denoted using short mnemonics: `KP` (aftertouch a.k.a. key pressure; followed by `:` and a note designation); `CC` (control change, followed by a controller number); `PC` (program change, followed by a program number); `CP` and `PB` (channel pressure and pitch bend; these don't have a numeric suffix, as they apply to the entire MIDI channel). 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.)
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.)
~~~ ~~~
token ::= msg [ "[" number "]" ] [ "-" number ] [ flag ] token ::= msg [ "[" number "]" ] [ "-" number ] [ flag ]
@ -226,9 +232,7 @@ Note that since translations are determined uniquely in each translation class,
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.) 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 flags are only permitted with `CC` messages.
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 flags are only permitted with `CC` messages.
## Keyboard and Mouse Translations ## Keyboard and Mouse Translations
@ -417,7 +421,7 @@ An in-depth discussion of controller feedback is beyond the scope of this manual
## Mod Translations ## 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 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. One important application, 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 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 = *v* div 16, where *v* is the key pressure value) and the corresponding meter value in the "low nibble" (bits 0..3 = *v* mod 16). 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. One important application, 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 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).
midizap offers a special variation of data mode to help decoding such messages. This involves calculations with integer moduli which enable you to modify output messages in certain ways, so for want of a better name we also call these bindings *mod translations*. The extended MIDI syntax being used here is described by the following grammar rules (please also refer to the beginning of Section *Translation Syntax* for the rest of the MIDI syntax): midizap offers a special variation of data mode to help decoding such messages. This involves calculations with integer moduli which enable you to modify output messages in certain ways, so for want of a better name we also call these bindings *mod translations*. The extended MIDI syntax being used here is described by the following grammar rules (please also refer to the beginning of Section *Translation Syntax* for the rest of the MIDI syntax):
@ -428,7 +432,7 @@ list ::= number { "," number | ":" number | "-" number }
flag ::= "'" flag ::= "'"
~~~ ~~~
There are two new elements in the syntax, the "transposition" flag `'`, and lists of numbers enclosed in curly braces. For convenience, the latter also support the following abbreviations: repetition *a*`:`*b* (denoting *b* consecutive *a*'s) and enumeration *a*`-`*b* (denoting *a*`,`*a*±1`,`...`,`*b*; note that an enumeration may go up or down, depending on whether *a*<*b* or *a*>*b*). The meaning of these constructs will be discussed below. There are two new elements in the syntax, the "transposition" flag `'`, and lists of numbers enclosed in curly braces. For convenience, the latter also support the following abbreviations: repetition *a*`:`*b* (denoting *b* consecutive *a*'s) and enumeration *a*`-`*b* (denoting *a*`,`*a*±1`,`...`,`*b*, which ramps either up or down depending on whether *a*<*b* or *a*>*b*, respectively). The meaning of these constructs will be discussed below.
For the sake of a concrete example, in the following we consider the mapping of channel pressure messages encoding MCU meter values to notes indicating buttons on the AKAI APCmini; please check examples/APCmini.midizaprc in the sources for details. But these translations 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 will help with other kinds of "scrambled" MIDI data. For the sake of a concrete example, in the following we consider the mapping of channel pressure messages encoding MCU meter values to notes indicating buttons on the AKAI APCmini; please check examples/APCmini.midizaprc in the sources for details. But these translations 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 will help with other kinds of "scrambled" MIDI data.
@ -442,7 +446,7 @@ In contrast to standard data translations, there's no increment flag here, so th
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 quotient (offset) *q* = *v* div *k* and the remainder (value) *r* = *v* mod *k*. E.g., with *k* = 16 and *v* = 21, you'll get *q* = 1 and *r* = 5 (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. 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 quotient (offset) *q* = *v* div *k* and the remainder (value) *r* = *v* mod *k*. E.g., with *k* = 16 and *v* = 21, you'll get *q* = 1 and *r* = 5 (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.
This simple kind of transformation is surprisingly versatile, and there are some variations of the syntax which make it even more flexible. One such variation is *transposition*, denoted with the `'` (apostrophe) flag at the end of the output message. It reverses the roles of *q* and *r*, so that the remainder becomes the offset and the quotient the value of the output message. For instance, with `CP[16] C0` and the same input value of 21, you'd get the note `F0` (`C0` offset by 5) with a velocity of 1 instead. We won't need this here, but it's very convenient in some situations, and we'll see more examples of its use in the following section. This simple kind of transformation is surprisingly versatile, and there are some variations of the syntax which make it even more flexible. One such variation is *transposition*, denoted with the `'` (apostrophe) flag at the end of the output message. It reverses the roles of *q* and *r*, so that the remainder becomes the offset and the quotient the value of the output message. For instance, with `CP[16] C0` and the same input value of 21, you'd get the note `F0` (`C0` offset by 5) with a velocity of 1 instead. We won't utilize this in the present example, but it's very convenient in some situations, and we'll see some more examples of its use in the following section.
As usual in data translations, you can also specify a step size to upscale the output value *r*: As usual in data translations, you can also specify a step size to upscale the output value *r*:
@ -484,7 +488,7 @@ 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. (The APCmini.midizaprc example uses a similar, albeit more elaborate translation to handle MCU meter data.) 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 uses a similar, albeit more elaborate translation to handle MCU meter data.)
Another example from the Mackie protocol is time feedback. The following rule (also from the APCmini.midizaprc example) decodes the lowest digit in the time display (`CC69`) 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. 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 (`CC69`) 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.
~~~ ~~~
CC69[128] F7{0:49,1,0} E7{0:50,1,0} Eb7{0:51,1,0} D7{0:52,1,0} CC69[128] F7{0:49,1,0} E7{0:50,1,0} Eb7{0:51,1,0} D7{0:52,1,0}
@ -502,29 +506,23 @@ One common trick that we already encountered in the preceding section is to choo
CC1[128] C5 CC1[128] C5
~~~ ~~~
This translates the `CC1` (modulation wheel) controller to a `C5` (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 `CC1 C5` (which only preserves the "on"/"off" status but looses the actual parameter value) and the incremental data translation `CC1= C5` (which usually preserves the value, but executes the translation in a step-wise fashion for each unit change in the value). Key and incremental data translations are more useful when used in conjunction with key and mouse output, but for pure MIDI bindings like the one above, a mod translation is often preferable. This translates the `CC1` (modulation wheel) controller to a `C5` (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 `CC1 C5` (which only preserves the "on"/"off" status but looses the actual parameter value) and the incremental data translation `CC1= C5` (which involves some internal state for keeping track of current values, and executes the translation in a step-wise fashion for each unit change). In contrast, a mod translation maps messages one-to-one and does not involve any ramping to arrive at the new value. Therefore, while key and incremental data translations are often used in conjunction with key and mouse output, for pure MIDI bindings like the one above a mod translation is often preferable.
You also need to use a trivial mod translation if your binding involves discrete value lists, because these are only available in mod translations. Value lists, which actually represent discrete *mappings* from input to output values, offer much more flexibility than simple step sizes. In fact, they can be used to realize *any* discrete mapping of the input values. For instance, here's how to map controller values to the first few Fibonacci numbers: 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 *any* 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:
~~~ ~~~
CC1[128] CC1{0,1,1,2,3,5,8,13,21,34,55,89} CC1[128] CC1{0,1,1,2,3,5,8,13,21,34,55,89}
~~~ ~~~
Another useful bit of notation are enumerations, which are used to denote an ascending or descending range of values. E.g., to reverse the values of a controller you may write: Value lists offer some conveniences to facilitate their use, *repetitions* (which we've already discussed in the previous section) and *enumerations*. Enumerations are used to denote an ascending or descending range of values. E.g., to reverse the values of a controller you may write:
~~~ ~~~
CC1[128] CC1{127-0} CC1[128] CC1{127-0}
~~~ ~~~
The output values might be in any order, and you can throw in any combination of singleton values, enumerations, and repetitions: The values in a list may be in any order, and you can throw in any combination of singleton values, enumerations and repetitions. E.g., the list `{0:2-5,7:5-0}` starts with two zeros, then ramps up to 5 followed by five 7s, before finally fading back to 0. For us mortals, that's much easier to read and also much less error-prone to write than `{0,0,1,2,3,4,5,7,7,7,7,7,6,5,4,3,2,1,0}`.
~~~ The mod translations above are all trivial translations with a zero offset. Conversely, you can also use a modulus of 1 to nullify the remainder instead, if you're only interested in the offset. This can be used, e.g., if you want to map controller values to note *numbers* (rather than velocities):
CC1[128] CC1{0:2-5,7:5-0}
~~~
The list on the `CC1` message there consists of two zeros, followed by the values 1-5, followed by five 7s, before finally going back down to 0.
The mod translations above are all trivial translations with a zero offset. Conversely, if you're only interested in the offset, you can also use a modulus of 1 to nullify the remainder instead. This can be used, e.g., if you want to map controller values to note *numbers* (rather than velocities):
~~~ ~~~
CC1[1] C0 CC1[1] C0
@ -554,12 +552,18 @@ CC1[16]{0} CC1
Extracting the *high* nibble is just as easy (this is another case where the transposition flag comes in handy): Extracting the *high* nibble is just as easy (this is another case where the transposition flag comes in handy):
~~~ ~~~
CC1[16]{0} CC1' CC1[16]{0} CC2'
~~~ ~~~
Using similar rules, you can extract pretty much any part of controller values, velocities etc. that you need. (A more elaborate example can be found at the end of the next section.) Note that this works because the output mapping (which in this case forces the offset to 0) is applied *after* the transposition. Thus you can also output *both* the low and high nibbles at the same time:
As you can see, mod translations in combination with discrete value lists are fairly powerful and let you implement pretty much any desired mapping with ease. There are some limitations, though. In particular, the reversal of the above "note-encoding" operation, i.e., *extracting* the note number from a note input is rather tedious (it involves writing down rules for each and every single note). Also, there's no direct way to combine different kinds of translations of the same input (but see below for a way to work around this problem). Conversely, there's no way to consolidate the values of multiple input messages into a single output message either (even the following section won't help with this). ~~~
CC1[16]{0} CC1 CC2'
~~~
Using similar rules, you can extract any part of an input value, down to every single bit if needed (see the example at the end of the next section).
As you can see, mod translations in combination with discrete value lists are fairly powerful and let you implement pretty much any desired mapping with ease. There are some limitations, though. In particular, the reversal of the `CC1[1] C0` translation, i.e., *extracting* the note number from a note input, is rather tedious (it involves writing down rules for each and every single note). Also, there's no direct way to combine different kinds of translations of the same input (but see below for a way to work around this problem), or to consolidate the values of multiple input messages into a single output message.
## Macro Translations ## Macro Translations
@ -569,7 +573,7 @@ There are some situations in which it is hard to construct a translation in a si
CC0= $CC1 CC0= $CC1
~~~ ~~~
Note that you can *only* call mod translations this way, so the message to be expanded (`CC1` 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. Also, we want to make sure that the message isn't also used as a "real" input, so that we are free to define it as needed. MIDI has 2048 distinct controllers, though (128 for each of the 16 MIDI channels), so in most cases it shouldn't be too hard to find a controller that's free to use for such internal translations. Note that you can *only* call mod translations this way, so the message to be expanded (`CC1` 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. Also, you want to make sure that the message isn't also used as a "real" input, so that you are free to define it as needed. MIDI has 2048 distinct controllers, though (128 for each of the 16 MIDI channels), so in most cases it shouldn't be too hard to find a controller that's free to use for such internal translations.
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 *macro translation*, and we also call the left-hand side of the translation a *macro*, and the invocation of a macro using the dollar symbol a *macro call*. 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 *macro translation*, and we also call the left-hand side of the translation a *macro*, and the invocation of a macro using the dollar symbol a *macro call*.
@ -580,24 +584,24 @@ CC0= $CC1 #1
CC1[128] C5 #2 CC1[128] C5 #2
~~~ ~~~
On a conceptual level, the macro expansion process works pretty much like the production rules of a grammar, with the "dollar" tokens playing the role of the non-terminals. Thus, with the definitions above a `CC0` message will be processed as follows: On a conceptual level, the macro expansion process works pretty much like the production rules of a grammar, with the "dollar" tokens playing the role of the nonterminals. Thus, with the definitions above a `CC0` message will be processed as follows:
- Rule #1 is applied, constructing the output sequence with the `CC1` message as usual. - Rule #1 is applied, constructing the output sequence with the `CC1` message as usual.
- Instead of outputting the resulting `CC1` message, the program now looks for a mod translation of that message which can be applied recursively. - Instead of outputting the resulting `CC1` message directly, the program now looks for a mod translation of that message which can be applied recursively.
- Rule #2 is applied, yielding a `C5` message which is substituted for the `$CC1` token in rule #1. - Rule #2 is applied, yielding a `C5` message which is substituted for the `$CC1` token in rule #1.
The end result is of course a `C5` message with the same velocity as the value of the `CC1` message, which in turn comes from the original `CC0` controller value. The end result is of course a `C5` message with the same velocity as the value of the `CC1` message, which in turn comes from the original `CC0` controller value.
This example is admittedly a bit silly, because we could just have written `CC0= C5` instead and be done with it. So let's try something more complicated which really *needs* recursive translations to work. For instance, suppose that we'd like to output *two* messages instead: the note message `C5` as before, followed by a `CC1` message with just the low nibble of the controller value. Now each of these translations is easy to define: Of course, we could also just have written `CC0= C5` here and be done with it. So let's try something slightly more complicated which really *needs* recursive translations to work. For instance, suppose that we'd like to output *two* messages instead: the note message `C5` as before, followed by a `CC1` message with just the low nibble of the controller value. Now each of these translations is easy to define:
~~~ ~~~
CC0= C5 CC0= C5
CC0[16]{0} CC1 CC0[16]{0} CC1
~~~ ~~~
But we can't write them this way, because we're not allowed to bind `CC0` to two different output sequences at once (if you try this, the parser will complain and just ignore the second rule). However, we can massage those rules a bit to obtain: But we can't write them this way, because we're not allowed to bind `CC0` in two different translations at once (the parser will complain and just ignore the second rule). The single rule `CC0[16]{0} C0 CC1` won't work either since it only passes the low nibble to the `C0` message. However, we can massage those rules a bit to obtain the following:
~~~ ~~~
CC0= C5 $CC1 CC0= C5 $CC1
@ -606,16 +610,16 @@ CC1[16]{0} CC1
This works and the transformation we did 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. This works and the transformation we did 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.
C programmers 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, midizap's configuration language provides no way to break out of a recursive macro, so you do *not* want to have a macro invoke itself (either directly or indirectly), because that will always lead to an infinite recursion. For instance: 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, the configuration language provides no way to break out of a recursive macro, so you do *not* want to have a macro invoke itself (either directly or indirectly), because that will always lead to an infinite recursion. E.g.:
~~~ ~~~
CC0[128] $CC1 CC0[128] $CC1
CC1[128] $CC0 # don't do this! CC1[128] $CC0 # don't do this!
~~~ ~~~
midizap *will* catch infinite recursion after a few iterations, so, for educational purposes you can (and should) try the example above with midizap and see what happens. As you'll notice, the program prints an error message indicating the translation and message which caused the problem, so that you can correct your mistake. midizap *will* catch infinite recursion after a few iterations, so for educational purposes you can (and should) try the example above and see what happens. As you'll notice, the program prints an error message indicating the translation and message which caused the problem, so that you can correct your mistake.
So macro translations are too limited to make for a Turing-complete programming language, but there's still a lot that can be done with them. Here's another 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 `CC7` in the example, and bit #*i* of the controller value becomes `CC`*i* in the output, where *i* runs from 0 to 6. (You should try these translations with the debugging options to see what exactly is going on there.) So macro translations are too limited to make for a Turing-complete programming language, but there's still a lot that can be done with them. 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 `CC7` in the example, and bit #*i* of the controller value becomes `CC`*i* in the output, where *i* runs from 0 to 6. Note that each of these rules uses successively smaller powers of 2 as its modulus and passes on the remainder to the next rule, while the topmost bit is extracted with transposition. (You may want to try these translations with the debugging options to see what exactly is going on here.)
~~~ ~~~
CC7[64]{0} $CC6 CC6' CC7[64]{0} $CC6 CC6'
@ -634,7 +638,7 @@ There probably are some. Please submit bug reports and pull requests at the midi
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 compatibility reasons. 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 compatibility reasons.
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. So there's no native Mac or Windows support, and there won't be until someone in the know about Mac and Windows equivalents for the X11 XTest extension comes along and ports it over. (Your pull requests are appreciated!) 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. So there's no native Mac or Windows support, and there won't be until someone in the know about Mac and Windows equivalents for the X11 XTest extension comes along and ports midizap to these systems.
midizap tries to keep things simple, which implies that it has its limitations. In particular, midizap lacks support for 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 at least some programming skills. Fortunately, midizap usually does the job reasonably well for simple mapping tasks (and even some rather complicated ones, such as the APCmini MCU emulation included in the distribution). But if things start getting fiddly then you should consider using a more comprehensive tool like [Pd][] instead. midizap tries to keep things simple, which implies that it has its limitations. In particular, midizap lacks support for 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 at least some programming skills. Fortunately, midizap usually does the job reasonably well for simple mapping tasks (and even some rather complicated ones, such as the APCmini MCU emulation included in the distribution). But if things start getting fiddly then you should consider using a more comprehensive tool like [Pd][] instead.
@ -653,7 +657,7 @@ midizap is free and open source software licensed under the GPLv3.
Copyright 2013 Eric Messick (FixedImagePhoto.com/Contact) Copyright 2013 Eric Messick (FixedImagePhoto.com/Contact)
Copyright 2018 Albert Graef (<aggraef@gmail.com>) Copyright 2018 Albert Graef (<aggraef@gmail.com>)
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 Graef. 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. 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.
[MIDI]: https://www.midi.org/ [MIDI]: https://www.midi.org/
[OSC]: http://opensoundcontrol.org/ [OSC]: http://opensoundcontrol.org/

207
midizap.1
View File

@ -467,14 +467,37 @@ ignored.
.PP .PP
Each \f[C][name]\ regex\f[] line introduces the list of MIDI message Each \f[C][name]\ regex\f[] line introduces the list of MIDI message
translations for the named translation class. translations for the named translation class.
The name is only used for debugging output and diagnostics, and needn't E.g., the following header might be used to begin a new section for the
be unique. Kdenlive video editor:
When focus is on a window whose class or title matches the regular .IP
expression \f[C]regex\f[], the corresponding translations are in effect. .nf
\f[C]
[Kdenlive]\ ^kdenlive$
\f[]
.fi
.PP
Please refer to regex(7) for an explanation of the regular expression
syntax.
The regex above will match \f[C]kdenlive\f[] and nothing else, because
we tied the match to beginning and end with the \f[C]^\f[] and
\f[C]$\f[] anchors.
.PP
When focus is on a window whose class or title matches the (basic)
regular expression \f[C]regex\f[], the corresponding translations are in
effect.
An empty regex for the last class will always match, allowing default An empty regex for the last class will always match, allowing default
translations. translations.
Any output sequences not bound in a matched section will be loaded from Any output sequences not bound in a matched section will be loaded from
the default section if they are bound there. the default section if they are bound there.
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 name is only used for debugging output and
diagnostics, and needn't be unique.
.PP .PP
The translations define what output should be produced for the given The translations define what output should be produced for the given
MIDI input. MIDI input.
@ -515,7 +538,6 @@ key pressure; followed by \f[C]:\f[] and a note designation);
\f[C]PC\f[] (program change, followed by a program number); \f[C]CP\f[] \f[C]PC\f[] (program change, followed by a program number); \f[C]CP\f[]
and \f[C]PB\f[] (channel pressure and pitch bend; these don't have a and \f[C]PB\f[] (channel pressure and pitch bend; these don't have a
numeric suffix, as they apply to the entire MIDI channel). numeric suffix, as they apply to the entire MIDI channel).
.PP
We will go into the other syntactic bits and pieces of MIDI message 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 designations later, but it's good to have the following grammar in EBNF
notation handy for reference. notation handy for reference.
@ -654,7 +676,6 @@ These usually take the form of jog wheels or rotary encoders which can
be turned endlessly in either direction. be turned endlessly in either direction.
In contrast, absolute\-valued controllers are usually faders or knobs 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 Encoders emit a special \f[I]sign bit\f[] value indicating a
\f[I]relative\f[] change, where a value < 64 usually denotes an \f[I]relative\f[] change, where a value < 64 usually denotes an
increment (representing clockwise rotation), and a value > 64 a increment (representing clockwise rotation), and a value > 64 a
@ -1132,9 +1153,8 @@ One important application, which we'll use as a running example below,
is the decoding of meter (RMS level) data in the Mackie protocol. is the decoding of meter (RMS level) data in the Mackie protocol.
There, each meter value is sent by the host application in the form of a 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 key pressure message whose value consists of a mixer channel index 0..7
in the \[lq]high nibble\[rq] (bits 4..6 = \f[I]v\f[] div 16, where in the \[lq]high nibble\[rq] (bits 4..6) and the corresponding meter
\f[I]v\f[] is the key pressure value) and the corresponding meter value value in the \[lq]low nibble\[rq] (bits 0..3).
in the \[lq]low nibble\[rq] (bits 0..3 = \f[I]v\f[] mod 16).
.PP .PP
midizap offers a special variation of data mode to help decoding such midizap offers a special variation of data mode to help decoding such
messages. messages.
@ -1160,9 +1180,9 @@ For convenience, the latter also support the following abbreviations:
repetition \f[I]a\f[]\f[C]:\f[]\f[I]b\f[] (denoting \f[I]b\f[] 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 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]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[]; \f[I]a\f[]\f[C],\f[]\f[I]a\f[]±1\f[C],\f[]\&...\f[C],\f[]\f[I]b\f[],
note that an enumeration may go up or down, depending on whether which ramps either up or down depending on whether \f[I]a\f[]<\f[I]b\f[]
\f[I]a\f[]<\f[I]b\f[] or \f[I]a\f[]>\f[I]b\f[]). or \f[I]a\f[]>\f[I]b\f[], respectively).
The meaning of these constructs will be discussed below. The meaning of these constructs will be discussed below.
.PP .PP
For the sake of a concrete example, in the following we consider the For the sake of a concrete example, in the following we consider the
@ -1220,8 +1240,9 @@ message.
For instance, with \f[C]CP[16]\ C0\f[] and the same input value of 21, For instance, with \f[C]CP[16]\ C0\f[] and the same input value of 21,
you'd get the note \f[C]F0\f[] (\f[C]C0\f[] offset by 5) with a velocity you'd get the note \f[C]F0\f[] (\f[C]C0\f[] offset by 5) with a velocity
of 1 instead. of 1 instead.
We won't need this here, but it's very convenient in some situations, We won't utilize this in the present example, but it's very convenient
and we'll see more examples of its use in the following section. in some situations, and we'll see some more examples of its use in the
following section.
.PP .PP
As usual in data translations, you can also specify a step size to As usual in data translations, you can also specify a step size to
upscale the output value \f[I]r\f[]: upscale the output value \f[I]r\f[]:
@ -1308,8 +1329,9 @@ translation to handle MCU meter data.)
.PP .PP
Another example from the Mackie protocol is time feedback. Another example from the Mackie protocol is time feedback.
The following rule (also from the APCmini.midizaprc example) decodes the The following rule (also from the APCmini.midizaprc example) decodes the
lowest digit in the time display (\f[C]CC69\f[]) to count off time on least significant digit of the beat number in the time display
some of the scene launch buttons of the APCmini. (\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 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 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. all the non\-digit characters at the beginning of the ASCII table.
@ -1354,21 +1376,21 @@ value becomes the velocity of the note.
Note that this is different from both the key translation 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] \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 status but looses the actual parameter value) and the incremental data
translation \f[C]CC1=\ C5\f[] (which usually preserves the value, but translation \f[C]CC1=\ C5\f[] (which involves some internal state for
executes the translation in a step\-wise fashion for each unit change in keeping track of current values, and executes the translation in a
the value). step\-wise fashion for each unit change).
Key and incremental data translations are more useful when used in In contrast, a mod translation maps messages one\-to\-one and does not
conjunction with key and mouse output, but for pure MIDI bindings like involve any ramping to arrive at the new value.
the one above, a mod translation is often preferable. Therefore, while key and incremental data translations are often used in
conjunction with key and mouse output, for pure MIDI bindings like the
one above a mod translation is often preferable.
.PP .PP
You also need to use a trivial mod translation if your binding involves You also need to use a mod translation if your binding involves discrete
discrete value lists, because these are only available in mod value lists, because these are not available in other kinds of
translations. translations.
Value lists, which actually represent discrete \f[I]mappings\f[] from Value lists can represent \f[I]any\f[] discrete mapping from input to
input to output values, offer much more flexibility than simple step output values, and thus offer much more flexibility than simple step
sizes. sizes.
In fact, they can be used to realize \f[I]any\f[] discrete mapping of
the input values.
For instance, here's how to map controller values to the first few For instance, here's how to map controller values to the first few
Fibonacci numbers: Fibonacci numbers:
.IP .IP
@ -1378,8 +1400,11 @@ CC1[128]\ CC1{0,1,1,2,3,5,8,13,21,34,55,89}
\f[] \f[]
.fi .fi
.PP .PP
Another useful bit of notation are enumerations, which are used to Value lists offer some conveniences to facilitate their use,
denote an ascending or descending range of values. \f[I]repetitions\f[] (which we've already discussed in the previous
section) 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: E.g., to reverse the values of a controller you may write:
.IP .IP
.nf .nf
@ -1388,23 +1413,18 @@ CC1[128]\ CC1{127\-0}
\f[] \f[]
.fi .fi
.PP .PP
The output values might be in any order, and you can throw in any The values in a list may be in any order, and you can throw in any
combination of singleton values, enumerations, and repetitions: combination of singleton values, enumerations and repetitions.
.IP E.g., the list \f[C]{0:2\-5,7:5\-0}\f[] starts with two zeros, then
.nf ramps up to 5 followed by five 7s, before finally fading back to 0.
\f[C] For us mortals, that's much easier to read and also much less
CC1[128]\ CC1{0:2\-5,7:5\-0} error\-prone to write than
\f[] \f[C]{0,0,1,2,3,4,5,7,7,7,7,7,6,5,4,3,2,1,0}\f[].
.fi
.PP
The list on the \f[C]CC1\f[] message there consists of two zeros,
followed by the values 1\-5, followed by five 7s, before finally going
back down to 0.
.PP .PP
The mod translations above are all trivial translations with a zero The mod translations above are all trivial translations with a zero
offset. offset.
Conversely, if you're only interested in the offset, you can also use a Conversely, you can also use a modulus of 1 to nullify the remainder
modulus of 1 to nullify the remainder instead. instead, if you're only interested in the offset.
This can be used, e.g., if you want to map controller values to note This can be used, e.g., if you want to map controller values to note
\f[I]numbers\f[] (rather than velocities): \f[I]numbers\f[] (rather than velocities):
.IP .IP
@ -1461,28 +1481,36 @@ case where the transposition flag comes in handy):
.IP .IP
.nf .nf
\f[C] \f[C]
CC1[16]{0}\ CC1\[aq] CC1[16]{0}\ CC2\[aq]
\f[] \f[]
.fi .fi
.PP .PP
Using similar rules, you can extract pretty much any part of controller Note that this works because the output mapping (which in this case
values, velocities etc. forces the offset to 0) is applied \f[I]after\f[] the transposition.
that you need. Thus you can also output \f[I]both\f[] the low and high nibbles at the
(A more elaborate example can be found at the end of the next section.) same time:
.IP
.nf
\f[C]
CC1[16]{0}\ CC1\ CC2\[aq]
\f[]
.fi
.PP
Using similar rules, you can extract any part of an input value, down to
every single bit if needed (see the example at the end of the next
section).
.PP .PP
As you can see, mod translations in combination with discrete value As you can see, mod translations in combination with discrete value
lists are fairly powerful and let you implement pretty much any desired lists are fairly powerful and let you implement pretty much any desired
mapping with ease. mapping with ease.
There are some limitations, though. There are some limitations, though.
In particular, the reversal of the above \[lq]note\-encoding\[rq] In particular, the reversal of the \f[C]CC1[1]\ C0\f[] translation,
operation, i.e., \f[I]extracting\f[] the note number from a note input i.e., \f[I]extracting\f[] the note number from a note input, is rather
is rather tedious (it involves writing down rules for each and every tedious (it involves writing down rules for each and every single note).
single note).
Also, there's no direct way to combine different kinds of translations Also, there's no direct way to combine different kinds of translations
of the same input (but see below for a way to work around this problem). of the same input (but see below for a way to work around this problem),
Conversely, there's no way to consolidate the values of multiple input or to consolidate the values of multiple input messages into a single
messages into a single output message either (even the following section output message.
won't help with this).
.SS Macro Translations .SS Macro Translations
.PP .PP
There are some situations in which it is hard to construct a translation There are some situations in which it is hard to construct a translation
@ -1503,8 +1531,8 @@ 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 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 mod translation somewhere; otherwise you'll get a warning about the
message being undefined and no output will be generated. message being undefined and no output will be generated.
Also, we want to make sure that the message isn't also used as a Also, you want to make sure that the message isn't also used as a
\[lq]real\[rq] input, so that we are free to define it as needed. \[lq]real\[rq] input, so that you are free to define it as needed.
MIDI has 2048 distinct controllers, though (128 for each of the 16 MIDI MIDI has 2048 distinct controllers, though (128 for each of the 16 MIDI
channels), so in most cases it shouldn't be too hard to find a channels), so in most cases it shouldn't be too hard to find a
controller that's free to use for such internal translations. controller that's free to use for such internal translations.
@ -1528,16 +1556,16 @@ CC1[128]\ C5\ \ #2
.PP .PP
On a conceptual level, the macro expansion process works pretty much On a conceptual level, the macro expansion process works pretty much
like the production rules of a grammar, with the \[lq]dollar\[rq] tokens like the production rules of a grammar, with the \[lq]dollar\[rq] tokens
playing the role of the non\-terminals. playing the role of the nonterminals.
Thus, with the definitions above a \f[C]CC0\f[] message will be Thus, with the definitions above a \f[C]CC0\f[] message will be
processed as follows: processed as follows:
.IP \[bu] 2 .IP \[bu] 2
Rule #1 is applied, constructing the output sequence with the Rule #1 is applied, constructing the output sequence with the
\f[C]CC1\f[] message as usual. \f[C]CC1\f[] message as usual.
.IP \[bu] 2 .IP \[bu] 2
Instead of outputting the resulting \f[C]CC1\f[] message, the program Instead of outputting the resulting \f[C]CC1\f[] message directly, the
now looks for a mod translation of that message which can be applied program now looks for a mod translation of that message which can be
recursively. applied recursively.
.IP \[bu] 2 .IP \[bu] 2
Rule #2 is applied, yielding a \f[C]C5\f[] message which is substituted Rule #2 is applied, yielding a \f[C]C5\f[] message which is substituted
for the \f[C]$CC1\f[] token in rule #1. for the \f[C]$CC1\f[] token in rule #1.
@ -1546,10 +1574,10 @@ The end result is of course 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 as the value of the \f[C]CC1\f[] message, which in turn comes from the
original \f[C]CC0\f[] controller value. original \f[C]CC0\f[] controller value.
.PP .PP
This example is admittedly a bit silly, because we could just have Of course, we could also just have written \f[C]CC0=\ C5\f[] here and be
written \f[C]CC0=\ C5\f[] instead and be done with it. done with it.
So let's try something more complicated which really \f[I]needs\f[] So let's try something slightly more complicated which really
recursive translations to work. \f[I]needs\f[] recursive translations to work.
For instance, suppose that we'd like to output \f[I]two\f[] messages 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 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. \f[C]CC1\f[] message with just the low nibble of the controller value.
@ -1563,9 +1591,11 @@ CC0[16]{0}\ CC1
.fi .fi
.PP .PP
But we can't write them this way, because we're not allowed to bind But we can't write them this way, because we're not allowed to bind
\f[C]CC0\f[] to two different output sequences at once (if you try this, \f[C]CC0\f[] in two different translations at once (the parser will
the parser will complain and just ignore the second rule). complain and just ignore the second rule).
However, we can massage those rules a bit to obtain: The single rule \f[C]CC0[16]{0}\ C0\ CC1\f[] won't work either since it
only passes the low nibble to the \f[C]C0\f[] message.
However, we can massage those rules a bit to obtain the following:
.IP .IP
.nf .nf
\f[C] \f[C]
@ -1580,14 +1610,15 @@ In the same vein, we can combine as many different mod translations as
we like, even if they involve different moduli and offset we like, even if they involve different moduli and offset
transformations. transformations.
.PP .PP
C programmers will have realized by now that macro translations work If you know C, you will have realized by now that macro translations
pretty much like parameter\-less macros in the C programming language. work pretty much like parameter\-less macros in the C programming
language.
The same caveats apply here, too. The same caveats apply here, too.
Specifically, midizap's configuration language provides no way to break Specifically, the configuration language provides no way to break out of
out of a recursive macro, so you do \f[I]not\f[] want to have a macro a recursive macro, so you do \f[I]not\f[] want to have a macro invoke
invoke itself (either directly or indirectly), because that will always itself (either directly or indirectly), because that will always lead to
lead to an infinite recursion. an infinite recursion.
For instance: E.g.:
.IP .IP
.nf .nf
\f[C] \f[C]
@ -1597,8 +1628,8 @@ CC1[128]\ $CC0\ #\ don\[aq]t\ do\ this!
.fi .fi
.PP .PP
midizap \f[I]will\f[] catch infinite recursion after a few iterations, midizap \f[I]will\f[] catch infinite recursion after a few iterations,
so, for educational purposes you can (and should) try the example above so for educational purposes you can (and should) try the example above
with midizap and see what happens. and see what happens.
As you'll notice, the program prints an error message indicating the As you'll notice, the program prints an error message indicating the
translation and message which caused the problem, so that you can translation and message which caused the problem, so that you can
correct your mistake. correct your mistake.
@ -1606,14 +1637,17 @@ correct your mistake.
So macro translations are too limited to make for a Turing\-complete So macro translations are too limited to make for a Turing\-complete
programming language, but there's still a lot that can be done with programming language, but there's still a lot that can be done with
them. them.
Here's another example which spits out the individual bits of a Here's another instructive example which spits out the individual bits
controller value, using the approach that we discussed earlier in the of a controller value, using the approach that we discussed earlier in
context of nibble extraction. the context of nibble extraction.
Input comes from \f[C]CC7\f[] in the example, and bit #\f[I]i\f[] of the 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 controller value becomes \f[C]CC\f[]\f[I]i\f[] in the output, where
\f[I]i\f[] runs from 0 to 6. \f[I]i\f[] runs from 0 to 6.
(You should try these translations with the debugging options to see Note that each of these rules uses successively smaller powers of 2 as
what exactly is going on there.) its modulus and passes on the remainder to the next rule, while the
topmost bit is extracted with transposition.
(You may want to try these translations with the debugging options to
see what exactly is going on here.)
.IP .IP
.nf .nf
\f[C] \f[C]
@ -1651,8 +1685,7 @@ support is tailored to X11, i.e., it's pretty much tied to Unix/X11
systems right now. systems right now.
So there's no native Mac or Windows support, and there won't be until So there's no native Mac or Windows support, and there won't be until
someone in the know about Mac and Windows equivalents for the X11 XTest someone in the know about Mac and Windows equivalents for the X11 XTest
extension comes along and ports it over. extension comes along and ports midizap to these systems.
(Your pull requests are appreciated!)
.PP .PP
midizap tries to keep things simple, which implies that it has its midizap tries to keep things simple, which implies that it has its
limitations. limitations.
@ -1699,7 +1732,7 @@ redesigned to work with Jack MIDI instead of the Contour Design Shuttle
devices. devices.
ShuttlePRO was written in 2013 by Eric Messick, based on earlier code by ShuttlePRO was written in 2013 by Eric Messick, based on earlier code by
Trammell Hudson and Arendt David. Trammell Hudson and Arendt David.
The MIDI support was added by Albert Graef. The MIDI support was added by Albert Gräf.
All the key and mouse translation features of the original program still All the key and mouse translation features of the original program still
work as before, but it goes without saying that the configuration work as before, but it goes without saying that the configuration
language and the translation code have undergone some substantial language and the translation code have undergone some substantial