@@ -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 |
@@ -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); | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} |
@@ -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"); | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
}; | |||
} |
@@ -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); | |||
}; | |||
} |
@@ -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); | |||
} | |||
@@ -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; | |||
} |
@@ -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, ¤t); | |||
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); | |||
} |
@@ -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, | |||