Browse Source

Remove example-clients and tools

Signed-off-by: falkTX <falktx@falktx.com>
pull/876/head
falkTX 3 months ago
parent
commit
564c710eef
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
54 changed files with 4 additions and 12960 deletions
  1. +0
    -353
      example-clients/capture_client.c
  2. +0
    -75
      example-clients/control.c
  3. +0
    -88
      example-clients/cpu_load.c
  4. +0
    -247
      example-clients/impulse_grabber.c
  5. +0
    -125
      example-clients/inprocess.c
  6. +0
    -123
      example-clients/internal_metro.cpp
  7. +0
    -68
      example-clients/internal_metro.h
  8. +0
    -217
      example-clients/latent_client.c
  9. +0
    -302
      example-clients/metro.c
  10. +0
    -969
      example-clients/midi_latency_test.c
  11. +0
    -133
      example-clients/midiseq.c
  12. +0
    -163
      example-clients/midisine.c
  13. +0
    -208
      example-clients/netmaster.c
  14. +0
    -168
      example-clients/netslave.c
  15. +0
    -244
      example-clients/server_control.cpp
  16. +0
    -119
      example-clients/showtime.c
  17. +0
    -415
      example-clients/simdtests.cpp
  18. +0
    -220
      example-clients/simple_client.c
  19. +0
    -206
      example-clients/simple_session_client.c
  20. +0
    -217
      example-clients/thru_client.c
  21. +0
    -110
      example-clients/wscript
  22. +0
    -95
      example-clients/zombie.c
  23. +0
    -133
      tools/alias.c
  24. +0
    -846
      tools/alsa_in.c
  25. +0
    -848
      tools/alsa_out.c
  26. +0
    -124
      tools/bufsize.c
  27. +0
    -248
      tools/connect.c
  28. +0
    -164
      tools/evmon.c
  29. +0
    -87
      tools/freewheel.c
  30. +0
    -246
      tools/ipload.c
  31. +0
    -93
      tools/ipunload.c
  32. +0
    -291
      tools/lsp.c
  33. +0
    -238
      tools/midi_dump.c
  34. +0
    -66
      tools/monitor_client.c
  35. +0
    -802
      tools/netsource.c
  36. +0
    -326
      tools/property.c
  37. +0
    -87
      tools/samplerate.c
  38. +0
    -186
      tools/session_notify.c
  39. +0
    -508
      tools/transport.c
  40. +0
    -264
      tools/tw.c
  41. +0
    -152
      tools/wait.c
  42. +0
    -130
      tools/wscript
  43. +0
    -226
      tools/zalsa/alsathread.cc
  44. +0
    -68
      tools/zalsa/alsathread.h
  45. +0
    -549
      tools/zalsa/jackclient.cc
  46. +0
    -120
      tools/zalsa/jackclient.h
  47. +0
    -89
      tools/zalsa/lfqueue.cc
  48. +0
    -182
      tools/zalsa/lfqueue.h
  49. +0
    -87
      tools/zalsa/pxthread.cc
  50. +0
    -53
      tools/zalsa/pxthread.h
  51. +0
    -53
      tools/zalsa/timers.h
  52. +0
    -409
      tools/zalsa/zita-a2j.cc
  53. +0
    -408
      tools/zalsa/zita-j2a.cc
  54. +4
    -12
      wscript

+ 0
- 353
example-clients/capture_client.c View File

@@ -1,353 +0,0 @@
/*
Copyright (C) 2001 Paul Davis
Copyright (C) 2003 Jack O'Quin

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

* 2002/08/23 - modify for libsndfile 1.0.0 <andy@alsaplayer.org>
* 2003/05/26 - use ringbuffers - joq
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sndfile.h>
#include <pthread.h>
#include <signal.h>
#include <getopt.h>
#include <inttypes.h>

#include <jack/jack.h>
#include <jack/ringbuffer.h>

typedef struct _thread_info {
pthread_t thread_id;
SNDFILE *sf;
jack_nframes_t duration;
jack_nframes_t rb_size;
jack_client_t *client;
unsigned int channels;
int bitdepth;
char *path;
volatile int can_capture;
volatile int can_process;
volatile int status;
} jack_thread_info_t;

/* JACK data */
unsigned int nports;
jack_port_t **ports;
jack_default_audio_sample_t **in;
jack_nframes_t nframes;
const size_t sample_size = sizeof(jack_default_audio_sample_t);

/* Synchronization between process thread and disk thread. */
#define DEFAULT_RB_SIZE 16384 /* ringbuffer size in frames */
jack_ringbuffer_t *rb;
pthread_mutex_t disk_thread_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t data_ready = PTHREAD_COND_INITIALIZER;
long overruns = 0;
jack_client_t *client;

static void signal_handler(int sig)
{
jack_client_close(client);
fprintf(stderr, "signal received, exiting ...\n");
exit(0);
}

static void *
disk_thread (void *arg)
{
jack_thread_info_t *info = (jack_thread_info_t *) arg;
static jack_nframes_t total_captured = 0;
jack_nframes_t samples_per_frame = info->channels;
size_t bytes_per_frame = samples_per_frame * sample_size;
void *framebuf = malloc (bytes_per_frame);

pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_mutex_lock (&disk_thread_lock);

info->status = 0;

while (1) {

/* Write the data one frame at a time. This is
* inefficient, but makes things simpler. */
while (info->can_capture &&
(jack_ringbuffer_read_space (rb) >= bytes_per_frame)) {

jack_ringbuffer_read (rb, framebuf, bytes_per_frame);

if (sf_writef_float (info->sf, framebuf, 1) != 1) {
char errstr[256];
sf_error_str (0, errstr, sizeof (errstr) - 1);
fprintf (stderr,
"cannot write sndfile (%s)\n",
errstr);
info->status = EIO; /* write failed */
goto done;
}

if (++total_captured >= info->duration) {
printf ("disk thread finished\n");
goto done;
}
}

/* wait until process() signals more data */
pthread_cond_wait (&data_ready, &disk_thread_lock);
}

done:
pthread_mutex_unlock (&disk_thread_lock);
free (framebuf);
return 0;
}

static int
process (jack_nframes_t nframes, void *arg)
{
int chn;
size_t i;
jack_thread_info_t *info = (jack_thread_info_t *) arg;

/* Do nothing until we're ready to begin. */
if ((!info->can_process) || (!info->can_capture))
return 0;

for (chn = 0; chn < nports; chn++)
in[chn] = jack_port_get_buffer (ports[chn], nframes);

/* Sndfile requires interleaved data. It is simpler here to
* just queue interleaved samples to a single ringbuffer. */
for (i = 0; i < nframes; i++) {
for (chn = 0; chn < nports; chn++) {
if (jack_ringbuffer_write (rb, (void *) (in[chn]+i),
sample_size)
< sample_size)
overruns++;
}
}

/* Tell the disk thread there is work to do. If it is already
* running, the lock will not be available. We can't wait
* here in the process() thread, but we don't need to signal
* in that case, because the disk thread will read all the
* data queued before waiting again. */
if (pthread_mutex_trylock (&disk_thread_lock) == 0) {
pthread_cond_signal (&data_ready);
pthread_mutex_unlock (&disk_thread_lock);
}

return 0;
}

static void
jack_shutdown (void *arg)
{
fprintf(stderr, "JACK shut down, exiting ...\n");
exit(1);
}

static void
setup_disk_thread (jack_thread_info_t *info)
{
SF_INFO sf_info;
int short_mask;

sf_info.samplerate = jack_get_sample_rate (info->client);
sf_info.channels = info->channels;

switch (info->bitdepth) {
case 8: short_mask = SF_FORMAT_PCM_U8;
break;
case 16: short_mask = SF_FORMAT_PCM_16;
break;
case 24: short_mask = SF_FORMAT_PCM_24;
break;
case 32: short_mask = SF_FORMAT_PCM_32;
break;
default: short_mask = SF_FORMAT_PCM_16;
break;
}
sf_info.format = SF_FORMAT_WAV|short_mask;

if ((info->sf = sf_open (info->path, SFM_WRITE, &sf_info)) == NULL) {
char errstr[256];
sf_error_str (0, errstr, sizeof (errstr) - 1);
fprintf (stderr, "cannot open sndfile \"%s\" for output (%s)\n", info->path, errstr);
jack_client_close (info->client);
exit (1);
}

info->duration *= sf_info.samplerate;
info->can_capture = 0;

pthread_create (&info->thread_id, NULL, disk_thread, info);
}

static void
run_disk_thread (jack_thread_info_t *info)
{
info->can_capture = 1;
pthread_join (info->thread_id, NULL);
sf_close (info->sf);
if (overruns > 0) {
fprintf (stderr,
"jackrec failed with %ld overruns.\n", overruns);
fprintf (stderr, " try a bigger buffer than -B %"
PRIu32 ".\n", info->rb_size);
info->status = EPIPE;
}
}

static void
setup_ports (int sources, char *source_names[], jack_thread_info_t *info)
{
unsigned int i;
size_t in_size;

/* Allocate data structures that depend on the number of ports. */
nports = sources;
ports = (jack_port_t **) malloc (sizeof (jack_port_t *) * nports);
in_size = nports * sizeof (jack_default_audio_sample_t *);
in = (jack_default_audio_sample_t **) malloc (in_size);
rb = jack_ringbuffer_create (nports * sample_size * info->rb_size);

/* When JACK is running realtime, jack_activate() will have
* called mlockall() to lock our pages into memory. But, we
* still need to touch any newly allocated pages before
* process() starts using them. Otherwise, a page fault could
* create a delay that would force JACK to shut us down. */
memset(in, 0, in_size);
memset(rb->buf, 0, rb->size);

for (i = 0; i < nports; i++) {
char name[64];

sprintf (name, "input%d", i+1);

if ((ports[i] = jack_port_register (info->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0)) == 0) {
fprintf (stderr, "cannot register input port \"%s\"!\n", name);
jack_client_close (info->client);
exit (1);
}
}

for (i = 0; i < nports; i++) {
if (jack_connect (info->client, source_names[i], jack_port_name (ports[i]))) {
fprintf (stderr, "cannot connect input port %s to %s\n", jack_port_name (ports[i]), source_names[i]);
jack_client_close (info->client);
exit (1);
}
}

info->can_process = 1; /* process() can start, now */
}

int
main (int argc, char *argv[])
{
jack_thread_info_t thread_info;
int c;
int longopt_index = 0;
extern int optind, opterr;
int show_usage = 0;
char *optstring = "d:f:b:B:h";
struct option long_options[] = {
{ "help", 0, 0, 'h' },
{ "duration", 1, 0, 'd' },
{ "file", 1, 0, 'f' },
{ "bitdepth", 1, 0, 'b' },
{ "bufsize", 1, 0, 'B' },
{ 0, 0, 0, 0 }
};

memset (&thread_info, 0, sizeof (thread_info));
thread_info.rb_size = DEFAULT_RB_SIZE;
opterr = 0;

while ((c = getopt_long (argc, argv, optstring, long_options, &longopt_index)) != -1) {
switch (c) {
case 1:
/* getopt signals end of '-' options */
break;

case 'h':
show_usage++;
break;
case 'd':
thread_info.duration = atoi (optarg);
break;
case 'f':
thread_info.path = optarg;
break;
case 'b':
thread_info.bitdepth = atoi (optarg);
break;
case 'B':
thread_info.rb_size = atoi (optarg);
break;
default:
fprintf (stderr, "error\n");
show_usage++;
break;
}
}

if (show_usage || thread_info.path == NULL || optind == argc) {
fprintf (stderr, "usage: jackrec -f filename [ -d second ] [ -b bitdepth ] [ -B bufsize ] port1 [ port2 ... ]\n");
exit (1);
}

if ((client = jack_client_open ("jackrec", JackNullOption, NULL)) == 0) {
fprintf (stderr, "JACK server not running?\n");
exit (1);
}

thread_info.client = client;
thread_info.channels = argc - optind;
thread_info.can_process = 0;

setup_disk_thread (&thread_info);

jack_set_process_callback (client, process, &thread_info);
jack_on_shutdown (client, jack_shutdown, &thread_info);

if (jack_activate (client)) {
fprintf (stderr, "cannot activate client");
}

setup_ports (argc - optind, &argv[optind], &thread_info);

/* install a signal handler to properly quits jack client */
#ifndef WIN32
signal(SIGQUIT, signal_handler);
signal(SIGHUP, signal_handler);
#endif
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);

run_disk_thread (&thread_info);

jack_client_close (client);

jack_ringbuffer_free (rb);

exit (0);
}

+ 0
- 75
example-clients/control.c View File

@@ -1,75 +0,0 @@
/** @file control.c
*
* @brief This simple client demonstrates the basic features of JACK
* as they would be used by many applications.
*/

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <math.h>
#include <jack/jack.h>

jack_client_t *client;
static int reorder = 0;

static int Jack_Graph_Order_Callback(void *arg)
{
const char **ports;
int i;

printf("Jack_Graph_Order_Callback count = %d\n", reorder++);

ports = jack_get_ports(client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput);
if (ports) {
for (i = 0; ports[i]; ++i) {
printf("name: %s\n", ports[i]);
}
jack_free(ports);
}

ports = jack_get_ports(client, NULL, NULL, JackPortIsPhysical|JackPortIsInput);
if (ports) {
for (i = 0; ports[i]; ++i) {
printf("name: %s\n", ports[i]);
}
jack_free(ports);
}

return 0;
}

int
main (int argc, char *argv[])
{
jack_options_t options = JackNullOption;
jack_status_t status;

/* open a client connection to the JACK server */

client = jack_client_open("control_client", options, &status);
if (client == NULL) {
printf("jack_client_open() failed \n");
exit(1);
}

if (jack_set_graph_order_callback(client, Jack_Graph_Order_Callback, 0) != 0) {
printf("Error when calling jack_set_graph_order_callback() !\n");
}

/* Tell the JACK server that we are ready to roll. Our
* process() callback will start running now. */

if (jack_activate(client)) {
printf("cannot activate client");
exit(1);
}

printf("Type 'q' to quit\n");
while ((getchar() != 'q')) {}

jack_client_close(client);
exit (0);
}

+ 0
- 88
example-clients/cpu_load.c View File

@@ -1,88 +0,0 @@
/** @file cpu_load.c
*
*/

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <signal.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <jack/jack.h>


jack_client_t *client;

static void signal_handler(int sig)
{
jack_client_close(client);
fprintf(stderr, "signal received, exiting ...\n");
exit(0);
}


/**
* JACK calls this shutdown_callback if the server ever shuts down or
* decides to disconnect the client.
*/
void
jack_shutdown(void *arg)
{
exit(1);
}

int
main(int argc, char *argv[])
{
jack_options_t options = JackNullOption;
jack_status_t status;

/* open a client connection to the JACK server */

client = jack_client_open ("jack_cpu_load", options, &status);
if (client == NULL) {
fprintf(stderr, "jack_client_open() failed, "
"status = 0x%2.0x\n", status);
if (status & JackServerFailed) {
fprintf(stderr, "Unable to connect to JACK server\n");
}
exit(1);
}

jack_on_shutdown(client, jack_shutdown, 0);

/* Tell the JACK server that we are ready to roll. Our
* process() callback will start running now. */

if (jack_activate(client)) {
fprintf(stderr, "cannot activate client");
exit(1);
}

/* install a signal handler to properly quits jack client */
#ifdef WIN32
signal(SIGINT, signal_handler);
signal(SIGABRT, signal_handler);
signal(SIGTERM, signal_handler);
#else
signal(SIGQUIT, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGHUP, signal_handler);
signal(SIGINT, signal_handler);
#endif

while (1) {
printf("jack DSP load %f\n", jack_cpu_load(client));
#ifdef WIN32
Sleep(1000);
#else
sleep(1);
#endif
}

jack_client_close(client);
exit(0 );
}

+ 0
- 247
example-clients/impulse_grabber.c View File

@@ -1,247 +0,0 @@
/*
* Copyright (C) 2001 Steve Harris
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <math.h>
#include <getopt.h>

#include <jack/jack.h>

jack_port_t *input_port;
jack_port_t *output_port;

unsigned int impulse_sent = 0;
float *response;
unsigned long response_duration;
unsigned long response_pos;
int grab_finished = 0;
jack_client_t *client;

static void signal_handler(int sig)
{
jack_client_close(client);
fprintf(stderr, "signal received, exiting ...\n");
exit(0);
}

static int
process (jack_nframes_t nframes, void *arg)

{
jack_default_audio_sample_t *out = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port, nframes);
jack_default_audio_sample_t *in = (jack_default_audio_sample_t *) jack_port_get_buffer (input_port, nframes);
unsigned int i;

if (grab_finished) {
return 0;
} else if (impulse_sent) {
for(i=0; i<nframes && response_pos < response_duration; i++) {
response[response_pos++] = in[i];
}
if (response_pos >= response_duration) {
grab_finished = 1;
}
for (i=0; i<nframes; i++) {
out[i] = 0.0f;;
}
} else {
out[0] = 1.0f;
for (i=1; i<nframes; i++) {
out[i] = 0.0f;
}
impulse_sent = 1;
}

return 0;
}

static void
jack_shutdown (void *arg)
{
fprintf(stderr, "JACK shut down, exiting ...\n");
exit (1);
}

int
main (int argc, char *argv[])
{
const char **ports;
float fs; // The sample rate
float peak;
unsigned long peak_sample;
unsigned int i;
float duration = 0.0f;
unsigned int c_format = 0;
int longopt_index = 0;
int c;
extern int optind, opterr;
int show_usage = 0;
char *optstring = "d:f:h";
struct option long_options[] = {
{ "help", 1, 0, 'h' },
{ "duration", 1, 0, 'd' },
{ "format", 1, 0, 'f' },
{ 0, 0, 0, 0 }
};

while ((c = getopt_long (argc, argv, optstring, long_options, &longopt_index)) != -1) {
switch (c) {
case 1:
// end of opts, but don't care
break;
case 'h':
show_usage++;
break;
case 'd':
duration = (float)atof(optarg);
break;
case 'f':
if (*optarg == 'c' || *optarg == 'C') {
c_format = 1;
}
break;
default:
show_usage++;
break;
}
}
if (show_usage || duration <= 0.0f) {
fprintf(stderr, "usage: jack_impulse_grab -d duration [-f (C|gnuplot)]\n");
exit(1);
}

/* try to become a client of the JACK server */

if ((client = jack_client_open("impulse_grabber", JackNullOption, NULL)) == 0) {
fprintf (stderr, "JACK server not running?\n");
return 1;
}

/* tell the JACK server to call `process()' whenever
there is work to be done.
*/

jack_set_process_callback (client, process, 0);

/* tell the JACK server to call `jack_shutdown()' if
it ever shuts down, either entirely, or if it
just decides to stop calling us.
*/

jack_on_shutdown (client, jack_shutdown, 0);

/* display the current sample rate. once the client is activated
(see below), you should rely on your own sample rate
callback (see above) for this value.
*/

fs = jack_get_sample_rate(client);
response_duration = (unsigned long) (fs * duration);
response = malloc(response_duration * sizeof(float));
fprintf(stderr,
"Grabbing %f seconds (%lu samples) of impulse response\n",
duration, response_duration);

/* create two ports */

input_port = jack_port_register (client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
output_port = jack_port_register (client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);

/* tell the JACK server that we are ready to roll */

if (jack_activate (client)) {
fprintf (stderr, "cannot activate client");
return 1;
}

/* connect the ports. Note: you can't do this before
the client is activated (this may change in the future).
*/

if ((ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput)) == NULL) {
fprintf(stderr, "Cannot find any physical capture ports");
exit(1);
}

if (jack_connect (client, ports[0], jack_port_name (input_port))) {
fprintf (stderr, "cannot connect input ports\n");
}

free (ports);

if ((ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) {
fprintf(stderr, "Cannot find any physical playback ports");
exit(1);
}

if (jack_connect (client, jack_port_name (output_port), ports[0])) {
fprintf (stderr, "cannot connect output ports\n");
}

free (ports);

/* install a signal handler to properly quits jack client */
signal(SIGQUIT, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGHUP, signal_handler);
signal(SIGINT, signal_handler);

/* Wait for grab to finish */
while (!grab_finished) {
sleep (1);
}
jack_client_close (client);

peak = response[0];
peak_sample = 0;
if (c_format) {
printf("impulse[%lu] = {", response_duration);
for (i=0; i<response_duration; i++) {
if (i % 4 != 0) {
printf(" ");
} else {
printf("\n\t");
}
printf("\"%+1.10f\"", response[i]);
if (i < response_duration - 1) {
printf(",");
}
if (fabs(response[i]) > peak) {
peak = fabs(response[i]);
peak_sample = i;
}
}
printf("\n};\n");
} else {
for (i=0; i<response_duration; i++) {
printf("%1.12f\n", response[i]);
if (fabs(response[i]) > peak) {
peak = fabs(response[i]);
peak_sample = i;
}
}
}
fprintf(stderr, "Peak value was %f at sample %lu\n", peak, peak_sample);

exit (0);
}

+ 0
- 125
example-clients/inprocess.c View File

@@ -1,125 +0,0 @@
/** @file inprocess.c
*
* @brief This demonstrates the basic concepts for writing a client
* that runs within the JACK server process.
*
* For the sake of example, a port_pair_t is allocated in
* jack_initialize(), passed to inprocess() as an argument, then freed
* in jack_finish().
*/

#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <jack/jack.h>

/**
* For the sake of example, an instance of this struct is allocated in
* jack_initialize(), passed to inprocess() as an argument, then freed
* in jack_finish().
*/
typedef struct {
jack_port_t *input_port;
jack_port_t *output_port;
} port_pair_t;

/**
* Called in the realtime thread on every process cycle. The entry
* point name was passed to jack_set_process_callback() from
* jack_initialize(). Although this is an internal client, its
* process() interface is identical to @ref simple_client.c.
*
* @return 0 if successful; otherwise jack_finish() will be called and
* the client terminated immediately.
*/
int
inprocess (jack_nframes_t nframes, void *arg)
{
port_pair_t *pp = arg;
jack_default_audio_sample_t *out =
jack_port_get_buffer (pp->output_port, nframes);
jack_default_audio_sample_t *in =
jack_port_get_buffer (pp->input_port, nframes);

memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes);

return 0; /* continue */
}

/**
* This required entry point is called after the client is loaded by
* jack_internal_client_load().
*
* @param client pointer to JACK client structure.
* @param load_init character string passed to the load operation.
*
* @return 0 if successful; otherwise jack_finish() will be called and
* the client terminated immediately.
*/
JACK_LIB_EXPORT
int
jack_initialize (jack_client_t *client, const char *load_init)
{
port_pair_t *pp = malloc (sizeof (port_pair_t));
const char **ports;

if (pp == NULL)
return 1; /* heap exhausted */

jack_set_process_callback (client, inprocess, pp);

/* create a pair of ports */
pp->input_port = jack_port_register (client, "input",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput, 0);
pp->output_port = jack_port_register (client, "output",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);

/* join the process() cycle */
jack_activate (client);
ports = jack_get_ports (client, NULL, NULL,
JackPortIsPhysical|JackPortIsOutput);
if (ports == NULL) {
fprintf(stderr, "no physical capture ports\n");
return 1; /* terminate client */
}

if (jack_connect (client, ports[0], jack_port_name (pp->input_port))) {
fprintf (stderr, "cannot connect input ports\n");
}
jack_free (ports);
ports = jack_get_ports (client, NULL, NULL,
JackPortIsPhysical|JackPortIsInput);
if (ports == NULL) {
fprintf(stderr, "no physical playback ports\n");
return 1; /* terminate client */
}
if (jack_connect (client, jack_port_name (pp->output_port), ports[0])) {
fprintf (stderr, "cannot connect output ports\n");
}
jack_free (ports);

return 0; /* success */
}

/**
* This required entry point is called immediately before the client
* is unloaded, which could happen due to a call to
* jack_internal_client_unload(), or a nonzero return from either
* jack_initialize() or inprocess().
*
* @param arg the same parameter provided to inprocess().
*/
JACK_LIB_EXPORT
void
jack_finish (void *arg)
{
if (arg)
free ((port_pair_t *) arg);
}

+ 0
- 123
example-clients/internal_metro.cpp View File

@@ -1,123 +0,0 @@
/*
Copyright (C) 2002 Anthony Van Groningen
Copyright (C) 2005 Grame
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "internal_metro.h"

typedef jack_default_audio_sample_t sample_t;

const double PI = 3.14;

static int process_audio (jack_nframes_t nframes, void* arg)
{
InternalMetro* metro = (InternalMetro*)arg;
sample_t *buffer = (sample_t *) jack_port_get_buffer (metro->output_port, nframes);
jack_nframes_t frames_left = nframes;

while (metro->wave_length - metro->offset < frames_left) {
memcpy (buffer + (nframes - frames_left), metro->wave + metro->offset, sizeof (sample_t) * (metro->wave_length - metro->offset));
frames_left -= metro->wave_length - metro->offset;
metro->offset = 0;
}
if (frames_left > 0) {
memcpy (buffer + (nframes - frames_left), metro->wave + metro->offset, sizeof (sample_t) * frames_left);
metro->offset += frames_left;
}

return 0;
}

InternalMetro::InternalMetro(int freq, double max_amp, int dur_arg, int bpm, char* client_name)
{
sample_t scale;
int i, attack_length, decay_length;
int attack_percent = 1, decay_percent = 10;
const char *bpm_string = "bpm";

offset = 0;

/* Initial Jack setup, get sample rate */
if (!client_name) {
client_name = (char *) malloc (9 * sizeof (char));
strcpy (client_name, "metro");
}
if ((client = jack_client_open (client_name, JackNullOption, NULL)) == 0) {
fprintf (stderr, "jack server not running?\n");
return;
}

jack_set_process_callback (client, process_audio, this);
output_port = jack_port_register (client, bpm_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
input_port = jack_port_register (client, "metro_in", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);

sr = jack_get_sample_rate (client);

/* setup wave table parameters */
wave_length = 60 * sr / bpm;
tone_length = sr * dur_arg / 1000;
attack_length = tone_length * attack_percent / 100;
decay_length = tone_length * decay_percent / 100;
scale = 2 * PI * freq / sr;

if (tone_length >= wave_length) {
/*
fprintf (stderr, "invalid duration (tone length = %" PRIu32
", wave length = %" PRIu32 "\n", tone_length,
wave_length);
*/
return;
}
if (attack_length + decay_length > (int)tone_length) {
fprintf (stderr, "invalid attack/decay\n");
return;
}

/* Build the wave table */
wave = (sample_t *) malloc (wave_length * sizeof(sample_t));
amp = (double *) malloc (tone_length * sizeof(double));

for (i = 0; i < attack_length; i++) {
amp[i] = max_amp * i / ((double) attack_length);
}
for (i = attack_length; i < (int) tone_length - decay_length; i++) {
amp[i] = max_amp;
}
for (i = (int)tone_length - decay_length; i < (int)tone_length; i++) {
amp[i] = - max_amp * (i - (double) tone_length) / ((double) decay_length);
}
for (i = 0; i < (int) tone_length; i++) {
wave[i] = amp[i] * sin (scale * i);
}
for (i = tone_length; i < (int) wave_length; i++) {
wave[i] = 0;
}

if (jack_activate (client)) {
fprintf(stderr, "cannot activate client");
}
}

InternalMetro::~InternalMetro()
{
jack_deactivate(client);
jack_port_unregister(client, input_port);
jack_port_unregister(client, output_port);
jack_client_close(client);
free(amp);
free(wave);
}

+ 0
- 68
example-clients/internal_metro.h View File

@@ -1,68 +0,0 @@
/*
Copyright (C) 2001 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#ifndef __internal_metro__
#define __internal_metro__

#ifdef __cplusplus
extern "C"
{
#endif

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <math.h>
#include <getopt.h>
#include <string.h>

#include "jack.h"
#include "transport.h"


typedef jack_default_audio_sample_t sample_t;

/*!
\brief A class to test internal clients
*/

struct InternalMetro {

jack_client_t *client;
jack_port_t *input_port;
jack_port_t *output_port;

unsigned long sr;
int freq;
int bpm;
jack_nframes_t tone_length, wave_length;
sample_t *wave;
double *amp;
long offset ;

InternalMetro(int freq, double max_amp, int dur_arg, int bpm, char* client_name);
virtual ~InternalMetro();

};

#ifdef __cplusplus
}
#endif

#endif

+ 0
- 217
example-clients/latent_client.c View File

@@ -1,217 +0,0 @@
/** @file latent_client.c
*
* @brief This simple client demonstrates the most basic features of JACK
* as they would be used by many applications.
*/

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>

#include <jack/jack.h>

jack_port_t *input_port;
jack_port_t *output_port;
jack_client_t *client;

jack_default_audio_sample_t *delay_line;
jack_nframes_t delay_index;
jack_nframes_t latency = 1024;

#ifdef WIN32
#define jack_sleep(val) Sleep((val))
#else
#define jack_sleep(val) usleep((val) * 1000)
#endif

/**
* The process callback for this JACK application is called in a
* special realtime thread once for each audio cycle.
*
* This client does nothing more than copy data from its input
* port to its output port. It will exit when stopped by
* the user (e.g. using Ctrl-C on a unix-ish operating system)
*/
int
process (jack_nframes_t nframes, void *arg)
{
jack_default_audio_sample_t *in, *out;
int k;

in = jack_port_get_buffer (input_port, nframes);
out = jack_port_get_buffer (output_port, nframes);

for (k=0; k<nframes; k++) {
out[k] = delay_line[delay_index];
delay_line[delay_index] = in[k];
delay_index = (delay_index + 1) % latency;
}

return 0;
}

void
latency_cb (jack_latency_callback_mode_t mode, void *arg)
{
jack_latency_range_t range;
if (mode == JackCaptureLatency) {
jack_port_get_latency_range (input_port, mode, &range);
range.min += latency;
range.max += latency;
jack_port_set_latency_range (output_port, mode, &range);
} else {
jack_port_get_latency_range (output_port, mode, &range);
range.min += latency;
range.max += latency;
jack_port_set_latency_range (input_port, mode, &range);
}
}

/**
* JACK calls this shutdown_callback if the server ever shuts down or
* decides to disconnect the client.
*/
void
jack_shutdown (void *arg)
{
fprintf(stderr, "JACK shut down, exiting ...\n");
exit (1);
}

int
main (int argc, char *argv[])
{
const char **ports;
const char *client_name = "latent";
const char *server_name = NULL;
jack_options_t options = JackNullOption;
jack_status_t status;


if (argc == 2)
latency = atoi(argv[1]);

delay_line = malloc( latency * sizeof(jack_default_audio_sample_t));
if (delay_line == NULL) {
fprintf (stderr, "no memory");
exit(1);
}

memset (delay_line, 0, latency * sizeof(jack_default_audio_sample_t));

/* open a client connection to the JACK server */

client = jack_client_open (client_name, options, &status, server_name);
if (client == NULL) {
fprintf (stderr, "jack_client_open() failed, "
"status = 0x%2.0x\n", status);
if (status & JackServerFailed) {
fprintf (stderr, "Unable to connect to JACK server\n");
}
exit (1);
}
if (status & JackServerStarted) {
fprintf (stderr, "JACK server started\n");
}
if (status & JackNameNotUnique) {
client_name = jack_get_client_name(client);
fprintf (stderr, "unique name `%s' assigned\n", client_name);
}

/* tell the JACK server to call `process()' whenever
there is work to be done.
*/

jack_set_process_callback (client, process, 0);

/* tell the JACK server to call `latency()' whenever
the latency needs to be recalculated.
*/
if (jack_set_latency_callback)
jack_set_latency_callback (client, latency_cb, 0);

/* tell the JACK server to call `jack_shutdown()' if
it ever shuts down, either entirely, or if it
just decides to stop calling us.
*/

jack_on_shutdown (client, jack_shutdown, 0);

/* display the current sample rate.
*/

printf ("engine sample rate: %" PRIu32 "\n",
jack_get_sample_rate (client));

/* create two ports */

input_port = jack_port_register (client, "input",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput, 0);
output_port = jack_port_register (client, "output",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);

if ((input_port == NULL) || (output_port == NULL)) {
fprintf(stderr, "no more JACK ports available\n");
exit (1);
}

/* Tell the JACK server that we are ready to roll. Our
* process() callback will start running now. */

if (jack_activate (client)) {
fprintf (stderr, "cannot activate client");
exit (1);
}

/* Connect the ports. You can't do this before the client is
* activated, because we can't make connections to clients
* that aren't running. Note the confusing (but necessary)
* orientation of the driver backend ports: playback ports are
* "input" to the backend, and capture ports are "output" from
* it.
*/

ports = jack_get_ports (client, NULL, NULL,
JackPortIsPhysical|JackPortIsOutput);
if (ports == NULL) {
fprintf(stderr, "no physical capture ports\n");
exit (1);
}

if (jack_connect (client, ports[0], jack_port_name (input_port))) {
fprintf (stderr, "cannot connect input ports\n");
}

free (ports);

ports = jack_get_ports (client, NULL, NULL,
JackPortIsPhysical|JackPortIsInput);
if (ports == NULL) {
fprintf(stderr, "no physical playback ports\n");
exit (1);
}

if (jack_connect (client, jack_port_name (output_port), ports[0])) {
fprintf (stderr, "cannot connect output ports\n");
}

free (ports);

/* keep running until stopped by the user */

jack_sleep (-1);

/* this is never reached but if the program
had some other way to exit besides being killed,
they would be important to call.
*/

jack_client_close (client);
exit (0);
}


+ 0
- 302
example-clients/metro.c View File

@@ -1,302 +0,0 @@
/*
Copyright (C) 2002 Anthony Van Groningen

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <math.h>
#include <signal.h>
#include <getopt.h>
#include <string.h>

#include <jack/jack.h>
#include <jack/transport.h>

typedef jack_default_audio_sample_t sample_t;

const double PI = 3.14;

jack_client_t *client;
jack_port_t *output_port;
unsigned long sr;
int freq = 880;
int bpm;
jack_nframes_t tone_length, wave_length;
sample_t *wave;
long offset = 0;
int transport_aware = 0;
jack_transport_state_t transport_state;

static void signal_handler(int sig)
{
jack_client_close(client);
fprintf(stderr, "signal received, exiting ...\n");
exit(0);
}

static void
usage ()
{
fprintf (stderr, "\n"
"usage: jack_metro \n"
" [ --frequency OR -f frequency (in Hz) ]\n"
" [ --amplitude OR -A maximum amplitude (between 0 and 1) ]\n"
" [ --duration OR -D duration (in ms) ]\n"
" [ --attack OR -a attack (in percent of duration) ]\n"
" [ --decay OR -d decay (in percent of duration) ]\n"
" [ --name OR -n jack name for metronome client ]\n"
" [ --transport OR -t transport aware ]\n"
" --bpm OR -b beats per minute\n"
);
}

static void
process_silence (jack_nframes_t nframes)
{
sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
memset (buffer, 0, sizeof (jack_default_audio_sample_t) * nframes);
}

jack_nframes_t last_time;
jack_time_t last_micro_time;

static void
process_audio (jack_nframes_t nframes)
{
sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
jack_nframes_t frames_left = nframes;

while (wave_length - offset < frames_left) {
memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * (wave_length - offset));
frames_left -= wave_length - offset;
offset = 0;
}
if (frames_left > 0) {
memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * frames_left);
offset += frames_left;
}

/*
jack_nframes_t cur_time = jack_frame_time(client);
jack_time_t cur_micro_time = jack_get_time();

printf("jack_frame_time %lld micro %lld delta %d\n", cur_time, (cur_micro_time - last_micro_time), cur_time - last_time);
last_time = cur_time;
last_micro_time = cur_micro_time;
*/
}

static int
process (jack_nframes_t nframes, void *arg)
{
if (transport_aware) {
jack_position_t pos;

if (jack_transport_query (client, &pos)
!= JackTransportRolling) {

process_silence (nframes);
return 0;
}
offset = pos.frame % wave_length;
}
process_audio (nframes);
return 0;
}

int
main (int argc, char *argv[])
{
sample_t scale;
int i, attack_length, decay_length;
double *amp;
double max_amp = 0.5;
int option_index;
int opt;
int got_bpm = 0;
int attack_percent = 1, decay_percent = 10, dur_arg = 100;
char *client_name = 0;
char *bpm_string = "bpm";
int verbose = 0;
jack_status_t status;

const char *options = "f:A:D:a:d:b:n:thv";
struct option long_options[] =
{
{"frequency", 1, 0, 'f'},
{"amplitude", 1, 0, 'A'},
{"duration", 1, 0, 'D'},
{"attack", 1, 0, 'a'},
{"decay", 1, 0, 'd'},
{"bpm", 1, 0, 'b'},
{"name", 1, 0, 'n'},
{"transport", 0, 0, 't'},
{"help", 0, 0, 'h'},
{"verbose", 0, 0, 'v'},
{0, 0, 0, 0}
};

while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != -1) {
switch (opt) {
case 'f':
if ((freq = atoi (optarg)) <= 0) {
fprintf (stderr, "invalid frequency\n");
return -1;
}
break;
case 'A':
if (((max_amp = atof (optarg)) <= 0)|| (max_amp > 1)) {
fprintf (stderr, "invalid amplitude\n");
return -1;
}
break;
case 'D':
dur_arg = atoi (optarg);
fprintf (stderr, "durarg = %u\n", dur_arg);
break;
case 'a':
if (((attack_percent = atoi (optarg)) < 0) || (attack_percent > 100)) {
fprintf (stderr, "invalid attack percent\n");
return -1;
}
break;
case 'd':
if (((decay_percent = atoi (optarg)) < 0) || (decay_percent > 100)) {
fprintf (stderr, "invalid decay percent\n");
return -1;
}
break;
case 'b':
got_bpm = 1;
if ((bpm = atoi (optarg)) < 0) {
fprintf (stderr, "invalid bpm\n");
return -1;
}
bpm_string = (char *) malloc ((strlen (optarg) + 5) * sizeof (char));
strcpy (bpm_string, optarg);
strcat (bpm_string, "_bpm");
break;
case 'n':
client_name = (char *) malloc ((strlen (optarg) + 1) * sizeof (char));
strcpy (client_name, optarg);
break;
case 'v':
verbose = 1;
break;
case 't':
transport_aware = 1;
break;
default:
fprintf (stderr, "unknown option %c\n", opt);
case 'h':
usage ();
return -1;
}
}
if (!got_bpm) {
fprintf (stderr, "bpm not specified\n");
usage ();
return -1;
}

/* Initial Jack setup, get sample rate */
if (!client_name) {
client_name = (char *) malloc (9 * sizeof (char));
strcpy (client_name, "metro");
}
if ((client = jack_client_open (client_name, JackNoStartServer, &status)) == 0) {
fprintf (stderr, "JACK server not running?\n");
return 1;
}
jack_set_process_callback (client, process, 0);
output_port = jack_port_register (client, bpm_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);

sr = jack_get_sample_rate (client);

/* setup wave table parameters */
wave_length = 60 * sr / bpm;
tone_length = sr * dur_arg / 1000;
attack_length = tone_length * attack_percent / 100;
decay_length = tone_length * decay_percent / 100;
scale = 2 * PI * freq / sr;

if (tone_length >= wave_length) {
fprintf (stderr, "invalid duration (tone length = %u, wave length = %u\n", tone_length, wave_length);
return -1;
}
if (attack_length + decay_length > (int)tone_length) {
fprintf (stderr, "invalid attack/decay\n");
return -1;
}

/* Build the wave table */
wave = (sample_t *) malloc (wave_length * sizeof(sample_t));
amp = (double *) malloc (tone_length * sizeof(double));

for (i = 0; i < attack_length; i++) {
amp[i] = max_amp * i / ((double) attack_length);
}
for (i = attack_length; i < (int)tone_length - decay_length; i++) {
amp[i] = max_amp;
}
for (i = (int)tone_length - decay_length; i < (int)tone_length; i++) {
amp[i] = - max_amp * (i - (double) tone_length) / ((double) decay_length);
}
for (i = 0; i < (int)tone_length; i++) {
wave[i] = amp[i] * sin (scale * i);
}
for (i = tone_length; i < (int)wave_length; i++) {
wave[i] = 0;
}

if (jack_activate (client)) {
fprintf (stderr, "cannot activate client\n");
goto error;
}

/* install a signal handler to properly quits jack client */
#ifdef WIN32
signal(SIGINT, signal_handler);
signal(SIGABRT, signal_handler);
signal(SIGTERM, signal_handler);
#else
signal(SIGQUIT, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGHUP, signal_handler);
signal(SIGINT, signal_handler);
#endif

/* run until interrupted */
while (1) {
#ifdef WIN32
Sleep(1000);
#else
sleep(1);
#endif
};

jack_client_close(client);

error:
free(amp);
free(wave);
exit (0);
}

+ 0
- 969
example-clients/midi_latency_test.c View File

@@ -1,969 +0,0 @@
/*
Copyright (C) 2010 Devin Anderson

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/

/*
* This program is used to measure MIDI latency and jitter. It writes MIDI
* messages to one port and calculates how long it takes before it reads the
* same MIDI message over another port. It was written to calculate the
* latency and jitter of hardware and JACK hardware drivers, but might have
* other practical applications.
*
* The latency results of the program include the latency introduced by the
* JACK system. Because JACK has sample accurate MIDI, the same latency
* imposed on audio is also imposed on MIDI going through the system. Make
* sure you take this into account before complaining to me or (*especially*)
* other JACK developers about reported MIDI latency.
*
* The jitter results are a little more interesting. The program attempts to
* calculate 'average jitter' and 'peak jitter', as defined here:
*
* http://openmuse.org/transport/fidelity.html
*
* It also outputs a jitter plot, which gives you a more specific idea about
* the MIDI jitter for the ports you're testing. This is useful for catching
* extreme jitter values, and for analyzing the amount of truth in the
* technical specifications for your MIDI interface(s). :)
*
* This program is loosely based on 'alsa-midi-latency-test' in the ALSA test
* suite.
*
* To port this program to non-POSIX platforms, you'll have to include
* implementations for semaphores and command-line argument handling.
*/

#include <assert.h>
#include <errno.h>
#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <getopt.h>

#include <jack/jack.h>
#include <jack/midiport.h>

#ifdef WIN32
#include <windows.h>
#include <unistd.h>
#else
#include <semaphore.h>
#endif

#define ABS(x) (((x) >= 0) ? (x) : (-(x)))

#ifdef WIN32
typedef HANDLE semaphore_t;
#else
typedef sem_t *semaphore_t;
#endif

const char *ERROR_MSG_TIMEOUT = "timed out while waiting for MIDI message";
const char *ERROR_RESERVE = "could not reserve MIDI event on port buffer";
const char *ERROR_SHUTDOWN = "the JACK server has been shutdown";

const char *SOURCE_EVENT_RESERVE = "jack_midi_event_reserve";
const char *SOURCE_PROCESS = "handle_process";
const char *SOURCE_SHUTDOWN = "handle_shutdown";
const char *SOURCE_SIGNAL_SEMAPHORE = "signal_semaphore";
const char *SOURCE_WAIT_SEMAPHORE = "wait_semaphore";

char *alias1;
char *alias2;
jack_client_t *client;
semaphore_t connect_semaphore;
volatile int connections_established;
const char *error_message;
const char *error_source;
jack_nframes_t highest_latency;
jack_time_t highest_latency_time;
jack_latency_range_t in_latency_range;
jack_port_t *in_port;
semaphore_t init_semaphore;
jack_nframes_t last_activity;
jack_time_t last_activity_time;
jack_time_t *latency_time_values;
jack_nframes_t *latency_values;
jack_nframes_t lowest_latency;
jack_time_t lowest_latency_time;
jack_midi_data_t *message_1;
jack_midi_data_t *message_2;
int messages_received;
int messages_sent;
size_t message_size;
jack_latency_range_t out_latency_range;
jack_port_t *out_port;
semaphore_t process_semaphore;
volatile sig_atomic_t process_state;
char *program_name;
jack_port_t *remote_in_port;
jack_port_t *remote_out_port;
size_t samples;
const char *target_in_port_name;
const char *target_out_port_name;
int timeout;
jack_nframes_t total_latency;
jack_time_t total_latency_time;
int unexpected_messages;
int xrun_count;

#ifdef WIN32
char semaphore_error_msg[1024];
#endif

static void
output_error(const char *source, const char *message);

static void
output_usage(void);

static void
set_process_error(const char *source, const char *message);

static int
signal_semaphore(semaphore_t semaphore);

static jack_port_t *
update_connection(jack_port_t *remote_port, int connected,
jack_port_t *local_port, jack_port_t *current_port,
const char *target_name);

static int
wait_semaphore(semaphore_t semaphore, int block);

static semaphore_t
create_semaphore(int id)
{
semaphore_t semaphore;

#ifdef WIN32
semaphore = CreateSemaphore(NULL, 0, 2, NULL);
#elif defined (__APPLE__)
char name[128];
sprintf(name, "midi_sem_%d", id);
semaphore = sem_open(name, O_CREAT, 0777, 0);
if (semaphore == (sem_t *) SEM_FAILED) {
semaphore = NULL;
}
#else
semaphore = malloc(sizeof(sem_t));
if (semaphore != NULL) {
if (sem_init(semaphore, 0, 0)) {
free(semaphore);
semaphore = NULL;
}
}
#endif

return semaphore;
}

static void
destroy_semaphore(semaphore_t semaphore, int id)
{

#ifdef WIN32
CloseHandle(semaphore);
#else
sem_destroy(semaphore);
#ifdef __APPLE__
{
char name[128];
sprintf(name, "midi_sem_%d", id);
sem_close(semaphore);
sem_unlink(name);
}
#else
free(semaphore);
#endif
#endif

}

static void
die(const char *source, const char *error_message)
{
output_error(source, error_message);
output_usage();
exit(EXIT_FAILURE);
}

static const char *
get_semaphore_error(void)
{

#ifdef WIN32
DWORD error = GetLastError();
if (! FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
semaphore_error_msg, 1024, NULL)) {
snprintf(semaphore_error_msg, 1023, "Unknown OS error code '%ld'",
error);
}
return semaphore_error_msg;
#else
return strerror(errno);
#endif

}

static void
handle_info(const char *message)
{
/* Suppress info */
}

static void
handle_port_connection_change(jack_port_id_t port_id_1,
jack_port_id_t port_id_2, int connected,
void *arg)
{
jack_port_t *port_1;
jack_port_t *port_2;
if ((remote_in_port != NULL) && (remote_out_port != NULL)) {
return;
}
port_1 = jack_port_by_id(client, port_id_1);
port_2 = jack_port_by_id(client, port_id_2);

/* The 'update_connection' call is not RT-safe. It calls
'jack_port_get_connections' and 'jack_free'. This might be a problem
with JACK 1, as this callback runs in the process thread in JACK 1. */

if (port_1 == in_port) {
remote_in_port = update_connection(port_2, connected, in_port,
remote_in_port,
target_in_port_name);
} else if (port_2 == in_port) {
remote_in_port = update_connection(port_1, connected, in_port,
remote_in_port,
target_in_port_name);
} else if (port_1 == out_port) {
remote_out_port = update_connection(port_2, connected, out_port,
remote_out_port,
target_out_port_name);
} else if (port_2 == out_port) {
remote_out_port = update_connection(port_1, connected, out_port,
remote_out_port,
target_out_port_name);
}
if ((remote_in_port != NULL) && (remote_out_port != NULL)) {
connections_established = 1;
if (! signal_semaphore(connect_semaphore)) {
/* Sigh ... */
die("post_semaphore", get_semaphore_error());
}
if (! signal_semaphore(init_semaphore)) {
/* Sigh ... */
die("post_semaphore", get_semaphore_error());
}
}
}

static int
handle_process(jack_nframes_t frames, void *arg)
{
jack_midi_data_t *buffer;
jack_midi_event_t event;
jack_nframes_t event_count;
jack_nframes_t event_time;
jack_nframes_t frame;
size_t i;
jack_nframes_t last_frame_time;
jack_midi_data_t *message;
jack_time_t microseconds;
void *port_buffer;
jack_time_t time;
jack_midi_clear_buffer(jack_port_get_buffer(out_port, frames));
switch (process_state) {

case 0:
/* State: initializing */
switch (wait_semaphore(init_semaphore, 0)) {
case -1:
set_process_error(SOURCE_WAIT_SEMAPHORE, get_semaphore_error());
/* Fallthrough on purpose */
case 0:
return 0;
}
highest_latency = 0;
lowest_latency = 0;
messages_received = 0;
messages_sent = 0;
process_state = 1;
total_latency = 0;
total_latency_time = 0;
unexpected_messages = 0;
xrun_count = 0;
jack_port_get_latency_range(remote_in_port, JackCaptureLatency,
&in_latency_range);
jack_port_get_latency_range(remote_out_port, JackPlaybackLatency,
&out_latency_range);
goto send_message;

case 1:
/* State: processing */
port_buffer = jack_port_get_buffer(in_port, frames);
event_count = jack_midi_get_event_count(port_buffer);
last_frame_time = jack_last_frame_time(client);
for (i = 0; i < event_count; i++) {
jack_midi_event_get(&event, port_buffer, i);
message = (messages_received % 2) ? message_2 : message_1;
if ((event.size == message_size) &&
(! memcmp(message, event.buffer,
message_size * sizeof(jack_midi_data_t)))) {
goto found_message;
}
unexpected_messages++;
}
microseconds = jack_frames_to_time(client, last_frame_time) -
last_activity_time;
if ((microseconds / 1000000) >= timeout) {
set_process_error(SOURCE_PROCESS, ERROR_MSG_TIMEOUT);
}
break;
found_message:
event_time = last_frame_time + event.time;
frame = event_time - last_activity;
time = jack_frames_to_time(client, event_time) - last_activity_time;
if ((! highest_latency) || (frame > highest_latency)) {
highest_latency = frame;
highest_latency_time = time;
}
if ((! lowest_latency) || (frame < lowest_latency)) {
lowest_latency = frame;
lowest_latency_time = time;
}
latency_time_values[messages_received] = time;
latency_values[messages_received] = frame;
total_latency += frame;
total_latency_time += time;
messages_received++;
if (messages_received == samples) {
process_state = 2;
if (! signal_semaphore(process_semaphore)) {
/* Sigh ... */
die(SOURCE_SIGNAL_SEMAPHORE, get_semaphore_error());
}
break;
}
send_message:
frame = (jack_nframes_t) ((((double) rand()) / RAND_MAX) * frames);
if (frame >= frames) {
frame = frames - 1;
}
port_buffer = jack_port_get_buffer(out_port, frames);
buffer = jack_midi_event_reserve(port_buffer, frame, message_size);
if (buffer == NULL) {
set_process_error(SOURCE_EVENT_RESERVE, ERROR_RESERVE);
break;
}
message = (messages_sent % 2) ? message_2 : message_1;
memcpy(buffer, message, message_size * sizeof(jack_midi_data_t));
last_activity = jack_last_frame_time(client) + frame;
last_activity_time = jack_frames_to_time(client, last_activity);
messages_sent++;

case 2:
/* State: finished - do nothing */
case -1:
/* State: error - do nothing */
case -2:
/* State: signalled - do nothing */
;
}
return 0;
}

static void
handle_shutdown(void *arg)
{
set_process_error(SOURCE_SHUTDOWN, ERROR_SHUTDOWN);
}

static void
handle_signal(int sig)
{
process_state = -2;
if (! signal_semaphore(connect_semaphore)) {
/* Sigh ... */
die(SOURCE_SIGNAL_SEMAPHORE, get_semaphore_error());
}
if (! signal_semaphore(process_semaphore)) {
/* Sigh ... */
die(SOURCE_SIGNAL_SEMAPHORE, get_semaphore_error());
}
}

static int
handle_xrun(void *arg)
{
xrun_count++;
return 0;
}

static void
output_error(const char *source, const char *message)
{
fprintf(stderr, "%s: %s: %s\n", program_name, source, message);
}

static void
output_usage(void)
{
fprintf(stderr, "Usage: %s [options] [out-port-name in-port-name]\n\n"
"\t-h, --help print program usage\n"
"\t-m, --message-size=size set size of MIDI messages to send "
"(default: 3)\n"
"\t-s, --samples=n number of MIDI messages to send "
"(default: 1024)\n"
"\t-t, --timeout=seconds message timeout (default: 5)\n\n",
program_name);
}

static unsigned long
parse_positive_number_arg(char *s, char *name)
{
char *end_ptr;
unsigned long result;
errno = 0;
result = strtoul(s, &end_ptr, 10);
if (errno) {
die(name, strerror(errno));
}
if (*s == '\0') {
die(name, "argument value cannot be empty");
}
if (*end_ptr != '\0') {
die(name, "invalid value");
}
if (! result) {
die(name, "must be a positive number");
}
return result;
}

static int
register_signal_handler(void (*func)(int))
{

#ifdef WIN32
if (signal(SIGABRT, func) == SIG_ERR) {
return 0;
}
#else
if (signal(SIGQUIT, func) == SIG_ERR) {
return 0;
}
if (signal(SIGHUP, func) == SIG_ERR) {
return 0;
}
#endif

if (signal(SIGINT, func) == SIG_ERR) {
return 0;
}
if (signal(SIGTERM, func) == SIG_ERR) {
return 0;
}
return 1;
}

static void
set_process_error(const char *source, const char *message)