diff --git a/example.midizaprc b/example.midizaprc index 2bf0126..9f7bb4f 100644 --- a/example.midizaprc +++ b/example.midizaprc @@ -6,11 +6,38 @@ # This program works pretty much like Eric Messick's shuttlepro program, # but it translates MIDI input rather than input events from the Contour -# Design Shuttle devices. The program creates a Jack MIDI client named -# "midizap" with a single input port, which you'll have to connect to -# the MIDI controller that you want to use (e.g., using a patchbay -# program like qjackctl; non-Jack ALSA MIDI inputs can be accommodated -# using a2jmidid). +# Design Shuttle devices. By default, the program creates a Jack MIDI +# client named "midizap" with a single input port, which you'll have to +# connect to the MIDI controller that you want to use (e.g., using a +# patchbay program like qjackctl; non-Jack ALSA MIDI inputs can be +# accommodated using a2jmidid). + +# Both the Jack client name and the number of (input and output) ports +# can be adjusted, either from the command line, using the -j and -o +# options (these always take priority), or by employing the following +# midizaprc directives. NOTE: These options only take effect +# immediately after program start, when the Jack client is initialized. +# If you edit them later, you need to restart the program, so that a new +# Jack client is created. + +# The JACK_NAME directive is used to change the client name. +# (Uncomment the line and edit the name as needed.) This is useful, +# e.g., if you're running multiple instances of midizap using different +# configurations for different controllers, and you want to have them +# named appropriately so that they can be wired up more easily using the +# qjackctl patchbay. + +#JACK_NAME "hello midizap" + +# The number of ports given with the JACK_PORTS directive must be +# 1 or 2. It causes the given number of both input and output ports to +# be created. This option is useful if you want to translate MIDI +# messages, see the [MIDI] section below for details. Two input and +# output ports can be employed, e.g., if you also need to provide +# backward translations for controller feedback, see the [MIDI2] section +# below for an example. + +#JACK_PORTS 2 # Other than the input being MIDI instead of the Shuttle's key and wheel # events, the program works exactly the same. Each section in the file diff --git a/jackdriver.c b/jackdriver.c index a42f979..b176df5 100644 --- a/jackdriver.c +++ b/jackdriver.c @@ -376,10 +376,11 @@ int init_jack(JACK_SEQ* seq, uint8_t verbose) { int err, k; - char portname[100]; + char portname[100], + *client_name = seq->client_name?seq->client_name:"midizap"; if(verbose)printf("opening client...\n"); - seq->jack_client = jack_client_open("midizap", JackNullOption, NULL); + seq->jack_client = jack_client_open(client_name, JackNullOption, NULL); if (seq->jack_client == NULL) { diff --git a/jackdriver.h b/jackdriver.h index 0278fd2..2c86a91 100644 --- a/jackdriver.h +++ b/jackdriver.h @@ -5,6 +5,7 @@ typedef struct _jseq { + char *client_name; jack_ringbuffer_t **ringbuffer_out; jack_ringbuffer_t **ringbuffer_in; jack_client_t *jack_client; diff --git a/midizap.c b/midizap.c index e442348..d1ee30f 100644 --- a/midizap.c +++ b/midizap.c @@ -23,7 +23,7 @@ typedef struct input_event EV; Display *display; JACK_SEQ seq; -int enable_jack_output = 0, debug_jack = 0; +int jack_num_outputs = 0, debug_jack = 0; void initdisplay(void) @@ -70,7 +70,7 @@ static int16_t pbvalue[16] = void send_midi(uint8_t portno, int status, int data, int step, int incr, int index, int dir) { - if (!enable_jack_output) return; // MIDI output not enabled + if (!jack_num_outputs) return; // MIDI output not enabled uint8_t msg[3]; int chan = status & 0x0f; msg[0] = status; @@ -273,7 +273,7 @@ send_strokes(translation *tr, uint8_t portno, int status, int chan, int data, int nkeys = 0; stroke *s = fetch_stroke(tr, portno, status, chan, data, index, dir); - if (!s && enable_jack_output) { + if (!s && jack_num_outputs) { // fall back to default MIDI translation tr = default_midi_translation[portno]; s = fetch_stroke(tr, portno, status, chan, data, index, dir); @@ -603,11 +603,12 @@ handle_event(uint8_t *msg, uint8_t portno) void help(char *progname) { - fprintf(stderr, "Usage: %s [-h] [-o[2]] [-r rcfile] [-d[rskj]]\n", progname); + fprintf(stderr, "Usage: %s [-h] [-o[2]] [-j name] [-r rcfile] [-d[rskmj]]\n", progname); fprintf(stderr, "-h print this message\n"); fprintf(stderr, "-o enable MIDI output (add 2 for a second pair of ports)\n"); + fprintf(stderr, "-j jack client name (default: midizap)\n"); fprintf(stderr, "-r config file name (default: MIDIZAP_CONFIG_FILE variable or ~/.midizaprc)\n"); - fprintf(stderr, "-d debug (r = regex, s = strokes, k = keys, j = jack; default: all)\n"); + fprintf(stderr, "-d debug (r = regex, s = strokes, k = keys, m = midi, j = jack; default: all)\n"); } uint8_t quit = 0; @@ -623,25 +624,23 @@ void quitter() #define CONF_FREQ 1 #define MAX_COUNT (1000000/CONF_FREQ/POLL_INTERVAL) -int n_ports = 1; - int main(int argc, char **argv) { uint8_t msg[3]; int opt, count = 0; - while ((opt = getopt(argc, argv, "ho::d::r:")) != -1) { + while ((opt = getopt(argc, argv, "ho::d::j:r:")) != -1) { switch (opt) { case 'h': help(argv[0]); exit(0); case 'o': - enable_jack_output = 1; + jack_num_outputs = 1; if (optarg && *optarg) { const char *a = optarg; if (*a == '2') { - n_ports = 2; + jack_num_outputs = 2; } else if (*a && *a != '1') { fprintf(stderr, "%s: wrong port number (-o), must be 1 or 2\n", argv[0]); fprintf(stderr, "Try -h for help.\n"); @@ -682,6 +681,9 @@ main(int argc, char **argv) debug_jack = 1; } break; + case 'j': + jack_client_name = optarg; + break; case 'r': config_file_name = optarg; break; @@ -698,14 +700,20 @@ main(int argc, char **argv) initdisplay(); - seq.n_in = n_ports; seq.n_out = enable_jack_output?n_ports:0; + // Force the config file to be loaded initially, so that we pick up the Jack + // client name to be used (if not set from the command line). This cannot be + // changed later, so if you want to make changes to the client name in the + // config file take effect, you need to restart the program. + read_config_file(); + + seq.client_name = jack_client_name; + seq.n_in = jack_num_outputs>1?jack_num_outputs:1; + seq.n_out = jack_num_outputs; if (!init_jack(&seq, debug_jack)) { exit(1); } signal(SIGINT, quitter); - // force the config file to be loaded initially - count = MAX_COUNT; while (!quit) { uint8_t portno; while (pop_midi(&seq, msg, &portno)) { diff --git a/midizap.h b/midizap.h index 497bf3b..22505da 100644 --- a/midizap.h +++ b/midizap.h @@ -93,5 +93,6 @@ extern int debug_regex, debug_strokes, debug_keys, debug_midi; extern int default_debug_regex, default_debug_strokes, default_debug_keys, default_debug_midi; extern char *config_file_name; -extern int enable_jack_output; +extern int jack_num_outputs; extern int midi_octave; +extern char *jack_client_name; diff --git a/readconfig.c b/readconfig.c index 312b8ae..46e88f1 100644 --- a/readconfig.c +++ b/readconfig.c @@ -199,6 +199,8 @@ int debug_midi = 0; int midi_octave = 0; +char *jack_client_name = NULL; + char * allocate(size_t len) { @@ -1211,6 +1213,27 @@ read_config_file(void) debug_midi = 1; continue; } + if (!strcmp(tok, "JACK_NAME")) { + char *a = token(NULL, &delim); + if (!jack_client_name) { + static char buf[100]; + strncpy(buf, a, 100); buf[99] = 0; // just in case... + jack_client_name = buf; + } + continue; + } + if (!strcmp(tok, "JACK_PORTS")) { + char *a = token(NULL, &delim); + int k, n; + if (!jack_num_outputs) { + if (sscanf(a, "%d%n", &k, &n) == 1 && !a[n] && k>=1 && k<=2) { + jack_num_outputs = k; + } else { + fprintf(stderr, "invalid port number: %s, must be 1 or 2\n", a); + } + } + continue; + } if (!strncmp(tok, "MIDI_OCTAVE", 11)) { char *a = tok+11; int k, n;