Add a built-in patchbay facility (JACK_IN/JACK_OUT directives).

master
Albert Graef 2018-10-13 03:27:07 +02:00
parent 483c2d3105
commit 56ea96686a
18 changed files with 423 additions and 375 deletions

View File

@ -76,9 +76,9 @@ The midizap program is a command line application, so you typically run it from
Try `midizap -h` for a brief summary of the available options with which the program can be invoked.
midizap uses [Jack][] for doing all its MIDI input and output, so you need to be able to run Jack and connect the Jack MIDI inputs and outputs of the program. We recommend using a Jack front-end and patchbay program like [QjackCtl][] for this purpose. In QjackCtl's setup, make sure that you have selected `seq` as the MIDI driver. This exposes the ALSA sequencer ports of your MIDI hardware and other non-Jack ALSA MIDI applications as Jack MIDI ports, so that they can easily be connected to midizap. As an alternative, you can also run [a2jmidid][] as a separate ALSA-Jack MIDI bridge. (The latter method will work with both Jack1 and Jack2, the former method is only recommended if you're using Jack1.)
midizap uses [Jack][] for doing all its MIDI input and output, so you need to be able to run Jack and connect the Jack MIDI inputs and outputs of the program. We recommend using a Jack front-end and patchbay program like [QjackCtl][] for this purpose. In QjackCtl's setup, make sure that you have selected `seq` as the MIDI driver. This exposes the ALSA sequencer ports of your MIDI hardware and other non-Jack ALSA MIDI applications as Jack MIDI ports, so that they can easily be connected to midizap. As an alternative, you can also run [a2jmidid][] as a separate ALSA-Jack MIDI bridge. (The latter method works well with both Jack1 and Jack2. Jack's built-in ALSA-Jack MIDI bridge also works very well in Jack1, but in Jack2 it doesn't list the ALSA ports by their name, which makes it rather unusable there because you'll have to guess which port represents which device or application.)
Having that set up, start Jack, make sure that your MIDI controller is connected, and try running `midizap` from the command line (without any arguments). In QjackCtl, open the Connections dialog and activate the second tab named "MIDI", which shows all available Jack MIDI inputs and outputs. On the right side of the MIDI tab, you should now see a client named `midizap` with one MIDI input port named `midi_in`. That's the one you need to connect to your MIDI controller, whose output port should be visible under the `alsa_midi` client on the left side of the dialog.
Having that set up, start Jack, make sure that your MIDI controller is connected, and try running `midizap` from the command line (without any arguments). In QjackCtl, open the Connections dialog and activate the second tab named "MIDI", which shows all available Jack MIDI inputs and outputs. On the right side of the MIDI tab, you should now see a client named `midizap` with one MIDI input port named `midi_in`. That's the one you need to connect to your MIDI controller, whose output port should be visible under the `alsa_midi` client on the left side of the dialog (or the `a2j` client, if you're using a2jmidid).
To test the waters, you can hook up just about any MIDI keyboard and give it a try with the default section in the distributed midizaprc file, which contains some basic translations for mouse and cursor key emulation. Here is the relevant excerpt from that section:
@ -143,7 +143,11 @@ Besides MIDI notes and control change (`CC`) messages, the midizap program also
# Jack-Related Options
There are some additional directives (and corresponding command line options) to set midizap's Jack client name and the number of input and output ports it uses. If both the command line options and directives in the midizaprc file are used, the former take priority, so that it's always possible to override the configuration settings from the command line.
There are some additional directives (and corresponding command line options) to configure midizap's Jack setup in various ways. We take a look at these in the following. If both the command line options and directives in the midizaprc file are used, the former take priority, so that it's possible to override the configuration settings from the command line.
Note that all these options can only be set at program startup. If you later edit the corresponding directives in the configuration file, the changes won't take effect until you restart the program.
## Jack Client Name and MIDI Port Setup
Firstly, there's the `-j` option and the `JACK_NAME` directive which change the Jack client name from the default (`midizap`) to whatever you want it to be. To use this option, simply invoke midizap as `midizap -j client-name`, or put the following directive into your midizaprc file:
@ -161,15 +165,44 @@ JACK_PORTS 1
The given number of output ports must be 0, 1 or 2. Zero means that MIDI output is disabled (which is the default). You may want to use `JACK_PORTS 1` if the configuration is primarily aimed at doing MIDI translations, so you'd like to have MIDI output enabled by default. `JACK_PORTS 2` or the `-o2` option indicates that *two* pairs of input and output ports are to be created. The second port is typically used to deal with controller feedback from the application, see the *MIDI Feedback* section for details.
Not very surprisingly, at least one output port is needed if you want to output any MIDI at all; otherwise MIDI messages on the right-hand side of translations will be silently ignored. Also note that midizap doesn't provide you with any options to actually connect the ports you created to other Jack MIDI clients. There already are plenty of excellent utilities specifically designed for this purpose, so there's no need to replicate that functionality in midizap. As already mentioned, we recommend using QjackCtl, which also offers a persistent MIDI patchbay, so that you can have the right connections automatically set up for you whenever you launch midizap. You then use the Jack client name option if you need to distinguish multiple midizap instances. (The examples folder in the sources contains a QjackCtl patchbay named midizap.xml which has been set up to work with any of the included examples. Use the "Load" button in QjackCtl's Patchbay dialog to load it, then hit the "Activate" button to have QjackCtl actually use it.)
Not very surprisingly, at least one output port is needed if you want to output any MIDI at all; otherwise MIDI messages on the right-hand side of translations will be silently ignored.
## MIDI Connections
Setting up all the required connections for the Jack MIDI ports can be a tedious and error-prone task, especially if you have to deal with complex setups involving feedback and/or multiple midizap instances. It's all to easy to mess this up when doing it manually, and either end up with a dysfunctional setup or, even worse, MIDI feedback loops crashing your Jack MIDI clients. While it's possible to automatize the MIDI connections, e.g., with QjackCtl's persistent MIDI patchbay facility, this is often inconvenient if you need to accommodate multiple midizap configurations and you already have a complicated studio setup which you don't want to mess with.
As a remedy, midizap offers its own built-in patchbay functionality using the `JACK_IN` and `JACK_OUT` directives, which let you specify the required connections in the configuration itself and be done with it. The port number is tacked on to the directive, so, e.g., `JACK_IN2` connects the second input port (if the port number is omitted then the first port is assumed). The directive is followed by an (extended) regular expression (see the regex(7) manual page) to be matched against the Jack MIDI ports of your devices and applications. A connection will be established automatically by midizap whenever a Jack MIDI port matches the regular expression, as well as the port type and I/O direction. This also works dynamically, as new devices get added and new applications are launched at runtime.
For instance, the following lines (from the XTouchONE.midizaprc example) connect midizap to an X-Touch One device on one side and Ardour's Mackie control port on the other:
~~~
JACK_IN1 X-Touch One MIDI 1
JACK_OUT1 ardour:mackie control in
JACK_IN2 ardour:mackie control out
JACK_OUT2 X-Touch One MIDI 1
~~~
To break this down, the X-Touch One device will be connected to midizap's first input port, midizap's first output port to Ardour's Mackie control input, Ardour's Mackie control output to midizap's second input port, and midizap's second output port back to the device. This is a typical setup for bidirectional communication between controller and application as described in the *MIDI Feedback* section. The sample configurations in the examples folder in the sources have all been set up in this manner, so that they will create the required connections automatically.
Please note that at this time, the built-in patchbay is only available through these directives, there are no corresponding command line options. Also, only one directive can be specified for each port, but since midizap will connect to all ports matching the given regular expression, you can connect to more than one application or device by just listing all the alternatives. For instance, to have midizap's output connected to both Ardour and Pd, you might use a directive like:
~~~
JACK_OUT1 ardour:MIDI control in|Pure Data Midi-In 1
~~~
## Pass-Through
If at least one output port is available then it also becomes possible to pass through MIDI messages from input to output unchanged. Two options are available for this: `-t` which passes through any ordinary (non-system) message for which there are no translations (not even in the default section), and `-s` which passes through all system messages. The former is convenient if the incoming MIDI data only needs to be modified in a few places to deal with slight variations in the protocol. The latter may be needed when the input data may contain system messages; midizap cannot translate these, but it can pass them on unchanged when necessary. You can find examples for both use cases in the examples folder in the sources.
The corresponding directives are named `PASSTHROUGH` and `SYSTEM_PASSTHROUGH`, respectively. In either case, you can optionally specify which port the pass-through should apply to (0 means none, 1 the first, 2 the second port; if no number is given, both ports are used). For instance, if you only need system pass-through on the feedback port, you might write `SYSTEM_PASSTHROUGH 2`, or use the `-s2` option on the command line; and to have unrecognized MIDI messages passed through in either direction, simply use `PASSTHROUGH`, or `-t`.
Note that all these options can only be set at program startup. If you later edit the corresponding directives in the configuration file, the changes won't take effect until you restart the program.
## Jack Sessions
midizap also supports *Jack session management*, which makes it possible to record the options the program was invoked with, along with all the MIDI connections. QjackCtl has its own built-in Jack session manager which is available in its Session dialog. To use this, launch midizap and any other Jack applications you want to have in the session, use QjackCtl to set up all the connections as needed, and then hit the "Save" button in the Session dialog to have the session recorded. Now, at any later time you can rerun the recorded session with the "Load" button in the same dialog. Also, your most recent sessions are available in the "Recent" menu from where they can be launched quickly.
midizap also supports *Jack session management* which provides a convenient alternative way to launch your midizap instances. Once you've finished a configuration, instead of running midizap manually each time you need it, you just invoke it once with the right command line options, and use a Jack session management program to record the session. The session manager can then be used to relaunch the program with the same options later.
Various Jack session managers are available for Linux, but if you're running QjackCtl already, you might just as well use it to record your sessions, too. QjackCtl's built-in Jack session manager is available in its Session dialog. To use it, launch midizap and any other Jack applications you want to have in the session, use QjackCtl to set up all the connections as needed, and then hit the "Save" button in the Session dialog to have the session recorded. Now, at any later time you can rerun the recorded session with the "Load" button in the same dialog. Also, your most recent sessions are available in the "Recent" menu from where they can be launched quickly.
## Realtime Priorities
Finally, midizap also offers an option to run the program with *real-time priorities*. Jack itself usually does that anyway where needed, but midizap's main thread won't unless you run it with the `-P` option (`midizap -P`, or `midizap -P80` if you also want to specify the priority). Using this option, midizap should be able to get down to MIDI latencies in the 1 msec ballpark which should be good enough for most purposes. (Note that there's no need to use this option unless you actually notice high latencies or jitter in the MIDI output.)
@ -189,7 +222,7 @@ 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.
Lines beginning with a `[`*name*`]` header are also special. Each such line introduces a translation class *name*, which may be followed by an extended regular expression *regex* (see the regex(7) manual page) to be matched against window class and title. A `CLASS` or `TITLE` token may precede *regex* to indicate that *only* the class or title is to be matched, respectively; otherwise both are matched. Note that the *regex* part is always taken verbatim, ignoring leading and trailing whitespace, but including embedded whitespace and `#` characters (so you can't place a comment on such lines).
Lines beginning with a `[`*name*`]` header are also special. Each such line introduces a translation class *name*, which may be followed by an extended regular expression *regex* to be matched against window class and title. A `CLASS` or `TITLE` token may precede *regex* to indicate that *only* the class or title is to be matched, respectively; otherwise both are matched. Note that the *regex* part is always taken verbatim, ignoring leading and trailing whitespace, but including embedded whitespace and `#` characters (so you can't place a comment on such lines).
To find a set of eligible translations, midizap matches class and/or title of the window with the keyboard focus against each section, in the order in which they are listed in the configuration file. If neither `CLASS` nor `TITLE` is specified, then both are tried; in this case, midizap first tries to match the window class (the `WM_CLASS` property), then the window title (the `WM_NAME` property). The first section which matches determines the translations to be used for that window. An empty *regex* for the last class will always match, allowing default translations. If a translation cannot be found in the matched section, it will be loaded from the default section if possible. In addition, there are two special default sections labeled `[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 given *name* is only used for debugging output and diagnostics, and needn't be unique.
@ -878,6 +911,10 @@ translation ::= midi-token { key-token | midi-token }
directive ::= "DEBUG_REGEX" | "DEBUG_STROKES" | "DEBUG_KEYS" |
"DEBUG_MIDI" | "MIDI_OCTAVE" number |
"JACK_NAME" string | "JACK_PORTS" number |
"JACK_IN" regex | "JACK_OUT" regex |
"JACK_IN1" regex | "JACK_OUT1" regex |
"JACK_IN2" regex | "JACK_OUT2" regex |
"PASSTHROUGH" [ number ] |
"SYSTEM_PASSTHROUGH" [ number ]
midi-token ::= msg [ mod ] [ steps ] [ "-" number] [ flag ]

View File

@ -19,7 +19,15 @@ JACK_PORTS 2
# SETUP: In Ardour, enable the Mackie control surface, then connect Ardour's
# Mackie control ports to midizap's midi_out and midi_in2 ports, and the
# APCmini to midizap's midi_in and midi_out2 ports.
# APCmini to midizap's midi_in and midi_out2 ports. The following lines will
# take care of setting up all the connections automatically, but you still
# need to enable the Mackie control surface in Ardour, so that Ardour exposes
# the Mackie control ports.
JACK_IN1 APC MINI MIDI 1
JACK_IN2 ardour:mackie control out
JACK_OUT1 ardour:mackie control in
JACK_OUT2 APC MINI MIDI 1
# PROTOCOL DOCUMENTATION: The Mackie protocol is fairly ubiquitous, but since
# manufacturers can't be bothered to properly *document* their stuff these
@ -206,8 +214,7 @@ CC69[] F7{0:49,1,0} E7{0:50,1,0} Eb7{0:51,1,0} D7{0:52,1,0}
# no feedback for faders (faders aren't motorized)
# NOTE: Feedback for rec/solo/mute/select also needs to be recognized in shift
# mode, so that the (shifted) bank/channel left/right keys work as expected.
# feedback for rec/solo/mute/select
# rec: color = red (vel. 3)
C0 C0[3]

View File

@ -11,14 +11,17 @@
JACK_NAME "midizap-MPKmini2"
JACK_PORTS 1
# Auto-connect to the MPKMini2 on the input, and Ardour's Mackie control input
# on the output side.
JACK_IN MPKmini2 MIDI 1
JACK_OUT ardour:mackie control in
# This configuration assumes that the MPKmini2 is set to factory defaults.
# The device doesn't provide much feedback possibilities, so we don't even
# try. Connections: Controller goes into midizap midi_in, midi_out into the
# Mackie control input of your DAW.
# Controls: The joystick can be used as a shuttle control (push to the left
# for rewind, to the right for fast forward). The eight knobs are mapped to
# the channel volume controls. The drum pads are assigned as follows, with
# try. Controls: The joystick can be used as a shuttle control (push to the
# left for rewind, to the right for fast forward). The eight knobs are mapped
# to the channel volume controls. The drum pads are assigned as follows, with
# the transport section on bank A and the cursor and bank controls on bank B:
# Bank A: Pad 1-4: Stop Play Rec Cycle; Pad 5-8: Rew FFwd Click Marker

View File

@ -12,6 +12,12 @@ JACK_NAME "midizap-Maschine"
JACK_PORTS 2
SYSTEM_PASSTHROUGH # pass through MCP feedback
# automatic connections
JACK_IN1 Ctlra Maschine Mk3
JACK_IN2 ardour:mackie control out
JACK_OUT1 ardour:mackie control in
JACK_OUT2 Ctlra Maschine Mk3
# NOTE: At present, this controller isn't properly supported by ALSA, but it
# can be made to work in Linux with Harry van Haaren's Ctlra software.
# Specifically, you'll need the ctlra_daemonx program from the
@ -22,10 +28,11 @@ SYSTEM_PASSTHROUGH # pass through MCP feedback
# branch, you can run the following to install the libctlra library along with
# ctlra_daemonx: meson build && cd build && ninja && sudo ninja install
# Then run ctlra_daemonx -fnm alongside with midizap, and connect the ports as
# follows: Ctlra Maschine Mk3 -> midizap midi_in / midi_out -> Ardour mackie
# control in / mackie control out -> midizap midi_in2 / midi_out2 -> Ctlra
# Maschine Mk3.
# Then run ctlra_daemonx -fnm alongside with midizap, and check that the ports
# are connected as follows (the JACK_IN/OUT directives above should take care
# of this automagically): Ctlra Maschine Mk3 -> midizap midi_in / midi_out ->
# Ardour mackie control in / mackie control out -> midizap midi_in2 /
# midi_out2 -> Ctlra Maschine Mk3.
# Usage (executive summary):

View File

@ -17,10 +17,8 @@ This folder contains a couple of sample midizap configurations for different con
Other interesting items:
- [midizap.xml](midizap.xml): ready-to-use QjackCtl patchbay for all the sample configurations, auto-connects to Ardour
Installation: Open QjackCtl's Patchbay dialog, load the midizap.xml file and activate the patchbay. To connect with Ardour, you also need to enable the Mackie control surface in Ardour's preferences dialog.
- [x-touch-one.device](x-touch-one.device): X-Touch ONE device description for Ardour 5.12 (this is basically the X-Touch description with a bank size of 1, so that all tracks become accessible)
Installation: Copy the x-touch-one.device file to your ~/.config/ardour5/mcp/ directory and select "Behringer X-Touch ONE" as your Mackie control surface in Ardour's preferences dialog.
Note: You can also use my patched-up version of Ardour 5.12 instead, which fixes up the single-channel bank changes so that the X-Touch ONE will work nicely with Ardour *without* having to set the bank size to 1 (which will be problematic if you use the ONE in combination with other Mackie controllers which require a larger bank size). You can find the sources here: https://github.com/agraef/ardour/tree/5.12-ag-mcpfixes. Make sure to check out the 5.12-ag-mcpfixes branch. This also has a few other bugfixes in the MCP code which will become available with Ardour 6.0, but aren't in the upstream 5.12 tree.

View File

@ -13,6 +13,12 @@
JACK_NAME "midizap-XTouchMini"
JACK_PORTS 2
# automatic connections
JACK_IN1 X-TOUCH MINI MIDI 1
JACK_IN2 ardour:mackie control out
JACK_OUT1 ardour:mackie control in
JACK_OUT2 X-TOUCH MINI MIDI 1
# Pass everything through, except for the translations below.
PASSTHROUGH
@ -30,7 +36,7 @@ SYSTEM_PASSTHROUGH
# as follows (with the shifted bindings given above and below in parentheses;
# these become active when holding down the MC/SHIFT key):
# (SELECT) ... (MARKER)
# (SELECT) (SELECT) ... (MARKER)
# [CLICK] [SOLO] [TRACK] [SEND] [PAN] [PLUGIN] [EQ] [INST] [BANK LEFT]
# [SHIFT] [REPLACE] [REW] [FFWD] [LOOP] [STOP] [PLAY] [REC] [BANK RIGHT]
# (DROP) (NUDGE)
@ -84,11 +90,10 @@ C#7 B3 # bank right
A#3 C7
B3 C#7
# NOTE: We might also want to provide some actual feedback for the *shifted*
# faders here in the future, so that the current values are shown in the LED
# rings of the encoders while the faders are being operated.
# dummy feedback for the faders, to take advantage of automatic feedback
# (see the alternative XTouchMini2.midizaprc configuration for some more
# comprehensive bindings which do some actual feedback using the LED rings
# of the encoders)
PB[]-1 NOP
PB[]-2 NOP
PB[]-3 NOP

View File

@ -1,7 +1,7 @@
# This is essentially the same as XTouchMini.midizaprc, but it assigns the
# shifted A/B keys to channel left/right, and also provides some other useful
# additional bindings on the SHIFT layer.
# additional bindings and feedback on the SHIFT layer.
# Copyright (c) 2018 Albert Graef <aggraef@gmail.com>
@ -13,14 +13,20 @@
JACK_NAME "midizap-XTouchMini"
JACK_PORTS 2
# automatic connections
JACK_IN1 X-TOUCH MINI MIDI 1
JACK_IN2 ardour:mackie control out
JACK_OUT1 ardour:mackie control in
JACK_OUT2 X-TOUCH MINI MIDI 1
# Pass everything through, except for the translations below.
PASSTHROUGH
SYSTEM_PASSTHROUGH
# As with XTouchMini.midizaprc, [MC] is the shift key, holding it while
# pressing a button or operating the encoders or the fader provides additional
# MC functions. The other controls are assigned as usual in unshifted state,
# As with XTouchMini.midizaprc, the MC button is the shift key, holding it
# while pressing a button or operating the encoders provides additional MC
# functions. The other controls are assigned as usual in unshifted state,
# except that the A/B keys switch banks. When shifted, the master fader is
# assigned to the first channel, like on the X-Touch ONE, and the encoders
# become the eight channel faders. The bindings of the buttons are shown

View File

@ -12,6 +12,12 @@
JACK_NAME "midizap-XTouchONE"
JACK_PORTS 2
# automatic connections
JACK_IN1 X-Touch One MIDI 1
JACK_IN2 ardour:mackie control out
JACK_OUT1 ardour:mackie control in
JACK_OUT2 X-Touch One MIDI 1
# Pass everything through, except for the one mapping below.
PASSTHROUGH
SYSTEM_PASSTHROUGH

View File

@ -14,6 +14,12 @@
JACK_NAME "midizap-XTouchONE"
JACK_PORTS 2
# automatic connections
JACK_IN1 X-Touch One MIDI 1
JACK_IN2 ardour:mackie control out
JACK_OUT1 ardour:mackie control in
JACK_OUT2 X-Touch One MIDI 1
# Pass everything through, except for the mappings below.
PASSTHROUGH
SYSTEM_PASSTHROUGH
@ -22,9 +28,9 @@ SYSTEM_PASSTHROUGH
# NOTE: This assumes that you use the default Mackie mode of the ONE.
# Otherwise you will have to adjust the mapping accordingly. I use the SCRUB
# key (F8 in MC mode) as a SHIFT key replacement, because I don't need that
# function (it's not available in Ardour yet). If you need that key, you'll
# have to use another one that you can spare.
# key (F8 in MC mode) as the SHIFT key, because I don't need that function
# (it's not available in Ardour yet). If you need that key, you'll have to use
# another one that you can spare.
F8 SHIFT ^F8 RELEASE SHIFT ^F8
@ -32,7 +38,7 @@ F8 SHIFT ^F8 RELEASE SHIFT ^F8
# the most important encoder assignment keys here, but of course you can
# change them to anything you want.
^F#4 E3 # Track (Trim)
^F#4 E3 # Track (Trim in Ardour)
^G4 F#3 # Pan
^G#4 F3 # Send
^A4 G3 # Plugin (not supported by Ardour)

View File

@ -1,150 +0,0 @@
<!DOCTYPE patchbay>
<patchbay name="midizap" version="0.5.4">
<output-sockets>
<socket type="jack-midi" name="Ctlra Maschine" exclusive="off" client="a2j">
<plug>Ctlra Maschine Mk3.*</plug>
</socket>
<socket type="jack-midi" name="midizap-Maschine" exclusive="off" client="midizap-Maschine">
<plug>midi_out</plug>
</socket>
<socket type="jack-midi" name="midizap-Maschine 2" exclusive="off" client="midizap-Maschine">
<plug>midi_out2</plug>
</socket>
<socket type="jack-midi" name="Ardour mackie out" exclusive="off" client="ardour">
<plug>mackie control out</plug>
</socket>
<socket type="jack-midi" name="nanoKONTROL2" exclusive="off" client="a2j">
<plug>nanoKONTROL2.* MIDI 1</plug>
</socket>
<socket type="jack-midi" name="midizap-nanoKONTROL 1" exclusive="off" client="midizap-nanoKONTROL2">
<plug>midi_out</plug>
</socket>
<socket type="jack-midi" name="midizap-nanoKONTROL 2" exclusive="off" client="midizap-nanoKONTROL2">
<plug>midi_out2</plug>
</socket>
<socket type="jack-midi" name="X-Touch" exclusive="off" client="a2j">
<plug>.*X-Touch MIDI 1</plug>
</socket>
<socket type="jack-midi" name="X-Touch MINI" exclusive="off" client="a2j">
<plug>.*X-TOUCH MINI MIDI 1</plug>
</socket>
<socket type="jack-midi" name="midizap-XTouchMini 1" exclusive="off" client="midizap-XTouchMini">
<plug>midi_out</plug>
</socket>
<socket type="jack-midi" name="midizap-XTouchMini 2" exclusive="off" client="midizap-XTouchMini">
<plug>midi_out2</plug>
</socket>
<socket type="jack-midi" name="X-Touch One" exclusive="off" client="a2j">
<plug>X-Touch One.* MIDI 1</plug>
</socket>
<socket type="jack-midi" name="midizap-XTouchONE 1" exclusive="off" client="midizap-XTouchONE">
<plug>midi_out</plug>
</socket>
<socket type="jack-midi" name="midizap-XTouchONE 2" exclusive="off" client="midizap-XTouchONE">
<plug>midi_out2</plug>
</socket>
<socket type="jack-midi" name="APCmini" exclusive="off" client="a2j">
<plug>APC MINI.* MIDI 1</plug>
</socket>
<socket type="jack-midi" name="midizap-APCmini 1" exclusive="off" client="midizap-APCmini">
<plug>midi_out</plug>
</socket>
<socket type="jack-midi" name="midizap-APCmini 2" exclusive="off" client="midizap-APCmini">
<plug>midi_out2</plug>
</socket>
<socket type="jack-midi" name="MPKmini2" exclusive="off" client="a2j">
<plug>MPKmini2.* MIDI 1</plug>
</socket>
<socket type="jack-midi" name="midizap-MPKmini 1" exclusive="off" client="midizap-MPKmini2">
<plug>midi_out</plug>
</socket>
<socket type="jack-midi" name="shuttlepro" exclusive="off" client="shuttlepro">
<plug>midi_out</plug>
</socket>
</output-sockets>
<input-sockets>
<socket type="jack-midi" name="midizap-Maschine" exclusive="off" client="midizap-Maschine">
<plug>midi_in</plug>
</socket>
<socket type="jack-midi" name="midizap-Maschine 2" exclusive="off" client="midizap-Maschine">
<plug>midi_in2</plug>
</socket>
<socket type="jack-midi" name="Ctlra Maschine" exclusive="off" client="a2j">
<plug>Ctlra Maschine Mk3.*</plug>
</socket>
<socket type="jack-midi" name="Ardour mackie in" exclusive="off" client="ardour">
<plug>mackie control in</plug>
</socket>
<socket type="jack-midi" name="midizap-nanoKONTROL 1" exclusive="off" client="midizap-nanoKONTROL2">
<plug>midi_in</plug>
</socket>
<socket type="jack-midi" name="midizap-nanoKONTROL 2" exclusive="off" client="midizap-nanoKONTROL2">
<plug>midi_in2</plug>
</socket>
<socket type="jack-midi" name="nanoKONTROL2" exclusive="off" client="a2j">
<plug>nanoKONTROL2.* MIDI 1</plug>
</socket>
<socket type="jack-midi" name="X-Touch" exclusive="off" client="a2j">
<plug>.*X-Touch MIDI 1</plug>
</socket>
<socket type="jack-midi" name="midizap-XTouchMini 1" exclusive="off" client="midizap-XTouchMini">
<plug>midi_in</plug>
</socket>
<socket type="jack-midi" name="midizap-XTouchMini 2" exclusive="off" client="midizap-XTouchMini">
<plug>midi_in2</plug>
</socket>
<socket type="jack-midi" name="X-Touch MINI" exclusive="off" client="a2j">
<plug>.*X-TOUCH MINI MIDI 1</plug>
</socket>
<socket type="jack-midi" name="midizap-XTouchONE 1" exclusive="off" client="midizap-XTouchONE">
<plug>midi_in</plug>
</socket>
<socket type="jack-midi" name="midizap-XTouchONE 2" exclusive="off" client="midizap-XTouchONE">
<plug>midi_in2</plug>
</socket>
<socket type="jack-midi" name="X-Touch One" exclusive="off" client="a2j">
<plug>X-Touch One.* MIDI 1</plug>
</socket>
<socket type="jack-midi" name="midizap-APCmini 1" exclusive="off" client="midizap-APCmini">
<plug>midi_in</plug>
</socket>
<socket type="jack-midi" name="midizap-APCmini 2" exclusive="off" client="midizap-APCmini">
<plug>midi_in2</plug>
</socket>
<socket type="jack-midi" name="APCmini" exclusive="off" client="a2j">
<plug>APC MINI.* MIDI 1</plug>
</socket>
<socket type="jack-midi" name="midizap-MPKmini 1" exclusive="off" client="midizap-MPKmini2">
<plug>midi_in</plug>
</socket>
</input-sockets>
<slots/>
<cables>
<cable type="jack-midi" output="Ctlra Maschine" input="midizap-Maschine"/>
<cable type="jack-midi" output="midizap-Maschine" input="Ardour mackie in"/>
<cable type="jack-midi" output="midizap-Maschine 2" input="Ctlra Maschine"/>
<cable type="jack-midi" output="Ardour mackie out" input="midizap-Maschine 2"/>
<cable type="jack-midi" output="Ardour mackie out" input="X-Touch"/>
<cable type="jack-midi" output="Ardour mackie out" input="midizap-APCmini 2"/>
<cable type="jack-midi" output="Ardour mackie out" input="midizap-XTouchONE 2"/>
<cable type="jack-midi" output="Ardour mackie out" input="midizap-nanoKONTROL 2"/>
<cable type="jack-midi" output="Ardour mackie out" input="midizap-XTouchMini 2"/>
<cable type="jack-midi" output="nanoKONTROL2" input="midizap-nanoKONTROL 1"/>
<cable type="jack-midi" output="midizap-nanoKONTROL 1" input="Ardour mackie in"/>
<cable type="jack-midi" output="midizap-nanoKONTROL 2" input="nanoKONTROL2"/>
<cable type="jack-midi" output="X-Touch" input="Ardour mackie in"/>
<cable type="jack-midi" output="X-Touch One" input="midizap-XTouchONE 1"/>
<cable type="jack-midi" output="midizap-XTouchONE 1" input="Ardour mackie in"/>
<cable type="jack-midi" output="midizap-XTouchONE 2" input="X-Touch One"/>
<cable type="jack-midi" output="APCmini" input="midizap-APCmini 1"/>
<cable type="jack-midi" output="midizap-APCmini 1" input="Ardour mackie in"/>
<cable type="jack-midi" output="midizap-APCmini 2" input="APCmini"/>
<cable type="jack-midi" output="MPKmini2" input="midizap-MPKmini 1"/>
<cable type="jack-midi" output="midizap-MPKmini 1" input="Ardour mackie in"/>
<cable type="jack-midi" output="shuttlepro" input="Ardour mackie in"/>
<cable type="jack-midi" output="X-Touch MINI" input="midizap-XTouchMini 1"/>
<cable type="jack-midi" output="midizap-XTouchMini 1" input="Ardour mackie in"/>
<cable type="jack-midi" output="midizap-XTouchMini 2" input="X-Touch MINI"/>
</cables>
</patchbay>

View File

@ -1,150 +0,0 @@
<!DOCTYPE patchbay>
<patchbay name="midizap" version="0.5.4">
<output-sockets>
<socket type="jack-midi" name="Ctlra Maschine" exclusive="off" client="alsa_midi">
<plug>Ctlra Maschine Mk3.*</plug>
</socket>
<socket type="jack-midi" name="midizap-Maschine" exclusive="off" client="midizap-Maschine">
<plug>midi_out</plug>
</socket>
<socket type="jack-midi" name="midizap-Maschine 2" exclusive="off" client="midizap-Maschine">
<plug>midi_out2</plug>
</socket>
<socket type="jack-midi" name="Ardour mackie out" exclusive="off" client="ardour">
<plug>mackie control out</plug>
</socket>
<socket type="jack-midi" name="nanoKONTROL2" exclusive="off" client="alsa_midi">
<plug>nanoKONTROL2.* MIDI 1.*</plug>
</socket>
<socket type="jack-midi" name="midizap-nanoKONTROL 1" exclusive="off" client="midizap-nanoKONTROL2">
<plug>midi_out</plug>
</socket>
<socket type="jack-midi" name="midizap-nanoKONTROL 2" exclusive="off" client="midizap-nanoKONTROL2">
<plug>midi_out2</plug>
</socket>
<socket type="jack-midi" name="X-Touch" exclusive="off" client="alsa_midi">
<plug>.*X-Touch MIDI 1.*</plug>
</socket>
<socket type="jack-midi" name="X-Touch MINI" exclusive="off" client="alsa_midi">
<plug>.*X-TOUCH MINI MIDI 1.*</plug>
</socket>
<socket type="jack-midi" name="midizap-XTouchMini 1" exclusive="off" client="midizap-XTouchMini">
<plug>midi_out</plug>
</socket>
<socket type="jack-midi" name="midizap-XTouchMini 2" exclusive="off" client="midizap-XTouchMini">
<plug>midi_out2</plug>
</socket>
<socket type="jack-midi" name="X-Touch One" exclusive="off" client="alsa_midi">
<plug>X-Touch One.* MIDI 1.*</plug>
</socket>
<socket type="jack-midi" name="midizap-XTouchONE 1" exclusive="off" client="midizap-XTouchONE">
<plug>midi_out</plug>
</socket>
<socket type="jack-midi" name="midizap-XTouchONE 2" exclusive="off" client="midizap-XTouchONE">
<plug>midi_out2</plug>
</socket>
<socket type="jack-midi" name="APCmini" exclusive="off" client="alsa_midi">
<plug>APC MINI.* MIDI 1.*</plug>
</socket>
<socket type="jack-midi" name="midizap-APCmini 1" exclusive="off" client="midizap-APCmini">
<plug>midi_out</plug>
</socket>
<socket type="jack-midi" name="midizap-APCmini 2" exclusive="off" client="midizap-APCmini">
<plug>midi_out2</plug>
</socket>
<socket type="jack-midi" name="MPKmini2" exclusive="off" client="alsa_midi">
<plug>MPKmini2.* MIDI 1.*</plug>
</socket>
<socket type="jack-midi" name="midizap-MPKmini 1" exclusive="off" client="midizap-MPKmini2">
<plug>midi_out</plug>
</socket>
<socket type="jack-midi" name="shuttlepro" exclusive="off" client="shuttlepro">
<plug>midi_out</plug>
</socket>
</output-sockets>
<input-sockets>
<socket type="jack-midi" name="midizap-Maschine" exclusive="off" client="midizap-Maschine">
<plug>midi_in</plug>
</socket>
<socket type="jack-midi" name="midizap-Maschine 2" exclusive="off" client="midizap-Maschine">
<plug>midi_in2</plug>
</socket>
<socket type="jack-midi" name="Ctlra Maschine" exclusive="off" client="alsa_midi">
<plug>Ctlra Maschine Mk3.*</plug>
</socket>
<socket type="jack-midi" name="Ardour mackie in" exclusive="off" client="ardour">
<plug>mackie control in</plug>
</socket>
<socket type="jack-midi" name="midizap-nanoKONTROL 1" exclusive="off" client="midizap-nanoKONTROL2">
<plug>midi_in</plug>
</socket>
<socket type="jack-midi" name="midizap-nanoKONTROL 2" exclusive="off" client="midizap-nanoKONTROL2">
<plug>midi_in2</plug>
</socket>
<socket type="jack-midi" name="nanoKONTROL2" exclusive="off" client="alsa_midi">
<plug>nanoKONTROL2.* MIDI 1.*</plug>
</socket>
<socket type="jack-midi" name="X-Touch" exclusive="off" client="alsa_midi">
<plug>.*X-Touch MIDI 1.*</plug>
</socket>
<socket type="jack-midi" name="midizap-XTouchMini 1" exclusive="off" client="midizap-XTouchMini">
<plug>midi_in</plug>
</socket>
<socket type="jack-midi" name="midizap-XTouchMini 2" exclusive="off" client="midizap-XTouchMini">
<plug>midi_in2</plug>
</socket>
<socket type="jack-midi" name="X-Touch MINI" exclusive="off" client="alsa_midi">
<plug>.*X-TOUCH MINI MIDI 1.*</plug>
</socket>
<socket type="jack-midi" name="midizap-XTouchONE 1" exclusive="off" client="midizap-XTouchONE">
<plug>midi_in</plug>
</socket>
<socket type="jack-midi" name="midizap-XTouchONE 2" exclusive="off" client="midizap-XTouchONE">
<plug>midi_in2</plug>
</socket>
<socket type="jack-midi" name="X-Touch One" exclusive="off" client="alsa_midi">
<plug>X-Touch One.* MIDI 1.*</plug>
</socket>
<socket type="jack-midi" name="midizap-APCmini 1" exclusive="off" client="midizap-APCmini">
<plug>midi_in</plug>
</socket>
<socket type="jack-midi" name="midizap-APCmini 2" exclusive="off" client="midizap-APCmini">
<plug>midi_in2</plug>
</socket>
<socket type="jack-midi" name="APCmini" exclusive="off" client="alsa_midi">
<plug>APC MINI.* MIDI 1.*</plug>
</socket>
<socket type="jack-midi" name="midizap-MPKmini 1" exclusive="off" client="midizap-MPKmini2">
<plug>midi_in</plug>
</socket>
</input-sockets>
<slots/>
<cables>
<cable type="jack-midi" output="Ctlra Maschine" input="midizap-Maschine"/>
<cable type="jack-midi" output="midizap-Maschine" input="Ardour mackie in"/>
<cable type="jack-midi" output="midizap-Maschine 2" input="Ctlra Maschine"/>
<cable type="jack-midi" output="Ardour mackie out" input="midizap-Maschine 2"/>
<cable type="jack-midi" output="Ardour mackie out" input="X-Touch"/>
<cable type="jack-midi" output="Ardour mackie out" input="midizap-APCmini 2"/>
<cable type="jack-midi" output="Ardour mackie out" input="midizap-XTouchONE 2"/>
<cable type="jack-midi" output="Ardour mackie out" input="midizap-nanoKONTROL 2"/>
<cable type="jack-midi" output="Ardour mackie out" input="midizap-XTouchMini 2"/>
<cable type="jack-midi" output="nanoKONTROL2" input="midizap-nanoKONTROL 1"/>
<cable type="jack-midi" output="midizap-nanoKONTROL 1" input="Ardour mackie in"/>
<cable type="jack-midi" output="midizap-nanoKONTROL 2" input="nanoKONTROL2"/>
<cable type="jack-midi" output="X-Touch" input="Ardour mackie in"/>
<cable type="jack-midi" output="X-Touch One" input="midizap-XTouchONE 1"/>
<cable type="jack-midi" output="midizap-XTouchONE 1" input="Ardour mackie in"/>
<cable type="jack-midi" output="midizap-XTouchONE 2" input="X-Touch One"/>
<cable type="jack-midi" output="APCmini" input="midizap-APCmini 1"/>
<cable type="jack-midi" output="midizap-APCmini 1" input="Ardour mackie in"/>
<cable type="jack-midi" output="midizap-APCmini 2" input="APCmini"/>
<cable type="jack-midi" output="MPKmini2" input="midizap-MPKmini 1"/>
<cable type="jack-midi" output="midizap-MPKmini 1" input="Ardour mackie in"/>
<cable type="jack-midi" output="shuttlepro" input="Ardour mackie in"/>
<cable type="jack-midi" output="X-Touch MINI" input="midizap-XTouchMini 1"/>
<cable type="jack-midi" output="midizap-XTouchMini 1" input="Ardour mackie in"/>
<cable type="jack-midi" output="midizap-XTouchMini 2" input="X-Touch MINI"/>
</cables>
</patchbay>

View File

@ -13,6 +13,12 @@
JACK_NAME "midizap-nanoKONTROL2"
JACK_PORTS 2
# automatic connections
JACK_IN1 nanoKONTROL2 MIDI 1
JACK_IN2 ardour:mackie control out
JACK_OUT1 ardour:mackie control in
JACK_OUT2 nanoKONTROL2 MIDI 1
# Pass everything through (including feedback), except for the mappings below.
PASSTHROUGH

View File

@ -443,9 +443,103 @@ connect_callback(jack_port_id_t a, jack_port_id_t b, int yn, void *seqq)
(yn ? "connected to" : "disconnected from"), aname);
}
// queue for pending connections, to be processed in the main thread
#define CONN_SIZE 256
static int n_inconn, n_outconn;
static struct {
int portno;
char *name;
} inconn[CONN_SIZE], outconn[CONN_SIZE];
static void add_inconn(int portno, const char *name)
{
if (n_inconn < CONN_SIZE) {
inconn[n_inconn].portno = portno;
inconn[n_inconn].name = strdup(name);
n_inconn++;
}
}
static void add_outconn(int portno, const char *name)
{
if (n_outconn < CONN_SIZE) {
outconn[n_outconn].portno = portno;
outconn[n_outconn].name = strdup(name);
n_outconn++;
}
}
static void match_connections(JACK_SEQ* seq, jack_port_t *port)
{
if (jack_port_is_mine(seq->jack_client, port)) return;
int flags = jack_port_flags(port);
const char *name = jack_port_name(port);
if (flags & JackPortIsInput) {
// Try to match the port name to one of our out regexes.
for (int i = 0; i < 2 && i < seq->n_out; i++) {
if (seq->out[i] && regexec(&seq->outre[i], name, 0, 0, 0) == 0 &&
// check that port types are compatible
jack_port_type(seq->output_port[i]) == jack_port_type(port) &&
// check that we're not connected yet
!jack_port_connected_to(seq->output_port[i], name)) {
// we can't connect right here, that has to be done in the main
// thread, so we simply store the request for later
add_outconn(i, name);
}
}
} else if (flags & JackPortIsOutput) {
// Try to match the port name to one of our in regexes.
for (int i = 0; i < 2 && i < seq->n_in; i++) {
if (seq->in[i] && regexec(&seq->inre[i], name, 0, 0, 0) == 0 &&
// check that port types are compatible
jack_port_type(seq->input_port[i]) == jack_port_type(port) &&
// check that we're not connected yet
!jack_port_connected_to(seq->input_port[i], name)) {
add_inconn(i, name);
}
}
}
}
void
registration_callback(jack_port_id_t id, int reg, void *seqq)
{
if (!reg) return;
JACK_SEQ* seq = (JACK_SEQ*)seqq;
jack_port_t *port = jack_port_by_id(seq->jack_client, id);
match_connections(seq, port);
}
////////////////////////////////
//this is run in the main thread
////////////////////////////////
void process_connections(JACK_SEQ* seq)
{
int i;
for (i = 0; i < n_inconn; i++)
if (inconn[i].name) {
if (jack_connect(seq->jack_client,
inconn[i].name,
jack_port_name(seq->input_port[inconn[i].portno])))
fprintf(stderr, "error trying to connect in%d to %s\n",
inconn[i].portno, inconn[i].name);
free(inconn[i].name);
}
n_inconn = 0;
for (i = 0; i < n_outconn; i++)
if (outconn[i].name) {
if (jack_connect(seq->jack_client,
jack_port_name(seq->output_port[outconn[i].portno]),
outconn[i].name))
fprintf(stderr, "error trying to connect out%d to %s\n",
outconn[i].portno, outconn[i].name);
free(outconn[i].name);
}
n_outconn = 0;
}
int
init_jack(JACK_SEQ* seq, uint8_t verbose)
{
@ -454,6 +548,36 @@ init_jack(JACK_SEQ* seq, uint8_t verbose)
*client_name = seq->client_name?seq->client_name:"midizap";
jack_status_t status;
// compile the in/out connection regexes
for (int i = 0; i < 2; i++) {
if (seq->in[i] && *seq->in[i]) {
int err = regcomp(&seq->inre[i], seq->in[i], REG_EXTENDED|REG_NOSUB);
if (err) {
char buf[1024];
regerror(err, &seq->inre[i], buf, sizeof(buf));
fprintf(stderr, "error compiling in%d regex: %s\n%s\n",
i, seq->in[i], buf);
regfree(&seq->inre[i]);
seq->in[i] = 0;
}
} else {
seq->in[i] = 0;
}
if (seq->out[i] && *seq->out[i]) {
int err = regcomp(&seq->outre[i], seq->out[i], REG_EXTENDED|REG_NOSUB);
if (err) {
char buf[1024];
regerror(err, &seq->outre[i], buf, sizeof(buf));
fprintf(stderr, "error compiling out%d regex: %s\n%s\n",
i, seq->out[i], buf);
regfree(&seq->outre[i]);
seq->out[i] = 0;
}
} else {
seq->out[i] = 0;
}
}
if(verbose)printf("opening client...\n");
seq->jack_client = jack_client_open(client_name, JackNullOption, &status);
@ -473,6 +597,7 @@ init_jack(JACK_SEQ* seq, uint8_t verbose)
jack_on_shutdown(seq->jack_client, shutdown_callback, (void*)seq);
jack_set_session_callback(seq->jack_client, session_callback, (void*)seq);
jack_set_port_registration_callback(seq->jack_client, registration_callback, (void*)seq);
if (verbose) jack_set_port_connect_callback(seq->jack_client, connect_callback, (void*)seq);
//if(verbose)printf("assigning process callback...\n");
@ -571,6 +696,16 @@ init_jack(JACK_SEQ* seq, uint8_t verbose)
fprintf(stderr, "Cannot activate JACK client.\n");
return 0;
}
// All done, set up the initial connections.
const char **ports = jack_get_ports(seq->jack_client, 0, 0, 0);
for (const char **name = ports; *name; ++name) {
jack_port_t *port = jack_port_by_name(seq->jack_client, *name);
match_connections(seq, port);
}
free(ports);
process_connections(seq);
return 1;
}

View File

@ -1,7 +1,10 @@
#ifndef JACKDRIVER_H
#define JACKDRIVER_H
#include<jack/jack.h>
#include<jack/ringbuffer.h>
#include <jack/jack.h>
#include <jack/ringbuffer.h>
#include <regex.h>
typedef struct _jseq
{
@ -12,6 +15,8 @@ typedef struct _jseq
jack_port_t **output_port;
jack_port_t **input_port;
uint8_t n_in, n_out, passthrough[2];
char *in[2], *out[2];
regex_t inre[2], outre[2];
} JACK_SEQ;
extern int jack_quit;
@ -19,6 +24,7 @@ extern int jack_quit;
extern char *jack_command_line;
int init_jack(JACK_SEQ* seq, uint8_t verbose);
void process_connections(JACK_SEQ* seq);
void close_jack(JACK_SEQ* seq);
void queue_midi(void* seqq, uint8_t msg[], uint8_t port_no);
int pop_midi(void* seqq, uint8_t msg[], uint8_t *port_no);

142
midizap.1
View File

@ -221,8 +221,11 @@ easily be connected to midizap.
As an alternative, you can also run
a2jmidid (http://repo.or.cz/a2jmidid.git) as a separate ALSA\-Jack MIDI
bridge.
(The latter method will work with both Jack1 and Jack2, the former
method is only recommended if you're using Jack1.)
(The latter method works well with both Jack1 and Jack2.
Jack's built\-in ALSA\-Jack MIDI bridge also works very well in Jack1,
but in Jack2 it doesn't list the ALSA ports by their name, which makes
it rather unusable there because you'll have to guess which port
represents which device or application.)
.PP
Having that set up, start Jack, make sure that your MIDI controller is
connected, and try running \f[C]midizap\f[] from the command line
@ -234,7 +237,8 @@ On the right side of the MIDI tab, you should now see a client named
\f[C]midizap\f[] with one MIDI input port named \f[C]midi_in\f[].
That's the one you need to connect to your MIDI controller, whose output
port should be visible under the \f[C]alsa_midi\f[] client on the left
side of the dialog.
side of the dialog (or the \f[C]a2j\f[] client, if you're using
a2jmidid).
.PP
To test the waters, you can hook up just about any MIDI keyboard and
give it a try with the default section in the distributed midizaprc
@ -394,11 +398,16 @@ option, see the following section for details.
.SH Jack\-Related Options
.PP
There are some additional directives (and corresponding command line
options) to set midizap's Jack client name and the number of input and
output ports it uses.
options) to configure midizap's Jack setup in various ways.
We take a look at these in the following.
If both the command line options and directives in the midizaprc file
are used, the former take priority, so that it's always possible to
override the configuration settings from the command line.
are used, the former take priority, so that it's possible to override
the configuration settings from the command line.
.PP
Note that all these options can only be set at program startup.
If you later edit the corresponding directives in the configuration
file, the changes won't take effect until you restart the program.
.SS Jack Client Name and MIDI Port Setup
.PP
Firstly, there's the \f[C]\-j\f[] option and the \f[C]JACK_NAME\f[]
directive which change the Jack client name from the default
@ -443,22 +452,76 @@ the application, see the \f[I]MIDI Feedback\f[] section for details.
Not very surprisingly, at least one output port is needed if you want to
output any MIDI at all; otherwise MIDI messages on the right\-hand side
of translations will be silently ignored.
Also note that midizap doesn't provide you with any options to actually
connect the ports you created to other Jack MIDI clients.
There already are plenty of excellent utilities specifically designed
for this purpose, so there's no need to replicate that functionality in
midizap.
As already mentioned, we recommend using QjackCtl, which also offers a
persistent MIDI patchbay, so that you can have the right connections
automatically set up for you whenever you launch midizap.
You then use the Jack client name option if you need to distinguish
multiple midizap instances.
(The examples folder in the sources contains a QjackCtl patchbay named
midizap.xml which has been set up to work with any of the included
examples.
Use the \[lq]Load\[rq] button in QjackCtl's Patchbay dialog to load it,
then hit the \[lq]Activate\[rq] button to have QjackCtl actually use
it.)
.SS MIDI Connections
.PP
Setting up all the required connections for the Jack MIDI ports can be a
tedious and error\-prone task, especially if you have to deal with
complex setups involving feedback and/or multiple midizap instances.
It's all to easy to mess this up when doing it manually, and either end
up with a dysfunctional setup or, even worse, MIDI feedback loops
crashing your Jack MIDI clients.
While it's possible to automatize the MIDI connections, e.g., with
QjackCtl's persistent MIDI patchbay facility, this is often inconvenient
if you need to accommodate multiple midizap configurations and you
already have a complicated studio setup which you don't want to mess
with.
.PP
As a remedy, midizap offers its own built\-in patchbay functionality
using the \f[C]JACK_IN\f[] and \f[C]JACK_OUT\f[] directives, which let
you specify the required connections in the configuration itself and be
done with it.
The port number is tacked on to the directive, so, e.g.,
\f[C]JACK_IN2\f[] connects the second input port (if the port number is
omitted then the first port is assumed).
The directive is followed by an (extended) regular expression (see the
regex(7) manual page) to be matched against the Jack MIDI ports of your
devices and applications.
A connection will be established automatically by midizap whenever a
Jack MIDI port matches the regular expression, as well as the port type
and I/O direction.
This also works dynamically, as new devices get added and new
applications are launched at runtime.
.PP
For instance, the following lines (from the XTouchONE.midizaprc example)
connect midizap to an X\-Touch One device on one side and Ardour's
Mackie control port on the other:
.IP
.nf
\f[C]
JACK_IN1\ \ X\-Touch\ One\ MIDI\ 1
JACK_OUT1\ ardour:mackie\ control\ in
JACK_IN2\ \ ardour:mackie\ control\ out
JACK_OUT2\ X\-Touch\ One\ MIDI\ 1
\f[]
.fi
.PP
To break this down, the X\-Touch One device will be connected to
midizap's first input port, midizap's first output port to Ardour's
Mackie control input, Ardour's Mackie control output to midizap's second
input port, and midizap's second output port back to the device.
This is a typical setup for bidirectional communication between
controller and application as described in the \f[I]MIDI Feedback\f[]
section.
The sample configurations in the examples folder in the sources have all
been set up in this manner, so that they will create the required
connections automatically.
.PP
Please note that at this time, the built\-in patchbay is only available
through these directives, there are no corresponding command line
options.
Also, only one directive can be specified for each port, but since
midizap will connect to all ports matching the given regular expression,
you can connect to more than one application or device by just listing
all the alternatives.
For instance, to have midizap's output connected to both Ardour and Pd,
you might use a directive like:
.IP
.nf
\f[C]
JACK_OUT1\ ardour:MIDI\ control\ in|Pure\ Data\ Midi\-In\ 1
\f[]
.fi
.SS Pass\-Through
.PP
If at least one output port is available then it also becomes possible
to pass through MIDI messages from input to output unchanged.
@ -484,17 +547,23 @@ port, you might write \f[C]SYSTEM_PASSTHROUGH\ 2\f[], or use the
\f[C]\-s2\f[] option on the command line; and to have unrecognized MIDI
messages passed through in either direction, simply use
\f[C]PASSTHROUGH\f[], or \f[C]\-t\f[].
.SS Jack Sessions
.PP
Note that all these options can only be set at program startup.
If you later edit the corresponding directives in the configuration
file, the changes won't take effect until you restart the program.
midizap also supports \f[I]Jack session management\f[] which provides a
convenient alternative way to launch your midizap instances.
Once you've finished a configuration, instead of running midizap
manually each time you need it, you just invoke it once with the right
command line options, and use a Jack session management program to
record the session.
The session manager can then be used to relaunch the program with the
same options later.
.PP
midizap also supports \f[I]Jack session management\f[], which makes it
possible to record the options the program was invoked with, along with
all the MIDI connections.
QjackCtl has its own built\-in Jack session manager which is available
in its Session dialog.
To use this, launch midizap and any other Jack applications you want to
Various Jack session managers are available for Linux, but if you're
running QjackCtl already, you might just as well use it to record your
sessions, too.
QjackCtl's built\-in Jack session manager is available in its Session
dialog.
To use it, launch midizap and any other Jack applications you want to
have in the session, use QjackCtl to set up all the connections as
needed, and then hit the \[lq]Save\[rq] button in the Session dialog to
have the session recorded.
@ -502,6 +571,7 @@ Now, at any later time you can rerun the recorded session with the
\[lq]Load\[rq] button in the same dialog.
Also, your most recent sessions are available in the \[lq]Recent\[rq]
menu from where they can be launched quickly.
.SS Realtime Priorities
.PP
Finally, midizap also offers an option to run the program with
\f[I]real\-time priorities\f[].
@ -542,8 +612,8 @@ ignored.
Lines beginning with a \f[C][\f[]\f[I]name\f[]\f[C]]\f[] header are also
special.
Each such line introduces a translation class \f[I]name\f[], which may
be followed by an extended regular expression \f[I]regex\f[] (see the
regex(7) manual page) to be matched against window class and title.
be followed by an extended regular expression \f[I]regex\f[] to be
matched against window class and title.
A \f[C]CLASS\f[] or \f[C]TITLE\f[] token may precede \f[I]regex\f[] to
indicate that \f[I]only\f[] the class or title is to be matched,
respectively; otherwise both are matched.
@ -2297,6 +2367,10 @@ translation\ ::=\ midi\-token\ {\ key\-token\ |\ midi\-token\ }
directive\ \ \ ::=\ "DEBUG_REGEX"\ |\ "DEBUG_STROKES"\ |\ "DEBUG_KEYS"\ |
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ "DEBUG_MIDI"\ |\ "MIDI_OCTAVE"\ number\ |
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ "JACK_NAME"\ string\ |\ "JACK_PORTS"\ number\ |
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ "JACK_IN"\ regex\ |\ "JACK_OUT"\ regex\ |
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ "JACK_IN1"\ regex\ |\ "JACK_OUT1"\ regex\ |
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ "JACK_IN2"\ regex\ |\ "JACK_OUT2"\ regex\ |
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ "PASSTHROUGH"\ [\ number\ ]\ |
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ "SYSTEM_PASSTHROUGH"\ [\ number\ ]
midi\-token\ \ ::=\ msg\ [\ mod\ ]\ [\ steps\ ]\ [\ "\-"\ number]\ [\ flag\ ]

View File

@ -1863,6 +1863,10 @@ main(int argc, char **argv)
seq.n_out = jack_num_outputs>0?jack_num_outputs:0;
seq.passthrough[0] = jack_num_outputs>0?system_passthrough[0]>0:0;
seq.passthrough[1] = jack_num_outputs>1?system_passthrough[1]>0:0;
seq.in[0] = jack_in_regex[0];
seq.in[1] = jack_num_outputs>1?jack_in_regex[1]:0;
seq.out[0] = jack_num_outputs>0?jack_out_regex[0]:0;
seq.out[1] = jack_num_outputs>1?jack_out_regex[1]:0;
if (!init_jack(&seq, debug_jack)) {
exit(1);
}
@ -1892,6 +1896,7 @@ main(int argc, char **argv)
close_jack(&seq);
exit(0);
}
process_connections(&seq);
while (pop_midi(&seq, msg, &portno)) {
handle_event(msg, portno, 0, 0);
time_t t = time(0);

View File

@ -137,4 +137,4 @@ extern char *config_file_name;
extern int jack_num_outputs, auto_feedback;
extern int passthrough[2], system_passthrough[2];
extern int midi_octave, shift;
extern char *jack_client_name;
extern char *jack_client_name, *jack_in_regex[2], *jack_out_regex[2];

View File

@ -60,7 +60,7 @@ int debug_midi = 0;
int midi_octave = 0;
char *jack_client_name = NULL;
char *jack_client_name, *jack_in_regex[2], *jack_out_regex[2];
char *
allocate(size_t len)
@ -1953,6 +1953,53 @@ read_config_file(void)
}
continue;
}
if (!strncmp(tok, "JACK_", 5)) {
// JACK_IN/OUT. The port number follows (default: 1), then a regex
// (taken verbatim from the rest of the line).
char *s = tok+5, *regex;
int is_input = strncmp(s, "IN", 2) == 0;
if (is_input)
s += 2;
else if (strncmp(s, "OUT", 3) == 0)
s += 3;
else {
fprintf(stderr, "invalid token: %s, must be JACK_IN or JACK_OUT\n",
tok);
continue;
}
int portno = !*s||*s=='1'?0:*s=='2'?1:-1;
if (portno < 0) {
fprintf(stderr, "invalid port number: %s, must be 1 or 2\n", s);
continue;
}
if (*s && *++s) {
// trailing garbage
fprintf(stderr, "invalid token: %s, must be JACK_IN or JACK_OUT\n",
tok);
continue;
}
s = token_src;
while (*s && isspace(*s)) {
s++;
}
regex = s;
while (*s) {
s++;
}
s--;
while (s > regex && isspace(*s)) {
s--;
}
s[1] = '\0';
char **jack_regex = is_input?jack_in_regex:jack_out_regex;
if (jack_regex[portno]) {
if (strcmp(jack_regex[portno], regex))
fprintf(stderr, "error: attempt to redefine %s as '%s'\n(is already defined as '%s')\n", tok, regex, jack_regex[portno]);
} else {
jack_regex[portno] = strdup(regex);
}
continue;
}
if (!strcmp(tok, "PASSTHROUGH")) { // -t
char *a = token(NULL, &delim);
int k, n;