Browse Source

Remove example-clients and tools

Signed-off-by: falkTX <falktx@falktx.com>
tags/v1.9.22
falkTX 3 years 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)
{
error_source = source;
error_message = message;
process_state = -1;
if (! signal_semaphore(process_semaphore)) {
/* Sigh ... */
output_error(source, message);
die(SOURCE_SIGNAL_SEMAPHORE, get_semaphore_error());
}
}

static int
signal_semaphore(semaphore_t semaphore)
{

#ifdef WIN32
return ReleaseSemaphore(semaphore, 1, NULL);
#else
return ! sem_post(semaphore);
#endif

}

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)
{
if (connected) {
if (current_port) {
return current_port;
}
if (target_name) {
char *aliases[2];
if (! strcmp(target_name, jack_port_name(remote_port))) {
return remote_port;
}
aliases[0] = alias1;
aliases[1] = alias2;
switch (jack_port_get_aliases(remote_port, aliases)) {
case -1:
/* Sigh ... */
die("jack_port_get_aliases", "Failed to get port aliases");
case 2:
if (! strcmp(target_name, alias2)) {
return remote_port;
}
/* Fallthrough on purpose */
case 1:
if (! strcmp(target_name, alias1)) {
return remote_port;
}
/* Fallthrough on purpose */
case 0:
return NULL;
}
/* This shouldn't happen. */
assert(0);
}
return remote_port;
}
if (! strcmp(jack_port_name(remote_port), jack_port_name(current_port))) {
const char **port_names;
if (target_name) {
return NULL;
}
port_names = jack_port_get_connections(local_port);
if (port_names == NULL) {
return NULL;
}

/* If a connected port is disconnected and other ports are still
connected, then we take the first port name in the array and use it
as our remote port. It's a dumb implementation. */
current_port = jack_port_by_name(client, port_names[0]);
jack_free(port_names);
if (current_port == NULL) {
/* Sigh */
die("jack_port_by_name", "failed to get port by name");
}
}
return current_port;
}

static int
wait_semaphore(semaphore_t semaphore, int block)
{

#ifdef WIN32
DWORD result = WaitForSingleObject(semaphore, block ? INFINITE : 0);
switch (result) {
case WAIT_OBJECT_0:
return 1;
case WAIT_TIMEOUT:
return 0;
}
return -1;
#else
if (block) {
while (sem_wait(semaphore)) {
if (errno != EINTR) {
return -1;
}
}
} else {
while (sem_trywait(semaphore)) {
switch (errno) {
case EAGAIN:
return 0;
case EINTR:
continue;
default:
return -1;
}
}
}
return 1;
#endif

}

int
main(int argc, char **argv)
{
int jitter_plot[101];
int latency_plot[101];
int long_index = 0;
struct option long_options[] = {
{"help", 0, NULL, 'h'},
{"message-size", 1, NULL, 'm'},
{"samples", 1, NULL, 's'},
{"timeout", 1, NULL, 't'}
};
size_t name_arg_count;
size_t name_size;
char *option_string = "hm:s:t:";
int show_usage = 0;
connections_established = 0;
error_message = NULL;
message_size = 3;
program_name = argv[0];
remote_in_port = 0;
remote_out_port = 0;
samples = 1024;
timeout = 5;

for (;;) {
signed char c = getopt_long(argc, argv, option_string, long_options,
&long_index);
switch (c) {
case 'h':
show_usage = 1;
break;
case 'm':
message_size = parse_positive_number_arg(optarg, "message-size");
break;
case 's':
samples = parse_positive_number_arg(optarg, "samples");
break;
case 't':
timeout = parse_positive_number_arg(optarg, "timeout");
break;
default:
{
char *s = "'- '";
s[2] = c;
die(s, "invalid switch");
}
case -1:
if (show_usage) {
output_usage();
exit(EXIT_SUCCESS);
}
goto parse_port_names;
case 1:
/* end of switch :) */
;
}
}
parse_port_names:
name_arg_count = argc - optind;
switch (name_arg_count) {
case 2:
target_in_port_name = argv[optind + 1];
target_out_port_name = argv[optind];
break;
case 0:
target_in_port_name = 0;
target_out_port_name = 0;
break;
default:
output_usage();
return EXIT_FAILURE;
}
name_size = jack_port_name_size();
alias1 = malloc(name_size * sizeof(char));
if (alias1 == NULL) {
error_message = strerror(errno);
error_source = "malloc";
goto show_error;
}
alias2 = malloc(name_size * sizeof(char));
if (alias2 == NULL) {
error_message = strerror(errno);
error_source = "malloc";
goto free_alias1;
}
latency_values = malloc(sizeof(jack_nframes_t) * samples);
if (latency_values == NULL) {
error_message = strerror(errno);
error_source = "malloc";
goto free_alias2;
}
latency_time_values = malloc(sizeof(jack_time_t) * samples);
if (latency_time_values == NULL) {
error_message = strerror(errno);
error_source = "malloc";
goto free_latency_values;
}
message_1 = malloc(message_size * sizeof(jack_midi_data_t));
if (message_1 == NULL) {
error_message = strerror(errno);
error_source = "malloc";
goto free_latency_time_values;
}
message_2 = malloc(message_size * sizeof(jack_midi_data_t));
if (message_2 == NULL) {
error_message = strerror(errno);
error_source = "malloc";
goto free_message_1;
}
switch (message_size) {
case 1:
message_1[0] = 0xf6;
message_2[0] = 0xfe;
break;
case 2:
message_1[0] = 0xc0;
message_1[1] = 0x00;
message_2[0] = 0xd0;
message_2[1] = 0x7f;
break;
case 3:
message_1[0] = 0x80;
message_1[1] = 0x00;
message_1[2] = 0x00;
message_2[0] = 0x90;
message_2[1] = 0x7f;
message_2[2] = 0x7f;
break;
default:
message_1[0] = 0xf0;
memset(message_1 + 1, 0,
(message_size - 2) * sizeof(jack_midi_data_t));
message_1[message_size - 1] = 0xf7;
message_2[0] = 0xf0;
memset(message_2 + 1, 0x7f,
(message_size - 2) * sizeof(jack_midi_data_t));
message_2[message_size - 1] = 0xf7;
}
client = jack_client_open(program_name, JackNullOption, NULL);
if (client == NULL) {
error_message = "failed to open JACK client";
error_source = "jack_client_open";
goto free_message_2;
}
in_port = jack_port_register(client, "in", JACK_DEFAULT_MIDI_TYPE,
JackPortIsInput, 0);
if (in_port == NULL) {
error_message = "failed to register MIDI-in port";
error_source = "jack_port_register";
goto close_client;
}
out_port = jack_port_register(client, "out", JACK_DEFAULT_MIDI_TYPE,
JackPortIsOutput, 0);
if (out_port == NULL) {
error_message = "failed to register MIDI-out port";
error_source = "jack_port_register";
goto unregister_in_port;
}
if (jack_set_process_callback(client, handle_process, NULL)) {
error_message = "failed to set process callback";
error_source = "jack_set_process_callback";
goto unregister_out_port;
}
if (jack_set_xrun_callback(client, handle_xrun, NULL)) {
error_message = "failed to set xrun callback";
error_source = "jack_set_xrun_callback";
goto unregister_out_port;
}
if (jack_set_port_connect_callback(client, handle_port_connection_change,
NULL)) {
error_message = "failed to set port connection callback";
error_source = "jack_set_port_connect_callback";
goto unregister_out_port;
}
jack_on_shutdown(client, handle_shutdown, NULL);
jack_set_info_function(handle_info);
process_state = 0;

connect_semaphore = create_semaphore(0);
if (connect_semaphore == NULL) {
error_message = get_semaphore_error();
error_source = "create_semaphore";
goto unregister_out_port;
}
init_semaphore = create_semaphore(1);
if (init_semaphore == NULL) {
error_message = get_semaphore_error();
error_source = "create_semaphore";
goto destroy_connect_semaphore;;
}
process_semaphore = create_semaphore(2);
if (process_semaphore == NULL) {
error_message = get_semaphore_error();
error_source = "create_semaphore";
goto destroy_init_semaphore;
}
if (jack_activate(client)) {
error_message = "could not activate client";
error_source = "jack_activate";
goto destroy_process_semaphore;
}
if (name_arg_count) {
if (jack_connect(client, jack_port_name(out_port),
target_out_port_name)) {
error_message = "could not connect MIDI out port";
error_source = "jack_connect";
goto deactivate_client;
}
if (jack_connect(client, target_in_port_name,
jack_port_name(in_port))) {
error_message = "could not connect MIDI in port";
error_source = "jack_connect";
goto deactivate_client;
}
}
if (! register_signal_handler(handle_signal)) {
error_message = strerror(errno);
error_source = "register_signal_handler";
goto deactivate_client;
}
printf("Waiting for connections ...\n");
if (wait_semaphore(connect_semaphore, 1) == -1) {
error_message = get_semaphore_error();
error_source = "wait_semaphore";
goto deactivate_client;
}
if (connections_established) {
printf("Waiting for test completion ...\n\n");
if (wait_semaphore(process_semaphore, 1) == -1) {
error_message = get_semaphore_error();
error_source = "wait_semaphore";
goto deactivate_client;
}
}
if (! register_signal_handler(SIG_DFL)) {
error_message = strerror(errno);
error_source = "register_signal_handler";
goto deactivate_client;
}
if (process_state == 2) {
double average_latency = ((double) total_latency) / samples;
double average_latency_time = total_latency_time / samples;
size_t i;
double latency_plot_offset =
floor(((double) lowest_latency_time) / 100.0) / 10.0;
double sample_rate = (double) jack_get_sample_rate(client);
jack_nframes_t total_jitter = 0;
jack_time_t total_jitter_time = 0;
for (i = 0; i <= 100; i++) {
jitter_plot[i] = 0;
latency_plot[i] = 0;
}
for (i = 0; i < samples; i++) {
double latency_time_value = (double) latency_time_values[i];
double latency_plot_time =
(latency_time_value / 1000.0) - latency_plot_offset;
double jitter_time = ABS(average_latency_time -
latency_time_value);
if (latency_plot_time >= 10.0) {
(latency_plot[100])++;
} else {
(latency_plot[(int) (latency_plot_time * 10.0)])++;
}
if (jitter_time >= 10000.0) {
(jitter_plot[100])++;
} else {
(jitter_plot[(int) (jitter_time / 100.0)])++;
}
total_jitter += ABS(average_latency -
((double) latency_values[i]));
total_jitter_time += jitter_time;
}
printf("Reported out-port latency: %.2f-%.2f ms (%u-%u frames)\n"
"Reported in-port latency: %.2f-%.2f ms (%u-%u frames)\n"
"Average latency: %.2f ms (%.2f frames)\n"
"Lowest latency: %.2f ms (%u frames)\n"
"Highest latency: %.2f ms (%u frames)\n"
"Peak MIDI jitter: %.2f ms (%u frames)\n"
"Average MIDI jitter: %.2f ms (%.2f frames)\n",
(out_latency_range.min / sample_rate) * 1000.0,
(out_latency_range.max / sample_rate) * 1000.0,
out_latency_range.min, out_latency_range.max,
(in_latency_range.min / sample_rate) * 1000.0,
(in_latency_range.max / sample_rate) * 1000.0,
in_latency_range.min, in_latency_range.max,
average_latency_time / 1000.0, average_latency,
lowest_latency_time / 1000.0, lowest_latency,
highest_latency_time / 1000.0, highest_latency,
(highest_latency_time - lowest_latency_time) / 1000.0,
highest_latency - lowest_latency,
(total_jitter_time / 1000.0) / samples,
((double) total_jitter) / samples);
printf("\nJitter Plot:\n");
for (i = 0; i < 100; i++) {
if (jitter_plot[i]) {
printf("%.1f - %.1f ms: %d\n", ((float) i) / 10.0,
((float) (i + 1)) / 10.0, jitter_plot[i]);
}
}
if (jitter_plot[100]) {
printf(" > 10 ms: %d\n", jitter_plot[100]);
}
printf("\nLatency Plot:\n");
for (i = 0; i < 100; i++) {
if (latency_plot[i]) {
printf("%.1f - %.1f ms: %d\n",
latency_plot_offset + (((float) i) / 10.0),
latency_plot_offset + (((float) (i + 1)) / 10.0),
latency_plot[i]);
}
}
if (latency_plot[100]) {
printf(" > %.1f ms: %d\n", latency_plot_offset + 10.0,
latency_plot[100]);
}
}
deactivate_client:
jack_deactivate(client);
printf("\nMessages sent: %d\nMessages received: %d\n", messages_sent,
messages_received);
if (unexpected_messages) {
printf("Unexpected messages received: %d\n", unexpected_messages);
}
if (xrun_count) {
printf("Xruns: %d\n", xrun_count);
}
destroy_process_semaphore:
destroy_semaphore(process_semaphore, 2);
destroy_init_semaphore:
destroy_semaphore(init_semaphore, 1);
destroy_connect_semaphore:
destroy_semaphore(connect_semaphore, 0);
unregister_out_port:
jack_port_unregister(client, out_port);
unregister_in_port:
jack_port_unregister(client, in_port);
close_client:
jack_client_close(client);
free_message_2:
free(message_2);
free_message_1:
free(message_1);
free_latency_time_values:
free(latency_time_values);
free_latency_values:
free(latency_values);
free_alias2:
free(alias2);
free_alias1:
free(alias1);
if (error_message != NULL) {
show_error:
output_error(error_source, error_message);
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}

+ 0
- 133
example-clients/midiseq.c View File

@@ -1,133 +0,0 @@
/*
Copyright (C) 2004 Ian Esten

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 <jack/jack.h>
#include <jack/midiport.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>

jack_client_t *client;
jack_port_t *output_port;

unsigned char* note_frqs;
jack_nframes_t* note_starts;
jack_nframes_t* note_lengths;
jack_nframes_t num_notes;
jack_nframes_t loop_nsamp;
jack_nframes_t loop_index;

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

static void usage()
{
fprintf(stderr, "usage: jack_midiseq name nsamp [startindex note nsamp] ...... [startindex note nsamp]\n");
fprintf(stderr, "eg: jack_midiseq Sequencer 24000 0 60 8000 12000 63 8000\n");
fprintf(stderr, "will play a 1/2 sec loop (if srate is 48khz) with a c4 note at the start of the loop\n");
fprintf(stderr, "that lasts for 12000 samples, then a d4# that starts at 1/4 sec that lasts for 800 samples\n");
}

static int process(jack_nframes_t nframes, void *arg)
{
int i,j;
void* port_buf = jack_port_get_buffer(output_port, nframes);
unsigned char* buffer;
jack_midi_clear_buffer(port_buf);
/*memset(buffer, 0, nframes*sizeof(jack_default_audio_sample_t));*/

for (i = 0; i < nframes; i++) {
for (j = 0; j < num_notes; j++) {
if (note_starts[j] == loop_index) {
if ((buffer = jack_midi_event_reserve(port_buf, i, 3))) {
/* printf("wrote a note on, port buffer = 0x%x, event buffer = 0x%x\n", port_buf, buffer); */
buffer[2] = 64; /* velocity */
buffer[1] = note_frqs[j];
buffer[0] = 0x90; /* note on */
}
} else if (note_starts[j] + note_lengths[j] == loop_index) {
if ((buffer = jack_midi_event_reserve(port_buf, i, 3))) {
/* printf("wrote a note off, port buffer = 0x%x, event buffer = 0x%x\n", port_buf, buffer); */
buffer[2] = 64; /* velocity */
buffer[1] = note_frqs[j];
buffer[0] = 0x80; /* note off */
}
}
}
loop_index = loop_index+1 >= loop_nsamp ? 0 : loop_index+1;
}
return 0;
}

int main(int narg, char **args)
{
int i;
jack_nframes_t nframes;
if ((narg<6) || ((narg-3)%3 != 0)) {
usage();
exit(1);
}
if ((client = jack_client_open (args[1], JackNullOption, NULL)) == 0) {
fprintf (stderr, "JACK server not running?\n");
return 1;
}
jack_set_process_callback (client, process, 0);
output_port = jack_port_register (client, "out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
nframes = jack_get_buffer_size(client);
loop_index = 0;
num_notes = (narg - 3)/3;
note_frqs = malloc(num_notes*sizeof(unsigned char));
note_starts = malloc(num_notes*sizeof(jack_nframes_t));
note_lengths = malloc(num_notes*sizeof(jack_nframes_t));
loop_nsamp = atoi(args[2]);
for (i = 0; i < num_notes; i++) {
note_starts[i] = atoi(args[3 + 3*i]);
note_frqs[i] = atoi(args[4 + 3*i]);
note_lengths[i] = atoi(args[5 + 3*i]);
}

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

/* 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 until interrupted */
while (1) {
#ifdef WIN32
Sleep(1*1000);
#else
sleep(1);
#endif
};

jack_client_close(client);
exit (0);
}

+ 0
- 163
example-clients/midisine.c View File

@@ -1,163 +0,0 @@
/*
Copyright (C) 2004 Ian Esten

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 <string.h>
#include <signal.h>
#include <math.h>
#include <inttypes.h>

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

jack_port_t *input_port;
jack_port_t *output_port;
jack_default_audio_sample_t ramp=0.0;
jack_default_audio_sample_t note_on;
unsigned char note = 0;
jack_default_audio_sample_t note_frqs[128];

jack_client_t *client;

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

static void calc_note_frqs(jack_default_audio_sample_t srate)
{
int i;
for(i=0; i<128; i++)
{
note_frqs[i] = (2.0 * 440.0 / 32.0) * pow(2, (((jack_default_audio_sample_t)i - 9.0) / 12.0)) / srate;
}
}

static int process(jack_nframes_t nframes, void *arg)
{
int i;
void* port_buf = jack_port_get_buffer(input_port, nframes);
jack_default_audio_sample_t *out = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port, nframes);
jack_midi_event_t in_event;
jack_nframes_t event_index = 0;
jack_nframes_t event_count = jack_midi_get_event_count(port_buf);
if(event_count > 1)
{
printf(" midisine: have %d events\n", event_count);
for(i=0; i<event_count; i++)
{
jack_midi_event_get(&in_event, port_buf, i);
printf(" event %d time is %d. 1st byte is 0x%x\n", i, in_event.time, *(in_event.buffer));
}
/* printf("1st byte of 1st event addr is %p\n", in_events[0].buffer);*/
}
jack_midi_event_get(&in_event, port_buf, 0);
for(i = 0; i < nframes; i++)
{
if ((in_event.time == i) && (event_index < event_count))
{
if (((*(in_event.buffer) & 0xf0)) == 0x90)
{
/* note on */
note = *(in_event.buffer + 1);
if (*(in_event.buffer + 2) == 0) {
note_on = 0.0;
} else {
note_on = (float)(*(in_event.buffer + 2)) / 127.f;
}
}
else if (((*(in_event.buffer)) & 0xf0) == 0x80)
{
/* note off */
note = *(in_event.buffer + 1);
note_on = 0.0;
}
event_index++;
if(event_index < event_count)
jack_midi_event_get(&in_event, port_buf, event_index);
}
ramp += note_frqs[note];
ramp = (ramp > 1.0) ? ramp - 2.0 : ramp;
out[i] = note_on*sin(2*M_PI*ramp);
}
return 0;
}

static int srate(jack_nframes_t nframes, void *arg)
{
printf("the sample rate is now %" PRIu32 "/sec\n", nframes);
calc_note_frqs((jack_default_audio_sample_t)nframes);
return 0;
}

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

int main(int narg, char **args)
{
if ((client = jack_client_open("midisine", JackNullOption, NULL)) == 0)
{
fprintf(stderr, "JACK server not running?\n");
return 1;
}

calc_note_frqs(jack_get_sample_rate (client));

jack_set_process_callback (client, process, 0);

jack_set_sample_rate_callback (client, srate, 0);

jack_on_shutdown (client, jack_shutdown, 0);

input_port = jack_port_register (client, "midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
output_port = jack_port_register (client, "audio_out", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);

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

/* 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 until interrupted */
while(1) {
#ifdef WIN32
Sleep(1*1000);
#else
sleep(1);
#endif
}
jack_client_close(client);
exit (0);
}


+ 0
- 208
example-clients/netmaster.c View File

@@ -1,208 +0,0 @@
/*
Copyright (C) 2009 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 <stdlib.h>
#include <stdbool.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 <assert.h>

#include <jack/net.h>

jack_net_master_t* net;

#define BUFFER_SIZE 512
#define SAMPLE_RATE 44100

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

static void
usage ()
{
fprintf (stderr, "\n"
"usage: jack_net_master \n"
" [ -b buffer size (default = %d) ]\n"
" [ -r sample rate (default = %d) ]\n"
" [ -a hostname (default = %s) ]\n"
" [ -p port (default = %d) ]\n", BUFFER_SIZE, SAMPLE_RATE, DEFAULT_MULTICAST_IP, DEFAULT_PORT);
}

int
main (int argc, char *argv[])
{
int buffer_size = BUFFER_SIZE;
int sample_rate = SAMPLE_RATE;
int udp_port = DEFAULT_PORT;
const char* multicast_ip = DEFAULT_MULTICAST_IP;
const char *options = "b:r:a:p:h";
int option_index;
int opt;

struct option long_options[] =
{
{"buffer size", 1, 0, 'b'},
{"sample rate", 1, 0, 'r'},
{"hostname", 1, 0, 'a'},
{"port", 1, 0, 'p'},
{0, 0, 0, 0}
};

while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != -1) {

switch (opt) {

case 'b':
buffer_size = atoi(optarg);
break;

case 'r':
sample_rate = atoi(optarg);
break;

case 'a':
multicast_ip = strdup(optarg);
break;

case 'p':
udp_port = atoi(optarg);
break;

case 'h':
usage();
return -1;
}
}

int i;
//jack_master_t request = { 4, 4, -1, -1, buffer_size, sample_rate, "master", -1 };
jack_master_t request = { -1, -1, -1, -1, buffer_size, sample_rate, "net_master", 6, true };
jack_slave_t result;
float** audio_input_buffer;
float** audio_output_buffer;
int wait_usec = (int) ((((float)buffer_size) * 1000000) / ((float)sample_rate));

printf("Waiting for a slave...\n");

if ((net = jack_net_master_open(multicast_ip, udp_port, &request, &result)) == 0) {
fprintf(stderr, "NetJack master can not be opened\n");
return 1;
}

printf("Slave is running...\n");

/* 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

// Allocate buffers
audio_input_buffer = (float**)calloc(result.audio_input, sizeof(float*));
for (i = 0; i < result.audio_input; i++) {
audio_input_buffer[i] = (float*)calloc(buffer_size, sizeof(float));
}

audio_output_buffer = (float**)calloc(result.audio_output, sizeof(float*));
for (i = 0; i < result.audio_output; i++) {
audio_output_buffer[i] = (float*)calloc(buffer_size, sizeof(float));
}

/*
Run until interrupted.

WARNING !! : this code is given for demonstration purpose. For proper timing bevahiour
it has to be called in a real-time context (which is *not* the case here...)
*/
//usleep(5*1000000);
printf("Wait...\n");
//sleep(10);
usleep(1000000);
printf("Wait...OK\n");
while (1) {

// Copy input to output
assert(result.audio_input == result.audio_output);
for (i = 0; i < result.audio_input; i++) {
memcpy(audio_output_buffer[i], audio_input_buffer[i], buffer_size * sizeof(float));
}
/*
if (jack_net_master_send(net, result.audio_output, audio_output_buffer, 0, NULL) < 0) {
printf("jack_net_master_send failure, exiting\n");
break;
}
usleep(10000);
if (jack_net_master_recv(net, result.audio_input, audio_input_buffer, 0, NULL) < 0) {
printf("jack_net_master_recv failure, exiting\n");
break;
}
*/
if (jack_net_master_send_slice(net, result.audio_output, audio_output_buffer, 0, NULL, BUFFER_SIZE/2) < 0) {
printf("jack_net_master_send failure, exiting\n");
break;
}
usleep(10000);
if (jack_net_master_recv_slice(net, result.audio_input, audio_input_buffer, 0, NULL, BUFFER_SIZE/2) < 0) {
printf("jack_net_master_recv failure, exiting\n");
break;
}
usleep(wait_usec);
};

// Wait for application end
jack_net_master_close(net);

for (i = 0; i < result.audio_input; i++) {
free(audio_input_buffer[i]);
}
free(audio_input_buffer);

for (i = 0; i < result.audio_output; i++) {
free(audio_output_buffer[i]);
}
free(audio_output_buffer);

exit (0);
}

+ 0
- 168
example-clients/netslave.c View File

@@ -1,168 +0,0 @@
/*
Copyright (C) 2009 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 <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/net.h>

jack_net_slave_t* net;

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

static void
usage ()
{
fprintf (stderr, "\n"
"usage: jack_net_slave \n"
" [ -C capture channels (default = 2)]\n"
" [ -P playback channels (default = 2) ]\n"
" [ -a hostname (default = %s) ]\n"
" [ -p port (default = %d)]\n", DEFAULT_MULTICAST_IP, DEFAULT_PORT);
}

static void net_shutdown(void* data)
{
printf("Restarting...\n");
}

static int net_process(jack_nframes_t buffer_size,
int audio_input,
float** audio_input_buffer,
int midi_input,
void** midi_input_buffer,
int audio_output,
float** audio_output_buffer,
int midi_output,
void** midi_output_buffer,
void* data)
{
int i;

// Copy input to output
for (i = 0; i < audio_input; i++) {
memcpy(audio_output_buffer[i], audio_input_buffer[i], buffer_size * sizeof(float));
}
return 0;
}

int
main (int argc, char *argv[])
{
int audio_input = 2;
int audio_output = 2;
int udp_port = DEFAULT_PORT;
const char* multicast_ip = DEFAULT_MULTICAST_IP;
const char *options = "C:P:a:p:h";
int option_index;
int opt;

struct option long_options[] =
{
{"audio input", 1, 0, 'C'},
{"audio output", 1, 0, 'P'},
{"hostname", 1, 0, 'a'},
{"port", 1, 0, 'p'},
{0, 0, 0, 0}
};

while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) {

switch (opt) {

case 'C':
audio_input = atoi(optarg);
break;

case 'P':
audio_output = atoi(optarg);
break;

case 'a':
multicast_ip = strdup(optarg);
break;

case 'p':
udp_port = atoi(optarg);
break;

case 'h':
usage();
return -1;
}
}

jack_slave_t request = { audio_input, audio_output, 0, 0, DEFAULT_MTU, -1, JackFloatEncoder, 0, 2 };
jack_master_t result;

printf("Waiting for a master...\n");

if ((net = jack_net_slave_open(multicast_ip, udp_port, "net_slave", &request, &result)) == 0) {
fprintf(stderr, "JACK server not running?\n");
return 1;
}

printf("Master is found and running...\n");

jack_set_net_slave_process_callback(net, net_process, NULL);
jack_set_net_slave_shutdown_callback(net, net_shutdown, NULL);

if (jack_net_slave_activate(net) != 0) {
fprintf(stderr, "Cannot activate slave client\n");
return 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

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

// Wait for application end
jack_net_slave_deactivate(net);
jack_net_slave_close(net);
exit(0);
}

+ 0
- 244
example-clients/server_control.cpp View File

@@ -1,244 +0,0 @@
/*
Copyright (C) 2008 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 <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <jack/jack.h>
#include <jack/control.h>

static jackctl_driver_t * jackctl_server_get_driver(jackctl_server_t *server, const char *driver_name)
{
const JSList * node_ptr = jackctl_server_get_drivers_list(server);

while (node_ptr) {
if (strcmp(jackctl_driver_get_name((jackctl_driver_t *)node_ptr->data), driver_name) == 0) {
return (jackctl_driver_t *)node_ptr->data;
}
node_ptr = jack_slist_next(node_ptr);
}

return NULL;
}

static jackctl_internal_t * jackctl_server_get_internal(jackctl_server_t *server, const char *internal_name)
{
const JSList * node_ptr = jackctl_server_get_internals_list(server);

while (node_ptr) {
if (strcmp(jackctl_internal_get_name((jackctl_internal_t *)node_ptr->data), internal_name) == 0) {
return (jackctl_internal_t *)node_ptr->data;
}
node_ptr = jack_slist_next(node_ptr);
}

return NULL;
}

#if 0
static jackctl_parameter_t *
jackctl_get_parameter(
const JSList * parameters_list,
const char * parameter_name)
{
while (parameters_list)
{
if (strcmp(jackctl_parameter_get_name((jackctl_parameter_t *)parameters_list->data), parameter_name) == 0)
{
return (jackctl_parameter_t *)parameters_list->data;
}

parameters_list = jack_slist_next(parameters_list);
}

return NULL;
}
#endif

static void print_value(union jackctl_parameter_value value, jackctl_param_type_t type)
{
switch (type) {

case JackParamInt:
printf("parameter value = %d\n", value.i);
break;

case JackParamUInt:
printf("parameter value = %u\n", value.ui);
break;

case JackParamChar:
printf("parameter value = %c\n", value.c);
break;

case JackParamString:
printf("parameter value = %s\n", value.str);
break;

case JackParamBool:
printf("parameter value = %d\n", value.b);
break;
}
}

static void print_parameters(const JSList * node_ptr)
{
while (node_ptr != NULL) {
jackctl_parameter_t * parameter = (jackctl_parameter_t *)node_ptr->data;
printf("\nparameter name = %s\n", jackctl_parameter_get_name(parameter));
printf("parameter id = %c\n", jackctl_parameter_get_id(parameter));
printf("parameter short decs = %s\n", jackctl_parameter_get_short_description(parameter));
printf("parameter long decs = %s\n", jackctl_parameter_get_long_description(parameter));
print_value(jackctl_parameter_get_default_value(parameter), jackctl_parameter_get_type(parameter));
node_ptr = jack_slist_next(node_ptr);
}
}

static void print_driver(jackctl_driver_t * driver)
{
printf("\n--------------------------\n");
printf("driver = %s\n", jackctl_driver_get_name(driver));
printf("-------------------------- \n");
print_parameters(jackctl_driver_get_parameters(driver));
}

static void print_internal(jackctl_internal_t * internal)
{
printf("\n-------------------------- \n");
printf("internal = %s\n", jackctl_internal_get_name(internal));
printf("-------------------------- \n");
print_parameters(jackctl_internal_get_parameters(internal));
}

static void usage()
{
fprintf (stderr, "\n"
"usage: jack_server_control \n"
" [ --driver OR -d driver_name ]\n"
" [ --client OR -c client_name ]\n"
);
}

int main(int argc, char *argv[])
{
jackctl_server_t * server;
const JSList * parameters;
const JSList * drivers;
const JSList * internals;
const JSList * node_ptr;
jackctl_sigmask_t * sigmask;
int opt, option_index;
const char* driver_name = "dummy";
const char* client_name = "audioadapter";

const char *options = "d:c:";
struct option long_options[] = {
{"driver", 1, 0, 'd'},
{"client", 1, 0, 'c'},
{0, 0, 0, 0}
};

while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != -1) {
switch (opt) {
case 'd':
driver_name = optarg;
break;
case 'c':
client_name = optarg;
break;
default:
usage();
exit(0);
}
}

server = jackctl_server_create2(NULL, NULL, NULL);
parameters = jackctl_server_get_parameters(server);

/*
jackctl_parameter_t* param;
union jackctl_parameter_value value;
param = jackctl_get_parameter(parameters, "verbose");
if (param != NULL) {
value.b = true;
jackctl_parameter_set_value(param, &value);
}
*/

printf("\n========================== \n");
printf("List of server parameters \n");
printf("========================== \n");

print_parameters(parameters);

printf("\n========================== \n");
printf("List of drivers \n");
printf("========================== \n");

drivers = jackctl_server_get_drivers_list(server);
node_ptr = drivers;
while (node_ptr != NULL) {
print_driver((jackctl_driver_t *)node_ptr->data);
node_ptr = jack_slist_next(node_ptr);
}

printf("\n========================== \n");
printf("List of internal clients \n");
printf("========================== \n");

internals = jackctl_server_get_internals_list(server);
node_ptr = internals;
while (node_ptr != NULL) {
print_internal((jackctl_internal_t *)node_ptr->data);
node_ptr = jack_slist_next(node_ptr);
}

// No error checking in this simple example...

jackctl_server_open(server, jackctl_server_get_driver(server, driver_name));
jackctl_server_start(server);

jackctl_server_load_internal(server, jackctl_server_get_internal(server, client_name));

/*
// Switch master test

jackctl_driver_t* master;

usleep(5000000);
printf("jackctl_server_load_master\n");
master = jackctl_server_get_driver(server, "coreaudio");
jackctl_server_switch_master(server, master);

usleep(5000000);
printf("jackctl_server_load_master\n");
master = jackctl_server_get_driver(server, "dummy");
jackctl_server_switch_master(server, master);

*/

sigmask = jackctl_setup_signals(0);
jackctl_wait_signals(sigmask);
jackctl_server_stop(server);
jackctl_server_close(server);
jackctl_server_destroy(server);
return 0;
}

+ 0
- 119
example-clients/showtime.c View File

@@ -1,119 +0,0 @@
/*
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 <signal.h>
#include <stdlib.h>
#include <inttypes.h>

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

jack_client_t *client;

static void
showtime ()
{
jack_position_t current;
jack_transport_state_t transport_state;
jack_nframes_t frame_time;

transport_state = jack_transport_query (client, &current);
frame_time = jack_frame_time (client);

printf ("frame = %u frame_time = %u usecs = %" PRIu64 "\t", current.frame, frame_time, current.usecs);

switch (transport_state) {
case JackTransportStopped:
printf ("state: Stopped");
break;
case JackTransportRolling:
printf ("state: Rolling");
break;
case JackTransportStarting:
printf ("state: Starting");
break;
default:
printf ("state: [unknown]");
}

if (current.valid & JackPositionBBT)
printf ("\tBBT: %3" PRIi32 "|%" PRIi32 "|%04"
PRIi32, current.bar, current.beat, current.tick);

if (current.valid & JackPositionTimecode)
printf ("\tTC: (%.6f, %.6f)",
current.frame_time, current.next_time);
printf ("\n");
}

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

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

int
main (int argc, char *argv[])
{
/* try to become a client of the JACK server */

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

#ifndef WIN32
signal (SIGQUIT, signal_handler);
signal (SIGHUP, signal_handler);
#endif

signal (SIGTERM, signal_handler);
signal (SIGINT, signal_handler);

/* 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);

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

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

while (1) {
usleep (20);
showtime ();
}

jack_client_close (client);
exit (0);
}

+ 0
- 415
example-clients/simdtests.cpp View File

@@ -1,415 +0,0 @@
/*
* simdtests.c -- test accuracy and performance of simd optimizations
*
* Copyright (C) 2017 Andreas Mueller.
*
* 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.
*/

/* We must include all headers memops.c includes to avoid trouble with
* out namespace game below.
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <memory.h>
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#ifdef __linux__
#include <endian.h>
#endif
#include "memops.h"

#if defined (__SSE2__) && !defined (__sun__)
#include <emmintrin.h>
#ifdef __SSE4_1__
#include <smmintrin.h>
#endif
#endif

#if defined (__ARM_NEON__) || defined (__ARM_NEON)
#include <arm_neon.h>
#endif

// our additional headers
#include <time.h>

/* Dirty: include mempos.c twice the second time with SIMD disabled
* so we can compare aceelerated non accelerated
*/
namespace accelerated {
#include "../common/memops.c"
}

namespace origerated {
#ifdef __SSE2__
#undef __SSE2__
#endif

#ifdef __ARM_NEON__
#undef __ARM_NEON__
#endif

#ifdef __ARM_NEON
#undef __ARM_NEON
#endif

#include "../common/memops.c"
}

// define conversion function types
typedef void (*t_jack_to_integer)(
char *dst,
jack_default_audio_sample_t *src,
unsigned long nsamples,
unsigned long dst_skip,
dither_state_t *state);

typedef void (*t_integer_to_jack)(
jack_default_audio_sample_t *dst,
char *src,
unsigned long nsamples,
unsigned long src_skip);

// define/setup test case data
typedef struct test_case_data {
uint32_t frame_size;
uint32_t sample_size;
bool reverse;
t_jack_to_integer jack_to_integer_accel;
t_jack_to_integer jack_to_integer_orig;
t_integer_to_jack integer_to_jack_accel;
t_integer_to_jack integer_to_jack_orig;
dither_state_t *ditherstate;
const char *name;
} test_case_data_t;

test_case_data_t test_cases[] = {
{
4,
3,
true,
accelerated::sample_move_d32u24_sSs,
origerated::sample_move_d32u24_sSs,
accelerated::sample_move_dS_s32u24s,
origerated::sample_move_dS_s32u24s,
NULL,
"32u24s" },
{
4,
3,
false,
accelerated::sample_move_d32u24_sS,
origerated::sample_move_d32u24_sS,
accelerated::sample_move_dS_s32u24,
origerated::sample_move_dS_s32u24,
NULL,
"32u24" },
{
4,
3,
true,
accelerated::sample_move_d32l24_sSs,
origerated::sample_move_d32l24_sSs,
accelerated::sample_move_dS_s32l24s,
origerated::sample_move_dS_s32l24s,
NULL,
"32l24s" },
{
4,
3,
false,
accelerated::sample_move_d32l24_sS,
origerated::sample_move_d32l24_sS,
accelerated::sample_move_dS_s32l24,
origerated::sample_move_dS_s32l24,
NULL,
"32l24" },
{
3,
3,
true,
accelerated::sample_move_d24_sSs,
origerated::sample_move_d24_sSs,
accelerated::sample_move_dS_s24s,
origerated::sample_move_dS_s24s,
NULL,
"24s" },
{
3,
3,
false,
accelerated::sample_move_d24_sS,
origerated::sample_move_d24_sS,
accelerated::sample_move_dS_s24,
origerated::sample_move_dS_s24,
NULL,
"24" },
{
2,
2,
true,
accelerated::sample_move_d16_sSs,
origerated::sample_move_d16_sSs,
accelerated::sample_move_dS_s16s,
origerated::sample_move_dS_s16s,
NULL,
"16s" },
{
2,
2,
false,
accelerated::sample_move_d16_sS,
origerated::sample_move_d16_sS,
accelerated::sample_move_dS_s16,
origerated::sample_move_dS_s16,
NULL,
"16" },
};

// we need to repeat for better accuracy at time measurement
const uint32_t retry_per_case = 1000;

// setup test buffers
#define TESTBUFF_SIZE 1024
jack_default_audio_sample_t jackbuffer_source[TESTBUFF_SIZE];
// integer buffers: max 4 bytes per value / * 2 for stereo
char integerbuffer_accel[TESTBUFF_SIZE*4*2];
char integerbuffer_orig[TESTBUFF_SIZE*4*2];
// float buffers
jack_default_audio_sample_t jackfloatbuffer_accel[TESTBUFF_SIZE];
jack_default_audio_sample_t jackfloatbuffer_orig[TESTBUFF_SIZE];

// comparing unsigned makes life easier
uint32_t extract_integer(
char* buff,
uint32_t offset,
uint32_t frame_size,
uint32_t sample_size,
bool big_endian)
{
uint32_t retval = 0;
unsigned char* curr;
uint32_t mult = 1;
if(big_endian) {
curr = (unsigned char*)buff + offset + sample_size-1;
for(uint32_t i=0; i<sample_size; i++) {
retval += *(curr--) * mult;
mult*=256;
}
}
else {
curr = (unsigned char*)buff + offset + frame_size-sample_size;
for(uint32_t i=0; i<sample_size; i++) {
retval += *(curr++) * mult;
mult*=256;
}
}
return retval;
}

int main(int argc, char *argv[])
{
// parse_arguments(argc, argv);
uint32_t maxerr_displayed = 10;

// fill jackbuffer
for(int i=0; i<TESTBUFF_SIZE; i++) {
// ramp
jack_default_audio_sample_t value =
((jack_default_audio_sample_t)((i % TESTBUFF_SIZE) - TESTBUFF_SIZE/2)) / (TESTBUFF_SIZE/2);
// force clipping
value *= 1.02;
jackbuffer_source[i] = value;
}

for(uint32_t testcase=0; testcase<sizeof(test_cases)/sizeof(test_case_data_t); testcase++) {
// test mono/stereo
for(uint32_t channels=1; channels<=2; channels++) {
//////////////////////////////////////////////////////////////////////////////
// jackfloat -> integer

// clean target buffers
memset(integerbuffer_accel, 0, sizeof(integerbuffer_accel));
memset(integerbuffer_orig, 0, sizeof(integerbuffer_orig));
// accel
clock_t time_to_integer_accel = clock();
for(uint32_t repetition=0; repetition<retry_per_case; repetition++)
{
test_cases[testcase].jack_to_integer_accel(
integerbuffer_accel,
jackbuffer_source,
TESTBUFF_SIZE,
test_cases[testcase].frame_size*channels,
test_cases[testcase].ditherstate);
}
float timediff_to_integer_accel = ((float)(clock() - time_to_integer_accel)) / CLOCKS_PER_SEC;
// orig
clock_t time_to_integer_orig = clock();
for(uint32_t repetition=0; repetition<retry_per_case; repetition++)
{
test_cases[testcase].jack_to_integer_orig(
integerbuffer_orig,
jackbuffer_source,
TESTBUFF_SIZE,
test_cases[testcase].frame_size*channels,
test_cases[testcase].ditherstate);
}
float timediff_to_integer_orig = ((float)(clock() - time_to_integer_orig)) / CLOCKS_PER_SEC;
// output performance results
printf(
"JackFloat->Integer @%7.7s/%u: Orig %7.6f sec / Accel %7.6f sec -> Win: %5.2f %%\n",
test_cases[testcase].name,
channels,
timediff_to_integer_orig,
timediff_to_integer_accel,
(timediff_to_integer_orig/timediff_to_integer_accel-1)*100.0);
uint32_t int_deviation_max = 0;
uint32_t int_error_count = 0;
// output error (avoid spam -> limit error lines per test case)
for(uint32_t sample=0; sample<TESTBUFF_SIZE; sample++) {
uint32_t sample_offset = sample*test_cases[testcase].frame_size*channels;
// compare both results
uint32_t intval_accel=extract_integer(
integerbuffer_accel,
sample_offset,
test_cases[testcase].frame_size,
test_cases[testcase].sample_size,
#if __BYTE_ORDER == __BIG_ENDIAN
!test_cases[testcase].reverse);
#else
test_cases[testcase].reverse);
#endif
uint32_t intval_orig=extract_integer(
integerbuffer_orig,
sample_offset,
test_cases[testcase].frame_size,
test_cases[testcase].sample_size,
#if __BYTE_ORDER == __BIG_ENDIAN
!test_cases[testcase].reverse);
#else
test_cases[testcase].reverse);
#endif
// allow a deviation of 1
if(intval_accel>intval_orig+1 || intval_orig>intval_accel+1) {
if(int_error_count<maxerr_displayed) {
printf("Value error sample %u:", sample);
printf(" Orig 0x");
char formatstr[10];
sprintf(formatstr, "%%0%uX", test_cases[testcase].sample_size*2);
printf(formatstr, intval_orig);
printf(" Accel 0x");
printf(formatstr, intval_accel);
printf("\n");
}
int_error_count++;
uint32_t int_deviation;
if(intval_accel > intval_orig)
int_deviation = intval_accel-intval_orig;
else
int_deviation = intval_orig-intval_accel;
if(int_deviation > int_deviation_max)
int_deviation_max = int_deviation;
}
}
printf(
"JackFloat->Integer @%7.7s/%u: Errors: %u Max deviation %u\n",
test_cases[testcase].name,
channels,
int_error_count,
int_deviation_max);

//////////////////////////////////////////////////////////////////////////////
// integer -> jackfloat

// clean target buffers
memset(jackfloatbuffer_accel, 0, sizeof(jackfloatbuffer_accel));
memset(jackfloatbuffer_orig, 0, sizeof(jackfloatbuffer_orig));
// accel
clock_t time_to_float_accel = clock();
for(uint32_t repetition=0; repetition<retry_per_case; repetition++)
{
test_cases[testcase].integer_to_jack_accel(
jackfloatbuffer_accel,
integerbuffer_orig,
TESTBUFF_SIZE,
test_cases[testcase].frame_size*channels);
}
float timediff_to_float_accel = ((float)(clock() - time_to_float_accel)) / CLOCKS_PER_SEC;
// orig
clock_t time_to_float_orig = clock();
for(uint32_t repetition=0; repetition<retry_per_case; repetition++)
{
test_cases[testcase].integer_to_jack_orig(
jackfloatbuffer_orig,
integerbuffer_orig,
TESTBUFF_SIZE,
test_cases[testcase].frame_size*channels);
}
float timediff_to_float_orig = ((float)(clock() - time_to_float_orig)) / CLOCKS_PER_SEC;
// output performance results
printf(
"Integer->JackFloat @%7.7s/%u: Orig %7.6f sec / Accel %7.6f sec -> Win: %5.2f %%\n",
test_cases[testcase].name,
channels,
timediff_to_float_orig,
timediff_to_float_accel,
(timediff_to_float_orig/timediff_to_float_accel-1)*100.0);
jack_default_audio_sample_t float_deviation_max = 0.0;
uint32_t float_error_count = 0;
// output error (avoid spam -> limit error lines per test case)
for(uint32_t sample=0; sample<TESTBUFF_SIZE; sample++) {
// For easier estimation/readability we scale floats back to integer
jack_default_audio_sample_t sample_scaling;
switch(test_cases[testcase].sample_size) {
case 2:
sample_scaling = SAMPLE_16BIT_SCALING;
break;
default:
sample_scaling = SAMPLE_24BIT_SCALING;
break;
}
jack_default_audio_sample_t floatval_accel = jackfloatbuffer_accel[sample] * sample_scaling;
jack_default_audio_sample_t floatval_orig = jackfloatbuffer_orig[sample] * sample_scaling;
// compare both results
jack_default_audio_sample_t float_deviation;
if(floatval_accel > floatval_orig)
float_deviation = floatval_accel-floatval_orig;
else
float_deviation = floatval_orig-floatval_accel;
if(float_deviation > float_deviation_max)
float_deviation_max = float_deviation;
// deviation > half bit => error
if(float_deviation > 0.5) {
if(float_error_count<maxerr_displayed) {
printf("Value error sample %u:", sample);
printf(" Orig %8.1f Accel %8.1f\n", floatval_orig, floatval_accel);
}
float_error_count++;
}
}
printf(
"Integer->JackFloat @%7.7s/%u: Errors: %u Max deviation %f\n",
test_cases[testcase].name,
channels,
float_error_count,
float_deviation_max);

printf("\n");
}
}
return 0;
}

+ 0
- 220
example-clients/simple_client.c View File

@@ -1,220 +0,0 @@
/** @file simple_client.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 <math.h>
#include <signal.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <jack/jack.h>

jack_port_t *output_port1, *output_port2;
jack_client_t *client;

#ifndef M_PI
#define M_PI (3.14159265)
#endif

#define TABLE_SIZE (200)
typedef struct
{
float sine[TABLE_SIZE];
int left_phase;
int right_phase;
}
paTestData;

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

/**
* The process callback for this JACK application is called in a
* special realtime thread once for each audio cycle.
*
* This client follows a simple rule: when the JACK transport is
* running, copy the input port to the output. When it stops, exit.
*/

int
process (jack_nframes_t nframes, void *arg)
{
jack_default_audio_sample_t *out1, *out2;
paTestData *data = (paTestData*)arg;
int i;

out1 = (jack_default_audio_sample_t*)jack_port_get_buffer (output_port1, nframes);
out2 = (jack_default_audio_sample_t*)jack_port_get_buffer (output_port2, nframes);

for( i=0; i<nframes; i++ )
{
out1[i] = data->sine[data->left_phase]; /* left */
out2[i] = data->sine[data->right_phase]; /* right */
data->left_phase += 1;
if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
}
return 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[])
{
const char **ports;
const char *client_name;
const char *server_name = NULL;
jack_options_t options = JackNullOption;
jack_status_t status;
paTestData data;
int i;

if (argc >= 2) { /* client name specified? */
client_name = argv[1];
if (argc >= 3) { /* server name specified? */
server_name = argv[2];
int my_option = JackNullOption | JackServerName;
options = (jack_options_t)my_option;
}
} else { /* use basename of argv[0] */
client_name = strrchr(argv[0], '/');
if (client_name == 0) {
client_name = argv[0];
} else {
client_name++;
}
}

for( i=0; i<TABLE_SIZE; i++ )
{
data.sine[i] = 0.2 * (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
}
data.left_phase = data.right_phase = 0;

/* 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, &data);

/* 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);

/* create two ports */

output_port1 = jack_port_register (client, "output1",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);

output_port2 = jack_port_register (client, "output2",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);

if ((output_port1 == NULL) || (output_port2 == 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|JackPortIsInput);
if (ports == NULL) {
fprintf(stderr, "no physical playback ports\n");
exit (1);
}

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

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

jack_free (ports);
/* 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

/* keep running until the Ctrl+C */

while (1) {
#ifdef WIN32
Sleep(1000);
#else
sleep (1);
#endif
}

jack_client_close (client);
exit (0);
}

+ 0
- 206
example-clients/simple_session_client.c View File

@@ -1,206 +0,0 @@
/** @file simple_session_client.c
*
* @brief This simple client demonstrates the most basic features of JACK
* as they would be used by many applications.
* this version also adds session manager functionality.
*/

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

#include <jack/jack.h>
#include <jack/types.h>
#include <jack/session.h>

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

int simple_quit = 0;

/**
* 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;

in = jack_port_get_buffer (input_port, nframes);
out = jack_port_get_buffer (output_port, nframes);
memcpy (out, in,
sizeof (jack_default_audio_sample_t) * nframes);

return 0;
}

void
session_callback (jack_session_event_t *event, void *arg)
{
char retval[100];
printf ("session notification\n");
printf ("path %s, uuid %s, type: %s\n", event->session_dir, event->client_uuid, event->type == JackSessionSave ? "save" : "quit");


snprintf (retval, 100, "jack_simple_session_client %s", event->client_uuid);
event->command_line = strdup (retval);

jack_session_reply( client, event );

if (event->type == JackSessionSaveAndQuit) {
simple_quit = 1;
}

jack_session_event_free (event);
}

/**
* 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[])
{
const char **ports;
const char *client_name = "simple";
jack_status_t status;

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

if( argc == 1 )
client = jack_client_open (client_name, JackNullOption, &status );
else if( argc == 2 )
client = jack_client_open (client_name, JackSessionID, &status, argv[1] );

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 `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);

/* tell the JACK server to call `session_callback()' if
the session is saved.
*/

jack_set_session_callback (client, session_callback, NULL);

/* 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.
*/


/* only do the autoconnect when not reloading from a session.
* in case of a session reload, the SM will restore our connections
*/

if (argc==1) {

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 until we get a quit event */

while (!simple_quit)
#ifdef WIN32
Sleep(1*1000);
#else
sleep(1);
#endif

jack_client_close (client);
exit (0);
}

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

@@ -1,217 +0,0 @@
/** @file thru_client.c
*
* @brief This simple through 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 <math.h>
#include <signal.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <jack/jack.h>

jack_port_t **input_ports;
jack_port_t **output_ports;
jack_client_t *client;

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

/**
* The process callback for this JACK application is called in a
* special realtime thread once for each audio cycle.
*
* This client follows a simple rule: when the JACK transport is
* running, copy the input port to the output. When it stops, exit.
*/

int
process ( jack_nframes_t nframes, void *arg )
{
int i;
jack_default_audio_sample_t *in, *out;
for ( i = 0; i < 2; i++ )
{
in = jack_port_get_buffer ( input_ports[i], nframes );
out = jack_port_get_buffer ( output_ports[i], nframes );
memcpy ( out, in, nframes * sizeof ( jack_default_audio_sample_t ) );
}
return 0;
}

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

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

if ( argc >= 2 ) /* client name specified? */
{
client_name = argv[1];
if ( argc >= 3 ) /* server name specified? */
{
server_name = argv[2];
options |= JackServerName;
}
}
else /* use basename of argv[0] */
{
client_name = strrchr ( argv[0], '/' );
if ( client_name == 0 )
{
client_name = argv[0];
}
else
{
client_name++;
}
}

/* 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 `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 );

/* create two ports pairs*/
input_ports = ( jack_port_t** ) calloc ( 2, sizeof ( jack_port_t* ) );
output_ports = ( jack_port_t** ) calloc ( 2, sizeof ( jack_port_t* ) );

char port_name[16];
for ( i = 0; i < 2; i++ )
{
sprintf ( port_name, "input_%d", i + 1 );
input_ports[i] = jack_port_register ( client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 );
sprintf ( port_name, "output_%d", i + 1 );
output_ports[i] = jack_port_register ( client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
if ( ( input_ports[i] == NULL ) || ( output_ports[i] == 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 );
}

for ( i = 0; i < 2; i++ )
if ( jack_connect ( client, ports[i], jack_port_name ( input_ports[i] ) ) )
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 );
}

for ( i = 0; i < 2; i++ )
if ( jack_connect ( client, jack_port_name ( output_ports[i] ), ports[i] ) )
fprintf ( stderr, "cannot connect input ports\n" );

free ( ports );

/* 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

/* keep running until the transport stops */

while (1)
{
#ifdef WIN32
Sleep ( 1000 );
#else
sleep ( 1 );
#endif
}

jack_client_close ( client );
exit ( 0 );
}

+ 0
- 110
example-clients/wscript View File

@@ -1,110 +0,0 @@
#! /usr/bin/python3
# encoding: utf-8

example_programs = {
'jack_cpu_load': 'cpu_load.c',
'jack_latent_client': 'latent_client.c',
'jack_metro': 'metro.c',
'jack_midi_latency_test': 'midi_latency_test.c',
'jack_midiseq': 'midiseq.c',
'jack_midisine': 'midisine.c',
'jack_net_master': 'netmaster.c',
'jack_net_slave': 'netslave.c',
'jack_server_control': 'server_control.cpp',
'jack_showtime': 'showtime.c',
'jack_simdtests': 'simdtests.cpp',
'jack_simple_client': 'simple_client.c',
'jack_simple_session_client': 'simple_session_client.c',
'jack_thru': 'thru_client.c',
'jack_zombie': 'zombie.c',
}

example_libs = {
'inprocess': 'inprocess.c',
}


def configure(conf):
conf.env['BUILD_EXAMPLE_CLIENT_REC'] = conf.env['SNDFILE']


def build(bld):
if bld.env['IS_LINUX']:
os_incdir = ['../linux', '../posix']
if bld.env['IS_MACOSX']:
os_incdir = ['../macosx', '../posix']
if bld.env['IS_FREEBSD']:
os_incdir = ['../freebsd', '../posix']
if bld.env['IS_SUN']:
os_incdir = ['../solaris', '../posix']
if bld.env['IS_WINDOWS']:
os_incdir = ['../windows']
for example_program, example_program_source in list(example_programs.items()):
if example_program == 'jack_server_control':
use = ['serverlib', 'STDC++']
elif example_program == 'jack_net_slave':
if not bld.env['BUILD_NETLIB']:
continue
use = ['netlib']
elif example_program == 'jack_net_master':
if not bld.env['BUILD_NETLIB']:
continue
use = ['netlib']
else:
use = ['clientlib']

if example_program == 'jack_simdtests':
ftrs = 'cxx cxxprogram'
else:
ftrs = 'c cprogram'

if bld.env['IS_MACOSX']:
prog = bld(features=ftrs, framework=['Foundation'])
else:
prog = bld(features=ftrs)
prog.includes = os_incdir + ['../common/jack', '../common']
prog.source = example_program_source
prog.use = use
if bld.env['IS_LINUX']:
prog.use += ['RT', 'M']
if bld.env['IS_SUN']:
prog.use += ['M']
if bld.env['IS_FREEBSD']:
prog.use += ['M']
if bld.env['IS_WINDOWS'] and bld.env['BUILD_STATIC']:
prog.env['LIB_PTHREAD'] = [':libwinpthread.a']

prog.target = example_program

if bld.env['BUILD_EXAMPLE_CLIENT_REC']:
prog = bld(features='c cprogram')
prog.includes = os_incdir + ['../common/jack', '../common']
prog.source = 'capture_client.c'
prog.use = ['clientlib']
if bld.env['IS_MACOSX']:
prog.use += ['SNDFILE']
if bld.env['IS_LINUX']:
prog.use += ['RT', 'SNDFILE']
if bld.env['IS_FREEBSD']:
prog.use += ['SNDFILE']
if bld.env['IS_SUN']:
prog.use += ['RT', 'SNDFILE']
if bld.env['IS_WINDOWS']:
prog.uselib = ['SNDFILE']
if bld.env['BUILD_STATIC']:
prog.env['LIB_PTHREAD'] = [':libwinpthread.a']
prog.target = 'jack_rec'

for example_lib, example_lib_source in list(example_libs.items()):
lib = bld(features='c cshlib')
if not bld.env['IS_WINDOWS']:
lib.env['cshlib_PATTERN'] = '%s.so'
lib.includes = os_incdir + ['../common/jack', '../common']
lib.target = example_lib
lib.source = example_lib_source
if bld.env['IS_SUN']:
lib.env.append_value('LINKFLAGS', '-lm')
if bld.env['IS_WINDOWS'] and bld.env['BUILD_STATIC']:
prog.env['LIB_PTHREAD'] = [':libwinpthread.a']
lib.use = 'serverlib'
lib.install_path = '${ADDON_DIR}/'

+ 0
- 95
example-clients/zombie.c View File

@@ -1,95 +0,0 @@
/*
Copyright (C) 2002 Jeremy Hall

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.

$Id: zombie.c,v 1.1 2005/08/18 11:42:08 letz Exp $
*/

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

int running = 1;
int count = 0;
jack_port_t* output_port;

static int
process(jack_nframes_t nframes, void* arg)
{
if (count++ == 1000) {
printf("process block\n");
//while (1) {}
#if WIN32
Sleep(1*1000);
#else
sleep(1);
#endif
}

return 0;
}

static void
shutdown_handler (void *arg)
{
printf("shutdown \n");
running = 0;
}

int
main (int argc, char *argv[])
{
jack_client_t* client = NULL;
/* try to become a client of the JACK server */
if ((client = jack_client_open ("zombie", JackNullOption, NULL)) == 0) {
fprintf (stderr, "JACK server not running?\n");
goto error;
}

jack_set_process_callback (client, process, NULL);
jack_on_shutdown(client, shutdown_handler, NULL);
output_port = jack_port_register (client, "port1", 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");
goto error;
}

jack_connect(client, jack_port_name(output_port), "coreaudio:Built-in Audio:in2");

while (running) {
#if WIN32
Sleep(1*1000);
#else
sleep(1);
#endif
printf ("run\n");
}

jack_deactivate (client);
jack_client_close (client);
return 0;

error:
if (client)
jack_client_close (client);
return 1;
}


+ 0
- 133
tools/alias.c View File

@@ -1,133 +0,0 @@
/*
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 <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include <jack/jack.h>

char * my_name;

void
show_version (void)
{
//fprintf (stderr, "%s: JACK Audio Connection Kit version " VERSION "\n", my_name);
}

void
show_usage (void)
{
show_version ();
fprintf (stderr, "\nUsage: %s [options] portname alias\n", my_name);
fprintf (stderr, "List active Jack ports, and optionally display extra information.\n\n");
fprintf (stderr, "Display options:\n");
fprintf (stderr, " -u, --unalias remove `alias' as an alias for `port'\n");
fprintf (stderr, " -h, --help Display this help message\n");
fprintf (stderr, " --version Output version information and exit\n\n");
fprintf (stderr, "For more information see http://jackaudio.org/\n");
}

int
main (int argc, char *argv[])
{
jack_client_t *client;
jack_status_t status;
char* portname;
char* alias;
int unset = 0;
int ret;
int c;
int option_index;
extern int optind;
jack_port_t* port;

struct option long_options[] = {
{ "unalias", 0, 0, 'u' },
{ "help", 0, 0, 'h' },
{ "version", 0, 0, 'v' },
{ 0, 0, 0, 0 }
};

if (argc < 3) {
show_usage ();
return 1;
}

my_name = strrchr(argv[0], '/');
if (my_name == 0) {
my_name = argv[0];
} else {
my_name ++;
}

while ((c = getopt_long (argc, argv, "uhv", long_options, &option_index)) >= 0) {
switch (c) {
case 'u':
unset = 1;
break;
case 'h':
show_usage ();
return 1;
break;
case 'v':
show_version ();
return 1;
break;
default:
show_usage ();
return 1;
break;
}
}

portname = argv[optind++];
alias = argv[optind];

/* Open a client connection to the JACK server. Starting a
* new server only to list its ports seems pointless, so we
* specify JackNoStartServer. */
//JOQ: need a new server name option

client = jack_client_open ("lsp", JackNoStartServer, &status);

if (client == NULL) {
if (status & JackServerFailed) {
fprintf (stderr, "JACK server not running\n");
} else {
fprintf (stderr, "jack_client_open() failed, "
"status = 0x%2.0x\n", status);
}
return 1;
}

if ((port = jack_port_by_name (client, portname)) == 0) {
fprintf (stderr, "No port named \"%s\"\n", portname);
return 1;
}

if (!unset) {
ret = jack_port_set_alias (port, alias);
} else {
ret = jack_port_unset_alias (port, alias);
}

jack_client_close (client);

return ret;

}

+ 0
- 846
tools/alsa_in.c View File

@@ -1,846 +0,0 @@
/** @file simple_client.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 <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#include <math.h>

#include <jack/jack.h>
#include <jack/jslist.h>
#include "memops.h"

#include "alsa/asoundlib.h"

#include <samplerate.h>

// Here are the lists of the jack ports...

JSList *capture_ports = NULL;
JSList *capture_srcs = NULL;
JSList *playback_ports = NULL;
JSList *playback_srcs = NULL;
jack_client_t *client;

snd_pcm_t *alsa_handle;

int jack_sample_rate;
int jack_buffer_size;

int quit = 0;
double resample_mean = 1.0;
double static_resample_factor = 1.0;
double resample_lower_limit = 0.25;
double resample_upper_limit = 4.0;

double *offset_array;
double *window_array;
int offset_differential_index = 0;

double offset_integral = 0;

// ------------------------------------------------------ commandline parameters

int sample_rate = 0; /* stream rate */
int num_channels = 2; /* count of channels */
int period_size = 1024;
int num_periods = 2;

int target_delay = 0; /* the delay which the program should try to approach. */
int max_diff = 0; /* the diff value, when a hard readpointer skip should occur */
int catch_factor = 100000;
int catch_factor2 = 10000;
double pclamp = 15.0;
double controlquant = 10000.0;
int smooth_size = 256;
int good_window=0;
int verbose = 0;
int instrument = 0;
int samplerate_quality = 2;

// Debug stuff:

volatile float output_resampling_factor = 1.0;
volatile int output_new_delay = 0;
volatile float output_offset = 0.0;
volatile float output_integral = 0.0;
volatile float output_diff = 0.0;
volatile int running_freewheel = 0;

snd_pcm_uframes_t real_buffer_size;
snd_pcm_uframes_t real_period_size;

// buffers

char *tmpbuf;
char *outbuf;
float *resampbuf;

// format selection, and corresponding functions from memops in a nice set of structs.

typedef struct alsa_format {
snd_pcm_format_t format_id;
size_t sample_size;
void (*jack_to_soundcard) (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
void (*soundcard_to_jack) (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip);
const char *name;
} alsa_format_t;

alsa_format_t formats[] = {
{ SND_PCM_FORMAT_FLOAT_LE, 4, sample_move_dS_floatLE, sample_move_floatLE_sSs, "float" },
{ SND_PCM_FORMAT_S32, 4, sample_move_d32u24_sS, sample_move_dS_s32u24, "32bit" },
{ SND_PCM_FORMAT_S24_3LE, 3, sample_move_d24_sS, sample_move_dS_s24, "24bit - real" },
{ SND_PCM_FORMAT_S24, 4, sample_move_d32l24_sS, sample_move_dS_s32l24, "24bit" },
{ SND_PCM_FORMAT_S16, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit" }
#ifdef __ANDROID__
,{ SND_PCM_FORMAT_S16_LE, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit little-endian" }
#endif
};
#define NUMFORMATS (sizeof(formats)/sizeof(formats[0]))
int format=0;

// Alsa stuff... i don't want to touch this bullshit in the next years.... please...

static int xrun_recovery(snd_pcm_t *handle, int err) {
// printf( "xrun !!!.... %d\n", err );
if (err == -EPIPE) { /* under-run */
err = snd_pcm_prepare(handle);
if (err < 0)
printf("Can't recover from underrun, prepare failed: %s\n", snd_strerror(err));
return 0;
} else if (err == -ESTRPIPE) {
while ((err = snd_pcm_resume(handle)) == -EAGAIN)
usleep(100); /* wait until the suspend flag is released */
if (err < 0) {
err = snd_pcm_prepare(handle);
if (err < 0)
printf("Can't recover from suspend, prepare failed: %s\n", snd_strerror(err));
}
return 0;
}
return err;
}

static int set_hwformat( snd_pcm_t *handle, snd_pcm_hw_params_t *params )
{
#ifdef __ANDROID__
format = 5;
snd_pcm_hw_params_set_format(handle, params, formats[format].format_id);
return 0;
#else
int i;
int err;

for( i=0; i<NUMFORMATS; i++ ) {
/* set the sample format */
err = snd_pcm_hw_params_set_format(handle, params, formats[i].format_id);
if (err == 0) {
format = i;
return 0;
}
}

return err;
#endif
}

static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access, int rate, int channels, int period, int nperiods ) {
int err, dir=0;
unsigned int buffer_time;
unsigned int period_time;
unsigned int rrate;
unsigned int rchannels;

/* choose all parameters */
err = snd_pcm_hw_params_any(handle, params);
if (err < 0) {
printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
return err;
}
/* set the interleaved read/write format */
err = snd_pcm_hw_params_set_access(handle, params, access);
if (err < 0) {
printf("Access type not available for playback: %s\n", snd_strerror(err));
return err;
}

/* set the sample format */
err = set_hwformat(handle, params);
if (err < 0) {
printf("Sample format not available for playback: %s\n", snd_strerror(err));
return err;
}
/* set the count of channels */
rchannels = channels;
err = snd_pcm_hw_params_set_channels_near(handle, params, &rchannels);
if (err < 0) {
printf("Channels count (%i) not available for record: %s\n", channels, snd_strerror(err));
return err;
}
if (rchannels != channels) {
printf("WARNING: channel count does not match (requested %d got %d)\n", channels, rchannels);
num_channels = rchannels;
}
/* set the stream rate */
rrate = rate;
err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
if (err < 0) {
printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err));
return err;
}
if (rrate != rate) {
printf("WARNING: Rate doesn't match (requested %iHz, get %iHz)\n", rate, rrate);
sample_rate = rrate;
}
/* set the buffer time */

buffer_time = 1000000*(uint64_t)period*nperiods/rate;
err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir);
if (err < 0) {
printf("Unable to set buffer time %i for playback: %s\n", 1000000*period*nperiods/rate, snd_strerror(err));
return err;
}
err = snd_pcm_hw_params_get_buffer_size( params, &real_buffer_size );
if (err < 0) {
printf("Unable to get buffer size back: %s\n", snd_strerror(err));
return err;
}
if( real_buffer_size != nperiods * period ) {
printf( "WARNING: buffer size does not match: (requested %d, got %d)\n", nperiods * period, (int) real_buffer_size );
}
/* set the period time */
period_time = 1000000*(uint64_t)period/rate;
err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir);
if (err < 0) {
printf("Unable to set period time %i for playback: %s\n", 1000000*period/rate, snd_strerror(err));
return err;
}
err = snd_pcm_hw_params_get_period_size(params, &real_period_size, NULL );
if (err < 0) {
printf("Unable to get period size back: %s\n", snd_strerror(err));
return err;
}
if( real_period_size != period ) {
printf( "WARNING: period size does not match: (requested %i, got %i)\n", period, (int)real_period_size );
}
/* write the parameters to device */
err = snd_pcm_hw_params(handle, params);
if (err < 0) {
printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
return err;
}
return 0;
}

static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams, int period) {
int err;

/* get the current swparams */
err = snd_pcm_sw_params_current(handle, swparams);
if (err < 0) {
printf("Unable to determine current swparams for capture: %s\n", snd_strerror(err));
return err;
}
/* start the transfer when the buffer is full */
err = snd_pcm_sw_params_set_start_threshold(handle, swparams, period );
if (err < 0) {
printf("Unable to set start threshold mode for capture: %s\n", snd_strerror(err));
return err;
}
err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, -1 );
if (err < 0) {
printf("Unable to set start threshold mode for capture: %s\n", snd_strerror(err));
return err;
}
/* allow the transfer when at least period_size samples can be processed */
err = snd_pcm_sw_params_set_avail_min(handle, swparams, 2*period );
if (err < 0) {
printf("Unable to set avail min for capture: %s\n", snd_strerror(err));
return err;
}
/* align all transfers to 1 sample */
err = snd_pcm_sw_params_set_xfer_align(handle, swparams, 1);
if (err < 0) {
printf("Unable to set transfer align for capture: %s\n", snd_strerror(err));
return err;
}
/* write the parameters to the playback device */
err = snd_pcm_sw_params(handle, swparams);
if (err < 0) {
printf("Unable to set sw params for capture: %s\n", snd_strerror(err));
return err;
}
return 0;
}

// ok... i only need this function to communicate with the alsa bloat api...

static snd_pcm_t *open_audiofd( char *device_name, int capture, int rate, int channels, int period, int nperiods ) {
int err;
snd_pcm_t *handle;
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;

snd_pcm_hw_params_alloca(&hwparams);
snd_pcm_sw_params_alloca(&swparams);

if ((err = snd_pcm_open(&(handle), device_name, capture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK )) < 0) {
printf("Capture open error: %s\n", snd_strerror(err));
return NULL;
}

if ((err = set_hwparams(handle, hwparams,SND_PCM_ACCESS_RW_INTERLEAVED, rate, channels, period, nperiods )) < 0) {
printf("Setting of hwparams failed: %s\n", snd_strerror(err));
return NULL;
}
if ((err = set_swparams(handle, swparams, period)) < 0) {
printf("Setting of swparams failed: %s\n", snd_strerror(err));
return NULL;
}

snd_pcm_start( handle );
snd_pcm_wait( handle, 200 );

return handle;
}

double hann( double x )
{
return 0.5 * (1.0 - cos( 2*M_PI * x ) );
}

/**
* The freewheel callback.
*/
void freewheel (int starting, void* arg) {
running_freewheel = starting;
}

/**
* The process callback for this JACK application.
* It is called by JACK at the appropriate times.
*/
int process (jack_nframes_t nframes, void *arg) {

if (running_freewheel) {
JSList *node = capture_ports;

while ( node != NULL)
{
jack_port_t *port = (jack_port_t *) node->data;
float *buf = jack_port_get_buffer (port, nframes);

memset(buf, 0, sizeof(float)*nframes);

node = jack_slist_next (node);
}

return 0;
}

int rlen;
int err;
snd_pcm_sframes_t delay = target_delay;
int put_back_samples=0;
int i;

delay = snd_pcm_avail( alsa_handle );

delay -= round( jack_frames_since_cycle_start( client ) / static_resample_factor );
// Do it the hard way.
// this is for compensating xruns etc...

if( delay > (target_delay+max_diff) ) {

output_new_delay = (int) delay;

while ((delay-target_delay) > 0) {
snd_pcm_uframes_t to_read = ((delay-target_delay) > 512) ? 512 : (delay-target_delay);
snd_pcm_readi( alsa_handle, tmpbuf, to_read );
delay -= to_read;
}

delay = target_delay;

// Set the resample_rate... we need to adjust the offset integral, to do this.
// first look at the PI controller, this code is just a special case, which should never execute once
// everything is swung in.
offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2;
// Also clear the array. we are beginning a new control cycle.
for( i=0; i<smooth_size; i++ )
offset_array[i] = 0.0;
}
if( delay < (target_delay-max_diff) ) {
snd_pcm_rewind( alsa_handle, target_delay - delay );
output_new_delay = (int) delay;
delay = target_delay;

// Set the resample_rate... we need to adjust the offset integral, to do this.
offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2;
// Also clear the array. we are beginning a new control cycle.
for( i=0; i<smooth_size; i++ )
offset_array[i] = 0.0;
}
/* ok... now we should have target_delay +- max_diff on the alsa side.
*
* calculate the number of frames, we want to get.
*/

double offset = delay - target_delay;

// Save offset.
offset_array[(offset_differential_index++)% smooth_size ] = offset;

// Build the mean of the windowed offset array
// basically fir lowpassing.
double smooth_offset = 0.0;
for( i=0; i<smooth_size; i++ )
smooth_offset +=
offset_array[ (i + offset_differential_index-1) % smooth_size] * window_array[i];
smooth_offset /= (double) smooth_size;

// this is the integral of the smoothed_offset
offset_integral += smooth_offset;

// Clamp offset.
// the smooth offset still contains unwanted noise
// which would go straight onto the resample coeff.
// it only used in the P component and the I component is used for the fine tuning anyways.
if( fabs( smooth_offset ) < pclamp )
smooth_offset = 0.0;

// ok. now this is the PI controller.
// u(t) = K * ( e(t) + 1/T \int e(t') dt' )
// K = 1/catch_factor and T = catch_factor2
double current_resample_factor = static_resample_factor - smooth_offset / (double) catch_factor - offset_integral / (double) catch_factor / (double)catch_factor2;

// now quantize this value around resample_mean, so that the noise which is in the integral component doesn't hurt.
current_resample_factor = floor( (current_resample_factor - resample_mean) * controlquant + 0.5 ) / controlquant + resample_mean;

// Output "instrumentatio" gonna change that to real instrumentation in a few.
output_resampling_factor = (float) current_resample_factor;
output_diff = (float) smooth_offset;
output_integral = (float) offset_integral;
output_offset = (float) offset;

// Clamp a bit.
if( current_resample_factor < resample_lower_limit ) current_resample_factor = resample_lower_limit;
if( current_resample_factor > resample_upper_limit ) current_resample_factor = resample_upper_limit;

// Now Calculate how many samples we need.
rlen = ceil( ((double)nframes) / current_resample_factor )+2;
assert( rlen > 2 );

// Calculate resample_mean so we can init ourselves to saner values.
resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor;

// get the data...
again:
err = snd_pcm_readi(alsa_handle, outbuf, rlen);
if( err < 0 ) {
printf( "err = %d\n", err );
if (xrun_recovery(alsa_handle, err) < 0) {
//printf("Write error: %s\n", snd_strerror(err));
//exit(EXIT_FAILURE);
}
goto again;
}
if( err != rlen ) {
//printf( "read = %d\n", rlen );
}

/*
* render jack ports to the outbuf...
*/

int chn = 0;
JSList *node = capture_ports;
JSList *src_node = capture_srcs;
SRC_DATA src;

while ( node != NULL)
{
jack_port_t *port = (jack_port_t *) node->data;
float *buf = jack_port_get_buffer (port, nframes);

SRC_STATE *src_state = src_node->data;

formats[format].soundcard_to_jack( resampbuf, outbuf + format[formats].sample_size * chn, rlen, num_channels*format[formats].sample_size );

src.data_in = resampbuf;
src.input_frames = rlen;

src.data_out = buf;
src.output_frames = nframes;
src.end_of_input = 0;

src.src_ratio = current_resample_factor;

src_process( src_state, &src );

put_back_samples = rlen-src.input_frames_used;

src_node = jack_slist_next (src_node);
node = jack_slist_next (node);
chn++;
}

// Put back the samples libsamplerate did not consume.
//printf( "putback = %d\n", put_back_samples );
snd_pcm_rewind( alsa_handle, put_back_samples );

return 0;
}

/**
* the latency callback.
* sets up the latencies on the ports.
*/

void
latency_cb (jack_latency_callback_mode_t mode, void *arg)
{
jack_latency_range_t range;
JSList *node;

range.min = range.max = round(target_delay * static_resample_factor);

if (mode == JackCaptureLatency) {
for (node = capture_ports; node; node = jack_slist_next (node)) {
jack_port_t *port = node->data;
jack_port_set_latency_range (port, mode, &range);
}
} else {
for (node = playback_ports; node; node = jack_slist_next (node)) {
jack_port_t *port = node->data;
jack_port_set_latency_range (port, mode, &range);
}
}
}


/**
* Allocate the necessary jack ports...
*/

void alloc_ports( int n_capture, int n_playback ) {

int port_flags = JackPortIsOutput;
int chn;
jack_port_t *port;
char buf[32];

capture_ports = NULL;
for (chn = 0; chn < n_capture; chn++)
{
snprintf (buf, sizeof(buf) - 1, "capture_%u", chn+1);

port = jack_port_register (client, buf,
JACK_DEFAULT_AUDIO_TYPE,
port_flags, 0);

if (!port)
{
printf( "jacknet_client: cannot register port for %s", buf);
break;
}

capture_srcs = jack_slist_append( capture_srcs, src_new( 4-samplerate_quality, 1, NULL ) );
capture_ports = jack_slist_append (capture_ports, port);
}

port_flags = JackPortIsInput;

playback_ports = NULL;
for (chn = 0; chn < n_playback; chn++)
{
snprintf (buf, sizeof(buf) - 1, "playback_%u", chn+1);

port = jack_port_register (client, buf,
JACK_DEFAULT_AUDIO_TYPE,
port_flags, 0);

if (!port)
{
printf( "jacknet_client: cannot register port for %s", buf);
break;
}

playback_srcs = jack_slist_append( playback_srcs, src_new( 4-samplerate_quality, 1, NULL ) );
playback_ports = jack_slist_append (playback_ports, port);
}
}

/**
* This is the shutdown callback for this JACK application.
* It is called by JACK if the server ever shuts down or
* decides to disconnect the client.
*/

void jack_shutdown (void *arg) {

exit (1);
}

/**
* be user friendly.
* be user friendly.
* be user friendly.
*/

void printUsage() {
fprintf(stderr, "usage: alsa_out [options]\n"
"\n"
" -j <jack name> - client name\n"
" -S <server name> - server to connect\n"
" -d <alsa_device> \n"
" -c <channels> \n"
" -p <period_size> \n"
" -n <num_period> \n"
" -r <sample_rate> \n"
" -q <sample_rate quality [0..4]\n"
" -m <max_diff> \n"
" -t <target_delay> \n"
" -i turns on instrumentation\n"
" -v turns on printouts\n"
"\n");
}


/**
* the main function....
*/

void
sigterm_handler( int signal )
{
quit = 1;
}


int main (int argc, char *argv[]) {
char jack_name[30] = "alsa_in";
char alsa_device[30] = "hw:0";
char *server_name = NULL;
int jack_opts = 0;

extern char *optarg;
extern int optind, optopt;
int errflg=0;
int c;

while ((c = getopt(argc, argv, "ivj:r:c:p:n:d:q:m:t:f:F:C:Q:s:S:")) != -1) {
switch(c) {
case 'j':
strcpy(jack_name,optarg);
break;
case 'r':
sample_rate = atoi(optarg);
break;
case 'c':
num_channels = atoi(optarg);
break;
case 'p':
period_size = atoi(optarg);
break;
case 'n':
num_periods = atoi(optarg);
break;
case 'd':
strcpy(alsa_device,optarg);
break;
case 't':
target_delay = atoi(optarg);
break;
case 'q':
samplerate_quality = atoi(optarg);
break;
case 'm':
max_diff = atoi(optarg);
break;
case 'f':
catch_factor = atoi(optarg);
break;
case 'F':
catch_factor2 = atoi(optarg);
break;
case 'C':
pclamp = (double) atoi(optarg);
break;
case 'Q':
controlquant = (double) atoi(optarg);
break;
case 'v':
verbose = 1;
break;
case 'i':
instrument = 1;
break;
case 's':
smooth_size = atoi(optarg);
break;
case 'S':
server_name = optarg;
jack_opts |= JackServerName;
break;
case ':':
fprintf(stderr,
"Option -%c requires an operand\n", optopt);
errflg++;
break;
case '?':
fprintf(stderr,
"Unrecognized option: -%c\n", optopt);
errflg++;
}
}
if (errflg) {
printUsage();
exit(2);
}

if( (samplerate_quality < 0) || (samplerate_quality > 4) ) {
fprintf (stderr, "invalid samplerate quality\n");
return 1;
}
if ((client = jack_client_open (jack_name, jack_opts, NULL, server_name)) == 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 `freewheel()' whenever
freewheel mode changes.
*/

jack_set_freewheel_callback (client, freewheel, 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);

if (jack_set_latency_callback)
jack_set_latency_callback (client, latency_cb, 0);

// get jack sample_rate
jack_sample_rate = jack_get_sample_rate( client );

if( !sample_rate )
sample_rate = jack_sample_rate;

// now open the alsa fd...
alsa_handle = open_audiofd( alsa_device, 1, sample_rate, num_channels, period_size, num_periods);
if( alsa_handle == 0 )
exit(20);

printf( "selected sample format: %s\n", formats[format].name );

static_resample_factor = (double) jack_sample_rate / (double) sample_rate;
resample_lower_limit = static_resample_factor * 0.25;
resample_upper_limit = static_resample_factor * 4.0;
resample_mean = static_resample_factor;

offset_array = malloc( sizeof(double) * smooth_size );
if( offset_array == NULL ) {
fprintf( stderr, "no memory for offset_array !!!\n" );
exit(20);
}
window_array = malloc( sizeof(double) * smooth_size );
if( window_array == NULL ) {
fprintf( stderr, "no memory for window_array !!!\n" );
exit(20);
}
int i;
for( i=0; i<smooth_size; i++ ) {
offset_array[i] = 0.0;
window_array[i] = hann( (double) i / ((double) smooth_size - 1.0) );
}

jack_buffer_size = jack_get_buffer_size( client );
// Setup target delay and max_diff for the normal user, who does not play with them...
if( !target_delay )
target_delay = (num_periods*period_size / 2) + jack_buffer_size/2;

if( !max_diff )
max_diff = num_periods*period_size - target_delay ;

if( max_diff > target_delay ) {
fprintf( stderr, "target_delay (%d) can not be smaller than max_diff(%d)\n", target_delay, max_diff );
exit(20);
}
if( (target_delay+max_diff) > (num_periods*period_size) ) {
fprintf( stderr, "target_delay+max_diff (%d) can not be bigger than buffersize(%d)\n", target_delay+max_diff, num_periods*period_size );
exit(20);
}
// alloc input ports, which are blasted out to alsa...
alloc_ports( num_channels, 0 );

outbuf = malloc( num_periods * period_size * formats[format].sample_size * num_channels );
resampbuf = malloc( num_periods * period_size * sizeof( float ) );
tmpbuf = malloc( 512 * formats[format].sample_size * num_channels );

if ((outbuf == NULL) || (resampbuf == NULL) || (tmpbuf == NULL))
{
fprintf( stderr, "no memory for buffers.\n" );
exit(20);
}

memset( tmpbuf, 0, 512 * formats[format].sample_size * num_channels);

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

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

signal( SIGTERM, sigterm_handler );
signal( SIGINT, sigterm_handler );

if( verbose ) {
while(!quit) {
usleep(500000);
if( output_new_delay ) {
printf( "delay = %d\n", output_new_delay );
output_new_delay = 0;
}
printf( "res: %f, \tdiff = %f, \toffset = %f \n", output_resampling_factor, output_diff, output_offset );
}
} else if( instrument ) {
printf( "# n\tresamp\tdiff\toffseti\tintegral\n");
int n=0;
while(!quit) {
usleep(1000);
printf( "%d\t%f\t%f\t%f\t%f\n", n++, output_resampling_factor, output_diff, output_offset, output_integral );
}
} else {
while(!quit)
{
usleep(500000);
if( output_new_delay ) {
printf( "delay = %d\n", output_new_delay );
output_new_delay = 0;
}
}
}

jack_deactivate( client );
jack_client_close (client);
exit (0);
}

+ 0
- 848
tools/alsa_out.c View File

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

#include <alloca.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#include <math.h>

#include <jack/jack.h>
#include <jack/jslist.h>
#include "memops.h"

#include "alsa/asoundlib.h"

#include <samplerate.h>

// Here are the lists of the jack ports...

JSList *capture_ports = NULL;
JSList *capture_srcs = NULL;
JSList *playback_ports = NULL;
JSList *playback_srcs = NULL;
jack_client_t *client;

snd_pcm_t *alsa_handle;

int jack_sample_rate;
int jack_buffer_size;

int quit = 0;
double resample_mean = 1.0;
double static_resample_factor = 1.0;
double resample_lower_limit = 0.25;
double resample_upper_limit = 4.0;

double *offset_array;
double *window_array;
int offset_differential_index = 0;

double offset_integral = 0;

// ------------------------------------------------------ commandline parameters

int sample_rate = 0; /* stream rate */
int num_channels = 2; /* count of channels */
int period_size = 1024;
int num_periods = 2;

int target_delay = 0; /* the delay which the program should try to approach. */
int max_diff = 0; /* the diff value, when a hard readpointer skip should occur */
int catch_factor = 100000;
int catch_factor2 = 10000;
double pclamp = 15.0;
double controlquant = 10000.0;
int smooth_size = 256;
int good_window=0;
int verbose = 0;
int instrument = 0;
int samplerate_quality = 2;

// Debug stuff:

volatile float output_resampling_factor = 1.0;
volatile int output_new_delay = 0;
volatile float output_offset = 0.0;
volatile float output_integral = 0.0;
volatile float output_diff = 0.0;
volatile int running_freewheel = 0;

snd_pcm_uframes_t real_buffer_size;
snd_pcm_uframes_t real_period_size;

// buffers

char *tmpbuf;
char *outbuf;
float *resampbuf;

// format selection, and corresponding functions from memops in a nice set of structs.

typedef struct alsa_format {
snd_pcm_format_t format_id;
size_t sample_size;
void (*jack_to_soundcard) (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
void (*soundcard_to_jack) (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip);
const char *name;
} alsa_format_t;

alsa_format_t formats[] = {
{ SND_PCM_FORMAT_FLOAT_LE, 4, sample_move_dS_floatLE, sample_move_floatLE_sSs, "float" },
{ SND_PCM_FORMAT_S32, 4, sample_move_d32u24_sS, sample_move_dS_s32u24, "32bit" },
{ SND_PCM_FORMAT_S24_3LE, 3, sample_move_d24_sS, sample_move_dS_s24, "24bit - real" },
{ SND_PCM_FORMAT_S24, 4, sample_move_d32l24_sS, sample_move_dS_s32l24, "24bit" },
{ SND_PCM_FORMAT_S16, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit" }
#ifdef __ANDROID__
,{ SND_PCM_FORMAT_S16_LE, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit little-endian" }
#endif
};
#define NUMFORMATS (sizeof(formats)/sizeof(formats[0]))
int format=0;

// Alsa stuff... i don't want to touch this bullshit in the next years.... please...

static int xrun_recovery(snd_pcm_t *handle, int err) {
// printf( "xrun !!!.... %d\n", err );
if (err == -EPIPE) { /* under-run */
err = snd_pcm_prepare(handle);
if (err < 0)
printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err));
return 0;
} else if (err == -ESTRPIPE) {
while ((err = snd_pcm_resume(handle)) == -EAGAIN)
usleep(100); /* wait until the suspend flag is released */
if (err < 0) {
err = snd_pcm_prepare(handle);
if (err < 0)
printf("Can't recovery from suspend, prepare failed: %s\n", snd_strerror(err));
}
return 0;
}
return err;
}

static int set_hwformat( snd_pcm_t *handle, snd_pcm_hw_params_t *params )
{
#ifdef __ANDROID__
format = 5;
snd_pcm_hw_params_set_format(handle, params, formats[format].format_id);
return 0;
#else
int i;
int err;

for( i=0; i<NUMFORMATS; i++ ) {
/* set the sample format */
err = snd_pcm_hw_params_set_format(handle, params, formats[i].format_id);
if (err == 0) {
format = i;
return 0;
}
}

return err;
#endif
}

static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access, int rate, int channels, int period, int nperiods ) {
int err, dir=0;
unsigned int buffer_time;
unsigned int period_time;
unsigned int rrate;
unsigned int rchannels;

/* choose all parameters */
err = snd_pcm_hw_params_any(handle, params);
if (err < 0) {
printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
return err;
}
/* set the interleaved read/write format */
err = snd_pcm_hw_params_set_access(handle, params, access);
if (err < 0) {
printf("Access type not available for playback: %s\n", snd_strerror(err));
return err;
}

/* set the sample format */
err = set_hwformat(handle, params);
if (err < 0) {
printf("Sample format not available for playback: %s\n", snd_strerror(err));
return err;
}
/* set the count of channels */
rchannels = channels;
err = snd_pcm_hw_params_set_channels_near(handle, params, &rchannels);
if (err < 0) {
printf("Channels count (%i) not available for record: %s\n", channels, snd_strerror(err));
return err;
}
if (rchannels != channels) {
printf("WARNING: channel count does not match (requested %d got %d)\n", channels, rchannels);
num_channels = rchannels;
}
/* set the stream rate */
rrate = rate;
err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
if (err < 0) {
printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err));
return err;
}
if (rrate != rate) {
printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, rrate);
return -EINVAL;
}
/* set the buffer time */

buffer_time = 1000000*(uint64_t)period*nperiods/rate;
err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir);
if (err < 0) {
printf("Unable to set buffer time %i for playback: %s\n", 1000000*period*nperiods/rate, snd_strerror(err));
return err;
}
err = snd_pcm_hw_params_get_buffer_size( params, &real_buffer_size );
if (err < 0) {
printf("Unable to get buffer size back: %s\n", snd_strerror(err));
return err;
}
if( real_buffer_size != nperiods * period ) {
printf( "WARNING: buffer size does not match: (requested %d, got %d)\n", nperiods * period, (int) real_buffer_size );
}
/* set the period time */
period_time = 1000000*(uint64_t)period/rate;
err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir);
if (err < 0) {
printf("Unable to set period time %i for playback: %s\n", 1000000*period/rate, snd_strerror(err));
return err;
}
err = snd_pcm_hw_params_get_period_size(params, &real_period_size, NULL );
if (err < 0) {
printf("Unable to get period size back: %s\n", snd_strerror(err));
return err;
}
if( real_period_size != period ) {
printf( "WARNING: period size does not match: (requested %i, got %i)\n", period, (int)real_period_size );
}
/* write the parameters to device */
err = snd_pcm_hw_params(handle, params);
if (err < 0) {
printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
return err;
}
return 0;
}

static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams, int period, int nperiods) {
int err;

/* get the current swparams */
err = snd_pcm_sw_params_current(handle, swparams);
if (err < 0) {
printf("Unable to determine current swparams for capture: %s\n", snd_strerror(err));
return err;
}
/* start the transfer when the buffer is full */
err = snd_pcm_sw_params_set_start_threshold(handle, swparams, period );
if (err < 0) {
printf("Unable to set start threshold mode for capture: %s\n", snd_strerror(err));
return err;
}
err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, -1 );
if (err < 0) {
printf("Unable to set start threshold mode for capture: %s\n", snd_strerror(err));
return err;
}
/* allow the transfer when at least period_size samples can be processed */
err = snd_pcm_sw_params_set_avail_min(handle, swparams, 1 );
if (err < 0) {
printf("Unable to set avail min for capture: %s\n", snd_strerror(err));
return err;
}
/* align all transfers to 1 sample */
err = snd_pcm_sw_params_set_xfer_align(handle, swparams, 1);
if (err < 0) {
printf("Unable to set transfer align for capture: %s\n", snd_strerror(err));
return err;
}
/* write the parameters to the playback device */
err = snd_pcm_sw_params(handle, swparams);
if (err < 0) {
printf("Unable to set sw params for capture: %s\n", snd_strerror(err));
return err;
}
return 0;
}

// ok... i only need this function to communicate with the alsa bloat api...

static snd_pcm_t *open_audiofd( char *device_name, int capture, int rate, int channels, int period, int nperiods ) {
int err;
snd_pcm_t *handle;
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;

snd_pcm_hw_params_alloca(&hwparams);
snd_pcm_sw_params_alloca(&swparams);

if ((err = snd_pcm_open(&(handle), device_name, capture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK )) < 0) {
printf("Capture open error: %s\n", snd_strerror(err));
return NULL;
}

if ((err = set_hwparams(handle, hwparams,SND_PCM_ACCESS_RW_INTERLEAVED, rate, channels, period, nperiods )) < 0) {
printf("Setting of hwparams failed: %s\n", snd_strerror(err));
return NULL;
}
if ((err = set_swparams(handle, swparams, period, nperiods)) < 0) {
printf("Setting of swparams failed: %s\n", snd_strerror(err));
return NULL;
}

//snd_pcm_start( handle );
//snd_pcm_wait( handle, 200 );
int num_null_samples = nperiods * period * channels;
char *tmp = alloca( num_null_samples * formats[format].sample_size );
memset( tmp, 0, num_null_samples * formats[format].sample_size );
snd_pcm_writei( handle, tmp, num_null_samples );

return handle;
}

double hann( double x )
{
return 0.5 * (1.0 - cos( 2*M_PI * x ) );
}

/**
* The freewheel callback.
*/
void freewheel (int starting, void* arg) {
running_freewheel = starting;
}

/**
* The process callback for this JACK application.
* It is called by JACK at the appropriate times.
*/
int process (jack_nframes_t nframes, void *arg) {

if (running_freewheel) {
JSList *node = playback_ports;

while ( node != NULL)
{
jack_port_t *port = (jack_port_t *) node->data;
float *buf = jack_port_get_buffer (port, nframes);

memset(buf, 0, sizeof(float)*nframes);

node = jack_slist_next (node);
}

return 0;
}

int rlen;
int err;
snd_pcm_sframes_t delay = target_delay;
int i;

delay = (num_periods*period_size)-snd_pcm_avail( alsa_handle ) ;

delay -= round( jack_frames_since_cycle_start( client ) * static_resample_factor );
// Do it the hard way.
// this is for compensating xruns etc...

if( delay > (target_delay+max_diff) ) {
snd_pcm_rewind( alsa_handle, delay - target_delay );
output_new_delay = (int) delay;

delay = target_delay;

// Set the resample_rate... we need to adjust the offset integral, to do this.
// first look at the PI controller, this code is just a special case, which should never execute once
// everything is swung in.
offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2;
// Also clear the array. we are beginning a new control cycle.
for( i=0; i<smooth_size; i++ )
offset_array[i] = 0.0;
}
if( delay < (target_delay-max_diff) ) {

output_new_delay = (int) delay;

while ((target_delay-delay) > 0) {
snd_pcm_uframes_t to_write = ((target_delay-delay) > 512) ? 512 : (target_delay-delay);
snd_pcm_writei( alsa_handle, tmpbuf, to_write );
delay += to_write;
}

delay = target_delay;

// Set the resample_rate... we need to adjust the offset integral, to do this.
offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2;
// Also clear the array. we are beginning a new control cycle.
for( i=0; i<smooth_size; i++ )
offset_array[i] = 0.0;
}
/* ok... now we should have target_delay +- max_diff on the alsa side.
*
* calculate the number of frames, we want to get.
*/

double offset = delay - target_delay;

// Save offset.
offset_array[(offset_differential_index++)% smooth_size ] = offset;

// Build the mean of the windowed offset array
// basically fir lowpassing.
double smooth_offset = 0.0;
for( i=0; i<smooth_size; i++ )
smooth_offset +=
offset_array[ (i + offset_differential_index-1) % smooth_size] * window_array[i];
smooth_offset /= (double) smooth_size;

// this is the integral of the smoothed_offset
offset_integral += smooth_offset;

// Clamp offset.
// the smooth offset still contains unwanted noise
// which would go straight onto the resample coeff.
// it only used in the P component and the I component is used for the fine tuning anyways.
if( fabs( smooth_offset ) < pclamp )
smooth_offset = 0.0;

// ok. now this is the PI controller.
// u(t) = K * ( e(t) + 1/T \int e(t') dt' )
// K = 1/catch_factor and T = catch_factor2
double current_resample_factor = static_resample_factor - smooth_offset / (double) catch_factor - offset_integral / (double) catch_factor / (double)catch_factor2;

// now quantize this value around resample_mean, so that the noise which is in the integral component doesn't hurt.
current_resample_factor = floor( (current_resample_factor - resample_mean) * controlquant + 0.5 ) / controlquant + resample_mean;

// Output "instrumentatio" gonna change that to real instrumentation in a few.
output_resampling_factor = (float) current_resample_factor;
output_diff = (float) smooth_offset;
output_integral = (float) offset_integral;
output_offset = (float) offset;

// Clamp a bit.
if( current_resample_factor < resample_lower_limit ) current_resample_factor = resample_lower_limit;
if( current_resample_factor > resample_upper_limit ) current_resample_factor = resample_upper_limit;

// Now Calculate how many samples we need.
rlen = ceil( ((double)nframes) * current_resample_factor )+2;
assert( rlen > 2 );

// Calculate resample_mean so we can init ourselves to saner values.
resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor;
/*
* now this should do it...
*/

outbuf = alloca( rlen * formats[format].sample_size * num_channels );

resampbuf = alloca( rlen * sizeof( float ) );
/*
* render jack ports to the outbuf...
*/

int chn = 0;
JSList *node = playback_ports;
JSList *src_node = playback_srcs;
SRC_DATA src;

while ( node != NULL)
{
jack_port_t *port = (jack_port_t *) node->data;
float *buf = jack_port_get_buffer (port, nframes);

SRC_STATE *src_state = src_node->data;

src.data_in = buf;
src.input_frames = nframes;

src.data_out = resampbuf;
src.output_frames = rlen;
src.end_of_input = 0;

src.src_ratio = current_resample_factor;

src_process( src_state, &src );

formats[format].jack_to_soundcard( outbuf + format[formats].sample_size * chn, resampbuf, src.output_frames_gen, num_channels*format[formats].sample_size, NULL);

src_node = jack_slist_next (src_node);
node = jack_slist_next (node);
chn++;
}

// now write the output...
again:
err = snd_pcm_writei(alsa_handle, outbuf, src.output_frames_gen);
//err = snd_pcm_writei(alsa_handle, outbuf, src.output_frames_gen);
if( err < 0 ) {
printf( "err = %d\n", err );
if (xrun_recovery(alsa_handle, err) < 0) {
printf("Write error: %s\n", snd_strerror(err));
exit(EXIT_FAILURE);
}
goto again;
}

return 0;
}

/**
* the latency callback.
* sets up the latencies on the ports.
*/

void
latency_cb (jack_latency_callback_mode_t mode, void *arg)
{
jack_latency_range_t range;
JSList *node;

range.min = range.max = round(target_delay / static_resample_factor);

if (mode == JackCaptureLatency) {
for (node = capture_ports; node; node = jack_slist_next (node)) {
jack_port_t *port = node->data;
jack_port_set_latency_range (port, mode, &range);
}
} else {
for (node = playback_ports; node; node = jack_slist_next (node)) {
jack_port_t *port = node->data;
jack_port_set_latency_range (port, mode, &range);
}
}
}


/**
* Allocate the necessary jack ports...
*/

void alloc_ports( int n_capture, int n_playback ) {

int port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal;
int chn;
jack_port_t *port;
char buf[32];

capture_ports = NULL;
for (chn = 0; chn < n_capture; chn++)
{
snprintf (buf, sizeof(buf) - 1, "capture_%u", chn+1);

port = jack_port_register (client, buf,
JACK_DEFAULT_AUDIO_TYPE,
port_flags, 0);

if (!port)
{
printf( "jacknet_client: cannot register port for %s", buf);
break;
}

capture_srcs = jack_slist_append( capture_srcs, src_new( 4-samplerate_quality, 1, NULL ) );
capture_ports = jack_slist_append (capture_ports, port);
}

port_flags = JackPortIsInput;

playback_ports = NULL;
for (chn = 0; chn < n_playback; chn++)
{
snprintf (buf, sizeof(buf) - 1, "playback_%u", chn+1);

port = jack_port_register (client, buf,
JACK_DEFAULT_AUDIO_TYPE,
port_flags, 0);

if (!port)
{
printf( "jacknet_client: cannot register port for %s", buf);
break;
}

playback_srcs = jack_slist_append( playback_srcs, src_new( 4-samplerate_quality, 1, NULL ) );
playback_ports = jack_slist_append (playback_ports, port);
}
}

/**
* This is the shutdown callback for this JACK application.
* It is called by JACK if the server ever shuts down or
* decides to disconnect the client.
*/

void jack_shutdown (void *arg) {

exit (1);
}

/**
* be user friendly.
* be user friendly.
* be user friendly.
*/

void printUsage() {
fprintf(stderr, "usage: alsa_out [options]\n"
"\n"
" -j <jack name> - client name\n"
" -d <alsa_device> \n"
" -c <channels> \n"
" -p <period_size> \n"
" -n <num_period> \n"
" -r <sample_rate> \n"
" -q <sample_rate quality [0..4]\n"
" -m <max_diff> \n"
" -t <target_delay> \n"
" -i turns on instrumentation\n"
" -v turns on printouts\n"
"\n");
}


/**
* the main function....
*/

void
sigterm_handler( int signal )
{
quit = 1;
}


int main (int argc, char *argv[]) {
char jack_name[30] = "alsa_out";
char alsa_device[30] = "hw:0";
int jack_opts = 0;
char *server_name = NULL;

extern char *optarg;
extern int optind, optopt;
int errflg=0;
int c;

while ((c = getopt(argc, argv, "ivj:r:c:p:n:d:q:m:t:f:F:C:Q:s:S:")) != -1) {
switch(c) {
case 'j':
strcpy(jack_name,optarg);
break;
case 'r':
sample_rate = atoi(optarg);
break;
case 'c':
num_channels = atoi(optarg);
break;
case 'p':
period_size = atoi(optarg);
break;
case 'n':
num_periods = atoi(optarg);
break;
case 'd':
strcpy(alsa_device,optarg);
break;
case 't':
target_delay = atoi(optarg);
break;
case 'q':
samplerate_quality = atoi(optarg);
break;
case 'm':
max_diff = atoi(optarg);
break;
case 'f':
catch_factor = atoi(optarg);
break;
case 'F':
catch_factor2 = atoi(optarg);
break;
case 'C':
pclamp = (double) atoi(optarg);
break;
case 'Q':
controlquant = (double) atoi(optarg);
break;
case 'v':
verbose = 1;
break;
case 'i':
instrument = 1;
break;
case 's':
smooth_size = atoi(optarg);
break;
case 'S':
server_name = optarg;
jack_opts |= JackServerName;
break;
case ':':
fprintf(stderr,
"Option -%c requires an operand\n", optopt);
errflg++;
break;
case '?':
fprintf(stderr,
"Unrecognized option: -%c\n", optopt);
errflg++;
}
}
if (errflg) {
printUsage();
exit(2);
}

if( (samplerate_quality < 0) || (samplerate_quality > 4) ) {
fprintf (stderr, "invalid samplerate quality\n");
return 1;
}
if ((client = jack_client_open (jack_name, jack_opts, NULL, server_name)) == 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 `freewheel()' whenever
freewheel mode changes.
*/

jack_set_freewheel_callback (client, freewheel, 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);

if (jack_set_latency_callback)
jack_set_latency_callback (client, latency_cb, 0);

// get jack sample_rate
jack_sample_rate = jack_get_sample_rate( client );

if( !sample_rate )
sample_rate = jack_sample_rate;

static_resample_factor = (double) sample_rate / (double) jack_sample_rate;
resample_lower_limit = static_resample_factor * 0.25;
resample_upper_limit = static_resample_factor * 4.0;
resample_mean = static_resample_factor;

offset_array = malloc( sizeof(double) * smooth_size );
if( offset_array == NULL ) {
fprintf( stderr, "no memory for offset_array !!!\n" );
exit(20);
}
window_array = malloc( sizeof(double) * smooth_size );
if( window_array == NULL ) {
fprintf( stderr, "no memory for window_array !!!\n" );
exit(20);
}
int i;
for( i=0; i<smooth_size; i++ ) {
offset_array[i] = 0.0;
window_array[i] = hann( (double) i / ((double) smooth_size - 1.0) );
}

jack_buffer_size = jack_get_buffer_size( client );
// Setup target delay and max_diff for the normal user, who does not play with them...
if( !target_delay )
target_delay = (num_periods*period_size / 2) - jack_buffer_size/2;

if( !max_diff )
max_diff = target_delay;

if( max_diff > target_delay ) {
fprintf( stderr, "target_delay (%d) can not be smaller than max_diff(%d)\n", target_delay, max_diff );
exit(20);
}
if( (target_delay+max_diff) > (num_periods*period_size) ) {
fprintf( stderr, "target_delay+max_diff (%d) can not be bigger than buffersize(%d)\n", target_delay+max_diff, num_periods*period_size );
exit(20);
}
// now open the alsa fd...
alsa_handle = open_audiofd( alsa_device, 0, sample_rate, num_channels, period_size, num_periods);
if( alsa_handle == 0 )
exit(20);

printf( "selected sample format: %s\n", formats[format].name );

// alloc input ports, which are blasted out to alsa...
alloc_ports( 0, num_channels );

outbuf = malloc( num_periods * period_size * formats[format].sample_size * num_channels );
resampbuf = malloc( num_periods * period_size * sizeof( float ) );
tmpbuf = malloc( 512 * formats[format].sample_size * num_channels );

if ((outbuf == NULL) || (resampbuf == NULL) || (tmpbuf == NULL))
{
fprintf( stderr, "no memory for buffers.\n" );
exit(20);
}


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

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

signal( SIGTERM, sigterm_handler );
signal( SIGINT, sigterm_handler );

if( verbose ) {
while(!quit) {
usleep(500000);
if( output_new_delay ) {
printf( "delay = %d\n", output_new_delay );
output_new_delay = 0;
}
printf( "res: %f, \tdiff = %f, \toffset = %f \n", output_resampling_factor, output_diff, output_offset );
}
} else if( instrument ) {
printf( "# n\tresamp\tdiff\toffseti\tintegral\n");
int n=0;
while(!quit) {
usleep(1000);
printf( "%d\t%f\t%f\t%f\t%f\n", n++, output_resampling_factor, output_diff, output_offset, output_integral );
}
} else {
while(!quit)
{
usleep(500000);
if( output_new_delay ) {
printf( "delay = %d\n", output_new_delay );
output_new_delay = 0;
}
}
}

jack_deactivate( client );
jack_client_close (client);
exit (0);
}

+ 0
- 124
tools/bufsize.c View File

@@ -1,124 +0,0 @@
/*
* bufsize.c -- change JACK buffer size.
*
* 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.
*/

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

char *package; /* program name */
jack_client_t *client;
jack_nframes_t nframes;
int just_print_bufsize=0;

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

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

void parse_arguments(int argc, char *argv[])
{
/* basename $0 */
package = strrchr(argv[0], '/');
if (package == 0)
package = argv[0];
else
package++;

if (argc==1) {
just_print_bufsize = 1;
return;
}
if (argc < 2) {
fprintf(stderr, "usage: %s <bufsize>\n", package);
exit(9);
}

if (strspn (argv[1], "0123456789") != strlen (argv[1])) {
fprintf(stderr, "usage: %s <bufsize>\n", package);
exit(8);
}

nframes = strtoul(argv[1], NULL, 0);
if (errno == ERANGE) {
fprintf(stderr, "%s: invalid buffer size: %s (range is 1-16384)\n",
package, argv[1]);
exit(2);
}
if (nframes < 1 || nframes > 16384) {
fprintf(stderr, "%s: invalid buffer size: %s (range is 1-16384)\n",
package, argv[1]);
exit(3);
}
}

void silent_function( const char *ignore )
{
}

int main(int argc, char *argv[])
{
int rc;
parse_arguments(argc, argv);

if (just_print_bufsize)
jack_set_info_function( silent_function );

/* become a JACK client */
if ((client = jack_client_open(package, JackNoStartServer, NULL)) == 0) {
fprintf(stderr, "JACK server not running?\n");
exit(1);
}

#ifndef WIN32
signal(SIGQUIT, signal_handler);
signal(SIGHUP, signal_handler);
#endif
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);

jack_on_shutdown(client, jack_shutdown, 0);

if (just_print_bufsize) {
fprintf(stdout, "%d\n", jack_get_buffer_size( client ) );
rc = 0;
}
else
{
rc = jack_set_buffer_size(client, nframes);
if (rc)
fprintf(stderr, "jack_set_buffer_size(): %s\n", strerror(rc));
}
jack_client_close(client);

return rc;
}

+ 0
- 248
tools/connect.c View File

@@ -1,248 +0,0 @@
/*
Copyright (C) 2002 Jeremy Hall

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>
#ifndef WIN32
#include <unistd.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <getopt.h>

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

#define TRUE 1
#define FALSE 0

volatile int done = 0;

void port_connect_callback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg)
{
done = 1;
}

void
show_version (char *my_name)
{
//fprintf (stderr, "%s: JACK Audio Connection Kit version " VERSION "\n", my_name);
}

void
show_usage (char *my_name)
{
show_version (my_name);
fprintf (stderr, "\nusage: %s [options] port1 port2\n", my_name);
fprintf (stderr, "Connects two JACK ports together.\n\n");
fprintf (stderr, " -s, --server <name> Connect to the jack server named <name>\n");
fprintf (stderr, " -v, --version Output version information and exit\n");
fprintf (stderr, " -h, --help Display this help message\n\n");
fprintf (stderr, "For more information see http://jackaudio.org/\n");
}

int
main (int argc, char *argv[])
{
jack_client_t *client;
jack_status_t status;
char *server_name = NULL;
int c;
int option_index;
jack_options_t options = JackNoStartServer;
char *my_name = strrchr(argv[0], '/');
jack_port_t *src_port = 0;
jack_port_t *dst_port = 0;
jack_port_t *port1 = 0;
jack_port_t *port2 = 0;
char portA[300];
char portB[300];
int use_uuid=0;
int connecting, disconnecting;
int port1_flags, port2_flags;
int rc = 1;

struct option long_options[] = {
{ "server", 1, 0, 's' },
{ "help", 0, 0, 'h' },
{ "version", 0, 0, 'v' },
{ "uuid", 0, 0, 'u' },
{ 0, 0, 0, 0 }
};

while ((c = getopt_long (argc, argv, "s:hvu", long_options, &option_index)) >= 0) {
switch (c) {
case 's':
server_name = (char *) malloc (sizeof (char) * (strlen(optarg) + 1));
strcpy (server_name, optarg);
options |= JackServerName;
break;
case 'u':
use_uuid = 1;
break;
case 'h':
show_usage (my_name);
return 1;
break;
case 'v':
show_version (my_name);
return 1;
break;
default:
show_usage (my_name);
return 1;
break;
}
}

connecting = disconnecting = FALSE;
if (my_name == 0) {
my_name = argv[0];
} else {
my_name ++;
}

if (strstr(my_name, "disconnect")) {
disconnecting = 1;
} else if (strstr(my_name, "connect")) {
connecting = 1;
} else {
fprintf(stderr, "ERROR! client should be called jack_connect or jack_disconnect. client is called %s\n", my_name);
return 1;
}

if (argc < 3) {
show_usage(my_name);
return 1;
}

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

if ((client = jack_client_open (my_name, options, &status, server_name)) == 0) {
fprintf (stderr, "jack server not running?\n");
return 1;
}

jack_set_port_connect_callback(client, port_connect_callback, NULL);

/* find the two ports */

if( use_uuid ) {
char *tmpname;
char *clientname;
char *portname;
tmpname = strdup( argv[argc-1] );
portname = strchr( tmpname, ':' );
portname[0] = '\0';
portname+=1;
clientname = jack_get_client_name_by_uuid( client, tmpname );
if( clientname ) {

snprintf( portA, sizeof(portA), "%s:%s", clientname, portname );
jack_free( clientname );
} else {
snprintf( portA, sizeof(portA), "%s", argv[argc-1] );
}
free( tmpname );

tmpname = strdup( argv[argc-2] );
portname = strchr( tmpname, ':' );
portname[0] = '\0';
portname+=1;
clientname = jack_get_client_name_by_uuid( client, tmpname );
if( clientname ) {
snprintf( portB, sizeof(portB), "%s:%s", clientname, portname );
jack_free( clientname );
} else {
snprintf( portB, sizeof(portB), "%s", argv[argc-2] );
}

free( tmpname );

} else {
snprintf( portA, sizeof(portA), "%s", argv[argc-1] );
snprintf( portB, sizeof(portB), "%s", argv[argc-2] );
}
if ((port1 = jack_port_by_name(client, portA)) == 0) {
fprintf (stderr, "ERROR %s not a valid port\n", portA);
goto exit;
}
if ((port2 = jack_port_by_name(client, portB)) == 0) {
fprintf (stderr, "ERROR %s not a valid port\n", portB);
goto exit;
}

port1_flags = jack_port_flags (port1);
port2_flags = jack_port_flags (port2);

if (port1_flags & JackPortIsInput) {
if (port2_flags & JackPortIsOutput) {
src_port = port2;
dst_port = port1;
}
} else {
if (port2_flags & JackPortIsInput) {
src_port = port1;
dst_port = port2;
}
}

if (!src_port || !dst_port) {
fprintf (stderr, "arguments must include 1 input port and 1 output port\n");
goto exit;
}

/* tell the JACK server that we are ready to roll */
if (jack_activate (client)) {
fprintf (stderr, "cannot activate client");
goto exit;
}

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

if (connecting) {
if (jack_connect(client, jack_port_name(src_port), jack_port_name(dst_port))) {
fprintf (stderr, "cannot connect client, already connected?\n");
goto exit;
}
}
if (disconnecting) {
if (jack_disconnect(client, jack_port_name(src_port), jack_port_name(dst_port))) {
fprintf (stderr, "cannot disconnect client, already disconnected?\n");
goto exit;
}
}

// Wait for connection/disconnection to be effective
while(!done) {
#ifdef WIN32
Sleep(10);
#else
usleep(10000);
#endif
}

/* everything was ok, so setting exitcode to 0 */
rc = 0;

exit:
jack_client_close (client);
exit (rc);
}

+ 0
- 164
tools/evmon.c View File

@@ -1,164 +0,0 @@
/*
Copyright (C) 2007 Paul Davis

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>
#ifndef WIN32
#include <unistd.h>
#endif
#include <string.h>
#include <signal.h>
#include <stdlib.h>

#include <jack/jack.h>
#include <jack/metadata.h>
#include <jack/uuid.h>

jack_client_t *client;

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

static void
port_rename_callback (jack_port_id_t port, const char* old_name, const char* new_name, void* arg)
{
printf ("Port %d renamed from %s to %s\n", port, old_name, new_name);
}

static void
port_callback (jack_port_id_t port, int yn, void* arg)
{
printf ("Port %d %s\n", port, (yn ? "registered" : "unregistered"));
}

static void
connect_callback (jack_port_id_t a, jack_port_id_t b, int yn, void* arg)
{
printf ("Ports %d and %d %s\n", a, b, (yn ? "connected" : "disconnected"));
}

static void
client_callback (const char* client, int yn, void* arg)
{
printf ("Client %s %s\n", client, (yn ? "registered" : "unregistered"));
}

static int
graph_callback (void* arg)
{
printf ("Graph reordered\n");
return 0;
}

static void
propchange (jack_uuid_t subject, const char* key, jack_property_change_t change, void* arg)
{
char buf[JACK_UUID_STRING_SIZE];
const char* action = "";

switch (change) {
case PropertyCreated:
action = "created";
break;

case PropertyChanged:
action = "changed";
break;

case PropertyDeleted:
action = "deleted";
break;
}

if (jack_uuid_empty (subject)) {
printf ("All properties changed!\n");
} else {
jack_uuid_unparse (subject, buf);
if (key) {
printf ("key [%s] for %s %s\n", key, buf, action);
} else {
printf ("all keys for %s %s\n", buf, action);
}
}
}

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

if ((client = jack_client_open ("event-monitor", options, &status, NULL)) == 0) {
fprintf (stderr, "jack_client_open() failed, "
"status = 0x%2.0x\n", status);
if (status & JackServerFailed) {
fprintf (stderr, "Unable to connect to JACK server\n");
}
return 1;
}
if (jack_set_port_registration_callback (client, port_callback, NULL)) {
fprintf (stderr, "cannot set port registration callback\n");
return 1;
}
if (jack_set_port_rename_callback (client, port_rename_callback, NULL)) {
fprintf (stderr, "cannot set port registration callback\n");
return 1;
}
if (jack_set_port_connect_callback (client, connect_callback, NULL)) {
fprintf (stderr, "cannot set port connect callback\n");
return 1;
}
if (jack_set_client_registration_callback (client, client_callback, NULL)) {
fprintf (stderr, "cannot set client registration callback\n");
return 1;
}
if (jack_set_graph_order_callback (client, graph_callback, NULL)) {
fprintf (stderr, "cannot set graph order registration callback\n");
return 1;
}
if (jack_set_property_change_callback (client, propchange, NULL)) {
fprintf (stderr, "cannot set property change callback\n");
return 1;
}
if (jack_activate (client)) {
fprintf (stderr, "cannot activate client");
return 1;
}

#ifndef WIN32
signal(SIGINT, signal_handler);
signal(SIGQUIT, signal_handler);
signal(SIGHUP, signal_handler);
#endif
signal(SIGABRT, signal_handler);
signal(SIGTERM, signal_handler);

#ifdef WIN32
Sleep(INFINITE);
#else
sleep (-1);
#endif
exit (0);
}


+ 0
- 87
tools/freewheel.c View File

@@ -1,87 +0,0 @@
/*
* freewheel - start/stop JACK "freewheeling" mode
*
* Copyright (C) 2003 Paul Davis.
*
* 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 <signal.h>
#include <stdlib.h>
#include <string.h>
#include <jack/jack.h>
#include <jack/transport.h>

char *package; /* program name */
jack_client_t *client;
int onoff;

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

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

static void parse_arguments(int argc, char *argv[])
{
if (argc < 2) {
fprintf(stderr, "usage: %s y|n\n", package);
exit(9);
}

if (argv[1][0] == 'y' || argv[1][0] == 'Y' || argv[1][0] == '1') {
onoff = 1;
} else {
onoff = 0;
}
}

int
main (int argc, char *argv[])
{
parse_arguments (argc, argv);

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

#ifndef WIN32
signal (SIGQUIT, signal_handler);
signal (SIGHUP, signal_handler);
#endif
signal (SIGTERM, signal_handler);
signal (SIGINT, signal_handler);

jack_on_shutdown (client, jack_shutdown, 0);

if (jack_set_freewheel (client, onoff)) {
fprintf (stderr, "failed to reset freewheel mode\n");
}

jack_client_close(client);
return 0;
}

+ 0
- 246
tools/ipload.c View File

@@ -1,246 +0,0 @@
/*
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 <stdlib.h>
#include <string.h>
#include <signal.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <getopt.h>
#include <jack/jack.h>
#include <jack/intclient.h>

jack_client_t *client;
jack_intclient_t intclient;
char *client_name;
char *intclient_name;
char *load_name;
char *load_init = "";
char *server_name = NULL;
int autoclose_opt = 0;
int wait_opt = 0;
volatile int idling = 1;

static void
signal_handler (int sig)
{
/* do nothing if internal client closed itself */
if (idling == 0)
return;

jack_status_t status;

fprintf (stderr, "signal received, unloading...");
status = jack_internal_client_unload (client, intclient);
if (status & JackFailure)
fprintf (stderr, "(failed), status = 0x%2.0x\n", status);
else
fprintf (stderr, "(succeeded)\n");
if (autoclose_opt)
jack_deactivate(client);
jack_client_close (client);
exit (0);
}

static void
registration_callback (const char *name, int reg, void *arg)
{
if (reg || strcmp(intclient_name, name))
return;

/* this will stop the wait loop and thus close this application. */
idling = 0;
return;

/* unused */
(void)arg;
}

static void
show_usage ()
{
fprintf (stderr, "usage: %s [ options ] client-name [ load-name "
"[ init-string]]\n\noptions:\n", client_name);
fprintf (stderr,
"\t-h, --help \t\t print help message\n"
"\t-a, --autoclose\t automatically close when intclient is unloaded\n"
"\t-i, --init string\t initialize string\n"
"\t-s, --server name\t select JACK server\n"
"\t-w, --wait \t\t wait for signal, then unload\n"
"\n"
);
}

static int
parse_args (int argc, char *argv[])
{
int c;
int option_index = 0;
char *short_options = "hai:s:w";
struct option long_options[] = {
{ "help", 0, 0, 'h' },
{ "autoclose", 0, 0, 'a' },
{ "init", required_argument, 0, 'i' },
{ "server", required_argument, 0, 's' },
{ "wait", 0, 0, 'w' },
{ 0, 0, 0, 0 }
};

client_name = strrchr(argv[0], '/');
if (client_name == NULL) {
client_name = argv[0];
} else {
client_name++;
}

while ((c = getopt_long (argc, argv, short_options, long_options,
&option_index)) >= 0) {
switch (c) {
case 'a':
autoclose_opt = 1;
break;
case 'i':
load_init = optarg;
break;
case 's':
server_name = optarg;
break;
case 'w':
wait_opt = 1;
break;
case 'h':
default:
show_usage ();
return 1;
}
}

/* autoclose makes no sense without wait */
if (autoclose_opt && ! wait_opt)
autoclose_opt = 0;

if (optind == argc) { /* no positional args? */
show_usage ();
return 1;
}
if (optind < argc)
load_name = intclient_name = argv[optind++];

if (optind < argc)
load_name = argv[optind++];

if (optind < argc)
load_init = argv[optind++];

//fprintf (stderr, "client-name = `%s', load-name = `%s', "
// "load-init = `%s', wait = %d\n",
// intclient_name, load_name, load_init, wait_opt);

return 0; /* args OK */
}

int
main (int argc, char *argv[])
{
jack_status_t status;
char* name;

/* parse and validate command arguments */
if (parse_args (argc, argv))
exit (1); /* invalid command line */

/* first, become a JACK client */
client = jack_client_open (client_name, JackServerName,
&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);
}

/* then, load the internal client */
intclient = jack_internal_client_load (client, intclient_name,
(JackLoadName|JackLoadInit),
&status, load_name, load_init);
if (status & JackFailure) {
fprintf (stderr, "could not load %s, intclient = %d status = 0x%2.0x\n",
load_name, (int)intclient, status);
return 2;
}
if (status & JackNameNotUnique) {
intclient_name =
jack_get_internal_client_name (client, intclient);
fprintf (stderr, "unique internal client name `%s' assigned\n",
intclient_name);
}

fprintf (stdout, "%s is running.\n", load_name);

name = jack_get_internal_client_name(client, intclient);
if (name) {
printf("client name = %s\n", name);
free(name);
}
fflush(stdout);

if (autoclose_opt) {
jack_set_client_registration_callback(client, registration_callback, NULL);
jack_activate(client);
}

if (wait_opt) {
/* define a signal handler to unload the client, then
* wait for it to exit */
#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 (idling) {
#ifdef WIN32
Sleep(1000);
#else
sleep (1);
#endif
}
}

if (autoclose_opt) {
jack_deactivate(client);
}

jack_client_close(client);
return 0;
}


+ 0
- 93
tools/ipunload.c View File

@@ -1,93 +0,0 @@
/*
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 <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <jack/jack.h>
#include <jack/intclient.h>

int
main (int argc, char *argv[])
{
char *my_name;
char *client_name;
jack_client_t *client;
jack_status_t status;
jack_intclient_t intclient;

/* validate args */
if ((argc < 2) || (argc > 3)) {
fprintf (stderr, "usage: %s client-name [ server-name ]]\n",
argv[0]);
return 1;
}

/* use `basename $0` for my own client name */
my_name = strrchr(argv[0], '/');
if (my_name == 0) {
my_name = argv[0];
} else {
my_name++;
}

/* first, become a JACK client */
if (argc > 2) {
client = jack_client_open (my_name,
(JackServerName|JackNoStartServer),
&status, argv[2]);
} else {
client = jack_client_open (my_name, JackNoStartServer, &status);
}

if (client == NULL) {
if (status & JackServerFailed) {
fprintf (stderr, "JACK server not running.\n");
} else {
fprintf (stderr, "JACK open failed, "
"status = 0x%2.0x\n", status);
}
exit (1);
}

/* then, get the internal client handle */
client_name = argv[1];
intclient = jack_internal_client_handle (client, client_name, &status);
if (status & JackFailure) {
fprintf (stderr, "client %s not found.\n", client_name);
exit (2);
}

/* now, unload the internal client */
status = jack_internal_client_unload (client, intclient);
if (status & JackFailure) {
if (status & JackNoSuchClient) {
fprintf (stderr, "client %s is gone.\n",
client_name);
} else {
fprintf (stderr, "could not unload %s, "
"returns 0x%2.0x\n", client_name, status);
}
exit (3);
} else {
fprintf (stdout, "%s unloaded.\n", client_name);
}

jack_client_close(client);
return 0;
}



+ 0
- 291
tools/lsp.c View File

@@ -1,291 +0,0 @@
/*
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 <stdlib.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <string.h>
#include <getopt.h>
#include <inttypes.h>

#include <jack/jack.h>
#include <jack/session.h>
#include <jack/uuid.h>

char * my_name;

static void
show_version (void)
{
//fprintf (stderr, "%s: JACK Audio Connection Kit version " VERSION "\n", my_name);
}

static void
printf_name2uuid (jack_client_t* client, const char* pname)
{
char *port_component = strchr( pname, ':' );
size_t csize = port_component - pname + 1;
char client_component[csize];
snprintf(client_component, csize, "%s", pname);

char *uuid = jack_get_uuid_for_client_name(client, client_component);
if (uuid) {
printf("%s%s\n", uuid, port_component );
} else {
printf("%s\n",pname);
}
jack_free(uuid);
}

static void
show_usage (void)
{
show_version ();
fprintf (stderr, "\nUsage: %s [options] [filter string]\n", my_name);
fprintf (stderr, "List active Jack ports, and optionally display extra information.\n");
fprintf (stderr, "Optionally filter ports which match ALL strings provided after any options.\n\n");
fprintf (stderr, "Display options:\n");
fprintf (stderr, " -s, --server <name> Connect to the jack server named <name>\n");
fprintf (stderr, " -A, --aliases List aliases for each port\n");
fprintf (stderr, " -c, --connections List connections to/from each port\n");
fprintf (stderr, " -l, --port-latency Display per-port latency in frames at each port\n");
fprintf (stderr, " -L, --total-latency Display total latency in frames at each port\n");
fprintf (stderr, " -p, --properties Display port properties. Output may include:\n"
" input|output, can-monitor, physical, terminal\n\n");
fprintf (stderr, " -t, --type Display port type\n");
fprintf (stderr, " -u, --uuid Display uuid instead of client name (if available)\n");
fprintf (stderr, " -U, --port-uuid Display port uuid\n");
fprintf (stderr, " -h, --help Display this help message\n");
fprintf (stderr, " --version Output version information and exit\n\n");
fprintf (stderr, "For more information see http://jackaudio.org/\n");
}

int
main (int argc, char *argv[])
{
jack_client_t *client;
jack_status_t status;
jack_options_t options = JackNoStartServer;
const char **ports, **connections;
unsigned int i, j, k;
int skip_port;
int show_aliases = 0;
int show_con = 0;
int show_port_latency = 0;
int show_total_latency = 0;
int show_properties = 0;
int show_type = 0;
int show_uuid = 0;
int show_port_uuid = 0;
int c;
int option_index;
char* aliases[2];
char *server_name = NULL;

struct option long_options[] = {
{ "server", 1, 0, 's' },
{ "aliases", 0, 0, 'A' },
{ "connections", 0, 0, 'c' },
{ "port-latency", 0, 0, 'l' },
{ "total-latency", 0, 0, 'L' },
{ "properties", 0, 0, 'p' },
{ "type", 0, 0, 't' },
{ "uuid", 0, 0, 'u' },
{ "port-uuid", 0, 0, 'U' },
{ "help", 0, 0, 'h' },
{ "version", 0, 0, 'v' },
{ 0, 0, 0, 0 }
};

my_name = strrchr(argv[0], '/');
if (my_name == 0) {
my_name = argv[0];
} else {
my_name ++;
}

while ((c = getopt_long (argc, argv, "s:AclLphvtuU", long_options, &option_index)) >= 0) {
switch (c) {
case 's':
server_name = (char *) malloc (sizeof (char) * strlen(optarg));
strcpy (server_name, optarg);
options |= JackServerName;
break;
case 'A':
aliases[0] = (char *) malloc (jack_port_name_size());
aliases[1] = (char *) malloc (jack_port_name_size());
show_aliases = 1;
break;
case 'c':
show_con = 1;
break;
case 'l':
show_port_latency = 1;
break;
case 'L':
show_total_latency = 1;
break;
case 'p':
show_properties = 1;
break;
case 't':
show_type = 1;
break;
case 'u':
show_uuid = 1;
break;
case 'U':
show_port_uuid = 1;
break;
case 'h':
show_usage ();
return 1;
break;
case 'v':
show_version ();
return 1;
break;
default:
show_usage ();
return 1;
break;
}
}

/* Open a client connection to the JACK server. Starting a
* new server only to list its ports seems pointless, so we
* specify JackNoStartServer. */
if ((client = jack_client_open ("lsp", options, &status, server_name)) == 0) {
fprintf (stderr, "Error: cannot connect to JACK, ");
if (status & JackServerFailed) {
fprintf (stderr, "server is not running.\n");
} else {
fprintf (stderr, "jack_client_open() failed, status = 0x%2.0x\n", status);
}
return 1;
}

ports = jack_get_ports (client, NULL, NULL, 0);

for (i = 0; ports && ports[i]; ++i) {
// skip over any that don't match ALL of the strings presented at command line
skip_port = 0;
for (k = optind; k < argc; k++){
if (strstr(ports[i], argv[k]) == NULL ){
skip_port = 1;
}
}
if (skip_port) continue;

if (show_uuid) {
printf_name2uuid(client, ports[i]);
} else {
printf ("%s\n", ports[i]);
}

jack_port_t *port = jack_port_by_name (client, ports[i]);

if (show_port_uuid) {
char buf[JACK_UUID_STRING_SIZE];
jack_uuid_t uuid = jack_port_uuid (port);
jack_uuid_unparse (uuid, buf);
printf (" uuid: %s\n", buf);
}

if (show_aliases) {
int cnt;
int i;

cnt = jack_port_get_aliases (port, aliases);
for (i = 0; i < cnt; ++i) {
printf (" %s\n", aliases[i]);
}
}

if (show_con) {
if ((connections = jack_port_get_all_connections (client, jack_port_by_name(client, ports[i]))) != 0) {
for (j = 0; connections[j]; j++) {
printf(" ");
if (show_uuid) {
printf_name2uuid(client, connections[j]);
} else {
printf("%s\n", connections[j]);
}
}
jack_free (connections);
}
}
if (show_port_latency) {
if (port) {
jack_latency_range_t range;

jack_port_get_latency_range (port, JackPlaybackLatency, &range);
printf (" port playback latency = [ %" PRIu32 " %" PRIu32 " ] frames\n",
range.min, range.max);

jack_port_get_latency_range (port, JackCaptureLatency, &range);
printf (" port capture latency = [ %" PRIu32 " %" PRIu32 " ] frames\n",
range.min, range.max);
}
}
if (show_total_latency) {
if (port) {
printf (" total latency = %d frames\n",
jack_port_get_total_latency (client, port));
}
}
if (show_properties) {
if (port) {
int flags = jack_port_flags (port);
printf (" properties: ");
if (flags & JackPortIsInput) {
fputs ("input,", stdout);
}
if (flags & JackPortIsOutput) {
fputs ("output,", stdout);
}
if (flags & JackPortCanMonitor) {
fputs ("can-monitor,", stdout);
}
if (flags & JackPortIsPhysical) {
fputs ("physical,", stdout);
}
if (flags & JackPortIsTerminal) {
fputs ("terminal,", stdout);
}
putc ('\n', stdout);
}
}
if (show_type) {
if (port) {
putc ('\t', stdout);
fputs (jack_port_type (port), stdout);
putc ('\n', stdout);
}
}
}

if (show_aliases) {
free(aliases[0]);
free(aliases[1]);
}
if (ports)
jack_free (ports);
jack_client_close (client);
exit (0);
}

+ 0
- 238
tools/midi_dump.c View File

@@ -1,238 +0,0 @@
// gcc -o jack_midi_dump -Wall midi_dump.c -ljack -pthread

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <inttypes.h>
#include <jack/jack.h>
#include <jack/midiport.h>
#include <jack/ringbuffer.h>

#ifdef __MINGW32__
#include <pthread.h>
#endif

#ifndef WIN32
#include <signal.h>
#include <pthread.h>
#include <sys/mman.h>
#endif

static jack_port_t* port;
static jack_ringbuffer_t *rb = NULL;
static pthread_mutex_t msg_thread_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t data_ready = PTHREAD_COND_INITIALIZER;

static int keeprunning = 1;
static uint64_t monotonic_cnt = 0;

#define RBSIZE 100
#define MSG_BUFFER_SIZE 4096

typedef struct {
uint8_t buffer[MSG_BUFFER_SIZE];
uint32_t size;
uint32_t tme_rel;
uint64_t tme_mon;
} midimsg;

static void
describe (midimsg* event)
{
if (event->size == 0) {
return;
}

uint8_t type = event->buffer[0] & 0xf0;
uint8_t channel = event->buffer[0] & 0xf;

switch (type) {
case 0x90:
assert (event->size == 3);
printf (" note on (channel %2d): pitch %3d, velocity %3d", channel, event->buffer[1], event->buffer[2]);
break;
case 0x80:
assert (event->size == 3);
printf (" note off (channel %2d): pitch %3d, velocity %3d", channel, event->buffer[1], event->buffer[2]);
break;
case 0xb0:
assert (event->size == 3);
printf (" control change (channel %2d): controller %3d, value %3d", channel, event->buffer[1], event->buffer[2]);
break;
default:
break;
}
}

int
process (jack_nframes_t frames, void* arg)
{
void* buffer;
jack_nframes_t N;
jack_nframes_t i;

buffer = jack_port_get_buffer (port, frames);
assert (buffer);

N = jack_midi_get_event_count (buffer);
for (i = 0; i < N; ++i) {
jack_midi_event_t event;
int r;
r = jack_midi_event_get (&event, buffer, i);

if (r != 0) {continue;}

if (event.size > MSG_BUFFER_SIZE) {
fprintf(stderr, "Error: MIDI message was too large, skipping event. Max. allowed size: %d bytes\n", MSG_BUFFER_SIZE);
}
else if (jack_ringbuffer_write_space (rb) >= sizeof(midimsg)) {
midimsg m;
m.tme_mon = monotonic_cnt;
m.tme_rel = event.time;
m.size = event.size;
memcpy (m.buffer, event.buffer, event.size);
jack_ringbuffer_write (rb, (void *) &m, sizeof(midimsg));
}
else {
fprintf (stderr, "Error: ringbuffer was full, skipping event.\n");
}
}

monotonic_cnt += frames;

if (pthread_mutex_trylock (&msg_thread_lock) == 0) {
pthread_cond_signal (&data_ready);
pthread_mutex_unlock (&msg_thread_lock);
}

return 0;
}

static void wearedone(int sig) {
fprintf(stderr, "Shutting down\n");
keeprunning = 0;
/* main loop might be blocked by data_ready when jack server dies. */
if (pthread_mutex_trylock (&msg_thread_lock) == 0) {
pthread_cond_signal (&data_ready);
pthread_mutex_unlock (&msg_thread_lock);
}
}

static void usage (int status) {
printf ("jack_midi_dump - JACK MIDI Monitor.\n\n");
printf ("Usage: jack_midi_dump [ OPTIONS ] [CLIENT-NAME]\n\n");
printf ("Options:\n\
-a use absolute timestamps relative to application start\n\
-h display this help and exit\n\
-r use relative timestamps to previous MIDI event\n\
\n");
printf ("\n\
This tool listens for MIDI events on a JACK MIDI port and prints\n\
the message to stdout.\n\
\n\
If no client name is given it defaults to 'midi-monitor'.\n\
\n\
See also: jackd(1)\n\
\n");
exit (status);
}

int
main (int argc, char* argv[])
{
jack_client_t* client;
char const default_name[] = "midi-monitor";
char const * client_name;
int time_format = 0;
int r;

int cn = 1;

if (argc > 1) {
if (!strcmp (argv[1], "-a")) { time_format = 1; cn = 2; }
else if (!strcmp (argv[1], "-r")) { time_format = 2; cn = 2; }
else if (!strcmp (argv[1], "-h")) { usage (EXIT_SUCCESS); }
else if (argv[1][0] == '-') { usage (EXIT_FAILURE); }
}

if (argc > cn) {
client_name = argv[cn];
} else {
client_name = default_name;
}

client = jack_client_open (client_name, JackNullOption, NULL);
if (client == NULL) {
fprintf (stderr, "Could not create JACK client.\n");
exit (EXIT_FAILURE);
}

rb = jack_ringbuffer_create (RBSIZE * sizeof(midimsg));

jack_set_process_callback (client, process, 0);

port = jack_port_register (client, "input", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
if (port == NULL) {
fprintf (stderr, "Could not register port.\n");
exit (EXIT_FAILURE);
}

#ifndef WIN32
if (mlockall (MCL_CURRENT | MCL_FUTURE)) {
fprintf (stderr, "Warning: Can not lock memory.\n");
}
#endif

r = jack_activate (client);
if (r != 0) {
fprintf (stderr, "Could not activate client.\n");
exit (EXIT_FAILURE);
}

#ifndef WIN32
signal(SIGHUP, wearedone);
signal(SIGINT, wearedone);
#endif

pthread_mutex_lock (&msg_thread_lock);

uint64_t prev_event = 0;
while (keeprunning) {
const int mqlen = jack_ringbuffer_read_space (rb) / sizeof(midimsg);
int i;
for (i=0; i < mqlen; ++i) {
size_t j;
midimsg m;
jack_ringbuffer_read(rb, (char*) &m, sizeof(midimsg));

switch(time_format) {
case 1:
printf ("%7"PRId64":", m.tme_rel + m.tme_mon);
break;
case 2:
printf ("%+6"PRId64":", m.tme_rel + m.tme_mon - prev_event);
break;
default:
printf ("%4d:", m.tme_rel);
break;
}
for (j = 0; j < m.size && j < sizeof(m.buffer); ++j) {
printf (" %02x", m.buffer[j]);
}

describe (&m);
printf("\n");
prev_event = m.tme_rel + m.tme_mon;
}
fflush (stdout);
pthread_cond_wait (&data_ready, &msg_thread_lock);
}
pthread_mutex_unlock (&msg_thread_lock);

jack_deactivate (client);
jack_client_close (client);
jack_ringbuffer_free (rb);

return 0;
}

+ 0
- 66
tools/monitor_client.c View File

@@ -1,66 +0,0 @@
/*
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 <unistd.h>
#include <stdlib.h>
#include <string.h>

#include <jack/jack.h>

#define TRUE 1
#define FALSE 0

int
main (int argc, char *argv[])
{
jack_client_t *client;
char *my_name = strrchr(argv[0], '/');

if (my_name == 0) {
my_name = argv[0];
} else {
my_name ++;
}

if (argc != 2) {
fprintf (stderr, "Usage: %s client\n", my_name);
return 1;
}

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

if (jack_port_request_monitor_by_name (client, argv[1], TRUE)) {
fprintf (stderr, "could not enable monitoring for %s\n", argv[1]);
jack_client_close (client);
return 1;
}

#ifdef WIN32
Sleep (30*1000);
#else
sleep (30);
#endif
if (jack_port_request_monitor_by_name (client, argv[1], FALSE)) {
fprintf (stderr, "could not disable monitoring for %s\n", argv[1]);
}
jack_client_close (client);
exit (0);
}


+ 0
- 802
tools/netsource.c View File

@@ -1,802 +0,0 @@
/*
NetJack Client

Copyright (C) 2008 Marc-Olivier Barre <marco@marcochapeau.org>
Copyright (C) 2008 Pieter Palmers <pieterpalmers@users.sourceforge.net>
Copyright (C) 2006 Torben Hohn <torbenh@gmx.de>

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.

*/

/** @file netsource.c
*
* @brief This client connects a remote slave JACK to a local JACK server assumed to be the master
*/


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

#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif

#ifdef WIN32
#include <winsock2.h>
#define socklen_t int
#include <malloc.h>
#else
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#endif

/* These two required by FreeBSD. */
#include <sys/types.h>

#include <jack/jack.h>

#include <netjack_packet.h>
#if HAVE_SAMPLERATE
#include <samplerate.h>
#endif

#if HAVE_CELT
#include <celt/celt.h>
#endif

#ifndef CUSTOM_MODES
#define CUSTOM_MODES // for opus_custom_decoder_init
#endif

#if HAVE_OPUS
#include <opus/opus.h>
#include <opus/opus_custom.h>
#endif

#include <math.h>

JSList *capture_ports = NULL;
JSList *capture_srcs = NULL;
int capture_channels = 0;
int capture_channels_audio = 2;
int capture_channels_midi = 1;
JSList *playback_ports = NULL;
JSList *playback_srcs = NULL;
int playback_channels = 0;
int playback_channels_audio = 2;
int playback_channels_midi = 1;
int dont_htonl_floats = 0;

int latency = 5;
jack_nframes_t factor = 1;
int bitdepth = 0;
int mtu = 1400;
int reply_port = 0;
int bind_port = 0;
int redundancy = 1;
jack_client_t *client;
packet_cache * packcache = 0;

int state_connected = 0;
int state_latency = 0;
int state_netxruns = 0;
int state_currentframe = 0;
int state_recv_packet_queue_time = 0;

int quit = 0;


int outsockfd;
int insockfd;
#ifdef WIN32
struct sockaddr_in destaddr;
struct sockaddr_in bindaddr;
#else
struct sockaddr destaddr;
struct sockaddr bindaddr;
#endif

int sync_state;
jack_transport_state_t last_transport_state;

int framecnt = 0;

int cont_miss = 0;

int freewheeling = 0;

/**
* This Function allocates all the I/O Ports which are added the lists.
*/
void
alloc_ports (int n_capture_audio, int n_playback_audio, int n_capture_midi, int n_playback_midi)
{

int port_flags = JackPortIsOutput;
int chn;
jack_port_t *port;
char buf[32];

capture_ports = NULL;
/* Allocate audio capture channels */
for (chn = 0; chn < n_capture_audio; chn++) {
snprintf (buf, sizeof (buf) - 1, "capture_%u", chn + 1);
port = jack_port_register (client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0);
if (!port) {
printf( "jack_netsource: cannot register %s port\n", buf);
break;
}
if (bitdepth == 1000) {
#if HAVE_CELT
#if HAVE_CELT_API_0_11
CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate( client ), jack_get_buffer_size(client), NULL );
capture_srcs = jack_slist_append(capture_srcs, celt_decoder_create_custom( celt_mode, 1, NULL ) );
#elif HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8
CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate( client ), jack_get_buffer_size(client), NULL );
capture_srcs = jack_slist_append(capture_srcs, celt_decoder_create( celt_mode, 1, NULL ) );
#else
CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate( client ), 1, jack_get_buffer_size(client), NULL );
capture_srcs = jack_slist_append(capture_srcs, celt_decoder_create( celt_mode ) );
#endif
#endif
} else if (bitdepth == 999) {
#if HAVE_OPUS
int err;
OpusCustomMode *opus_mode = opus_custom_mode_create(jack_get_sample_rate( client ), jack_get_buffer_size(client), &err);
if (err != OPUS_OK) { printf("OPUS MODE FAILED\n"); }
OpusCustomDecoder *decoder = opus_custom_decoder_create(opus_mode, 1, &err);
if (err != OPUS_OK) { printf("OPUS DECODER FAILED\n"); }
opus_custom_decoder_init(decoder, opus_mode, 1);
capture_srcs = jack_slist_append(capture_srcs, decoder);
#endif
} else {
#if HAVE_SAMPLERATE
capture_srcs = jack_slist_append (capture_srcs, src_new (SRC_LINEAR, 1, NULL));
#endif
}
capture_ports = jack_slist_append (capture_ports, port);
}

/* Allocate midi capture channels */
for (chn = n_capture_audio; chn < n_capture_midi + n_capture_audio; chn++) {
snprintf (buf, sizeof (buf) - 1, "capture_%u", chn + 1);
port = jack_port_register (client, buf, JACK_DEFAULT_MIDI_TYPE, port_flags, 0);
if (!port) {
printf ("jack_netsource: cannot register %s port\n", buf);
break;
}
capture_ports = jack_slist_append(capture_ports, port);
}

/* Allocate audio playback channels */
port_flags = JackPortIsInput;
playback_ports = NULL;
for (chn = 0; chn < n_playback_audio; chn++) {
snprintf (buf, sizeof (buf) - 1, "playback_%u", chn + 1);
port = jack_port_register (client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0);
if (!port) {
printf ("jack_netsource: cannot register %s port\n", buf);
break;
}
if( bitdepth == 1000 ) {
#if HAVE_CELT
#if HAVE_CELT_API_0_11
CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate (client), jack_get_buffer_size(client), NULL );
playback_srcs = jack_slist_append(playback_srcs, celt_encoder_create_custom( celt_mode, 1, NULL ) );
#elif HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8
CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate (client), jack_get_buffer_size(client), NULL );
playback_srcs = jack_slist_append(playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) );
#else
CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate (client), 1, jack_get_buffer_size(client), NULL );
playback_srcs = jack_slist_append(playback_srcs, celt_encoder_create( celt_mode ) );
#endif
#endif
} else if( bitdepth == 999 ) {
#if HAVE_OPUS
const int kbps = factor;
printf("new opus encoder %d kbps\n", kbps);
int err;
OpusCustomMode *opus_mode = opus_custom_mode_create(jack_get_sample_rate (client), jack_get_buffer_size(client), &err ); // XXX free me
if (err != OPUS_OK) { printf("OPUS MODE FAILED\n"); }
OpusCustomEncoder *oe = opus_custom_encoder_create( opus_mode, 1, &err );
if (err != OPUS_OK) { printf("OPUS ENCODER FAILED\n"); }
opus_custom_encoder_ctl(oe, OPUS_SET_BITRATE(kbps*1024)); // bits per second
opus_custom_encoder_ctl(oe, OPUS_SET_COMPLEXITY(10));
opus_custom_encoder_ctl(oe, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC));
opus_custom_encoder_ctl(oe, OPUS_SET_SIGNAL(OPUS_APPLICATION_RESTRICTED_LOWDELAY));
opus_custom_encoder_init(oe, opus_mode, 1);
playback_srcs = jack_slist_append(playback_srcs, oe);
#endif
} else {
#if HAVE_SAMPLERATE
playback_srcs = jack_slist_append (playback_srcs, src_new (SRC_LINEAR, 1, NULL));
#endif
}
playback_ports = jack_slist_append (playback_ports, port);
}

/* Allocate midi playback channels */
for (chn = n_playback_audio; chn < n_playback_midi + n_playback_audio; chn++) {
snprintf (buf, sizeof (buf) - 1, "playback_%u", chn + 1);
port = jack_port_register (client, buf, JACK_DEFAULT_MIDI_TYPE, port_flags, 0);
if (!port) {
printf ("jack_netsource: cannot register %s port\n", buf);
break;
}
playback_ports = jack_slist_append (playback_ports, port);
}
}

/**
* The Sync callback... sync state is set elsewhere...
* we will see if this is working correctly.
* i don't really believe in it yet.
*/
int
sync_cb (jack_transport_state_t state, jack_position_t *pos, void *arg)
{
static int latency_count = 0;
int retval = sync_state;

if (! state_connected) {
return 1;
}
if (latency_count) {
latency_count--;
retval = 0;
}

else if (state == JackTransportStarting && last_transport_state != JackTransportStarting) {
retval = 0;
latency_count = latency - 1;
}

last_transport_state = state;
return retval;
}

void
freewheel_cb (int starting, void *arg)
{
freewheeling = starting;
}

int deadline_goodness = 0;
/**
* The process callback for this JACK application.
* It is called by JACK at the appropriate times.
*/
int
process (jack_nframes_t nframes, void *arg)
{
jack_nframes_t net_period;
int rx_bufsize, tx_bufsize;

jack_default_audio_sample_t *buf;
jack_port_t *port;
JSList *node;
int chn;
int size, i;
const char *porttype;
int input_fd;

jack_position_t local_trans_pos;

uint32_t *packet_buf_tx, *packet_bufX;
uint32_t *rx_packet_ptr;
jack_time_t packet_recv_timestamp;

if( bitdepth == 1000 || bitdepth == 999)
net_period = (factor * jack_get_buffer_size(client) * 1024 / jack_get_sample_rate(client) / 8) & (~1) ;
else
net_period = (float) nframes / (float) factor;

rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header);
tx_bufsize = get_sample_size (bitdepth) * playback_channels * net_period + sizeof (jacknet_packet_header);

/* Allocate a buffer where both In and Out Buffer will fit */
packet_buf_tx = alloca (tx_bufsize);

jacknet_packet_header *pkthdr_tx = (jacknet_packet_header *) packet_buf_tx;

/*
* for latency==0 we need to send out the packet before we wait on the reply.
* but this introduces a cycle of latency, when netsource is connected to itself.
* so we send out before read only in zero latency mode.
*
*/

if( latency == 0 ) {
/* reset packet_bufX... */
packet_bufX = packet_buf_tx + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t);

/* ---------- Send ---------- */
render_jack_ports_to_payload (bitdepth, playback_ports, playback_srcs, nframes,
packet_bufX, net_period, dont_htonl_floats);

/* fill in packet hdr */
pkthdr_tx->transport_state = jack_transport_query (client, &local_trans_pos);
pkthdr_tx->transport_frame = local_trans_pos.frame;
pkthdr_tx->framecnt = framecnt;
pkthdr_tx->latency = latency;
pkthdr_tx->reply_port = reply_port;
pkthdr_tx->sample_rate = jack_get_sample_rate (client);
pkthdr_tx->period_size = nframes;

/* playback for us is capture on the other side */
pkthdr_tx->capture_channels_audio = playback_channels_audio;
pkthdr_tx->playback_channels_audio = capture_channels_audio;
pkthdr_tx->capture_channels_midi = playback_channels_midi;
pkthdr_tx->playback_channels_midi = capture_channels_midi;
pkthdr_tx->mtu = mtu;
if( freewheeling != 0 )
pkthdr_tx->sync_state = (jack_nframes_t)MASTER_FREEWHEELS;
else
pkthdr_tx->sync_state = (jack_nframes_t)deadline_goodness;
//printf("goodness=%d\n", deadline_goodness );

packet_header_hton (pkthdr_tx);
if (cont_miss < 3 * latency + 5) {
int r;
for( r = 0; r < redundancy; r++ )
netjack_sendto (outsockfd, (char *) packet_buf_tx, tx_bufsize, 0, &destaddr, sizeof (destaddr), mtu);
} else if (cont_miss > 50 + 5 * latency) {
state_connected = 0;
packet_cache_reset_master_address( packcache );
//printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss);
cont_miss = 0;
}
}

/*
* ok... now the RECEIVE code.
*
*/


if( reply_port )
input_fd = insockfd;
else
input_fd = outsockfd;

// for latency == 0 we can poll.
if( (latency == 0) || (freewheeling != 0) ) {
jack_time_t deadline = jack_get_time() + 1000000 * jack_get_buffer_size(client) / jack_get_sample_rate(client);
// Now loop until we get the right packet.
while(1) {
jack_nframes_t got_frame;
if ( ! netjack_poll_deadline( input_fd, deadline ) )
break;

packet_cache_drain_socket(packcache, input_fd);

if (packet_cache_get_next_available_framecnt( packcache, framecnt - latency, &got_frame ))
if( got_frame == (framecnt - latency) )
break;
}
} else {
// normally:
// only drain socket.
packet_cache_drain_socket(packcache, input_fd);
}

size = packet_cache_retreive_packet_pointer( packcache, framecnt - latency, (char**)&rx_packet_ptr, rx_bufsize, &packet_recv_timestamp );
/* First alternative : we received what we expected. Render the data
* to the JACK ports so it can be played. */
if (size == rx_bufsize) {
uint32_t *packet_buf_rx = rx_packet_ptr;
jacknet_packet_header *pkthdr_rx = (jacknet_packet_header *) packet_buf_rx;
packet_bufX = packet_buf_rx + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t);
// calculate how much time there would have been, if this packet was sent at the deadline.

int recv_time_offset = (int) (jack_get_time() - packet_recv_timestamp);
packet_header_ntoh (pkthdr_rx);
deadline_goodness = recv_time_offset - (int)pkthdr_rx->latency;
//printf( "deadline goodness = %d ---> off: %d\n", deadline_goodness, recv_time_offset );

if (cont_miss) {
//printf("Frame %d \tRecovered from dropouts\n", framecnt);
cont_miss = 0;
}
render_payload_to_jack_ports (bitdepth, packet_bufX, net_period,
capture_ports, capture_srcs, nframes, dont_htonl_floats);

state_currentframe = framecnt;
state_recv_packet_queue_time = recv_time_offset;
state_connected = 1;
sync_state = pkthdr_rx->sync_state;
packet_cache_release_packet( packcache, framecnt - latency );
}
/* Second alternative : we've received something that's not
* as big as expected or we missed a packet. We render silence
* to the output ports */
else {
jack_nframes_t latency_estimate;
if( packet_cache_find_latency( packcache, framecnt, &latency_estimate ) )
//if( (state_latency == 0) || (latency_estimate < state_latency) )
state_latency = latency_estimate;

// Set the counters up.
state_currentframe = framecnt;
//state_latency = framecnt - pkthdr->framecnt;
state_netxruns += 1;

//printf ("Frame %d \tPacket missed or incomplete (expected: %d bytes, got: %d bytes)\n", framecnt, rx_bufsize, size);
//printf ("Frame %d \tPacket missed or incomplete\n", framecnt);
cont_miss += 1;
chn = 0;
node = capture_ports;
while (node != NULL) {
port = (jack_port_t *) node->data;
buf = jack_port_get_buffer (port, nframes);
porttype = jack_port_type (port);
if (strncmp (porttype, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size ()) == 0)
for (i = 0; i < nframes; i++)
buf[i] = 0.0;
else if (strncmp (porttype, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size ()) == 0)
jack_midi_clear_buffer (buf);
node = jack_slist_next (node);
chn++;
}
}
if (latency != 0) {
/* reset packet_bufX... */
packet_bufX = packet_buf_tx + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t);

/* ---------- Send ---------- */
render_jack_ports_to_payload (bitdepth, playback_ports, playback_srcs, nframes,
packet_bufX, net_period, dont_htonl_floats);

/* fill in packet hdr */
pkthdr_tx->transport_state = jack_transport_query (client, &local_trans_pos);
pkthdr_tx->transport_frame = local_trans_pos.frame;
pkthdr_tx->framecnt = framecnt;
pkthdr_tx->latency = latency;
pkthdr_tx->reply_port = reply_port;
pkthdr_tx->sample_rate = jack_get_sample_rate (client);
pkthdr_tx->period_size = nframes;

/* playback for us is capture on the other side */
pkthdr_tx->capture_channels_audio = playback_channels_audio;
pkthdr_tx->playback_channels_audio = capture_channels_audio;
pkthdr_tx->capture_channels_midi = playback_channels_midi;
pkthdr_tx->playback_channels_midi = capture_channels_midi;
pkthdr_tx->mtu = mtu;
if( freewheeling != 0 )
pkthdr_tx->sync_state = (jack_nframes_t)MASTER_FREEWHEELS;
else
pkthdr_tx->sync_state = (jack_nframes_t)deadline_goodness;
//printf("goodness=%d\n", deadline_goodness );

packet_header_hton (pkthdr_tx);
if (cont_miss < 3 * latency + 5) {
int r;
for( r = 0; r < redundancy; r++ )
netjack_sendto (outsockfd, (char *) packet_buf_tx, tx_bufsize, 0, &destaddr, sizeof (destaddr), mtu);
} else if (cont_miss > 50 + 5 * latency) {
state_connected = 0;
packet_cache_reset_master_address( packcache );
//printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss);
cont_miss = 0;
}
}

framecnt++;
return 0;
}

/**
* This is the shutdown callback for this JACK application.
* It is called by JACK 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);
}

void
init_sockaddr_in (struct sockaddr_in *name , const char *hostname , uint16_t port)
{
name->sin_family = AF_INET ;
name->sin_port = htons (port);
if (hostname) {
struct hostent *hostinfo = gethostbyname (hostname);
if (hostinfo == NULL) {
fprintf (stderr, "init_sockaddr_in: unknown host: %s.\n", hostname);
fflush( stderr );
}
#ifdef WIN32
name->sin_addr.s_addr = inet_addr( hostname );
#else
name->sin_addr = *(struct in_addr *) hostinfo->h_addr ;
#endif
} else
name->sin_addr.s_addr = htonl (INADDR_ANY) ;

}

void
printUsage ()
{
fprintf (stderr, "usage: jack_netsource [options]\n"
"\n"
" -h this help text\n"
" -H <slave host> - Host name of the slave JACK\n"
" -o <num channels> - Number of audio playback channels\n"
" -i <num channels> - Number of audio capture channels\n"
" -O <num channels> - Number of midi playback channels\n"
" -I <num channels> - Number of midi capture channels\n"
" -n <periods> - Network latency in JACK periods\n"
" -p <port> - UDP port that the slave is listening on\n"
" -r <reply port> - UDP port that we are listening on\n"
" -B <bind port> - reply port, for use in NAT environments\n"
" -b <bitdepth> - Set transport to use 16bit or 8bit\n"
" -c <kbits> - Use CELT encoding with <kbits> kbits per channel\n"
" -P <kbits> - Use Opus encoding with <kbits> kbits per channel\n"
" -m <mtu> - Assume this mtu for the link\n"
" -R <N> - Redundancy: send out packets N times.\n"
" -e - skip host-to-network endianness conversion\n"
" -N <jack name> - Reports a different name to jack\n"
" -s <server name> - The name of the local jack server\n"
"\n");
}

void
sigterm_handler( int signal )
{
quit = 1;
}

int
main (int argc, char *argv[])
{
/* Some startup related basics */
char *client_name, *server_name = NULL, *peer_ip;
int peer_port = 3000;
jack_options_t options = JackNullOption;
jack_status_t status;
#ifdef WIN32
WSADATA wsa;
int rc = WSAStartup(MAKEWORD(2, 0), &wsa);
#endif
/* Torben's famous state variables, aka "the reporting API" ! */
/* heh ? these are only the copies of them ;) */
int statecopy_connected, statecopy_latency, statecopy_netxruns;
jack_nframes_t net_period;
/* Argument parsing stuff */
extern char *optarg;
extern int optind, optopt;
int errflg = 0, c;

if (argc < 3) {
printUsage ();
return 1;
}

client_name = (char *) malloc (sizeof (char) * 10);
peer_ip = (char *) malloc (sizeof (char) * 10);
sprintf(client_name, "netjack");
sprintf(peer_ip, "localhost");

while ((c = getopt (argc, argv, ":h:H:o:i:O:I:n:p:r:B:b:c:m:R:e:N:s:P:")) != -1) {
switch (c) {
case 'h':
printUsage();
exit (0);
break;
case 'H':
free(peer_ip);
peer_ip = (char *) malloc (sizeof (char) * strlen (optarg) + 1);
strcpy (peer_ip, optarg);
break;
case 'o':
playback_channels_audio = atoi (optarg);
break;
case 'i':
capture_channels_audio = atoi (optarg);
break;
case 'O':
playback_channels_midi = atoi (optarg);
break;
case 'I':
capture_channels_midi = atoi (optarg);
break;
case 'n':
latency = atoi (optarg);
break;
case 'p':
peer_port = atoi (optarg);
break;
case 'r':
reply_port = atoi (optarg);
break;
case 'B':
bind_port = atoi (optarg);
break;
case 'f':
factor = atoi (optarg);
printf("This feature is deprecated and will be removed in future netjack versions. CELT offers a superiour way to conserve bandwidth");
break;
case 'b':
bitdepth = atoi (optarg);
break;
case 'c':
#if HAVE_CELT
bitdepth = 1000;
factor = atoi (optarg);
#else
printf( "not built with celt support\n" );
exit(10);
#endif
break;
case 'P':
#if HAVE_OPUS
bitdepth = 999;
factor = atoi (optarg);
#else
printf( "not built with opus support\n" );
exit(10);
#endif
break;
case 'm':
mtu = atoi (optarg);
break;
case 'R':
redundancy = atoi (optarg);
break;
case 'e':
dont_htonl_floats = 1;
break;
case 'N':
free(client_name);
client_name = (char *) malloc (sizeof (char) * strlen (optarg) + 1);
strcpy (client_name, optarg);
break;
case 's':
server_name = (char *) malloc (sizeof (char) * strlen (optarg) + 1);
strcpy (server_name, optarg);
options |= JackServerName;
break;
case ':':
fprintf (stderr, "Option -%c requires an operand\n", optopt);
errflg++;
break;
case '?':
fprintf (stderr, "Unrecognized option: -%c\n", optopt);
errflg++;
}
}
if (errflg) {
printUsage ();
exit (2);
}

capture_channels = capture_channels_audio + capture_channels_midi;
playback_channels = playback_channels_audio + playback_channels_midi;

outsockfd = socket (AF_INET, SOCK_DGRAM, 0);
insockfd = socket (AF_INET, SOCK_DGRAM, 0);

if ((outsockfd == -1) || (insockfd == -1)) {
fprintf (stderr, "can not open sockets\n" );
return 1;
}

init_sockaddr_in ((struct sockaddr_in *) &destaddr, peer_ip, peer_port);
if (bind_port) {
init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, bind_port);
if( bind (outsockfd, &bindaddr, sizeof (bindaddr)) ) {
fprintf (stderr, "bind failure\n" );
}
}
if (reply_port) {
init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, reply_port);
if( bind (insockfd, &bindaddr, sizeof (bindaddr)) ) {
fprintf (stderr, "bind failure\n" );
}
}

/* try to become a client of 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"
"Is the JACK server running ?\n", status);
return 1;
}

/* Set up jack callbacks */
jack_set_process_callback (client, process, 0);
jack_set_sync_callback (client, sync_cb, 0);
jack_set_freewheel_callback (client, freewheel_cb, 0);
jack_on_shutdown (client, jack_shutdown, 0);

alloc_ports (capture_channels_audio, playback_channels_audio, capture_channels_midi, playback_channels_midi);

if( bitdepth == 1000 || bitdepth == 999)
net_period = (factor * jack_get_buffer_size(client) * 1024 / jack_get_sample_rate(client) / 8) & (~1) ;
else
net_period = ceilf((float) jack_get_buffer_size (client) / (float) factor);

int rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header);
packcache = packet_cache_new (latency + 50, rx_bufsize, mtu);

/* tell the JACK server that we are ready to roll */
if (jack_activate (client)) {
fprintf (stderr, "Cannot activate client");
return 1;
}

/* Now sleep forever... and evaluate the state_ vars */

signal( SIGTERM, sigterm_handler );
signal( SIGINT, sigterm_handler );

statecopy_connected = 2; // make it report unconnected on start.
statecopy_latency = state_latency;
statecopy_netxruns = state_netxruns;

while ( !quit ) {
#ifdef WIN32
Sleep (1000);
#else
sleep(1);
#endif
if (statecopy_connected != state_connected) {
statecopy_connected = state_connected;
if (statecopy_connected) {
state_netxruns = 1; // We want to reset the netxrun count on each new connection
printf ("Connected :-)\n");
} else
printf ("Not Connected\n");

fflush(stdout);
}

if (statecopy_connected) {
if (statecopy_netxruns != state_netxruns) {
statecopy_netxruns = state_netxruns;
printf ("%s: at frame %06d -> total netxruns %d (%d%%) queue time= %d\n",
client_name,
state_currentframe,
statecopy_netxruns,
100 * statecopy_netxruns / state_currentframe,
state_recv_packet_queue_time);

fflush(stdout);
}
} else {
if (statecopy_latency != state_latency) {
statecopy_latency = state_latency;
if (statecopy_latency > 1)
printf ("current latency %d\n", statecopy_latency);
fflush(stdout);
}
}
}

jack_client_close (client);
packet_cache_free (packcache);
exit (0);
}

+ 0
- 326
tools/property.c View File

@@ -1,326 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>

#include <jack/jack.h>
#include <jack/metadata.h>
#include <jack/uuid.h>
#include <jack/session.h>

static int subject_is_client = 0;
static int subject_is_port = 0;
static jack_uuid_t uuid = JACK_UUID_EMPTY_INITIALIZER;
static char* subject = NULL;

static void
show_usage (void)
{
fprintf (stderr, "\nUsage: jack_property [options] UUID [ key [ value [ type ] ] ]\n");
fprintf (stderr, "Set/Display JACK properties (metadata).\n\n");
fprintf (stderr, "Set options:\n");
fprintf (stderr, " -s, --set Set property \"key\" to \"value\" for \"UUID\" with optional MIME type \"type\"\n");
fprintf (stderr, " -d, --delete Remove/delete property \"key\" for \"UUID\"\n");
fprintf (stderr, " -d, --delete UUID Remove/delete all properties for \"UUID\"\n");
fprintf (stderr, " -D, --delete-all Remove/delete all properties\n");
fprintf (stderr, " --client Interpret UUID as a client name, not a UUID\n");
fprintf (stderr, " --port \tInterpret UUID as a port name, not a UUID\n");
fprintf (stderr, "\nDisplay options:\n");
fprintf (stderr, " -l Show all properties\n");
fprintf (stderr, " -l, --list UUID \tShow value for all properties of UUID\n");
fprintf (stderr, " -l, --list UUID key Show value for key of UUID\n");
fprintf (stderr, "\nFor more information see https://jackaudio.org/\n");
}

static int
get_subject (jack_client_t* client, char* argv[], int* optind)
{
if (subject_is_client) {
char* cstr = argv[(*optind)++];
char* ustr;

if ((ustr = jack_get_uuid_for_client_name (client, cstr)) == NULL) {
fprintf (stderr, "cannot get UUID for client named %s\n", cstr);
return -1;
}

if (jack_uuid_parse (ustr, &uuid)) {
fprintf (stderr, "cannot parse client UUID as UUID '%s' '%s'\n", cstr, ustr);
return -1;
}

subject = cstr;

} else if (subject_is_port) {

char* pstr = argv[(*optind)++];
jack_port_t* port;

if ((port = jack_port_by_name (client, pstr)) == NULL) {
fprintf (stderr, "cannot find port name %s\n", pstr);
return -1;
}

uuid = jack_port_uuid (port);
subject = pstr;

} else {
char* str = argv[(*optind)++];

if (jack_uuid_parse (str, &uuid)) {
fprintf (stderr, "cannot parse subject as UUID\n");
return -1;
}

subject = str;
}

return 0;
}

int main (int argc, char* argv[])
{
jack_client_t* client = NULL;
jack_options_t options = JackNoStartServer;
char* key = NULL;
char* value = NULL;
char* type = NULL;
int set = 1;
int delete = 0;
int delete_all = 0;
int c;
int option_index;
extern int optind;
struct option long_options[] = {
{ "set", 0, 0, 's' },
{ "delete", 0, 0, 'd' },
{ "delete-all", 0, 0, 'D' },
{ "list", 0, 0, 'l' },
{ "client", 0, 0, 'c' },
{ "port", 0, 0, 'p' },
{ 0, 0, 0, 0 }
};

if (argc < 2) {
show_usage ();
exit (1);
}

while ((c = getopt_long (argc, argv, "sdDlaApc", long_options, &option_index)) >= 0) {
switch (c) {
case 's':
if (argc < 5) {
show_usage ();
exit (1);
}
set = 1;
break;
case 'd':
if (argc < 3) {
show_usage ();
return 1;
}
set = 0;
delete = 1;
break;

case 'D':
delete = 0;
set = 0;
delete_all = 1;
break;

case 'l':
set = 0;
delete = 0;
delete_all = 0;
break;

case 'p':
subject_is_port = 1;
break;

case 'c':
subject_is_client = 1;
break;

case '?':
default:
show_usage ();
exit (1);
}
}

if ((client = jack_client_open ("jack-property", options, NULL)) == 0) {
fprintf (stderr, "Cannot connect to JACK server\n");
exit (1);
}

if (delete_all) {

if (jack_remove_all_properties (client) == 0) {
printf ("JACK metadata successfully delete\n");
exit (0);
}
exit (1);
}

if (delete) {

int args_left = argc - optind;

if (args_left < 1) {
show_usage ();
exit (1);
}

/* argc == 3: delete all properties for a subject
argc == 4: delete value of key for subject
*/

if (args_left >= 2) {

if (get_subject (client, argv, &optind)) {
return 1;
}

key = argv[optind++];

if (jack_remove_property (client, uuid, key)) {
fprintf (stderr, "\"%s\" property not removed for %s\n", key, subject);
exit (1);
}

} else {

if (get_subject (client, argv, &optind)) {
return 1;
}

if (jack_remove_properties (client, uuid) < 0) {
fprintf (stderr, "cannot remove properties for UUID %s\n", subject);
exit (1);
}
}

} else if (set) {

int args_left = argc - optind;

if (get_subject (client, argv, &optind)) {
return -1;
}

key = argv[optind++];
value = argv[optind++];

if (args_left >= 3) {
type = argv[optind++];
} else {
type = "";
}

if (jack_set_property (client, uuid, key, value, type)) {
fprintf (stderr, "cannot set value for key %s of %s\n", key, subject);
exit (1);
}

} else {

/* list properties */

int args_left = argc - optind;

if (args_left >= 2) {

/* list properties for a UUID/key pair */

if (get_subject (client, argv, &optind)) {
return -1;
}

key = argv[optind++];

if (jack_get_property (uuid, key, &value, &type) == 0) {
printf ("%s\n", value);
free (value);
if (type) {
free (type);
}
} else {
fprintf (stderr, "Value not found for %s of %s\n", key, subject);
exit (1);
}

} else if (args_left == 1) {

/* list all properties for a given UUID */

jack_description_t description;
int cnt, n;

if (get_subject (client, argv, &optind)) {
return -1;
}

if ((cnt = jack_get_properties (uuid, &description)) < 0) {
fprintf (stderr, "could not retrieve properties for %s\n", subject);
exit (1);
}

for (n = 0; n < cnt; ++n) {
if (description.properties[n].type) {
printf ("key: %s value: %s type: %s\n",
description.properties[n].key,
description.properties[n].data,
description.properties[n].type);
} else {
printf ("key: %s value: %s\n",
description.properties[n].key,
description.properties[n].data);
}
}

jack_free_description (&description, 0);

} else {

/* list all properties */

jack_description_t* description;
int cnt, n;
size_t p;
char buf[JACK_UUID_STRING_SIZE];

if ((cnt = jack_get_all_properties (&description)) < 0) {
fprintf (stderr, "could not retrieve all properties\n");
exit (1);
}

for (n = 0; n < cnt; ++n) {
jack_uuid_unparse (description[n].subject, buf);
printf ("%s\n", buf);
for (p = 0; p < description[n].property_cnt; ++p) {
if (description[n].properties[p].type) {
printf ("key: %s value: %s type: %s\n",
description[n].properties[p].key,
description[n].properties[p].data,
description[n].properties[p].type);
} else {
printf ("key: %s value: %s\n",
description[n].properties[p].key,
description[n].properties[p].data);
}
}
jack_free_description (&description[n], 0);
}

free (description);
}
}


(void) jack_client_close (client);
return 0;
}

+ 0
- 87
tools/samplerate.c View File

@@ -1,87 +0,0 @@
/*
* smaplerate.c -- get current samplerate
*
* 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.
*/

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

char *package; /* program name */
jack_client_t *client;

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

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

void parse_arguments(int argc, char *argv[])
{

/* basename $0 */
package = strrchr(argv[0], '/');
if (package == 0)
package = argv[0];
else
package++;

if (argc==1) {
return;
}
fprintf(stderr, "usage: %s\n", package);
exit(9);
}

int main(int argc, char *argv[])
{
parse_arguments(argc, argv);

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

#ifndef WIN32
signal(SIGQUIT, signal_handler);
signal(SIGHUP, signal_handler);
#endif
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);

jack_on_shutdown(client, jack_shutdown, 0);

fprintf(stdout, "%d\n", jack_get_sample_rate( client ) );

jack_client_close(client);

return 0;
}

+ 0
- 186
tools/session_notify.c View File

@@ -1,186 +0,0 @@
/*
* session_notify.c -- ultra minimal session manager
*
* Copyright (C) 2018 Karl Linden <karl.j.linden@gmail.com>
* Copyright (C) 2010 Torben Hohn.
*
* 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 <alloca.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <jack/jack.h>
#include <jack/jslist.h>
#include <jack/transport.h>
#include <jack/session.h>

char *package; /* program name */
jack_client_t *client;

jack_session_event_type_t notify_type;
char *save_path = NULL;

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

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

void parse_arguments(int argc, char *argv[])
{

/* basename $0 */
package = strrchr(argv[0], '/');
if (package == 0)
package = argv[0];
else
package++;

if (argc==2) {
if( !strcmp( argv[1], "quit" ) ) {
notify_type = JackSessionSaveAndQuit;
return;
}
}
if (argc==3) {
if( !strcmp( argv[1], "save" ) ) {
notify_type = JackSessionSave;
save_path = argv[2];
return;
}

}
fprintf(stderr, "usage: %s quit|save [path]\n", package);
exit(9);
}

typedef struct {
char name[32];
char uuid[16];
} uuid_map_t;

JSList *uuid_map = NULL;

void add_uuid_mapping( const char *uuid ) {
char *clientname = jack_get_client_name_by_uuid( client, uuid );
if( !clientname ) {
printf( "error... can not find client for uuid" );
return;
}

uuid_map_t *mapping = malloc( sizeof(uuid_map_t) );
snprintf( mapping->uuid, sizeof(mapping->uuid), "%s", uuid );
snprintf( mapping->name, sizeof(mapping->name), "%s", clientname );
uuid_map = jack_slist_append( uuid_map, mapping );
}

char *map_port_name_to_uuid_port( const char *port_name )
{
JSList *node;
char retval[300];
char *port_component = strchr( port_name,':' );
char *client_component = strdup( port_name );
strchr( client_component, ':' )[0] = '\0';

sprintf( retval, "%s", port_name );

for( node=uuid_map; node; node=jack_slist_next(node) ) {
uuid_map_t *mapping = node->data;
if( !strcmp( mapping->name, client_component ) ) {
sprintf( retval, "%s%s", mapping->uuid, port_component );
break;
}
}

return strdup(retval);
}

int main(int argc, char *argv[])
{
parse_arguments(argc, argv);
jack_session_command_t *retval;
int k,i,j;


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

#ifndef WIN32
signal(SIGQUIT, signal_handler);
signal(SIGHUP, signal_handler);
#endif

signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);

jack_on_shutdown(client, jack_shutdown, 0);

jack_activate(client);


retval = jack_session_notify( client, NULL, notify_type, save_path );
for (i = 0; retval[i].uuid; i++) {
printf( "export SESSION_DIR=\"%s%s/\"\n", save_path, retval[i].client_name );
printf( "%s &\n", retval[i].command );
add_uuid_mapping(retval[i].uuid);
}

printf( "sleep 10\n" );

for (k = 0; retval[k].uuid; k++) {

char* port_regexp = alloca( jack_client_name_size()+3 );
char* client_name = jack_get_client_name_by_uuid( client, retval[k].uuid );
snprintf( port_regexp, jack_client_name_size()+3, "%s:.*", client_name );
jack_free(client_name);
const char **ports = jack_get_ports( client, port_regexp, NULL, 0 );
if( !ports ) {
continue;
}
for (i = 0; ports[i]; ++i) {
const char **connections;
if ((connections = jack_port_get_all_connections (client, jack_port_by_name(client, ports[i]))) != 0) {
for (j = 0; connections[j]; j++) {
char *src = map_port_name_to_uuid_port( ports[i] );
char *dst = map_port_name_to_uuid_port( connections[j] );
printf( "jack_connect -u \"%s\" \"%s\"\n", src, dst );
}
jack_free (connections);
}
}
jack_free(ports);

}
jack_session_commands_free(retval);

jack_client_close(client);

return 0;
}

+ 0
- 508
tools/transport.c View File

@@ -1,508 +0,0 @@
/*
* transport.c -- JACK transport master example client.
*
* 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.
*/

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#if HAVE_READLINE
#include <readline/readline.h>
#include <readline/history.h>
#endif
#include <jack/jack.h>
#include <jack/transport.h>

/* Use a copy of the readline macro whitespace if it does not exist.
* Not all readline compatible libraries supply the whitespace macro
* (libedit for example), so pull in the copy in those cases too. */
#if !HAVE_READLINE || !defined(whitespace)
#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
#endif

char *package; /* program name */
int done = 0;
jack_client_t *client;

/* Time and tempo variables. These are global to the entire,
* transport timeline. There is no attempt to keep a true tempo map.
* The default time signature is: "march time", 4/4, 120bpm
*/
float time_beats_per_bar = 4.0;
float time_beat_type = 4.0;
double time_ticks_per_beat = 1920.0;
double time_beats_per_minute = 120.0;
volatile int time_reset = 1; /* true when time values change */

/* JACK timebase callback.
*
* Runs in the process thread. Realtime, must not wait.
*/
static void timebase(jack_transport_state_t state, jack_nframes_t nframes,
jack_position_t *pos, int new_pos, void *arg)
{
double min; /* minutes since frame 0 */
long abs_tick; /* ticks since frame 0 */
long abs_beat; /* beats since frame 0 */

if (new_pos || time_reset) {

pos->valid = JackPositionBBT;
pos->beats_per_bar = time_beats_per_bar;
pos->beat_type = time_beat_type;
pos->ticks_per_beat = time_ticks_per_beat;
pos->beats_per_minute = time_beats_per_minute;

time_reset = 0; /* time change complete */

/* Compute BBT info from frame number. This is relatively
* simple here, but would become complex if we supported tempo
* or time signature changes at specific locations in the
* transport timeline. */

min = pos->frame / ((double) pos->frame_rate * 60.0);
abs_tick = min * pos->beats_per_minute * pos->ticks_per_beat;
abs_beat = abs_tick / pos->ticks_per_beat;

pos->bar = abs_beat / pos->beats_per_bar;
pos->beat = abs_beat - (pos->bar * pos->beats_per_bar) + 1;
pos->tick = abs_tick - (abs_beat * pos->ticks_per_beat);
pos->bar_start_tick = pos->bar * pos->beats_per_bar *
pos->ticks_per_beat;
pos->bar++; /* adjust start to bar 1 */

#if 0
/* some debug code... */
fprintf(stderr, "\nnew position: %" PRIu32 "\tBBT: %3"
PRIi32 "|%" PRIi32 "|%04" PRIi32 "\n",
pos->frame, pos->bar, pos->beat, pos->tick);
#endif

} else {

/* Compute BBT info based on previous period. */
pos->tick +=
nframes * pos->ticks_per_beat * pos->beats_per_minute
/ (pos->frame_rate * 60);

while (pos->tick >= pos->ticks_per_beat) {
pos->tick -= pos->ticks_per_beat;
if (++pos->beat > pos->beats_per_bar) {
pos->beat = 1;
++pos->bar;
pos->bar_start_tick +=
pos->beats_per_bar
* pos->ticks_per_beat;
}
}
}
}

static void jack_shutdown(void *arg)
{
#if defined(RL_READLINE_VERSION) && RL_READLINE_VERSION >= 0x0400
rl_cleanup_after_signal();
#endif
fprintf(stderr, "JACK shut down, exiting ...\n");
exit(1);
}

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

/* Command functions: see commands[] table following. */

static void com_activate(char *arg)
{
if (jack_activate(client)) {
fprintf(stderr, "cannot activate client");
}
}

static void com_deactivate(char *arg)
{
if (jack_deactivate(client)) {
fprintf(stderr, "cannot deactivate client");
}
}

static void com_exit(char *arg)
{
done = 1;
}

static void com_help(char *); /* forward declaration */

static void com_locate(char *arg)
{
jack_nframes_t frame = 0;

if (*arg != '\0')
frame = atoi(arg);

jack_transport_locate(client, frame);
}

static void com_master(char *arg)
{
int cond = (*arg != '\0');
if (jack_set_timebase_callback(client, cond, timebase, NULL) != 0)
fprintf(stderr, "Unable to take over timebase.\n");
}

static void com_play(char *arg)
{
jack_transport_start(client);
}

static void com_release(char *arg)
{
jack_release_timebase(client);
}

static void com_stop(char *arg)
{
jack_transport_stop(client);
}

/* Change the tempo for the entire timeline, not just from the current
* location. */
static void com_tempo(char *arg)
{
float tempo = 120.0;

if (*arg != '\0')
tempo = atof(arg);

time_beats_per_minute = tempo;
time_reset = 1;
}

/* Set sync timeout in seconds. */
static void com_timeout(char *arg)
{
double timeout = 2.0;

if (*arg != '\0')
timeout = atof(arg);

jack_set_sync_timeout(client, (jack_time_t) (timeout*1000000));
}

/* Toggle between play and stop state */
static void com_toggle(char *arg)
{
jack_position_t current;
jack_transport_state_t transport_state;

transport_state = jack_transport_query (client, &current);

switch (transport_state) {
case JackTransportStopped:
com_play( arg );
break;
case JackTransportRolling:
com_stop( arg );
break;
case JackTransportStarting:
fprintf(stderr, "state: Starting - no transport toggling");
break;
default:
fprintf(stderr, "unexpected state: no transport toggling");
}
}


/* Command parsing based on GNU readline info examples. */

typedef void cmd_function_t(char *); /* command function type */

/* Transport command table. */
typedef struct {
char *name; /* user printable name */
cmd_function_t *func; /* function to call */
char *doc; /* documentation */
} command_t;

/* command table must be in alphabetical order */
command_t commands[] = {
{"activate", com_activate, "Call jack_activate()"},
{"exit", com_exit, "Exit transport program"},
{"deactivate", com_deactivate, "Call jack_deactivate()"},
{"help", com_help, "Display help text [<command>]"},
{"locate", com_locate, "Locate to frame <position>"},
{"master", com_master, "Become timebase master "
"[<conditionally>]"},
{"play", com_play, "Start transport rolling"},
{"quit", com_exit, "Synonym for `exit'"},
{"release", com_release, "Release timebase"},
{"stop", com_stop, "Stop transport"},
{"tempo", com_tempo, "Set beat tempo <beats_per_min>"},
{"timeout", com_timeout, "Set sync timeout in <seconds>"},
{"toggle", com_toggle, "Toggle transport rolling"},
{"?", com_help, "Synonym for `help'" },
{(char *)NULL, (cmd_function_t *)NULL, (char *)NULL }
};

static command_t *find_command(char *name)
{
register int i;
size_t namelen;

if ((name == NULL) || (*name == '\0'))
return ((command_t *)NULL);

namelen = strlen(name);
for (i = 0; commands[i].name; i++)
if (strncmp(name, commands[i].name, namelen) == 0) {

/* make sure the match is unique */
if ((commands[i+1].name) &&
(strncmp(name, commands[i+1].name, namelen) == 0))
return ((command_t *)NULL);
else
return (&commands[i]);
}

return ((command_t *)NULL);
}

static void com_help(char *arg)
{
register int i;
command_t *cmd;

if (!*arg) {
/* print help for all commands */
for (i = 0; commands[i].name; i++) {
printf("%s\t\t%s.\n", commands[i].name,
commands[i].doc);
}

} else if ((cmd = find_command(arg))) {
printf("%s\t\t%s.\n", cmd->name, cmd->doc);

} else {
int printed = 0;

printf("No `%s' command. Valid command names are:\n", arg);

for (i = 0; commands[i].name; i++) {
/* Print in six columns. */
if (printed == 6) {
printed = 0;
printf ("\n");
}

printf ("%s\t", commands[i].name);
printed++;
}

printf("\n\nTry `help [command]\' for more information.\n");
}
}

static void execute_command(char *line)
{
register int i;
command_t *command;
char *word;

/* Isolate the command word. */
i = 0;
while (line[i] && whitespace(line[i]))
i++;
word = line + i;

while (line[i] && !whitespace(line[i]))
i++;

if (line[i])
line[i++] = '\0';

command = find_command(word);

if (!command) {
fprintf(stderr, "%s: No such command. There is `help\'.\n",
word);
return;
}

/* Get argument to command, if any. */
while (whitespace(line[i]))
i++;

word = line + i;

/* invoke the command function. */
(*command->func)(word);
}


/* Strip whitespace from the start and end of string. */
static char *stripwhite(char *string)
{
register char *s, *t;

s = string;
while (whitespace(*s))
s++;

if (*s == '\0')
return s;

t = s + strlen (s) - 1;
while (t > s && whitespace(*t))
t--;
*++t = '\0';

return s;
}

static char *dupstr(char *s)
{
char *r = malloc(strlen(s) + 1);
strcpy(r, s);
return r;
}

/* Readline generator function for command completion. */
static char *command_generator (const char *text, int state)
{
static int list_index, len;
char *name;

/* If this is a new word to complete, initialize now. This
includes saving the length of TEXT for efficiency, and
initializing the index variable to 0. */
if (!state) {
list_index = 0;
len = strlen (text);
}

/* Return the next name which partially matches from the
command list. */
while ((name = commands[list_index].name)) {
list_index++;

if (strncmp(name, text, len) == 0)
return dupstr(name);
}

return (char *) NULL; /* No names matched. */
}

static void command_loop()
{
#if HAVE_READLINE
char *line, *cmd;
char prompt[32];

snprintf(prompt, sizeof(prompt), "%s> ", package);

/* Allow conditional parsing of the ~/.inputrc file. */
rl_readline_name = package;

/* Define a custom completion function. */
rl_completion_entry_function = command_generator;
#else
char line[64] = {0,};
char *cmd = NULL;
#endif

/* Read and execute commands until the user quits. */
while (!done) {

#if HAVE_READLINE
line = readline(prompt);

if (line == NULL) { /* EOF? */
printf("\n"); /* close out prompt */
done = 1;
break;
}
#else
printf("%s> ", package);
fgets(line, sizeof(line), stdin);
line[strlen(line)-1] = '\0';
#endif

/* Remove leading and trailing whitespace from the line. */
cmd = stripwhite(line);

/* If anything left, add to history and execute it. */
if (*cmd)
{
#if HAVE_READLINE
add_history(cmd);
#endif
execute_command(cmd);
}

#if HAVE_READLINE
free(line); /* realine() called malloc() */
#endif
}
}

int main(int argc, char *argv[])
{
jack_status_t status;

/* basename $0 */
package = strrchr(argv[0], '/');
if (package == 0)
package = argv[0];
else
package++;

/* open a connection to the JACK server */
client = jack_client_open (package, JackNullOption, &status);
if (client == NULL) {
fprintf (stderr, "jack_client_open() failed, "
"status = 0x%2.0x\n", status);
return 1;
}

#if !WIN32
signal(SIGQUIT, signal_handler);
signal(SIGHUP, signal_handler);
#endif
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);

jack_on_shutdown(client, jack_shutdown, 0);

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

/* execute commands until done */
command_loop();

jack_client_close(client);
exit(0);
}

+ 0
- 264
tools/tw.c View File

@@ -1,264 +0,0 @@
/** @file tw.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 <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#include <jack/jack.h>

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

/* a simple state machine for this client */
volatile enum {
Init,
Run,
Exit
} client_state = Init;

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

/**
* The process callback for this JACK application is called in a
* special realtime thread once for each audio cycle.
*
* This client follows a simple rule: when the JACK transport is
* running, copy the input port to the output. When it stops, exit.
*/
static int
_process (jack_nframes_t nframes)
{
jack_default_audio_sample_t *in, *out;
jack_transport_state_t ts = jack_transport_query(client, NULL);

if (ts == JackTransportRolling) {

if (client_state == Init)
client_state = Run;

in = jack_port_get_buffer (input_port, nframes);
out = jack_port_get_buffer (output_port, nframes);
memcpy (out, in,
sizeof (jack_default_audio_sample_t) * nframes);

} else if (ts == JackTransportStopped) {

if (client_state == Run) {
client_state = Exit;
return -1; // to stop the thread
}
}

return 0;
}

static void* jack_thread(void *arg)
{
jack_client_t* client = (jack_client_t*) arg;

while (1) {

jack_nframes_t frames = jack_cycle_wait (client);
int status = _process(frames);
jack_cycle_signal (client, status);

/*
Possibly do something else after signaling next clients in the graph
*/

/* End condition */
if (status != 0)
return 0;
}

/* not reached*/
return 0;
}

/*
static void* jack_thread(void *arg)
{
jack_client_t* client = (jack_client_t*) arg;

while (1) {
jack_nframes_t frames;
int status;
// cycle 1
frames = jack_cycle_wait (client);
status = _process(frames);
jack_cycle_signal (client, status);
// cycle 2
frames = jack_cycle_wait (client);
status = _process(frames);
jack_cycle_signal (client, status);
// cycle 3
frames = jack_cycle_wait (client);
status = _process(frames);
jack_cycle_signal (client, status);
// cycle 4
frames = jack_cycle_wait (client);
status = _process(frames);
jack_cycle_signal (client, status);
}

return 0;
}
*/

/**
* JACK calls this shutdown_callback if the server ever shuts down or
* decides to disconnect the client.
*/
static 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;
const char *server_name = NULL;
jack_options_t options = JackNullOption;
jack_status_t status;

if (argc >= 2) { /* client name specified? */
client_name = argv[1];
if (argc >= 3) { /* server name specified? */
server_name = argv[2];
options |= JackServerName;
}
} else { /* use basename of argv[0] */
client_name = strrchr(argv[0], '/');
if (client_name == 0) {
client_name = argv[0];
} else {
client_name++;
}
}

/* 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.
*/
if (jack_set_process_thread(client, jack_thread, client) < 0)
exit(1);

/* 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");
}

jack_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");
}

jack_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);

/* keep running until the transport stops */

while (client_state != Exit) {
sleep (1);
}

jack_client_close (client);
exit (0);
}

+ 0
- 152
tools/wait.c View File

@@ -1,152 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>

#include <time.h>

#include <jack/jack.h>

char * my_name;

void
show_usage(void)
{
fprintf(stderr, "\nUsage: %s [options]\n", my_name);
fprintf(stderr, "Check for jack existence, or wait, until it either quits, or gets started\n");
fprintf(stderr, "options:\n");
fprintf(stderr, " -s, --server <name> Connect to the jack server named <name>\n");
fprintf(stderr, " -n, --name <name> Set client name to <name>\n");
fprintf(stderr, " -w, --wait Wait for server to become available\n");
fprintf(stderr, " -q, --quit Wait until server is quit\n");
fprintf(stderr, " -c, --check Check whether server is running\n");
fprintf(stderr, " -t, --timeout Wait timeout in seconds\n");
fprintf(stderr, " -h, --help Display this help message\n");
fprintf(stderr, "For more information see http://jackaudio.org/\n");
}

int
main(int argc, char *argv[])
{
jack_client_t *client;
jack_status_t status;
jack_options_t options = JackNoStartServer;
int c;
int option_index;
char *server_name = NULL;
char *client_name = NULL;
int wait_for_start = 0;
int wait_for_quit = 0;
int just_check = 0;
int wait_timeout = 0;
time_t start_timestamp;


struct option long_options[] = {
{ "server", 1, 0, 's' },
{ "wait", 0, 0, 'w' },
{ "name", 1, 0, 'n'},
{ "quit", 0, 0, 'q' },
{ "check", 0, 0, 'c' },
{ "timeout", 1, 0, 't' },
{ "help", 0, 0, 'h' },
{ 0, 0, 0, 0 }
};

my_name = strrchr(argv[0], '/');
if (my_name == 0) {
my_name = argv[0];
} else {
my_name ++;
}

while ((c = getopt_long (argc, argv, "s:n:wqct:hv", long_options, &option_index)) >= 0) {
switch (c) {
case 's':
server_name = (char *) malloc (sizeof (char) * (strlen(optarg) + 1));
strcpy (server_name, optarg);
options |= JackServerName;
break;
case 'n':
client_name = (char *) malloc (sizeof (char) * (strlen(optarg) + 1));
strcpy (client_name, optarg);
break;
case 'w':
wait_for_start = 1;
break;
case 'q':
wait_for_quit = 1;
break;
case 'c':
just_check = 1;
break;
case 't':
wait_timeout = atoi(optarg);
break;
case 'h':
show_usage();
return 1;
break;
default:
show_usage();
return 1;
break;
}
}

/* try to open server in a loop. breaking under certein conditions */

start_timestamp = time(NULL);

while (1) {
if (client_name) {
client = jack_client_open (client_name, options, &status, server_name);
}
else {
client = jack_client_open ("wait", options, &status, server_name);
}
/* check for some real error and bail out */
if ((client == NULL) && !(status & JackServerFailed)) {
fprintf (stderr, "jack_client_open() failed, "
"status = 0x%2.0x\n", status);
return 1;
}

if (client == NULL) {
if (wait_for_quit) {
fprintf(stdout, "server is gone\n");
break;
}
if (just_check) {
fprintf(stdout, "not running\n");
break;
}
} else {
jack_client_close(client);
if (wait_for_start) {
fprintf(stdout, "server is available\n");
break;
}
if (just_check) {
fprintf(stdout, "running\n");
break;
}
}
if (wait_timeout) {
if ((time(NULL) - start_timestamp) > wait_timeout) {
fprintf(stdout, "timeout\n");
exit(EXIT_FAILURE);
}
}

// Wait a second, and repeat
#ifdef WIN32
Sleep(1*1000);
#else
sleep(1);
#endif
}

exit(0);
}

+ 0
- 130
tools/wscript View File

@@ -1,130 +0,0 @@
#! /usr/bin/python3
# encoding: utf-8

example_tools = {
'jack_alias': 'alias.c',
'jack_bufsize': 'bufsize.c',
'jack_connect': 'connect.c',
'jack_evmon': 'evmon.c',
'jack_freewheel': 'freewheel.c',
'jack_load': 'ipload.c',
'jack_lsp': 'lsp.c',
'jack_midi_dump': 'midi_dump.c',
'jack_monitor_client': 'monitor_client.c',
'jack_property': 'property.c',
'jack_samplerate': 'samplerate.c',
'jack_session_notify': 'session_notify.c',
'jack_unload': 'ipunload.c',
'jack_wait': 'wait.c',
}


def configure(conf):
conf.env['BUILD_TOOL_ALSA_IO'] = conf.env['SAMPLERATE'] and conf.env['BUILD_DRIVER_ALSA']
conf.env['BUILD_TOOL_CLIENT_TRANSPORT'] = conf.env['READLINE']
conf.env['BUILD_TOOL_CLIENT_NETSOURCE'] = conf.env['CELT'] or conf.env['OPUS']
conf.env['BUILD_TOOL_ZALSA'] = conf.env['ZALSA']


def build(bld):
if bld.env['IS_LINUX']:
os_incdir = ['../linux', '../posix']
if bld.env['IS_MACOSX']:
os_incdir = ['../macosx', '../posix']
if bld.env['IS_FREEBSD']:
os_incdir = ['../freebsd', '../posix']
if bld.env['IS_SUN']:
os_incdir = ['../solaris', '../posix']
if bld.env['IS_WINDOWS']:
os_incdir = ['../windows']
for example_tool, example_tool_source in list(example_tools.items()):
if bld.env['IS_MACOSX']:
prog = bld(features='c cprogram', framework=['Foundation'])
else:
prog = bld(features='c cprogram')
prog.includes = os_incdir + ['../common/jack', '../common']
prog.source = example_tool_source
prog.use = ['clientlib']
if bld.env['IS_LINUX']:
prog.use += ['RT', 'M']
if bld.env['IS_SUN']:
prog.use += ['M']
if bld.env['IS_WINDOWS'] and bld.env['BUILD_STATIC']:
prog.env['LIB_PTHREAD'] = [':libwinpthread.a']
# prog.cflags = ['-Wno-deprecated-declarations', '-Wno-misleading-indentation']
# prog.cxxflags = ['-Wno-deprecated-declarations', '-Wno-misleading-indentation']

prog.target = example_tool

if bld.env['BUILD_TOOL_CLIENT_TRANSPORT']:
prog = bld(features='c cprogram')
prog.includes = os_incdir + ['../common/jack', '../common']
prog.source = 'transport.c'
prog.use = ['clientlib']
if bld.env['IS_LINUX']:
prog.use += ['RT', 'READLINE']
if bld.env['IS_MACOSX']:
prog.use += ['READLINE']
if bld.env['IS_WINDOWS']:
prog.use += ['READLINE']
if bld.env['BUILD_STATIC']:
prog.env['LIB_PTHREAD'] = [':libwinpthread.a']
prog.target = 'jack_transport'

if bld.env['BUILD_TOOL_CLIENT_NETSOURCE']:
prog = bld(features='c cprogram')
prog.includes = os_incdir + ['.', '..', '../common/jack', '../common']
prog.source = ['netsource.c', '../common/netjack_packet.c']
prog.env.append_value('CFLAGS', '-DNO_JACK_ERROR')
prog.use = ['CELT', 'SAMPLERATE', 'OPUS', 'M', 'clientlib']
prog.target = 'jack_netsource'
prog.defines = ['HAVE_CONFIG_H']

if bld.env['IS_LINUX'] and bld.env['BUILD_TOOL_ALSA_IO']:
prog = bld(features='c cprogram')
prog.includes = os_incdir + ['../common/jack', '../common']
prog.source = ['alsa_in.c', '../common/memops.c']
prog.env.append_value('CFLAGS', '-DNO_JACK_ERROR')
prog.use = ['clientlib', 'ALSA', 'SAMPLERATE', 'M']
prog.target = 'alsa_in'

prog = bld(features='c cprogram')
prog.includes = os_incdir + ['../common/jack', '../common']
prog.source = ['alsa_out.c', '../common/memops.c']
prog.env.append_value('CFLAGS', '-DNO_JACK_ERROR')
prog.use = ['clientlib', 'ALSA', 'SAMPLERATE', 'M']
prog.target = 'alsa_out'

if bld.env['IS_LINUX'] and bld.env['BUILD_TOOL_ZALSA']:
prog = bld(features=['cxx', 'cxxshlib'])
prog.defines = ['HAVE_CONFIG_H', 'SERVER_SIDE', 'APPNAME="zalsa_in"', 'VERSION="0.4.0"']
prog.install_path = '${ADDON_DIR}/'
prog.includes = os_incdir + ['../common/jack', '../common', 'zalsa']
prog.source = [
'zalsa/zita-a2j.cc',
'zalsa/alsathread.cc',
'zalsa/jackclient.cc',
'zalsa/pxthread.cc',
'zalsa/lfqueue.cc',
]
prog.target = 'zalsa_in'
prog.use = ['ZITA-ALSA-PCMI', 'ZITA-RESAMPLER', 'ALSA', 'M', 'RT', 'serverlib']
prog.env['cxxshlib_PATTERN'] = '%s.so'

prog = bld(features=['cxx', 'cxxshlib'])
prog.defines = ['HAVE_CONFIG_H', 'SERVER_SIDE', 'APPNAME="zalsa_out"', 'VERSION="0.4.0"']
prog.install_path = '${ADDON_DIR}/'
prog.includes = os_incdir + ['../common/jack', '../common', 'zalsa']
prog.source = [
'zalsa/zita-j2a.cc',
'zalsa/alsathread.cc',
'zalsa/jackclient.cc',
'zalsa/pxthread.cc',
'zalsa/lfqueue.cc',
]
prog.target = 'zalsa_out'
prog.use = ['ZITA-ALSA-PCMI', 'ZITA-RESAMPLER', 'ALSA', 'M', 'RT', 'serverlib']
prog.env['cxxshlib_PATTERN'] = '%s.so'

if not bld.env['IS_WINDOWS']:
bld.symlink_as('${PREFIX}/bin/jack_disconnect', 'jack_connect')

+ 0
- 226
tools/zalsa/alsathread.cc View File

@@ -1,226 +0,0 @@
// ----------------------------------------------------------------------------
//
// Copyright (C) 2012-2018 Fons Adriaensen <fons@linuxaudio.org>
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------


#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include "alsathread.h"
#include "timers.h"


Alsathread::Alsathread (Alsa_pcmi *alsadev, int mode) :
_alsadev (alsadev ),
_mode (mode),
_state (INIT),
_fsize (alsadev->fsize ()),
_audioq (0),
_commq (0),
_alsaq (0)
{
// Compute DLL filter coefficients.
_dt = (double) _fsize / _alsadev->fsamp ();
_w1 = 2 * M_PI * 0.1 * _dt;
_w2 = _w1 * _w1;
_w1 *= 1.6;
}


Alsathread::~Alsathread (void)
{
if (_state != INIT)
{
_state = TERM;
thr_wait ();
}
else
{
_alsadev->pcm_stop ();
}
}


int Alsathread::start (Lfq_audio *audioq, Lfq_int32 *commq, Lfq_adata *alsaq, int rtprio)
{
// Start the ALSA thread.
_audioq = audioq;
_commq = commq;
_alsaq = alsaq;
_state = WAIT;
if (thr_start (SCHED_FIFO, rtprio, 0x10000)) return 1;
return 0;
}


void Alsathread::send (int k, double t)
{
Adata *D;

// Send (state, frame count, timestamp) to Jack thread.
if (_alsaq->wr_avail ())
{
D = _alsaq->wr_datap ();
D->_state = _state;
D->_nsamp = k;
D->_timer = t;
_alsaq->wr_commit ();
}
}


// The following two functions transfer data between the audio queue
// and the ALSA device. Note that we do *not* check the queue's fill
// state, and it may overrun or underrun. It actually will in the first
// few iterations and in error conditions. This is entirely intentional.
// The queue keeps correct read and write counters even in that case,
// and the main control loop and error recovery depend on it working
// and being used in this way.

int Alsathread::capture (void)
{
int c, n, k;
float *p;

// Start reading from ALSA device.
_alsadev->capt_init (_fsize);
if (_state == PROC)
{
// Input frames from the ALSA device to the audio queue.
// The outer loop takes care of wraparound.
for (n = _fsize; n; n -= k)
{
p = _audioq->wr_datap (); // Audio queue write pointer.
k = _audioq->wr_linav (); // Number of frames that can be
if (k > n) k = n; // written without wraparound.
for (c = 0; c < _audioq->nchan (); c++)
{
// Copy and interleave one channel.
_alsadev->capt_chan (c, p + c, k, _audioq->nchan ());
}
_audioq->wr_commit (k); // Update audio queue state.
}
}
// Finish reading from ALSA device.
_alsadev->capt_done (_fsize);
return _fsize;
}


int Alsathread::playback (void)
{
int c, n, k;
float *p;

// Start writing to ALSA device.
_alsadev->play_init (_fsize);
c = 0;
if (_state == PROC)
{
// Output frames from the audio queue to the ALSA device.
// The outer loop takes care of wraparound.
for (n = _fsize; n; n -= k)
{
p = _audioq->rd_datap (); // Audio queue read pointer.
k = _audioq->rd_linav (); // Number of frames that can
if (k > n) k = n; // be read without wraparound.
for (c = 0; c < _audioq->nchan (); c++)
{
// De-interleave and copy one channel.
_alsadev->play_chan (c, p + c, k, _audioq->nchan ());
}
_audioq->rd_commit (k); // Update audio queue state.
}
}
// Clear all or remaining channels.
while (c < _alsadev->nplay ()) _alsadev->clear_chan (c++, _fsize);
// Finish writing to ALSA device.
_alsadev->play_done (_fsize);
return _fsize;
}


void Alsathread::thr_main (void)
{
int na, nu;
double tw, er;

_alsadev->pcm_start ();
while (_state != TERM)
{
// Wait for next cycle, then take timestamp.
na = _alsadev->pcm_wait ();

tw = tjack (jack_get_time ());
// Check for errors - requires restart.
if (_alsadev->state () && (na == 0))
{
_state = WAIT;
send (0, 0);
usleep (10000);
continue;
}
// Check for commands from the Jack thread.
if (_commq->rd_avail ())
{
_state = _commq->rd_int32 ();
if (_state == PROC) _first = true;
if (_state == TERM) send (0, 0);
}

// We could have more than one period.
nu = 0;
while (na >= _fsize)
{
// Transfer frames.
if (_mode == PLAY) nu += playback ();
else nu += capture ();
// Update loop condition.
na -= _fsize;
// Run the DLL if in PROC state.
if (_state == PROC)
{
if (_first)
{
// Init DLL in first iteration.
_first = false;
_dt = (double) _fsize / _alsadev->fsamp ();
_t0 = tw;
_t1 = tw + _dt;
}
else
{
// Update the DLL.
// If we have more than one period, use
// the time error only for the last one.
if (na >= _fsize) er = 0;
else er = tjack_diff (tw, _t1);
_t0 = _t1;
_t1 = tjack_diff (_t1 + _dt + _w1 * er, 0.0);
_dt += _w2 * er;
}
}
}

// Send number of frames used and timestamp to Jack thread.
if (_state == PROC) send (nu, _t1);
}
_alsadev->pcm_stop ();
}

+ 0
- 68
tools/zalsa/alsathread.h View File

@@ -1,68 +0,0 @@
// ----------------------------------------------------------------------------
//
// Copyright (C) 2012-2018 Fons Adriaensen <fons@linuxaudio.org>
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------


#ifndef __ALSATHREAD_H
#define __ALSATHREAD_H


#include <zita-alsa-pcmi.h>
#include "jack/jack.h"
#include "pxthread.h"
#include "lfqueue.h"


class Alsathread : public Pxthread
{
public:

enum { INIT, WAIT, PROC, TERM };
enum { PLAY, CAPT };

Alsathread (Alsa_pcmi *alsadev, int mode);
virtual ~Alsathread (void);
virtual void thr_main (void);

int start (Lfq_audio *audioq, Lfq_int32 *commq, Lfq_adata *alsaq, int rtprio);

private:

void send (int k, double t);
int capture (void);
int playback (void);
Alsa_pcmi *_alsadev;
int _mode;
int _state;
int _nfail;
int _fsize;
Lfq_audio *_audioq;
Lfq_int32 *_commq;
Lfq_adata *_alsaq;
bool _first;
// double _jtmod;
double _t0;
double _t1;
double _dt;
double _w1;
double _w2;
};


#endif

+ 0
- 549
tools/zalsa/jackclient.cc View File

@@ -1,549 +0,0 @@
// ----------------------------------------------------------------------------
//
// Copyright (C) 2012-2018 Fons Adriaensen <fons@linuxaudio.org>
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------


#include <stdio.h>
#include <math.h>
#include "jackclient.h"
#include "alsathread.h"
#include "timers.h"


Jackclient::Jackclient (jack_client_t* cl, const char *jserv, int mode, int nchan, bool sync, void *arg) :
_client (cl),
_arg (arg),
_mode (mode),
_nchan (nchan),
_state (INIT),
_freew (false),
_resamp (0)
{
init (jserv);
if (!sync) _resamp = new VResampler ();
}


Jackclient::~Jackclient (void)
{
fini ();
}


bool Jackclient::init (const char *jserv)
{
int i, spol, flags;
char s [64];
struct sched_param spar;

if (_client == 0)
{
fprintf (stderr, "Can't connect to Jack, is the server running ?\n");
return false;
}
jack_set_process_callback (_client, jack_static_process, (void *) this);
jack_set_latency_callback (_client, jack_static_latency, (void *) this);
jack_set_freewheel_callback (_client, jack_static_freewheel, (void *) this);
jack_set_buffer_size_callback (_client, jack_static_buffsize, (void *) this);
jack_on_shutdown (_client, jack_static_shutdown, (void *) this);

_bsize = 0;
_fsamp = 0;
if (jack_activate (_client))
{
fprintf(stderr, "Can't activate Jack");
return false;
}
_jname = jack_get_client_name (_client);
_bsize = jack_get_buffer_size (_client);
_fsamp = jack_get_sample_rate (_client);

flags = JackPortIsTerminal | JackPortIsPhysical;
for (i = 0; i < _nchan; i++)
{
if (_mode == PLAY)
{
sprintf (s, "playback_%d", i + 1);
_ports [i] = jack_port_register (_client, s, JACK_DEFAULT_AUDIO_TYPE,
flags | JackPortIsInput, 0);
}
else
{
sprintf (s, "capture_%d", i + 1);
_ports [i] = jack_port_register (_client, s, JACK_DEFAULT_AUDIO_TYPE,
flags | JackPortIsOutput, 0);
}
}
pthread_getschedparam (jack_client_thread_id (_client), &spol, &spar);
_rprio = spar.sched_priority - sched_get_priority_max (spol);
_buff = new float [_bsize * _nchan];
return true;
}


void Jackclient::fini (void)
{
delete[] _buff;
delete _resamp;
}


void Jackclient::jack_static_shutdown (void *arg)
{
((Jackclient *) arg)->sendinfo (TERM, 0, 0);
}


int Jackclient::jack_static_buffsize (jack_nframes_t nframes, void *arg)
{
Jackclient *J = (Jackclient *) arg;

if (J->_bsize == 0) J->_bsize = nframes;
else if (J->_bsize != (int) nframes) J->_state = Jackclient::TERM;
return 0;
}


void Jackclient::jack_static_freewheel (int state, void *arg)
{
((Jackclient *) arg)->jack_freewheel (state);
}


void Jackclient::jack_static_latency (jack_latency_callback_mode_t jlcm, void *arg)
{
((Jackclient *) arg)->jack_latency (jlcm);
}


int Jackclient::jack_static_process (jack_nframes_t nframes, void *arg)
{
return ((Jackclient *) arg)->jack_process (nframes);
}


void Jackclient::start (Lfq_audio *audioq,
Lfq_int32 *commq,
Lfq_adata *alsaq,
Lfq_jdata *infoq,
double ratio,
int delay,
int ltcor,
int rqual)
{
double d;

_audioq = audioq;
_commq = commq;
_alsaq = alsaq;
_infoq = infoq;
_ratio = ratio;
_delay = delay;
_rcorr = 1.0;
if (_resamp)
{
_resamp->setup (_ratio, _nchan, rqual);
_resamp->set_rrfilt (100);
d = _resamp->inpsize () / 2.0;
if (_mode == PLAY) d *= _ratio;
_delay += d;
}
_ltcor = ltcor;
_ppsec = (_fsamp + _bsize / 2) / _bsize;
initwait (_ppsec / 2);
jack_recompute_total_latencies (_client);
}


void Jackclient::initwait (int nwait)
{
_count = -nwait;
_commq->wr_int32 (Alsathread::WAIT);
_state = WAIT;
if (nwait > _ppsec) sendinfo (WAIT, 0, 0);
}


void Jackclient::initsync (void)
{
// Reset all lock-free queues.
_commq->reset ();
_alsaq->reset ();
_audioq->reset ();
if (_resamp)
{
// Reset and prefill the resampler.
_resamp->reset ();
_resamp->inp_count = _resamp->inpsize () / 2 - 1;
_resamp->out_count = 99999;
_resamp->process ();
}
// Initialise state variables.
_t_a0 = _t_a1 = 0;
_k_a0 = _k_a1 = 0;
// Initialise loop filter state.
_z1 = _z2 = _z3 = 0;
// Activate the ALSA thread,
_commq->wr_int32 (Alsathread::PROC);
_state = SYNC0;
sendinfo (SYNC0, 0, 0);
}


void Jackclient::setloop (double bw)
{
double w;

// Set the loop bandwidth to bw Hz.
w = 6.28 * bw * _bsize / _fsamp;
_w0 = 1.0 - exp (-20.0 * w);
_w1 = w * 2 / _bsize;
_w2 = w / 2;
if (_mode == PLAY) _w1 /= _ratio;
else _w1 *= _ratio;
}


void Jackclient::playback (int nframes)
{
int i, j, n;
float *p, *q;
float *inp [MAXCHAN];

_bstat = _audioq->rd_avail ();
for (i = 0; i < _nchan; i++)
{
inp [i] = (float *)(jack_port_get_buffer (_ports [i], nframes));
}
if (_resamp)
{
// Interleave inputs into _buff.
for (i = 0; i < _nchan; i++)
{
p = inp [i];
q = _buff + i;
for (j = 0; j < _bsize; j++) q [j * _nchan] = p [j];
}
// Resample _buff and write to audio queue.
// The while loop takes care of wraparound.
_resamp->inp_count = _bsize;
_resamp->inp_data = _buff;
while (_resamp->inp_count)
{
_resamp->out_count = _audioq->wr_linav ();
_resamp->out_data = _audioq->wr_datap ();
n = _resamp->out_count;
_resamp->process ();
n -= _resamp->out_count;
_audioq->wr_commit (n);
}
}
else
{
// Interleave inputs into audio queue.
// The while loop takes care of wraparound.
while (nframes)
{
q = _audioq->wr_datap ();
n = _audioq->wr_linav ();
if (n > nframes) n = nframes;
for (i = 0; i < _nchan; i++)
{
p = inp [i];
for (j = 0; j < n; j++) q [j * _nchan] = p [j];
inp [i] += n;
q += 1;
}
_audioq->wr_commit (n);
nframes -= n;
}
}
}


void Jackclient::capture (int nframes)
{
int i, j, n;
float *p, *q;
float *out [MAXCHAN];

for (i = 0; i < _nchan; i++)
{
out [i] = (float *)(jack_port_get_buffer (_ports [i], nframes));
}
if (_resamp)
{
// Read from audio queue and resample.
// The while loop takes care of wraparound.
_resamp->out_count = _bsize;
_resamp->out_data = _buff;
while (_resamp->out_count)
{
_resamp->inp_count = _audioq->rd_linav ();
_resamp->inp_data = _audioq->rd_datap ();
n = _resamp->inp_count;
_resamp->process ();
n -= _resamp->inp_count;
_audioq->rd_commit (n);
}
// Deinterleave _buff to outputs.
for (i = 0; i < _nchan; i++)
{
p = _buff + i;
q = out [i];
for (j = 0; j < _bsize; j++) q [j] = p [j * _nchan];
}
}
else
{
// Deinterleave audio queue to outputs.
// The while loop takes care of wraparound.
while (nframes)
{
p = _audioq->rd_datap ();
n = _audioq->rd_linav ();
if (n > nframes) n = nframes;
for (i = 0; i < _nchan; i++)
{
q = out [i];
for (j = 0; j < n; j++) q [j] = p [j * _nchan];
out [i] += n;
p += 1;
}
_audioq->rd_commit (n);
nframes -= n;
}
}
_bstat = _audioq->rd_avail ();
}


void Jackclient::silence (int nframes)
{
int i;
float *q;

// Write silence to all jack ports.
for (i = 0; i < _nchan; i++)
{
q = (float *)(jack_port_get_buffer (_ports [i], nframes));
memset (q, 0, nframes * sizeof (float));
}
}


void Jackclient::sendinfo (int state, double error, double ratio)
{
Jdata *J;

if (_infoq->wr_avail ())
{
J = _infoq->wr_datap ();
J->_state = state;
J->_error = error;
J->_ratio = ratio;
J->_bstat = _bstat;
_infoq->wr_commit ();
}
}


void Jackclient::jack_freewheel (int state)
{
_freew = state ? true : false;
if (_freew) initwait (_ppsec / 4);
}


void Jackclient::jack_latency (jack_latency_callback_mode_t jlcm)
{
jack_latency_range_t R;
int i;

if (_state < WAIT) return;
if (_mode == PLAY)
{
if (jlcm != JackPlaybackLatency) return;
R.min = R.max = (int)(_delay / _ratio) + _ltcor;
}
else
{
if (jlcm != JackCaptureLatency) return;
R.min = R.max = (int)(_delay * _ratio) + _ltcor;
}
for (i = 0; i < _nchan; i++)
{
jack_port_set_latency_range (_ports [i], jlcm, &R);
}
}


int Jackclient::jack_process (int nframes)
{
int dk, n;
Adata *D;
jack_time_t t0, t1;
jack_nframes_t ft;
float us;
double tj, err, d1, d2, rd;

// Buffer size change or other evil.
if (_state == TERM)
{
sendinfo (TERM, 0, 0);
return 0;
}
// Skip cylce if ports may not yet exist.
if (_state < WAIT) return 0;

// Start synchronisation 1/2 second after entering
// the WAIT state. This delay allows the ALSA thread
// to restart cleanly if necessary. Disabled while
// freewheeling.
if (_state == WAIT)
{
if (_freew) return 0;
if (_mode == CAPT) silence (nframes);
if (++_count == 0) initsync ();
else return 0;
}

// Get the start time of the current cycle.
jack_get_cycle_times (_client, &ft, &t0, &t1, &us);
tj = tjack (t0);

// Check for any skipped cycles.
if (_state >= SYNC1)
{
dk = ft - _ft - _bsize;
if (_mode == PLAY)
{
dk = (int)(dk * _ratio + 0.5);
_audioq->wr_commit (dk);
}
else
{
dk = (int)(dk / _ratio + 0.5);
_audioq->rd_commit (dk);
}
}
_ft = ft;
// Check if we have timing data from the ALSA thread.
n = _alsaq->rd_avail ();
// If the data queue is full restart synchronisation.
// This can happen e.g. on a jack engine timeout, or
// when too many cycles have been skipped.
if (n == _alsaq->size ())
{
initwait (_ppsec / 2);
return 0;
}
if (n)
{
// Else move interval end to start, and update the
// interval end keeping only the most recent data.
if (_state < SYNC2) _state++;
_t_a0 = _t_a1;
_k_a0 = _k_a1;
while (_alsaq->rd_avail ())
{
D = _alsaq->rd_datap ();
// Restart synchronisation in case of
// an error in the ALSA interface.
if (D->_state == Alsathread::WAIT)
{
initwait (_ppsec / 2);
return 0;
}
_t_a1 = D->_timer;
_k_a1 += D->_nsamp;
_alsaq->rd_commit ();
}
}

err = 0;
if (_state >= SYNC2)
{
// Compute the delay error.
d1 = tjack_diff (tj, _t_a0);
d2 = tjack_diff (_t_a1, _t_a0);
rd = _resamp ? _resamp->inpdist () : 0.0;

if (_mode == PLAY)
{
n = _audioq->nwr () - _k_a0; // Must be done as integer as both terms will overflow.
err = n - (_k_a1 - _k_a0) * d1 / d2 + rd * _ratio - _delay;
}
else
{
n = _k_a0 - _audioq->nrd (); // Must be done as integer as both terms will overflow.
err = n + (_k_a1 - _k_a0) * d1 / d2 + rd - _delay ;
}
n = (int)(floor (err + 0.5));
if (_state == SYNC2)
{
// We have the first delay error value. Adjust the audio
// queue to obtain the actually wanted delay, and start
// tracking.
if (_mode == PLAY) _audioq->wr_commit (-n);
else _audioq->rd_commit (n);
err -= n;
setloop (1.0);
_state = PROC1;
}
}

// Switch to lower bandwidth after 4 seconds.
if ((_state == PROC1) && (++_count == 4 * _ppsec))
{
_state = PROC2;
setloop (0.05);
}

if (_state >= PROC1)
{
_z1 += _w0 * (_w1 * err - _z1);
_z2 += _w0 * (_z1 - _z2);
_z3 += _w2 * _z2;
// Check error conditions.
if (fabs (_z3) > 0.05)
{
// Something is really wrong, wait 10 seconds then restart.
initwait (10 * _ppsec);
return 0;
}
// Run loop filter and set resample ratio.
if (_resamp)
{
_rcorr = 1 - (_z2 + _z3);
if (_rcorr > 1.05) _rcorr = 1.05;
if (_rcorr < 0.95) _rcorr = 0.95;
_resamp->set_rratio (_rcorr);
}
sendinfo (_state, err, _rcorr);

// Resample and transfer between audio
// queue and jack ports.
if (_mode == PLAY) playback (nframes);
else capture (nframes);
}
else if (_mode == CAPT) silence (nframes);

return 0;
}

+ 0
- 120
tools/zalsa/jackclient.h View File

@@ -1,120 +0,0 @@
// ----------------------------------------------------------------------------
//
// Copyright (C) 2012-2018 Fons Adriaensen <fons@linuxaudio.org>
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------


#ifndef __JACKCLIENT_H
#define __JACKCLIENT_H


#include <zita-resampler/vresampler.h>
#include "jack/jack.h"
#include "lfqueue.h"


class Jackclient
{
public:

Jackclient (jack_client_t*, const char *jserv, int mode, int nchan, bool sync, void *arg);
virtual ~Jackclient (void);
enum { PLAY, CAPT, MAXCHAN = 64 };
enum { INIT, TERM, WAIT, SYNC0, SYNC1, SYNC2, PROC1, PROC2 };

void start (Lfq_audio *audioq,
Lfq_int32 *commq,
Lfq_adata *alsaq,
Lfq_jdata *infoq,
double ratio,
int delay,
int ltcor,
int rqual);

const char *jname (void) const { return _jname; }
int fsamp (void) const { return _fsamp; }
int bsize (void) const { return _bsize; }
int rprio (void) const { return _rprio; }
void *getarg(void) const { return _arg; }

private:

bool init (const char *jserv);
void fini (void);
void initwait (int nwait);
void initsync (void);
void setloop (double bw);
void silence (int nframes);
void playback (int nframes);
void capture (int nframes);
void sendinfo (int state, double error, double ratio);

virtual void thr_main (void) {}

void jack_freewheel (int state);
void jack_latency (jack_latency_callback_mode_t jlcm);
int jack_process (int nframes);

jack_client_t *_client;
jack_port_t *_ports [MAXCHAN];
void *_arg;
const char *_jname;
int _mode;
int _nchan;
int _state;
int _count;
int _fsamp;
int _bsize;
int _rprio;
bool _freew;
float *_buff;
Lfq_audio *_audioq;
Lfq_int32 *_commq;
Lfq_adata *_alsaq;
Lfq_jdata *_infoq;
double _ratio;
int _ppsec;
int _bstat;

jack_nframes_t _ft;
double _t_a0;
double _t_a1;
int _k_a0;
int _k_a1;
double _delay;
int _ltcor;

double _w0;
double _w1;
double _w2;
double _z1;
double _z2;
double _z3;
double _rcorr;
VResampler *_resamp;

static void jack_static_shutdown (void *arg);
static int jack_static_buffsize (jack_nframes_t nframes, void *arg);
static void jack_static_freewheel (int state, void *arg);
static void jack_static_latency (jack_latency_callback_mode_t jlcm, void *arg);
static int jack_static_process (jack_nframes_t nframes, void *arg);
};


#endif

+ 0
- 89
tools/zalsa/lfqueue.cc View File

@@ -1,89 +0,0 @@
// ----------------------------------------------------------------------------
//
// Copyright (C) 2012 Fons Adriaensen <fons@linuxaudio.org>
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------


#include <assert.h>
#include "lfqueue.h"


Lfq_adata::Lfq_adata (int size) :
_size (size),
_mask (size - 1),
_nwr (0),
_nrd (0)
{
assert (!(_size & _mask));
_data = new Adata [_size];
}

Lfq_adata::~Lfq_adata (void)
{
delete[] _data;
}


Lfq_jdata::Lfq_jdata (int size) :
_size (size),
_mask (size - 1),
_nwr (0),
_nrd (0)
{
assert (!(_size & _mask));
_data = new Jdata [_size];
}

Lfq_jdata::~Lfq_jdata (void)
{
delete[] _data;
}


Lfq_int32::Lfq_int32 (int size) :
_size (size),
_mask (size - 1),
_nwr (0),
_nrd (0)
{
assert (!(_size & _mask));
_data = new int32_t [_size];
}

Lfq_int32::~Lfq_int32 (void)
{
delete[] _data;
}


Lfq_audio::Lfq_audio (int nsamp, int nchan) :
_size (nsamp),
_mask (nsamp - 1),
_nch (nchan),
_nwr (0),
_nrd (0)
{
assert (!(_size & _mask));
_data = new float [_nch * _size];
}

Lfq_audio::~Lfq_audio (void)
{
delete[] _data;
}



+ 0
- 182
tools/zalsa/lfqueue.h View File

@@ -1,182 +0,0 @@
// ----------------------------------------------------------------------------
//
// Copyright (C) 2012 Fons Adriaensen <fons@linuxaudio.org>
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------


#ifndef __LFQUEUE_H
#define __LFQUEUE_H


#include <stdint.h>
#include <string.h>


class Adata
{
public:

int32_t _state;
int32_t _nsamp;
double _timer;
};


class Lfq_adata
{
public:

Lfq_adata (int size);
~Lfq_adata (void);

void reset (void) { _nwr = _nrd = 0; }
int size (void) const { return _size; }

int wr_avail (void) const { return _size - _nwr + _nrd; }
Adata *wr_datap (void) { return _data + (_nwr & _mask); }
void wr_commit (void) { _nwr++; }

int rd_avail (void) const { return _nwr - _nrd; }
Adata *rd_datap (void) { return _data + (_nrd & _mask); }
void rd_commit (void) { _nrd++; }

private:

Adata *_data;
int _size;
int _mask;
int _nwr;
int _nrd;
};


class Jdata
{
public:

int32_t _state;
double _error;
double _ratio;
int _bstat;
};


class Lfq_jdata
{
public:

Lfq_jdata (int size);
~Lfq_jdata (void);

void reset (void) { _nwr = _nrd = 0; }
int size (void) const { return _size; }

int wr_avail (void) const { return _size - _nwr + _nrd; }
Jdata *wr_datap (void) { return _data + (_nwr & _mask); }
void wr_commit (void) { _nwr++; }

int rd_avail (void) const { return _nwr - _nrd; }
Jdata *rd_datap (void) { return _data + (_nrd & _mask); }
void rd_commit (void) { _nrd++; }

private:

Jdata *_data;
int _size;
int _mask;
int _nwr;
int _nrd;
};


class Lfq_int32
{
public:

Lfq_int32 (int size);
~Lfq_int32 (void);

int size (void) const { return _size; }
void reset (void) { _nwr = _nrd = 0; }

int wr_avail (void) const { return _size - _nwr + _nrd; }
int32_t *wr_datap (void) { return _data + (_nwr & _mask); }
void wr_commit (void) { _nwr++; }

int rd_avail (void) const { return _nwr - _nrd; }
int32_t *rd_datap (void) { return _data + (_nrd & _mask); }
void rd_commit (void) { _nrd++; }

void wr_int32 (int32_t v) { _data [_nwr++ & _mask] = v; }
void wr_uint32 (uint32_t v) { _data [_nwr++ & _mask] = v; }
void wr_float (float v) { *(float *)(_data + (_nwr++ & _mask)) = v; }

int32_t rd_int32 (void) { return _data [_nrd++ & _mask]; }
int32_t rd_uint32 (void) { return _data [_nrd++ & _mask]; }
float rd_float (void) { return *(float *)(_data + (_nrd++ & _mask)); }

private:

int32_t *_data;
int _size;
int _mask;
int _nwr;
int _nrd;
};


class Lfq_audio
{
public:

Lfq_audio (int nsamp, int nchan);
~Lfq_audio (void);

int size (void) const { return _size; }
void reset (void)
{
_nwr = _nrd = 0;
memset (_data, 0, _size * _nch * sizeof (float));
}

int nchan (void) const { return _nch; }
int nwr (void) const { return _nwr; };
int nrd (void) const { return _nrd; };

int wr_avail (void) const { return _size - _nwr + _nrd; }
int wr_linav (void) const { return _size - (_nwr & _mask); }
float *wr_datap (void) { return _data + _nch * (_nwr & _mask); }
void wr_commit (int k) { _nwr += k; }

int rd_avail (void) const { return _nwr - _nrd; }
int rd_linav (void) const { return _size - (_nrd & _mask); }
float *rd_datap (void) { return _data + _nch * (_nrd & _mask); }
void rd_commit (int k) { _nrd += k; }

private:

float *_data;
int _size;
int _mask;
int _nch;
int _nwr;
int _nrd;
};


#endif


+ 0
- 87
tools/zalsa/pxthread.cc View File

@@ -1,87 +0,0 @@
// ----------------------------------------------------------------------------
//
// Copyright (C) 2012 Fons Adriaensen <fons@linuxaudio.org>
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------


#include "pxthread.h"


Pxthread::Pxthread (void) : _thrid (0)
{
}


Pxthread::~Pxthread (void)
{
}


extern "C" void *Pxthread_entry_point (void *arg)
{
Pxthread *T = (Pxthread *) arg;
T->thr_main ();
return NULL;
}


int Pxthread::thr_start (int policy, int priority, size_t stacksize)
{
int min, max, rc;
pthread_attr_t attr;
struct sched_param parm;

min = sched_get_priority_min (policy);
max = sched_get_priority_max (policy);
priority += max;
if (priority > max) priority = max;
if (priority < min) priority = min;
parm.sched_priority = priority;

pthread_attr_init (&attr);
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
pthread_attr_setschedpolicy (&attr, policy);
pthread_attr_setschedparam (&attr, &parm);
pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED);
pthread_attr_setstacksize (&attr, stacksize);

_thrid = 0;
rc = pthread_create (&_thrid,
&attr,
Pxthread_entry_point,
this);

pthread_attr_destroy (&attr);

return rc;
}


void Pxthread::thr_main (void)
{
}


void Pxthread::thr_wait (void)
{
if (_thrid == 0)
return;
pthread_join (_thrid, NULL);
_thrid = 0;
}


+ 0
- 53
tools/zalsa/pxthread.h View File

@@ -1,53 +0,0 @@
// ----------------------------------------------------------------------------
//
// Copyright (C) 2012 Fons Adriaensen <fons@linuxaudio.org>
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------


#ifndef __PXTHREAD_H
#define __PXTHREAD_H


#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <errno.h>
#include <pthread.h>


class Pxthread
{
public:

Pxthread (void);
virtual ~Pxthread (void);
Pxthread (const Pxthread&);
Pxthread& operator=(const Pxthread&);

virtual void thr_main (void) = 0;
virtual int thr_start (int policy, int priority, size_t stacksize = 0);
virtual void thr_wait (void);

private:
pthread_t _thrid;
};


#endif

+ 0
- 53
tools/zalsa/timers.h View File

@@ -1,53 +0,0 @@
// ----------------------------------------------------------------------------
//
// Copyright (C) 2012-2018 Fons Adriaensen <fons@linuxaudio.org>
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------


#ifndef __TIMERS_H
#define __TIMERS_H


#include <math.h>
#include <sys/time.h>
#include <jack/jack.h>


#define tjack_mod ldexp (1e-6f, 32)



inline double tjack_diff (double a, double b)
{
double d, m;

d = a - b;
m = tjack_mod;
while (d < -m / 2) d += m;
while (d >= m / 2) d -= m;
return d;
}


inline double tjack (jack_time_t t, double dt = 0)
{
int32_t u = (int32_t)(t & 0xFFFFFFFFLL);
return 1e-6 * u;
}


#endif

+ 0
- 409
tools/zalsa/zita-a2j.cc View File

@@ -1,409 +0,0 @@
// ----------------------------------------------------------------------------
//
// Copyright (C) 2012 Fons Adriaensen <fons@linuxaudio.org>
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------


#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <signal.h>
#include "alsathread.h"
#include "jackclient.h"
#include "lfqueue.h"
#include "jack/control.h"

static const char *clopt = "hvLSwj:d:r:p:n:c:Q:I:";

static void help (void)
{
jack_info ("%s-%s", APPNAME, VERSION);
jack_info ("(C) 2012-2018 Fons Adriaensen <fons@linuxaudio.org>");
jack_info ("Use ALSA capture device as a Jack client.");
jack_info ("Options:");
jack_info (" -h Display this text");
jack_info (" -j <jackname> Name as Jack client [%s]", APPNAME);
jack_info (" -d <device> ALSA capture device [none]");
jack_info (" -r <rate> Sample rate [48000]");
jack_info (" -p <period> Period size [256]");
jack_info (" -n <nfrags> Number of fragments [2]");
jack_info (" -c <nchannels> Number of channels [2]");
jack_info (" -S Word clock sync, no resampling");
jack_info (" -Q <quality> Resampling quality, 16..96 [auto]");
jack_info (" -I <samples> Latency adjustment [0]");
jack_info (" -L Force 16-bit and 2 channels [off]");
jack_info (" -w Wait until soundcard is available [off]");
jack_info (" -v Print tracing information [off]");
}

class zita_a2j
{
Lfq_int32 *commq;
Lfq_adata *alsaq;
Lfq_jdata *infoq;
Lfq_audio *audioq;
bool stop;
bool v_opt;
bool L_opt;
bool S_opt;
bool w_opt;
char *jname;
char *device;
int fsamp;
int bsize;
int nfrag;
int nchan;
int rqual;
int ltcor;

public:

zita_a2j()
{
commq = new Lfq_int32(16);
alsaq = new Lfq_adata(256);
infoq = new Lfq_jdata(256);
audioq = 0;
stop = false;
v_opt = false;
L_opt = false;
S_opt = false;
w_opt = false;
jname = strdup(APPNAME);
device = 0;
fsamp = 48000;
bsize = 128;
nfrag = 2;
nchan = 2;
rqual = 0;
ltcor = 0;
A = 0;
C = 0;
J = 0;
t = 0;
}

private:

int procoptions (int ac, const char *av [])
{
int k;
optind = 1;
opterr = 0;
while ((k = getopt (ac, (char **) av, (char *) clopt)) != -1)
{
if (optarg && (*optarg == '-'))
{
jack_error (APPNAME ": Missing argument for '-%c' option.", k);
jack_error (APPNAME ": Use '-h' to see all options.");
return 1;
}
switch (k)
{
case 'h' : help (); return 1;
case 'v' : v_opt = true; break;
case 'L' : L_opt = true; break;
case 'S' : S_opt = true; break;
case 'w' : w_opt = true; break;
case 'j' : jname = optarg; break;
case 'd' : device = optarg; break;
case 'r' : fsamp = atoi (optarg); break;
case 'p' : bsize = atoi (optarg); break;
case 'n' : nfrag = atoi (optarg); break;
case 'c' : nchan = atoi (optarg); break;
case 'Q' : rqual = atoi (optarg); break;
case 'I' : ltcor = atoi (optarg); break;
case '?':
if (optopt != ':' && strchr (clopt, optopt))
{
jack_error (APPNAME ": Missing argument for '-%c' option.", optopt);
}
else if (isprint (optopt))
{
jack_error (APPNAME ": Unknown option '-%c'.", optopt);
}
else
{
jack_error (APPNAME ": Unknown option character '0x%02x'.", optopt & 255);
}
jack_error (APPNAME ": Use '-h' to see all options.");
return 1;
default:
return 1;
}
}
return 0;
}

int parse_options (const char* load_init)
{
int argsz;
int argc = 0;
const char** argv;
char* args = strdup (load_init);
char* token;
char* ptr = args;
char* savep;

if (!load_init) {
return 0;
}

argsz = 8; /* random guess at "maxargs" */
argv = (const char **) malloc (sizeof (char *) * argsz);

argv[argc++] = APPNAME;

while (1) {

if ((token = strtok_r (ptr, " ", &savep)) == NULL) {
break;
}

if (argc == argsz) {
argsz *= 2;
argv = (const char **) realloc (argv, sizeof (char *) * argsz);
}

argv[argc++] = token;
ptr = NULL;
}

return procoptions (argc, argv);
}

void printinfo (void)
{
int n, k;
double e, r;
Jdata *J;

n = 0;
k = 99999;
e = r = 0;
while (infoq->rd_avail ())
{
J = infoq->rd_datap ();
if (J->_state == Jackclient::TERM)
{
jack_error (APPNAME ": Fatal error condition, terminating.");
stop = true;
return;
}
else if (J->_state == Jackclient::WAIT)
{
jack_info (APPNAME ": Detected excessive timing errors, waiting 10 seconds.");
n = 0;
}
else if (J->_state == Jackclient::SYNC0)
{
jack_info (APPNAME ": Starting synchronisation.");
}
else if (v_opt)
{
n++;
e += J->_error;
r += J->_ratio;
if (J->_bstat < k) k = J->_bstat;
}
infoq->rd_commit ();
}
if (n) jack_info (APPNAME ": %8.3lf %10.6lf %5d", e / n, r / n, k);
}


Alsa_pcmi *A;
Alsathread *C;
Jackclient *J;

pthread_t t;
int topts;

static void* _retry_alsa_pcmi (void *arg)
{
((zita_a2j*)arg)->retry_alsa_pcmi ();
return NULL;
}

void retry_alsa_pcmi ()
{
Alsa_pcmi *a;

while (! stop)
{
sleep(1);

a = new Alsa_pcmi (0, device, 0, fsamp, bsize, nfrag, topts);
if (a->state ())
{
delete a;
continue;
}

A = a;
if (v_opt) A->printinfo ();
C = new Alsathread (A, Alsathread::CAPT);
usleep (100*1000);
jack_initialize_part2 ();
jack_info (APPNAME ": Device is now available and has been activated");
break;
}

t = 0;
}

public:

int
jack_initialize (jack_client_t* client, const char* load_init)
{
int opts;

if (parse_options (load_init)) {
jack_error (APPNAME ": parse options failed");
delete this;
return 1;
}

if (device == 0)
{
help ();
delete this;
return 1;
}
if (rqual < 16) rqual = 16;
if (rqual > 96) rqual = 96;
if ((fsamp < 8000) || (bsize < 16) || (nfrag < 2) || (nchan < 1))
{
jack_error (APPNAME ": Illegal parameter value(s).");
delete this;
return 1;
}

opts = 0;
if (v_opt) opts |= Alsa_pcmi::DEBUG_ALL;
if (L_opt) opts |= Alsa_pcmi::FORCE_16B | Alsa_pcmi::FORCE_2CH;
if (w_opt)
{
J = new Jackclient (client, 0, Jackclient::CAPT, nchan, S_opt, this);
A = new Alsa_pcmi (0, device, 0, fsamp, bsize, nfrag, opts);

// if device is not available, spawn thread to keep trying
if (A->state ())
{
delete A;
A = NULL;
topts = opts;
pthread_create (&t, NULL, _retry_alsa_pcmi, this);
jack_info (APPNAME ": Could not open device, will keep trying in new thread...");
return 0;
}

// otherwise continue as normal
if (v_opt) A->printinfo ();
C = new Alsathread (A, Alsathread::CAPT);
}
else
{
A = new Alsa_pcmi (0, device, 0, fsamp, bsize, nfrag, opts);
if (A->state ())
{
jack_error (APPNAME ": Can't open ALSA capture device '%s'.", device);
delete this;
return 1;
}
if (v_opt) A->printinfo ();
if (nchan > A->ncapt ())
{
nchan = A->ncapt ();
jack_error (APPNAME ": Warning: only %d channels are available.", nchan);
}
C = new Alsathread (A, Alsathread::CAPT);
J = new Jackclient (client, 0, Jackclient::CAPT, nchan, S_opt, this);
}

usleep (100*1000);
jack_initialize_part2 ();
return 0;
}

void jack_initialize_part2 ()
{
int k, k_del;
double t_alsa;
double t_jack;
double t_del;

t_alsa = (double) bsize / fsamp;
if (t_alsa < 1e-3) t_alsa = 1e-3;
t_jack = (double) J->bsize () / J->fsamp ();
t_del = t_alsa + t_jack;
k_del = (int)(t_del * fsamp);
for (k = 256; k < 2 * k_del; k *= 2);
audioq = new Lfq_audio (k, nchan);

if (rqual == 0)
{
k = (fsamp < J->fsamp ()) ? fsamp : J->fsamp ();
if (k < 44100) k = 44100;
rqual = (int)((6.7 * k) / (k - 38000));
}
if (rqual < 16) rqual = 16;
if (rqual > 96) rqual = 96;

C->start (audioq, commq, alsaq, J->rprio () + 10);
J->start (audioq, commq, alsaq, infoq, J->fsamp () / (double) fsamp, k_del, ltcor, rqual);
}

void jack_finish (void* arg)
{
if (t != 0)
{
stop = true;
pthread_join(t, NULL);
}

commq->wr_int32 (Alsathread::TERM);
usleep (100000);
delete C;
delete A;
delete J;
delete audioq;
}
};

extern "C" {

int
jack_initialize (jack_client_t* client, const char* load_init)
{
zita_a2j *c = new zita_a2j();
return c->jack_initialize(client, load_init);
}

void jack_finish (void* arg)
{
if (!arg) return;
Jackclient *J = (Jackclient *)arg;
zita_a2j *c = (zita_a2j *)J->getarg();
c->jack_finish(arg);
delete c;
}

} /* extern "C" */

+ 0
- 408
tools/zalsa/zita-j2a.cc View File

@@ -1,408 +0,0 @@
// ----------------------------------------------------------------------------
//
// Copyright (C) 2012 Fons Adriaensen <fons@linuxaudio.org>
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------


#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <signal.h>
#include "alsathread.h"
#include "jackclient.h"
#include "lfqueue.h"
#include "jack/control.h"

static const char *clopt = "hvLSwj:d:r:p:n:c:Q:O:";

static void help (void)
{
jack_info ("%s-%s", APPNAME, VERSION);
jack_info ("(C) 2012-2018 Fons Adriaensen <fons@linuxaudio.org>");
jack_info ("Use ALSA playback device as a Jack client.");
jack_info ("Options:");
jack_info (" -h Display this text");
jack_info (" -j <jackname> Name as Jack client [%s]", APPNAME);
jack_info (" -d <device> ALSA playback device [none]");
jack_info (" -r <rate> Sample rate [48000]");
jack_info (" -p <period> Period size [256]");
jack_info (" -n <nfrags> Number of fragments [2]");
jack_info (" -c <nchannels> Number of channels [2]");
jack_info (" -S Word clock sync, no resampling");
jack_info (" -Q <quality> Resampling quality, 16..96 [auto]");
jack_info (" -O <samples> Latency adjustment [0]");
jack_info (" -L Force 16-bit and 2 channels [off]");
jack_info (" -w Wait until soundcard is available [off]");
jack_info (" -v Print tracing information [off]");
}

class zita_j2a
{
Lfq_int32 *commq;
Lfq_adata *alsaq;
Lfq_jdata *infoq;
Lfq_audio *audioq;
bool stop;
bool v_opt;
bool L_opt;
bool S_opt;
bool w_opt;
char *jname;
char *device;
int fsamp;
int bsize;
int nfrag;
int nchan;
int rqual;
int ltcor;

public:

zita_j2a()
{
commq = new Lfq_int32(16);
alsaq = new Lfq_adata(256);
infoq = new Lfq_jdata(256);
audioq = 0;
stop = false;
v_opt = false;
L_opt = false;
S_opt = false;
w_opt = false;
jname = strdup(APPNAME);
device = 0;
fsamp = 48000;
bsize = 128;
nfrag = 2;
nchan = 2;
rqual = 0;
ltcor = 0;
A = 0;
P = 0;
J = 0;
t = 0;
}

private:

int procoptions (int ac, const char *av [])
{
int k;

optind = 1;
opterr = 0;
while ((k = getopt (ac, (char **) av, (char *) clopt)) != -1)
{
if (optarg && (*optarg == '-'))
{
jack_error (APPNAME ": Missing argument for '-%c' option.", k);
jack_error (APPNAME ": Use '-h' to see all options.");
return 1;
}
switch (k)
{
case 'h' : help (); return 1;
case 'v' : v_opt = true; break;
case 'L' : L_opt = true; break;
case 'S' : S_opt = true; break;
case 'w' : w_opt = true; break;
case 'j' : jname = optarg; break;
case 'd' : device = optarg; break;
case 'r' : fsamp = atoi (optarg); break;
case 'p' : bsize = atoi (optarg); break;
case 'n' : nfrag = atoi (optarg); break;
case 'c' : nchan = atoi (optarg); break;
case 'Q' : rqual = atoi (optarg); break;
case 'O' : ltcor = atoi (optarg); break;
case '?':
if (optopt != ':' && strchr (clopt, optopt))
{
jack_error (APPNAME ": Missing argument for '-%c' option.", optopt);
}
else if (isprint (optopt))
{
jack_error (APPNAME ": Unknown option '-%c'.", optopt);
}
else
{
jack_error (APPNAME ": Unknown option character '0x%02x'.", optopt & 255);
}
jack_error (APPNAME ": Use '-h' to see all options.");
return 1;
default:
return 1;
}
}

return 0;
}

int parse_options (const char* load_init)
{
int argsz;
int argc = 0;
const char** argv;
char* args = strdup (load_init);
char* token;
char* ptr = args;
char* savep;

if (!load_init) {
return 0;
}

argsz = 8; /* random guess at "maxargs" */
argv = (const char **) malloc (sizeof (char *) * argsz);

argv[argc++] = APPNAME;

while (1) {

if ((token = strtok_r (ptr, " ", &savep)) == NULL) {
break;
}

if (argc == argsz) {
argsz *= 2;
argv = (const char **) realloc (argv, sizeof (char *) * argsz);
}

argv[argc++] = token;
ptr = NULL;
}

return procoptions (argc, argv);
}

void printinfo (void)
{
int n, k;
double e, r;
Jdata *J;

n = 0;
k = 99999;
e = r = 0;
while (infoq->rd_avail ())
{
J = infoq->rd_datap ();
if (J->_state == Jackclient::TERM)
{
jack_info (APPNAME ": Fatal error condition, terminating.");
stop = true;
return;
}
else if (J->_state == Jackclient::WAIT)
{
jack_info (APPNAME ": Detected excessive timing errors, waiting 10 seconds.");
n = 0;
}
else if (J->_state == Jackclient::SYNC0)
{
jack_info (APPNAME ": Starting synchronisation.");
}
else if (v_opt)
{
n++;
e += J->_error;
r += J->_ratio;
if (J->_bstat < k) k = J->_bstat;
}
infoq->rd_commit ();
}
if (n) jack_info ("%8.3lf %10.6lf %5d", e / n, r / n, k);
}

Alsa_pcmi *A;
Alsathread *P;
Jackclient *J;

pthread_t t;
int topts;

static void* _retry_alsa_pcmi (void *arg)
{
((zita_j2a*)arg)->retry_alsa_pcmi ();
return NULL;
}

void retry_alsa_pcmi ()
{
Alsa_pcmi *a;

while (! stop)
{
sleep(1);

a = new Alsa_pcmi (device, 0, 0, fsamp, bsize, nfrag, topts);
if (a->state ())
{
delete a;
continue;
}

A = a;
if (v_opt) A->printinfo ();
P = new Alsathread (A, Alsathread::PLAY);
usleep (100*1000);
jack_initialize_part2 ();
jack_info (APPNAME ": Device is now available and has been activated");
break;
}

t = 0;
}

public:

int jack_initialize (jack_client_t* client, const char* load_init)
{
int opts;

if (parse_options (load_init)) {
delete this;
return 1;
}

if (device == 0)
{
help ();
delete this;
return 1;
}
if (rqual < 16) rqual = 16;
if (rqual > 96) rqual = 96;
if ((fsamp < 8000) || (bsize < 16) || (nfrag < 2) || (nchan < 1))
{
jack_error (APPNAME ": Illegal parameter value(s).");
delete this;
return 1;
}

opts = 0;
if (v_opt) opts |= Alsa_pcmi::DEBUG_ALL;
if (L_opt) opts |= Alsa_pcmi::FORCE_16B | Alsa_pcmi::FORCE_2CH;
if (w_opt)
{
J = new Jackclient (client, 0, Jackclient::PLAY, nchan, S_opt, this);

// if device is not available, spawn thread to keep trying
A = new Alsa_pcmi (device, 0, 0, fsamp, bsize, nfrag, opts);
if (A->state ())
{
delete A;
A = NULL;
topts = opts;
pthread_create (&t, NULL, _retry_alsa_pcmi, this);
jack_info (APPNAME ": Could not open device, will keep trying in new thread...");
return 0;
}

// otherwise continue as normal
if (v_opt) A->printinfo ();
P = new Alsathread (A, Alsathread::PLAY);
}
else
{
A = new Alsa_pcmi (device, 0, 0, fsamp, bsize, nfrag, opts);
if (A->state ())
{
jack_error (APPNAME ": Can't open ALSA playback device '%s'.", device);
delete this;
return 1;
}
if (v_opt) A->printinfo ();
if (nchan > A->nplay ())
{
nchan = A->nplay ();
jack_error (APPNAME ": Warning: only %d channels are available.", nchan);
}
P = new Alsathread (A, Alsathread::PLAY);
J = new Jackclient (client, 0, Jackclient::PLAY, nchan, S_opt, this);
}

usleep (100*1000);
jack_initialize_part2 ();
return 0;
}

void jack_initialize_part2 ()
{
int k, k_del;
double t_jack;
double t_alsa;
double t_del;

t_alsa = (double) bsize / fsamp;
if (t_alsa < 1e-3) t_alsa = 1e-3;
t_jack = (double) J->bsize () / J->fsamp ();
t_del = t_alsa + t_jack;
k_del = (int)(t_del * fsamp);
for (k = 256; k < 2 * k_del; k *= 2);
audioq = new Lfq_audio (k, nchan);

if (rqual == 0)
{
k = (fsamp < J->fsamp ()) ? fsamp : J->fsamp ();
if (k < 44100) k = 44100;
rqual = (int)((6.7 * k) / (k - 38000));
}
if (rqual < 16) rqual = 16;
if (rqual > 96) rqual = 96;

P->start (audioq, commq, alsaq, J->rprio () + 10);
J->start (audioq, commq, alsaq, infoq, (double) fsamp / J->fsamp (), k_del, ltcor, rqual);
}

void jack_finish (void* arg)
{
if (t != 0)
{
stop = true;
pthread_join(t, NULL);
t = 0;
}

commq->wr_int32 (Alsathread::TERM);
usleep (100*1000);
delete P;
delete A;
delete J;
delete audioq;
}
};

extern "C" {

int
jack_initialize (jack_client_t* client, const char* load_init)
{
zita_j2a *c = new zita_j2a();
return c->jack_initialize(client, load_init);
}

void jack_finish (void* arg)
{
if (!arg) return;
Jackclient *J = (Jackclient *)arg;
zita_j2a *c = (zita_j2a *)J->getarg();
c->jack_finish(arg);
delete c;
}

} /* extern "C" */

+ 4
- 12
wscript View File

@@ -169,9 +169,9 @@ def options(opt):
help='Build with CELT')
celt.add_function(check_for_celt)
opt.add_auto_option(
'example-tools',
help='Build with jack-example-tools',
conf_dest='BUILD_JACK_EXAMPLE_TOOLS',
'tests',
help='Build tests',
conf_dest='BUILD_TESTS',
default=False,
)

@@ -337,10 +337,6 @@ def configure(conf):
else:
conf.env['SYSTEMD_USER_UNIT_DIR'] = None

if conf.env['BUILD_JACK_EXAMPLE_TOOLS']:
conf.recurse('example-clients')
conf.recurse('tools')

# test for the availability of ucontext, and how it should be used
for t in ['gp_regs', 'uc_regs', 'mc_gregs', 'gregs']:
fragment = '#include <ucontext.h>\n'
@@ -853,14 +849,10 @@ def build(bld):

build_drivers(bld)

if bld.env['BUILD_JACK_EXAMPLE_TOOLS']:
bld.recurse('example-clients')
bld.recurse('tools')

if bld.env['IS_LINUX'] or bld.env['IS_FREEBSD']:
bld.recurse('man')
bld.recurse('systemd')
if not bld.env['IS_WINDOWS'] and bld.env['BUILD_JACK_EXAMPLE_TOOLS']:
if not bld.env['IS_WINDOWS'] and bld.env['BUILD_TESTS']:
bld.recurse('tests')
if bld.env['BUILD_JACKDBUS']:
bld.recurse('dbus')


Loading…
Cancel
Save