@@ -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, | |||||
they would be important to call. | |||||
*/ | |||||
jack_client_close (client); | |||||
exit (0); | |||||
} |
@@ -0,0 +1,201 @@ | |||||
/** @file simple_session_client.c | |||||
* | |||||
* @brief This simple client demonstrates the most basic features of JACK | |||||
* as they would be used by many applications. | |||||
* this version also adds session manager functionality. | |||||
*/ | |||||
#include <stdio.h> | |||||
#include <errno.h> | |||||
#include <unistd.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#include <jack/jack.h> | |||||
#include <jack/session.h> | |||||
jack_port_t *input_port; | |||||
jack_port_t *output_port; | |||||
jack_client_t *client; | |||||
int simple_quit = 0; | |||||
/** | |||||
* The process callback for this JACK application is called in a | |||||
* special realtime thread once for each audio cycle. | |||||
* | |||||
* This client does nothing more than copy data from its input | |||||
* port to its output port. It will exit when stopped by | |||||
* the user (e.g. using Ctrl-C on a unix-ish operating system) | |||||
*/ | |||||
int | |||||
process (jack_nframes_t nframes, void *arg) | |||||
{ | |||||
jack_default_audio_sample_t *in, *out; | |||||
in = jack_port_get_buffer (input_port, nframes); | |||||
out = jack_port_get_buffer (output_port, nframes); | |||||
memcpy (out, in, | |||||
sizeof (jack_default_audio_sample_t) * nframes); | |||||
return 0; | |||||
} | |||||
void | |||||
session_callback (jack_session_event_t *event, void *arg) | |||||
{ | |||||
char retval[100]; | |||||
printf ("session notification\n"); | |||||
printf ("path %s, uuid %s, type: %s\n", event->session_dir, event->client_uuid, event->type == JackSessionSave ? "save" : "quit"); | |||||
snprintf (retval, 100, "jack_simple_session_client %s", event->client_uuid); | |||||
event->command_line = strdup (retval); | |||||
jack_session_reply( client, event ); | |||||
if (event->type == JackSessionSaveAndQuit) { | |||||
simple_quit = 1; | |||||
} | |||||
jack_session_event_free (event); | |||||
} | |||||
/** | |||||
* JACK calls this shutdown_callback if the server ever shuts down or | |||||
* decides to disconnect the client. | |||||
*/ | |||||
void | |||||
jack_shutdown (void *arg) | |||||
{ | |||||
exit (1); | |||||
} | |||||
int | |||||
main (int argc, char *argv[]) | |||||
{ | |||||
const char **ports; | |||||
const char *client_name = "simple"; | |||||
jack_status_t status; | |||||
/* open a client connection to the JACK server */ | |||||
if( argc == 1 ) | |||||
client = jack_client_open (client_name, JackNullOption, &status ); | |||||
else if( argc == 2 ) | |||||
client = jack_client_open (client_name, JackSessionID, &status, argv[1] ); | |||||
if (client == NULL) { | |||||
fprintf (stderr, "jack_client_open() failed, " | |||||
"status = 0x%2.0x\n", status); | |||||
if (status & JackServerFailed) { | |||||
fprintf (stderr, "Unable to connect to JACK server\n"); | |||||
} | |||||
exit (1); | |||||
} | |||||
if (status & JackServerStarted) { | |||||
fprintf (stderr, "JACK server started\n"); | |||||
} | |||||
if (status & JackNameNotUnique) { | |||||
client_name = jack_get_client_name(client); | |||||
fprintf (stderr, "unique name `%s' assigned\n", client_name); | |||||
} | |||||
/* tell the JACK server to call `process()' whenever | |||||
there is work to be done. | |||||
*/ | |||||
jack_set_process_callback (client, process, 0); | |||||
/* tell the JACK server to call `jack_shutdown()' if | |||||
it ever shuts down, either entirely, or if it | |||||
just decides to stop calling us. | |||||
*/ | |||||
jack_on_shutdown (client, jack_shutdown, 0); | |||||
/* tell the JACK server to call `session_callback()' if | |||||
the session is saved. | |||||
*/ | |||||
jack_set_session_callback (client, session_callback, NULL); | |||||
/* display the current sample rate. | |||||
*/ | |||||
printf ("engine sample rate: %" PRIu32 "\n", | |||||
jack_get_sample_rate (client)); | |||||
/* create two ports */ | |||||
input_port = jack_port_register (client, "input", | |||||
JACK_DEFAULT_AUDIO_TYPE, | |||||
JackPortIsInput, 0); | |||||
output_port = jack_port_register (client, "output", | |||||
JACK_DEFAULT_AUDIO_TYPE, | |||||
JackPortIsOutput, 0); | |||||
if ((input_port == NULL) || (output_port == NULL)) { | |||||
fprintf(stderr, "no more JACK ports available\n"); | |||||
exit (1); | |||||
} | |||||
/* Tell the JACK server that we are ready to roll. Our | |||||
* process() callback will start running now. */ | |||||
if (jack_activate (client)) { | |||||
fprintf (stderr, "cannot activate client"); | |||||
exit (1); | |||||
} | |||||
/* Connect the ports. You can't do this before the client is | |||||
* activated, because we can't make connections to clients | |||||
* that aren't running. Note the confusing (but necessary) | |||||
* orientation of the driver backend ports: playback ports are | |||||
* "input" to the backend, and capture ports are "output" from | |||||
* it. | |||||
*/ | |||||
/* only do the autoconnect when not reloading from a session. | |||||
* in case of a session reload, the SM will restore our connections | |||||
*/ | |||||
if (argc==1) { | |||||
ports = jack_get_ports (client, NULL, NULL, | |||||
JackPortIsPhysical|JackPortIsOutput); | |||||
if (ports == NULL) { | |||||
fprintf(stderr, "no physical capture ports\n"); | |||||
exit (1); | |||||
} | |||||
if (jack_connect (client, ports[0], jack_port_name (input_port))) { | |||||
fprintf (stderr, "cannot connect input ports\n"); | |||||
} | |||||
free (ports); | |||||
ports = jack_get_ports (client, NULL, NULL, | |||||
JackPortIsPhysical|JackPortIsInput); | |||||
if (ports == NULL) { | |||||
fprintf(stderr, "no physical playback ports\n"); | |||||
exit (1); | |||||
} | |||||
if (jack_connect (client, jack_port_name (output_port), ports[0])) { | |||||
fprintf (stderr, "cannot connect output ports\n"); | |||||
} | |||||
free (ports); | |||||
} | |||||
/* keep running until until we get a quit event */ | |||||
while (!simple_quit) | |||||
sleep(1); | |||||
jack_client_close (client); | |||||
exit (0); | |||||
} |
@@ -0,0 +1,197 @@ | |||||
/** @file transport_client.c | |||||
* | |||||
* @brief This client demonstrates very simple use of the JACK | |||||
* transport API. Compare it with the simple_client example, | |||||
* which is even simpler. It also demonstrates taking a client | |||||
* name and optionally server name from the command line, rather | |||||
* than hard-coding either of these names. | |||||
*/ | |||||
#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; | |||||
/* a simple state machine for this client */ | |||||
volatile enum { | |||||
Init, | |||||
Run, | |||||
Exit | |||||
} client_state = Init; | |||||
/** | |||||
* The process callback for this JACK application is called in a | |||||
* special realtime thread once for each audio cycle. | |||||
* | |||||
* This client follows a simple rule: when the JACK transport is | |||||
* running, copy the input port to the output. When it stops, exit. | |||||
*/ | |||||
int | |||||
process (jack_nframes_t nframes, void *arg) | |||||
{ | |||||
jack_default_audio_sample_t *in, *out; | |||||
jack_transport_state_t ts = jack_transport_query(client, NULL); | |||||
if (ts == JackTransportRolling) { | |||||
if (client_state == Init) | |||||
client_state = Run; | |||||
in = jack_port_get_buffer (input_port, nframes); | |||||
out = jack_port_get_buffer (output_port, nframes); | |||||
memcpy (out, in, | |||||
sizeof (jack_default_audio_sample_t) * nframes); | |||||
} else if (ts == JackTransportStopped) { | |||||
if (client_state == Run) | |||||
client_state = Exit; | |||||
} | |||||
return 0; | |||||
} | |||||
/** | |||||
* JACK calls this shutdown_callback if the server ever shuts down or | |||||
* decides to disconnect the client. | |||||
*/ | |||||
void | |||||
jack_shutdown (void *arg) | |||||
{ | |||||
exit (1); | |||||
} | |||||
int | |||||
main (int argc, char *argv[]) | |||||
{ | |||||
const char **ports; | |||||
const char *client_name; | |||||
const char *server_name = NULL; | |||||
jack_options_t options = JackNullOption; | |||||
jack_status_t status; | |||||
if (argc >= 2) { /* client name specified? */ | |||||
client_name = argv[1]; | |||||
if (argc >= 3) { /* server name specified? */ | |||||
server_name = argv[2]; | |||||
options |= JackServerName; | |||||
} | |||||
} else { /* use basename of argv[0] */ | |||||
client_name = strrchr(argv[0], '/'); | |||||
if (client_name == 0) { | |||||
client_name = argv[0]; | |||||
} else { | |||||
client_name++; | |||||
} | |||||
} | |||||
/* open a client connection to the JACK server */ | |||||
client = jack_client_open (client_name, options, &status, server_name); | |||||
if (client == NULL) { | |||||
fprintf (stderr, "jack_client_open() failed, " | |||||
"status = 0x%2.0x\n", status); | |||||
if (status & JackServerFailed) { | |||||
fprintf (stderr, "Unable to connect to JACK server\n"); | |||||
} | |||||
exit (1); | |||||
} | |||||
if (status & JackServerStarted) { | |||||
fprintf (stderr, "JACK server started\n"); | |||||
} | |||||
if (status & JackNameNotUnique) { | |||||
client_name = jack_get_client_name(client); | |||||
fprintf (stderr, "unique name `%s' assigned\n", client_name); | |||||
} | |||||
/* tell the JACK server to call `process()' whenever | |||||
there is work to be done. | |||||
*/ | |||||
jack_set_process_callback (client, process, 0); | |||||
/* tell the JACK server to call `jack_shutdown()' if | |||||
it ever shuts down, either entirely, or if it | |||||
just decides to stop calling us. | |||||
*/ | |||||
jack_on_shutdown (client, jack_shutdown, 0); | |||||
/* 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 the transport stops */ | |||||
while (client_state != Exit) { | |||||
sleep (1); | |||||
} | |||||
jack_client_close (client); | |||||
exit (0); | |||||
} |