Browse Source

Import jack1 example clients from svn r4772

pull/1/merge
Nedko Arnaudov 12 years ago
commit
4b9f2362b4
14 changed files with 2584 additions and 0 deletions
  1. +92
    -0
      Makefile.am
  2. +344
    -0
      capture_client.c
  3. +233
    -0
      impulse_grabber.c
  4. +110
    -0
      inprocess.c
  5. +157
    -0
      intime.c
  6. +208
    -0
      latent_client.c
  7. +268
    -0
      metro.c
  8. +118
    -0
      midiseq.c
  9. +138
    -0
      midisine.c
  10. +237
    -0
      server_control.c
  11. +117
    -0
      showtime.c
  12. +164
    -0
      simple_client.c
  13. +201
    -0
      simple_session_client.c
  14. +197
    -0
      transport_client.c

+ 92
- 0
Makefile.am View File

@@ -0,0 +1,92 @@
MAINTAINERCLEANFILES = Makefile.in

if HAVE_SNDFILE
JACKREC = jack_rec
dist-check-sndfile:
else
JACKREC =
dist-check-sndfile:
@echo
@echo ' ******' You need sndfile installed to make dist.' ******'
@echo
@false
endif

bin_PROGRAMS = jack_simple_client \
jack_simple_session_client \
jack_transport_client \
jack_impulse_grabber \
jack_metro \
jack_showtime \
jack_midisine \
jack_midiseq \
jack_latent_client \
jack_server_control \
$(JACKREC)

if HAVE_SNDFILE
# note! jackrec_CFLAGS syntax not supported by automake-1.4
sndfile_cflags = @SNDFILE_CFLAGS@
endif

AM_CFLAGS = -I.. $(JACK_CFLAGS) $(sndfile_cflags)
AM_CXXFLAGS = -I.. $(JACK_CFLAGS) $(sndfile_cflags)

jack_simple_client_SOURCES = simple_client.c
jack_simple_client_LDFLAGS = @OS_LDFLAGS@
jack_simple_client_LDADD = $(top_builddir)/libjack/libjack.la

jack_simple_session_client_SOURCES = simple_session_client.c
jack_simple_session_client_LDFLAGS = @OS_LDFLAGS@
jack_simple_session_client_LDADD = $(top_builddir)/libjack/libjack.la

jack_transport_client_SOURCES = transport_client.c
jack_transport_client_LDFLAGS = @OS_LDFLAGS@
jack_transport_client_LDADD = $(top_builddir)/libjack/libjack.la

jack_metro_SOURCES = metro.c
jack_metro_LDFLAGS = @OS_LDFLAGS@
jack_metro_LDADD = $(top_builddir)/libjack/libjack.la

jack_showtime_SOURCES = showtime.c
jack_showtime_LDFLAGS = @OS_LDFLAGS@
jack_showtime_LDADD = $(top_builddir)/libjack/libjack.la

jack_impulse_grabber_SOURCES = impulse_grabber.c
jack_impulse_grabber_LDFLAGS = @OS_LDFLAGS@
jack_impulse_grabber_LDADD = $(top_builddir)/libjack/libjack.la

jack_midiseq_SOURCES = midiseq.c
jack_midiseq_LDFLAGS = @OS_LDFLAGS@
jack_midiseq_LDADD = $(top_builddir)/libjack/libjack.la

jack_midisine_SOURCES = midisine.c
jack_midisine_LDFLAGS = @OS_LDFLAGS@
jack_midisine_LDADD = $(top_builddir)/libjack/libjack.la

jack_latent_client_SOURCES = latent_client.c
jack_latent_client_LDFLAGS = @OS_LDFLAGS@
jack_latent_client_LDADD = $(top_builddir)/libjack/libjack.la

jack_server_control_SOURCES = server_control.c
jack_server_control_LDFLAGS = @OS_LDFLAGS@
jack_server_control_LDADD = $(top_builddir)/jackd/libjackserver.la

if HAVE_SNDFILE
jack_rec_SOURCES = capture_client.c
jack_rec_LDFLAGS = @SNDFILE_LIBS@ @OS_LDFLAGS@
jack_rec_LDADD = $(top_builddir)/libjack/libjack.la
endif

#
# sample in-process client(s)
#
ip_clientdir = $(ADDON_DIR)

ip_client_LTLIBRARIES = inprocess.la intime.la

inprocess_la_LDFLAGS = -module -avoid-version @OS_LDFLAGS@
inprocess_la_SOURCES = inprocess.c

intime_la_LDFLAGS = -module -avoid-version @OS_LDFLAGS@
intime_la_SOURCES = intime.c

+ 344
- 0
capture_client.c View File

@@ -0,0 +1,344 @@
/*
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 <getopt.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;


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;
}
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;
}

void
jack_shutdown (void *arg)
{
fprintf (stderr, "JACK shutdown\n");
// exit (0);
abort();
}

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

if (info->duration == 0) {
info->duration = JACK_MAX_FRAMES;
} else {
info->duration *= sf_info.samplerate;
}

info->can_capture = 0;

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

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;
}
}

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_client_t *client;
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);

run_disk_thread (&thread_info);

jack_client_close (client);

jack_ringbuffer_free (rb);

exit (0);
}

+ 233
- 0
impulse_grabber.c View File

@@ -0,0 +1,233 @@
/*
* 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 <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;

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;
}

void
jack_shutdown (void *arg)
{
exit (1);
}

int
main (int argc, char *argv[])

{
jack_client_t *client;
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);

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

+ 110
- 0
inprocess.c View File

@@ -0,0 +1,110 @@
/** @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.
*/
int
jack_initialize (jack_client_t *client, const char *load_init)
{
port_pair_t *pp = malloc (sizeof (port_pair_t));

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

/* try to connect to the first physical input & output ports */

if (jack_connect (client, "system:capture_1",
jack_port_name (pp->input_port))) {
fprintf (stderr, "cannot connect input port\n");
return 1; /* terminate client */
}

if (jack_connect (client, jack_port_name (pp->output_port),
"system:playback_1")) {
fprintf (stderr, "cannot connect output port\n");
return 1; /* terminate client */
}

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().
*/
void
jack_finish (void *arg)
{
if (arg)
free ((port_pair_t *) arg);
}

+ 157
- 0
intime.c View File

@@ -0,0 +1,157 @@
/*
* intime.c -- JACK internal timebase master example client.
*
* To run: first start `jackd', then `jack_load intime intime 6/8,180bpm'.
*/

/* 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 <string.h>
#include <jack/jack.h>

/* Time and tempo variables, 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;

/* BBT timebase callback.
*
* Runs in the process thread. Realtime, must not wait.
*/
void
timebbt (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) {

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;

/* 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. I
* make no claims for the numerical accuracy or
* efficiency of these calculations. */

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

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

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

/* experimental timecode callback
*
* Fill in extended timecode fields using the trivial assumption that
* we are running at nominal speed, hence with no drift.
*
* It would probably be faster to compute frame_time without the
* conditional expression. But, this demonstrates the invariant:
* next_time[i] == frame_time[i+1], unless a reposition occurs.
*
* Runs in the process thread. Realtime, must not wait.
*/
void
timecode (jack_transport_state_t state, jack_nframes_t nframes,
jack_position_t *pos, int new_pos, void *arg)
{
/* nominal transport speed */
double seconds_per_frame = 1.0 / (double) pos->frame_rate;

pos->valid = JackPositionTimecode;
pos->frame_time = (new_pos?
pos->frame * seconds_per_frame:
pos->next_time);
pos->next_time = (pos->frame + nframes) * seconds_per_frame;
}

/* after internal client loaded */
int
jack_initialize (jack_client_t *client, const char *load_init)
{
JackTimebaseCallback callback = timebbt;

int rc = sscanf(load_init, " %f/%f, %lf bpm ", &time_beats_per_bar,
&time_beat_type, &time_beats_per_minute);

if (rc > 0) {
fprintf (stderr, "counting %.1f/%.1f at %.2f bpm\n",
time_beats_per_bar, time_beat_type,
time_beats_per_minute);
} else {
int len = strlen(load_init);
if ((len > 0) && (strncmp(load_init, "timecode", len) == 0))
callback = timecode;
}

if (jack_set_timebase_callback(client, 0, callback, NULL) != 0) {
fprintf (stderr, "Unable to take over timebase.\n");
return 1; /* terminate */
}

fprintf (stderr, "Internal timebase master defined.\n");
jack_activate (client);
return 0; /* success */
}

/* before unloading */
void
jack_finish (void *arg)
{
fprintf (stderr, "Internal timebase client exiting.\n");
}

+ 208
- 0
latent_client.c View File

@@ -0,0 +1,208 @@
/** @file simple_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 <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;

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

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

+ 268
- 0
metro.c View File

@@ -0,0 +1,268 @@
/*
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>
#include <unistd.h>
#include <math.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;

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"
);
}

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

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;
}
}

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
sample_rate_change () {
printf("Sample rate has changed! Exiting...\n");
exit(-1);
}

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)) != EOF) {
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) + 4) * sizeof (char));
strcpy (bpm_string, optarg);
strcat (bpm_string, "_bpm");
break;
case 'n':
client_name = (char *) malloc (strlen (optarg) * 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 = %" PRIu32
", wave length = %" PRIu32 "\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");
return 1;
}

while (1) {
sleep(1);
};
}

+ 118
- 0
midiseq.c View File

@@ -0,0 +1,118 @@
/*
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 <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;

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");
}

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)
{
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)
{
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(unsigned char));
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;
}

while (1)
{
sleep(1);
};
}

+ 138
- 0
midisine.c View File

@@ -0,0 +1,138 @@
/*
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 <math.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];

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;
}
}

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);
note_on = 1.0;
}
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;
}

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;
}

void jack_shutdown(void *arg)
{
exit(1);
}

int main(int narg, char **args)
{
jack_client_t *client;

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;
}

/* run until interrupted */
while(1)
{
sleep(1);
}
jack_client_close(client);
exit (0);
}


+ 237
- 0
server_control.c View File

@@ -0,0 +1,237 @@
/*
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;
}

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;
}

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;
sigset_t signals;
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'},
};
while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) {
switch (opt) {
case 'd':
driver_name = optarg;
break;
case 'c':
client_name = optarg;
break;
default:
usage();
exit(0);
}
}
server = jackctl_server_create(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);
}
signals = jackctl_setup_signals(0);

jackctl_server_start(server, jackctl_server_get_driver(server, driver_name));
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);
*/
jackctl_wait_signals(signals);
jackctl_server_destroy(server);
return 0;
}

+ 117
- 0
showtime.c View File

@@ -0,0 +1,117 @@
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>

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

jack_client_t *client;


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: %7" PRIu32 " @ %" PRIu32 "\t", current.frame, frame_time);

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

if (current.valid & JackBBTFrameOffset)
printf ("\tBBT offset: (%" PRIi32 ")",
current.bbt_offset);

if (current.valid & JackAudioVideoRatio)
printf ("\taudio/video: (%f)",
current.audio_frames_per_video_frame);

if (current.valid & JackVideoFrameOffset) {
if (current.video_offset) {
printf ("\t video@: (%" PRIi32 ")", current.video_offset);
} else {
printf ("\t no video");
}
}
printf ("\n");
}

void
jack_shutdown (void *arg)
{
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;
}

signal (SIGQUIT, signal_handler);
signal (SIGTERM, signal_handler);
signal (SIGHUP, 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);
}

+ 164
- 0
simple_client.c View File

@@ -0,0 +1,164 @@
/** @file simple_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 <jack/jack.h>

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

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

/**
* 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";
const char *server_name = NULL;
jack_options_t options = JackNullOption;
jack_status_t status;
/* 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);

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

sleep (-1);

/* this is never reached but if the program
had some other way to exit besides being killed,