Add basic Jack session support.
parent
fa25596e6f
commit
a138c37a0e
31
jackdriver.c
31
jackdriver.c
|
@ -40,6 +40,7 @@
|
||||||
#include <jack/jack.h>
|
#include <jack/jack.h>
|
||||||
#include <jack/midiport.h>
|
#include <jack/midiport.h>
|
||||||
#include <jack/ringbuffer.h>
|
#include <jack/ringbuffer.h>
|
||||||
|
#include <jack/session.h>
|
||||||
#include "jackdriver.h"
|
#include "jackdriver.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -369,13 +370,35 @@ int pop_midi(void* seqq, uint8_t msg[], uint8_t *port_no)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int jack_shutdown;
|
int jack_quit;
|
||||||
|
|
||||||
void
|
void
|
||||||
shutdown_callback()
|
shutdown_callback()
|
||||||
{
|
{
|
||||||
// we can't do anything fancy here, just ping the main thread
|
// we can't do anything fancy here, just ping the main thread
|
||||||
jack_shutdown = 1;
|
jack_quit = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *jack_command_line = "midizap";
|
||||||
|
|
||||||
|
void
|
||||||
|
session_callback(jack_session_event_t *event, void *seqq)
|
||||||
|
{
|
||||||
|
JACK_SEQ* seq = (JACK_SEQ*)seqq;
|
||||||
|
// XXXTODO: In order to better support Jack session management in the future
|
||||||
|
// we may want to copy over the loaded midizaprc file and store it in the
|
||||||
|
// session dir, so that we can reload it from there later. For the time
|
||||||
|
// being, we simply record the command line here.
|
||||||
|
//printf("path %s, uuid %s, type: %s\n", event->session_dir, event->client_uuid, event->type == JackSessionSave ? "save" : "quit");
|
||||||
|
|
||||||
|
event->command_line = strdup(jack_command_line);
|
||||||
|
jack_session_reply(seq->jack_client, event);
|
||||||
|
|
||||||
|
if (event->type == JackSessionSaveAndQuit) {
|
||||||
|
jack_quit = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
jack_session_event_free (event);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
@ -409,6 +432,9 @@ init_jack(JACK_SEQ* seq, uint8_t verbose)
|
||||||
if(verbose)printf("assigning shutdown callback...\n");
|
if(verbose)printf("assigning shutdown callback...\n");
|
||||||
jack_on_shutdown(seq->jack_client, shutdown_callback, (void*)seq);
|
jack_on_shutdown(seq->jack_client, shutdown_callback, (void*)seq);
|
||||||
|
|
||||||
|
if(verbose)printf("assigning session callback...\n");
|
||||||
|
jack_set_session_callback(seq->jack_client, session_callback, (void*)seq);
|
||||||
|
|
||||||
if(verbose)printf("assigning process callback...\n");
|
if(verbose)printf("assigning process callback...\n");
|
||||||
err = jack_set_process_callback(seq->jack_client, process_callback, (void*)seq);
|
err = jack_set_process_callback(seq->jack_client, process_callback, (void*)seq);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -519,4 +545,5 @@ void close_jack(JACK_SEQ* seq)
|
||||||
for (k = 0; k < seq->n_in; k++)
|
for (k = 0; k < seq->n_in; k++)
|
||||||
jack_ringbuffer_free(seq->ringbuffer_in[k]);
|
jack_ringbuffer_free(seq->ringbuffer_in[k]);
|
||||||
}
|
}
|
||||||
|
jack_client_close(seq->jack_client);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,9 @@ typedef struct _jseq
|
||||||
uint8_t n_out;
|
uint8_t n_out;
|
||||||
} JACK_SEQ;
|
} JACK_SEQ;
|
||||||
|
|
||||||
extern int jack_shutdown;
|
extern int jack_quit;
|
||||||
|
// This is supposed to be set properly by main().
|
||||||
|
extern char *jack_command_line;
|
||||||
|
|
||||||
int init_jack(JACK_SEQ* seq, uint8_t verbose);
|
int init_jack(JACK_SEQ* seq, uint8_t verbose);
|
||||||
void close_jack(JACK_SEQ* seq);
|
void close_jack(JACK_SEQ* seq);
|
||||||
|
|
90
midizap.c
90
midizap.c
|
@ -798,6 +798,58 @@ void quitter()
|
||||||
quit = 1;
|
quit = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper functions to process the command line, so that we can pass it to
|
||||||
|
// Jack session management.
|
||||||
|
|
||||||
|
static char *command_line;
|
||||||
|
static size_t len;
|
||||||
|
|
||||||
|
static void add_command(char *arg)
|
||||||
|
{
|
||||||
|
char *a = arg;
|
||||||
|
// Do some simplistic quoting if the argument contains blanks. This won't do
|
||||||
|
// the right thing if the argument also contains quotes. Oh well.
|
||||||
|
if ((strchr(a, ' ') || strchr(a, '\t')) && !strchr(a, '"')) {
|
||||||
|
a = malloc(strlen(arg)+3);
|
||||||
|
sprintf(a, "\"%s\"", arg);
|
||||||
|
}
|
||||||
|
if (!command_line) {
|
||||||
|
len = strlen(a);
|
||||||
|
command_line = malloc(len+1);
|
||||||
|
strcpy(command_line, a);
|
||||||
|
} else {
|
||||||
|
size_t l = strlen(a)+1;
|
||||||
|
command_line = realloc(command_line, len+l+1);
|
||||||
|
command_line[len] = ' ';
|
||||||
|
strcpy(command_line+len+1, a);
|
||||||
|
len += l;
|
||||||
|
}
|
||||||
|
if (a != arg) free(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *absolute_path(char *name)
|
||||||
|
{
|
||||||
|
if (*name == '/') {
|
||||||
|
return name;
|
||||||
|
} else {
|
||||||
|
// This is a relative pathname, we turn it into a canonicalized absolute
|
||||||
|
// path. NOTE: This requires glibc. We should probably rewrite this code
|
||||||
|
// to be more portable.
|
||||||
|
char *pwd = getcwd(NULL, 0);
|
||||||
|
if (!pwd) {
|
||||||
|
perror("getcwd");
|
||||||
|
return name;
|
||||||
|
} else {
|
||||||
|
char *path = malloc(strlen(pwd)+strlen(name)+2);
|
||||||
|
static char abspath[PATH_MAX];
|
||||||
|
sprintf(path, "%s/%s", pwd, name);
|
||||||
|
realpath(path, abspath);
|
||||||
|
free(path); free(pwd);
|
||||||
|
return abspath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// poll interval in microsec (this shouldn't be too large to avoid jitter)
|
// poll interval in microsec (this shouldn't be too large to avoid jitter)
|
||||||
#define POLL_INTERVAL 1000
|
#define POLL_INTERVAL 1000
|
||||||
// how often we check the config file per sec (> 0, < 1000000/POLL_INTERVAL)
|
// how often we check the config file per sec (> 0, < 1000000/POLL_INTERVAL)
|
||||||
|
@ -810,6 +862,9 @@ main(int argc, char **argv)
|
||||||
uint8_t msg[3];
|
uint8_t msg[3];
|
||||||
int opt, count = 0;
|
int opt, count = 0;
|
||||||
|
|
||||||
|
// Start recording the command line to be passed to Jack session management.
|
||||||
|
add_command(argv[0]);
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "hko::d::j:r:")) != -1) {
|
while ((opt = getopt(argc, argv, "hko::d::j:r:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h':
|
case 'h':
|
||||||
|
@ -818,23 +873,29 @@ main(int argc, char **argv)
|
||||||
case 'k':
|
case 'k':
|
||||||
// see comment on -k and keydown_tracker above
|
// see comment on -k and keydown_tracker above
|
||||||
keydown_tracker = 1;
|
keydown_tracker = 1;
|
||||||
|
add_command("-k");
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
jack_num_outputs = 1;
|
jack_num_outputs = 1;
|
||||||
if (optarg && *optarg) {
|
if (optarg && *optarg) {
|
||||||
const char *a = optarg;
|
const char *a = optarg;
|
||||||
if (*a == '2') {
|
if (!strcmp(a, "2")) {
|
||||||
jack_num_outputs = 2;
|
jack_num_outputs = 2;
|
||||||
} else if (*a && *a != '1') {
|
add_command("-o2");
|
||||||
|
} else if (strcmp(a, "1")) {
|
||||||
fprintf(stderr, "%s: wrong port number (-o), must be 1 or 2\n", argv[0]);
|
fprintf(stderr, "%s: wrong port number (-o), must be 1 or 2\n", argv[0]);
|
||||||
fprintf(stderr, "Try -h for help.\n");
|
fprintf(stderr, "Try -h for help.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
} else
|
||||||
}
|
add_command("-o1");
|
||||||
|
} else
|
||||||
|
add_command("-o");
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
if (optarg && *optarg) {
|
if (optarg && *optarg) {
|
||||||
const char *a = optarg;
|
const char *a = optarg; char buf[100];
|
||||||
|
snprintf(buf, 100, "-d%s", optarg);
|
||||||
|
add_command(buf);
|
||||||
while (*a) {
|
while (*a) {
|
||||||
switch (*a) {
|
switch (*a) {
|
||||||
case 'r':
|
case 'r':
|
||||||
|
@ -863,13 +924,20 @@ main(int argc, char **argv)
|
||||||
default_debug_regex = default_debug_strokes = default_debug_keys =
|
default_debug_regex = default_debug_strokes = default_debug_keys =
|
||||||
default_debug_midi = 1;
|
default_debug_midi = 1;
|
||||||
debug_jack = 1;
|
debug_jack = 1;
|
||||||
|
add_command("-d");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'j':
|
case 'j':
|
||||||
jack_client_name = optarg;
|
jack_client_name = optarg;
|
||||||
|
add_command("-j");
|
||||||
|
add_command(optarg);
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
config_file_name = optarg;
|
config_file_name = optarg;
|
||||||
|
add_command("-r");
|
||||||
|
// We need to convert this to an absolute pathname for Jack session
|
||||||
|
// management.
|
||||||
|
add_command(absolute_path(optarg));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "Try -h for help.\n");
|
fprintf(stderr, "Try -h for help.\n");
|
||||||
|
@ -882,6 +950,8 @@ main(int argc, char **argv)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (command_line) jack_command_line = command_line;
|
||||||
|
|
||||||
initdisplay();
|
initdisplay();
|
||||||
|
|
||||||
// Force the config file to be loaded initially, so that we pick up the Jack
|
// Force the config file to be loaded initially, so that we pick up the Jack
|
||||||
|
@ -897,11 +967,14 @@ main(int argc, char **argv)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int do_flush = debug_regex || debug_strokes || debug_keys || debug_midi ||
|
||||||
|
debug_jack;
|
||||||
signal(SIGINT, quitter);
|
signal(SIGINT, quitter);
|
||||||
while (!quit) {
|
while (!quit) {
|
||||||
uint8_t portno;
|
uint8_t portno;
|
||||||
if (jack_shutdown) {
|
if (jack_quit) {
|
||||||
fprintf(stderr, "%s: jack shutting down, exiting\n", argv[0]);
|
printf("[jack %s, exiting]\n",
|
||||||
|
(jack_quit>0)?"asked us to quit":"shutting down");
|
||||||
close_jack(&seq);
|
close_jack(&seq);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
@ -918,6 +991,9 @@ main(int argc, char **argv)
|
||||||
if (read_config_file()) last_focused_window = 0;
|
if (read_config_file()) last_focused_window = 0;
|
||||||
count = 0;
|
count = 0;
|
||||||
}
|
}
|
||||||
|
// Make sure that debugging output gets flushed every once in a while (may
|
||||||
|
// be buffered when midizap is running inside a QjackCtl session).
|
||||||
|
if (do_flush) fflush(NULL);
|
||||||
}
|
}
|
||||||
printf(" [exiting]\n");
|
printf(" [exiting]\n");
|
||||||
close_jack(&seq);
|
close_jack(&seq);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// 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>
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
Loading…
Reference in New Issue