git-svn-id: svn+ssh://jackaudio.org/trunk/jack@189 0c269be4-1314-0410-8aa9-9f06e86f4224tags/0.109.0
@@ -0,0 +1,3 @@ | |||||
Welcome to JACK, the Jack Audio Connection Kit. | |||||
Please see the website (http://jackit.sf.net/) for more information. |
@@ -1,176 +0,0 @@ | |||||
#include <stdio.h> | |||||
#include <errno.h> | |||||
#include <unistd.h> | |||||
#include <stdlib.h> | |||||
#include <jack/jack.h> | |||||
#include <glib.h> | |||||
#include <jack/port.h> | |||||
#include <jack/cycles.h> | |||||
jack_port_t *input_port; | |||||
jack_port_t *output_port; | |||||
volatile char *buf; | |||||
unsigned long stompsize; | |||||
int do_stomp = 0; | |||||
pthread_mutex_t foolock = PTHREAD_MUTEX_INITIALIZER; | |||||
int | |||||
process (jack_nframes_t nframes, void *arg) | |||||
{ | |||||
unsigned long i; | |||||
unsigned long long now, then; | |||||
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); | |||||
now = get_cycles (); | |||||
if (pthread_mutex_trylock (&foolock) == 0) { | |||||
then = get_cycles (); | |||||
if (do_stomp) { | |||||
for (i = 0; i < stompsize; ++i) { | |||||
buf[i]++; | |||||
} | |||||
} else { | |||||
for (i = 0; i < stompsize; ++i) { | |||||
buf[0]++; | |||||
} | |||||
} | |||||
then = get_cycles (); | |||||
pthread_mutex_unlock (&foolock); | |||||
} | |||||
memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes); | |||||
return 0; | |||||
} | |||||
int | |||||
bufsize (jack_nframes_t nframes, void *arg) | |||||
{ | |||||
printf ("the maximum buffer size is now %lu\n", nframes); | |||||
return 0; | |||||
} | |||||
int | |||||
srate (jack_nframes_t nframes, void *arg) | |||||
{ | |||||
printf ("the sample rate is now %lu/sec\n", nframes); | |||||
return 0; | |||||
} | |||||
void | |||||
jack_shutdown (void *arg) | |||||
{ | |||||
printf ("shutdown by JACK\n"); | |||||
exit (1); | |||||
} | |||||
void * | |||||
other_thread (void *arg) | |||||
{ | |||||
while (1) { | |||||
pthread_mutex_lock (&foolock); | |||||
usleep (3000); | |||||
pthread_mutex_unlock (&foolock); | |||||
usleep (3000); | |||||
} | |||||
return 0; | |||||
} | |||||
int | |||||
main (int argc, char *argv[]) | |||||
{ | |||||
jack_client_t *client; | |||||
pthread_t other; | |||||
if (argc < 2) { | |||||
fprintf (stderr, "usage: jack_simple_client <name>\n"); | |||||
return 1; | |||||
} | |||||
/* try to become a client of the JACK server */ | |||||
if ((client = jack_client_new (argv[1])) == 0) { | |||||
fprintf (stderr, "jack server not running?\n"); | |||||
return 1; | |||||
} | |||||
stompsize = atoi (argv[2]); | |||||
buf = (char *) malloc (sizeof (char) * stompsize); | |||||
do_stomp = atoi (argv[3]); | |||||
pthread_create (&other, NULL, other_thread, NULL); | |||||
/* 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 `bufsize()' whenever | |||||
the maximum number of frames that will be passed | |||||
to `process()' changes | |||||
*/ | |||||
jack_set_buffer_size_callback (client, bufsize, 0); | |||||
/* tell the JACK server to call `srate()' whenever | |||||
the sample rate of the system changes. | |||||
*/ | |||||
jack_set_sample_rate_callback (client, srate, 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. | |||||
*/ | |||||
printf ("engine sample rate: %lu\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); | |||||
/* 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 (jack_connect (client, "alsa_pcm:in_1", jack_port_name (input_port))) { | |||||
fprintf (stderr, "cannot connect input ports\n"); | |||||
} | |||||
if (jack_connect (client, jack_port_name (output_port), "alsa_pcm:out_1")) { | |||||
fprintf (stderr, "cannot connect output ports\n"); | |||||
} | |||||
/* Since this is just a toy, run for a few seconds, then finish */ | |||||
sleep (10); | |||||
jack_client_close (client); | |||||
printf ("finished OK\n"); | |||||
exit (0); | |||||
} | |||||
@@ -1,372 +0,0 @@ | |||||
/* | |||||
Copyright (C) 2001 Paul Davis | |||||
This program is free software; you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation; either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program; if not, write to the Free Software | |||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
$Id$ | |||||
*/ | |||||
#include <stdio.h> | |||||
#include <errno.h> | |||||
#include <unistd.h> | |||||
#include <sndfile.h> | |||||
#include <pthread.h> | |||||
#include <glib.h> | |||||
#include <getopt.h> | |||||
#include <jack/jack.h> | |||||
typedef struct _thread_info { | |||||
pthread_t thread_id; | |||||
SNDFILE *sf; | |||||
jack_nframes_t duration; | |||||
jack_client_t *client; | |||||
unsigned int channels; | |||||
int bitdepth; | |||||
int can_capture; | |||||
char *path; | |||||
int status; | |||||
int can_process; | |||||
} thread_info_t; | |||||
unsigned int nports; | |||||
jack_port_t **ports; | |||||
pthread_mutex_t buffer_lock = PTHREAD_MUTEX_INITIALIZER; | |||||
pthread_cond_t data_ready = PTHREAD_COND_INITIALIZER; | |||||
typedef struct _sample_buffer { | |||||
jack_nframes_t nframes; | |||||
jack_default_audio_sample_t **data; | |||||
} sample_buffer_t; | |||||
sample_buffer_t * | |||||
sample_buffer_new (jack_nframes_t nframes, unsigned int nchans) | |||||
{ | |||||
sample_buffer_t *buf; | |||||
unsigned int i; | |||||
buf = (sample_buffer_t *) malloc (sizeof (sample_buffer_t)); | |||||
buf->nframes = nframes; | |||||
buf->data = (jack_default_audio_sample_t **) malloc (sizeof (jack_default_audio_sample_t *) * nchans); | |||||
for (i = 0; i < nchans; i++) { | |||||
buf->data[i] = (jack_default_audio_sample_t *) malloc (sizeof (jack_default_audio_sample_t) * nframes); | |||||
} | |||||
return buf; | |||||
} | |||||
GSList *pending_writes = NULL; | |||||
GSList *free_buffers = NULL; | |||||
sample_buffer_t * | |||||
get_free_buffer (jack_nframes_t nframes, unsigned int nchans) | |||||
{ | |||||
sample_buffer_t *buf; | |||||
if (free_buffers == NULL) { | |||||
buf = sample_buffer_new (nframes, nchans); | |||||
} else { | |||||
buf = (sample_buffer_t *) free_buffers->data; | |||||
free_buffers = g_slist_next (free_buffers); | |||||
} | |||||
return buf; | |||||
} | |||||
sample_buffer_t * | |||||
get_write_buffer () | |||||
{ | |||||
sample_buffer_t *buf; | |||||
if (pending_writes == NULL) { | |||||
return NULL; | |||||
} | |||||
buf = (sample_buffer_t *) pending_writes->data; | |||||
pending_writes = g_slist_next (pending_writes); | |||||
return buf; | |||||
} | |||||
void | |||||
put_write_buffer (sample_buffer_t *buf) | |||||
{ | |||||
pending_writes = g_slist_append (pending_writes, buf); | |||||
} | |||||
void | |||||
put_free_buffer (sample_buffer_t *buf) | |||||
{ | |||||
free_buffers = g_slist_prepend (free_buffers, buf); | |||||
} | |||||
void * | |||||
disk_thread (void *arg) | |||||
{ | |||||
sample_buffer_t *buf; | |||||
thread_info_t *info = (thread_info_t *) arg; | |||||
int i; | |||||
unsigned int chn; | |||||
jack_nframes_t total_captured = 0; | |||||
int done = 0; | |||||
double *fbuf; | |||||
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | |||||
pthread_mutex_lock (&buffer_lock); | |||||
/* preload the buffer cache */ | |||||
for (i = 0; i < 8; i++) { | |||||
buf = sample_buffer_new (jack_get_buffer_size (info->client), info->channels); | |||||
put_free_buffer (buf); | |||||
} | |||||
info->status = 0; | |||||
while (!done) { | |||||
pthread_cond_wait (&data_ready, &buffer_lock); | |||||
while ((buf = get_write_buffer ()) != 0) { | |||||
pthread_mutex_unlock (&buffer_lock); | |||||
/* grrr ... libsndfile doesn't do float data yet, only double */ | |||||
if (info->can_capture) { | |||||
fbuf = (double *) malloc (sizeof (double) * buf->nframes * info->channels); | |||||
for (chn = 0; chn < info->channels; chn++) { | |||||
for (i = 0; i < buf->nframes; i++) { | |||||
fbuf[chn+(i*info->channels)] = buf->data[chn][i]; | |||||
} | |||||
} | |||||
if (sf_writef_double (info->sf, fbuf, buf->nframes, 1) != buf->nframes) { | |||||
char errstr[256]; | |||||
sf_error_str (0, errstr, sizeof (errstr) - 1); | |||||
fprintf (stderr, "cannot write data to sndfile (%s)\n", errstr); | |||||
info->status = -1; | |||||
done = 1; | |||||
break; | |||||
} | |||||
free (fbuf); | |||||
total_captured += buf->nframes; | |||||
if (total_captured >= info->duration) { | |||||
printf ("disk thread finished\n"); | |||||
done = 1; | |||||
break; | |||||
} | |||||
} | |||||
pthread_mutex_lock (&buffer_lock); | |||||
put_free_buffer (buf); | |||||
} | |||||
} | |||||
pthread_mutex_unlock (&buffer_lock); | |||||
return 0; | |||||
} | |||||
int | |||||
process (jack_nframes_t nframes, void *arg) | |||||
{ | |||||
thread_info_t *info = (thread_info_t *) arg; | |||||
jack_default_audio_sample_t *in; | |||||
sample_buffer_t *buf; | |||||
unsigned int i; | |||||
if (!info->can_process) { | |||||
return 0; | |||||
} | |||||
/* we don't like taking locks, but until we have a lock | |||||
free ringbuffer written in C, this is what has to be done | |||||
*/ | |||||
pthread_mutex_lock (&buffer_lock); | |||||
buf = get_free_buffer (nframes, nports); | |||||
for (i = 0; i < nports; i++) { | |||||
in = (jack_default_audio_sample_t *) jack_port_get_buffer (ports[i], nframes); | |||||
memcpy (buf->data[i], in, sizeof (jack_default_audio_sample_t) * nframes); | |||||
} | |||||
put_write_buffer (buf); | |||||
/* tell the disk thread that there is work to do */ | |||||
pthread_cond_signal (&data_ready); | |||||
pthread_mutex_unlock (&buffer_lock); | |||||
return 0; | |||||
} | |||||
void | |||||
jack_shutdown (void *arg) | |||||
{ | |||||
fprintf (stderr, "JACK shutdown\n"); | |||||
exit (0); | |||||
} | |||||
void | |||||
setup_disk_thread (thread_info_t *info) | |||||
{ | |||||
SF_INFO sf_info; | |||||
sf_info.samplerate = jack_get_sample_rate (info->client); | |||||
sf_info.channels = info->channels; | |||||
sf_info.format = SF_FORMAT_WAV|SF_FORMAT_PCM; | |||||
sf_info.pcmbitwidth = info->bitdepth; | |||||
if ((info->sf = sf_open_write (info->path, &sf_info)) == NULL) { | |||||
char errstr[256]; | |||||
sf_error_str (0, errstr, sizeof (errstr) - 1); | |||||
fprintf (stderr, "cannot open sndfile \"%s\" for output (%s)\n", info->path, errstr); | |||||
jack_client_close (info->client); | |||||
exit (1); | |||||
} | |||||
info->duration *= sf_info.samplerate; | |||||
info->can_capture = 0; | |||||
pthread_create (&info->thread_id, NULL, disk_thread, info); | |||||
} | |||||
void | |||||
run_disk_thread (thread_info_t *info) | |||||
{ | |||||
info->can_capture = 1; | |||||
pthread_join (info->thread_id, NULL); | |||||
sf_close (info->sf); | |||||
if (info->status) { | |||||
unlink (info->path); | |||||
} | |||||
} | |||||
void | |||||
setup_ports (int sources, char *source_names[], thread_info_t *info) | |||||
{ | |||||
int i; | |||||
nports = sources; | |||||
ports = (jack_port_t **) malloc (sizeof (jack_port_t *) * nports); | |||||
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; | |||||
} | |||||
int | |||||
main (int argc, char *argv[]) | |||||
{ | |||||
jack_client_t *client; | |||||
thread_info_t thread_info; | |||||
int c; | |||||
int longopt_index = 0; | |||||
extern int optind, opterr; | |||||
int show_usage = 0; | |||||
char *optstring = "d:f:b:h"; | |||||
struct option long_options[] = { | |||||
{ "help", 1, 0, 'h' }, | |||||
{ "duration", 1, 0, 'd' }, | |||||
{ "file", 1, 0, 'f' }, | |||||
{ "bitdepth", 1, 0, 'b' }, | |||||
{ 0, 0, 0, 0 } | |||||
}; | |||||
memset (&thread_info, 0, sizeof (thread_info)); | |||||
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; | |||||
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 ] port1 [ port2 ... ]\n"); | |||||
exit (1); | |||||
} | |||||
if ((client = jack_client_new ("jackrec")) == 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, NULL); | |||||
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); | |||||
exit (0); | |||||
} |
@@ -1,121 +0,0 @@ | |||||
#include <stdio.h> | |||||
/* | |||||
Copyright (C) 2002 Jeremy Hall | |||||
This program is free software; you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation; either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program; if not, write to the Free Software | |||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
$Id$ | |||||
*/ | |||||
#include <errno.h> | |||||
#include <unistd.h> | |||||
#include <string.h> | |||||
#include <jack/jack.h> | |||||
jack_port_t *input_port; | |||||
jack_port_t *output_port; | |||||
int connecting, disconnecting; | |||||
#define TRUE 1 | |||||
#define FALSE 0 | |||||
int | |||||
main (int argc, char *argv[]) | |||||
{ | |||||
jack_client_t *client; | |||||
char *my_name = strrchr(argv[0], '/'); | |||||
connecting = disconnecting = FALSE; | |||||
if (my_name == 0) { | |||||
my_name = argv[0]; | |||||
} else { | |||||
my_name ++; | |||||
} | |||||
if (strstr(my_name, "disconnect")) { | |||||
disconnecting = TRUE; | |||||
} else | |||||
if (strstr(my_name, "connect")) { | |||||
connecting = TRUE; | |||||
} else { | |||||
fprintf(stderr, "ERROR! client should be called jack_connect or jack_disconnect. client is called %s\n", my_name); | |||||
return 1; | |||||
} | |||||
if (argc != 3) { | |||||
fprintf (stderr, "usage: %s <src_port> <dst_port>\n", my_name); | |||||
fprintf(stderr, "The source port must be an output port of the source client.\n"); | |||||
fprintf (stderr, "The destination port must be an input port of the destination client.\n"); | |||||
return 1; | |||||
} | |||||
/* try to become a client of the JACK server */ | |||||
if ((client = jack_client_new (my_name)) == 0) { | |||||
fprintf (stderr, "jack server not running?\n"); | |||||
return 1; | |||||
} | |||||
/* 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. | |||||
*/ | |||||
printf ("engine sample rate: %lu\n", jack_get_sample_rate (client)); | |||||
/* find the two ports */ | |||||
if ((input_port = jack_port_by_name(client, argv[1])) == 0) { | |||||
fprintf (stderr, "ERROR %s not a valid port\n", argv[1]); | |||||
return 1; | |||||
} | |||||
if ((output_port = jack_port_by_name(client, argv[2])) == 0) { | |||||
fprintf (stderr, "ERROR %s not a valid port\n", argv[2]); | |||||
return 1; | |||||
} | |||||
/* 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). | |||||
*/ | |||||
/* jack_port_connect not implemented | |||||
if (jack_port_connect(client, input_port, output_port)) { | |||||
fprintf (stderr, "cannot connect ports\n"); | |||||
} | |||||
*/ | |||||
if (connecting) { | |||||
if (jack_connect(client, jack_port_name(input_port), jack_port_name(output_port))) { | |||||
fprintf (stderr, "cannot connect ports\n"); | |||||
return 1; | |||||
} | |||||
} | |||||
if (disconnecting) { | |||||
if (jack_disconnect(client, jack_port_name(input_port), jack_port_name(output_port))) { | |||||
fprintf (stderr, "cannot disconnect ports\n"); | |||||
return 1; | |||||
} | |||||
} | |||||
jack_client_close (client); | |||||
exit (0); | |||||
} | |||||
@@ -1,106 +0,0 @@ | |||||
/* | |||||
Copyright (C) 2001 Paul Davis | |||||
This program is free software; you can redistribute it and/or modify | |||||
it under the terms of the GNU Lesser General Public License as published by | |||||
the Free Software Foundation; either version 2.1 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU Lesser General Public License for more details. | |||||
You should have received a copy of the GNU Lesser General Public License | |||||
along with this program; if not, write to the Free Software | |||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||||
$Id$ | |||||
*/ | |||||
#include <stdio.h> | |||||
#include <string.h> | |||||
#include <stdarg.h> | |||||
#include <stdlib.h> | |||||
#include <stdio.h> | |||||
#include <jack/driver.h> | |||||
#include <jack/internal.h> | |||||
#include <jack/error.h> | |||||
static int dummy_attach (jack_driver_t *drv, jack_engine_t *eng) { return 0; } | |||||
static int dummy_detach (jack_driver_t *drv, jack_engine_t *eng) { return 0; } | |||||
static jack_nframes_t dummy_wait (jack_driver_t *drv, int fd, int *status, float *delayed_usecs) { *status = 0; *delayed_usecs = 0; return 0; } | |||||
static int dummy_process (jack_driver_t *drv, jack_nframes_t nframes) { return 0; } | |||||
static int dummy_stop (jack_driver_t *drv) { return 0; } | |||||
static int dummy_start (jack_driver_t *drv) { return 0; } | |||||
void | |||||
jack_driver_init (jack_driver_t *driver) | |||||
{ | |||||
memset (driver, 0, sizeof (*driver)); | |||||
driver->attach = dummy_attach; | |||||
driver->detach = dummy_detach; | |||||
driver->wait = dummy_wait; | |||||
driver->process = dummy_process; | |||||
driver->start = dummy_start; | |||||
driver->stop = dummy_stop; | |||||
} | |||||
jack_driver_t * | |||||
jack_driver_load (int argc, char **argv) | |||||
{ | |||||
const char *errstr; | |||||
dlhandle handle; | |||||
jack_driver_t *driver; | |||||
jack_driver_t *(*initialize)(int, char **); | |||||
void (*finish)(jack_driver_t *); | |||||
char path_to_so[PATH_MAX+1]; | |||||
snprintf (path_to_so, sizeof (path_to_so), ADDON_DIR "/jack_%s.so", argv[0]); | |||||
handle = dlopen (path_to_so, RTLD_NOW|RTLD_GLOBAL); | |||||
if (handle == 0) { | |||||
if ((errstr = dlerror ()) != 0) { | |||||
jack_error ("can't load \"%s\": %s", path_to_so, errstr); | |||||
} else { | |||||
jack_error ("bizarre error loading driver shared object %s", path_to_so); | |||||
} | |||||
return 0; | |||||
} | |||||
initialize = dlsym (handle, "driver_initialize"); | |||||
if ((errstr = dlerror ()) != 0) { | |||||
jack_error ("no initialize function in shared object %s\n", path_to_so); | |||||
dlclose (handle); | |||||
return 0; | |||||
} | |||||
finish = dlsym (handle, "driver_finish"); | |||||
if ((errstr = dlerror ()) != 0) { | |||||
jack_error ("no finish function in in shared driver object %s", path_to_so); | |||||
dlclose (handle); | |||||
return 0; | |||||
} | |||||
if ((driver = initialize (argc, argv)) != 0) { | |||||
driver->handle = handle; | |||||
driver->finish = finish; | |||||
} | |||||
return driver; | |||||
} | |||||
void | |||||
jack_driver_unload (jack_driver_t *driver) | |||||
{ | |||||
driver->finish (driver); | |||||
dlclose (driver->handle); | |||||
} |
@@ -1,99 +0,0 @@ | |||||
#include <stdio.h> | |||||
#include <stdlib.h> | |||||
#include <errno.h> | |||||
#include <unistd.h> | |||||
extern "C" | |||||
{ | |||||
#include <jack/jack.h> | |||||
} | |||||
#include <FL/Fl.H> | |||||
#include <FL/Fl_Window.H> | |||||
#include <FL/Fl_Slider.H> | |||||
jack_port_t *input_port; | |||||
jack_port_t *output_port; | |||||
float gain = 0.0; /* slider starts out with zero gain */ | |||||
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); | |||||
while (nframes--) | |||||
out[nframes] = in[nframes] * gain; | |||||
return 0; | |||||
} | |||||
int | |||||
bufsize (jack_nframes_t nframes, void *arg) | |||||
{ | |||||
printf ("the maximum buffer size is now %lu\n", nframes); | |||||
return 0; | |||||
} | |||||
int | |||||
srate (jack_nframes_t nframes, void *arg) | |||||
{ | |||||
printf ("the sample rate is now %lu/sec\n", nframes); | |||||
return 0; | |||||
} | |||||
void callback(Fl_Slider* s) | |||||
{ | |||||
gain = s->value(); | |||||
} | |||||
int | |||||
main (int argc, char *argv[]) | |||||
{ | |||||
Fl_Window w(0,0,100,120); | |||||
Fl_Slider s(10,10,20,100); | |||||
w.show(); | |||||
s.callback((Fl_Callback*) callback); | |||||
jack_client_t *client; | |||||
if ((client = jack_client_new ("fltktest")) == 0) { | |||||
fprintf (stderr, "jack server not running?\n"); | |||||
return 1; | |||||
} | |||||
jack_set_process_callback (client, process, 0); | |||||
jack_set_buffer_size_callback (client, bufsize, 0); | |||||
jack_set_sample_rate_callback (client, srate, 0); | |||||
printf ("engine sample rate: %lu\n", jack_get_sample_rate (client)); | |||||
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 (jack_activate (client)) { | |||||
fprintf (stderr, "cannot activate client"); | |||||
} | |||||
printf ("client activated\n"); | |||||
if (jack_connect (client, "alsa_pcm:in_1", jack_port_name (input_port))) { | |||||
fprintf (stderr, "cannot connect input ports\n"); | |||||
} | |||||
if (jack_connect (client, jack_port_name (output_port), "alsa_pcm:out_1")) { | |||||
fprintf (stderr, "cannot connect output ports\n"); | |||||
} | |||||
Fl::run(); | |||||
printf ("done sleeping, now closing...\n"); | |||||
jack_client_close (client); | |||||
exit (0); | |||||
} | |||||
@@ -1,57 +0,0 @@ | |||||
/* | |||||
Copyright (C) 2001 Paul Davis | |||||
This program is free software; you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation; either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program; if not, write to the Free Software | |||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
$Id$ | |||||
*/ | |||||
#include <jack/hardware.h> | |||||
#include <jack/alsa_driver.h> | |||||
static int generic_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask) | |||||
{ | |||||
return -1; | |||||
} | |||||
static int generic_change_sample_clock (jack_hardware_t *hw, SampleClockMode mode) | |||||
{ | |||||
return -1; | |||||
} | |||||
void | |||||
jack_alsa_generic_hw_release (jack_hardware_t *hw) | |||||
{ | |||||
return; | |||||
} | |||||
jack_hardware_t * | |||||
jack_alsa_generic_hw_new (alsa_driver_t *driver) | |||||
{ | |||||
jack_hardware_t *hw; | |||||
hw = (jack_hardware_t *) malloc (sizeof (jack_hardware_t)); | |||||
hw->capabilities = 0; | |||||
hw->input_monitor_mask = 0; | |||||
hw->set_input_monitor_mask = generic_set_input_monitor_mask; | |||||
hw->change_sample_clock = generic_change_sample_clock; | |||||
hw->release = jack_alsa_generic_hw_release; | |||||
return hw; | |||||
} |
@@ -1,296 +0,0 @@ | |||||
/* | |||||
Copyright (C) 2001 Paul Davis | |||||
This program is free software; you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation; either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program; if not, write to the Free Software | |||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
$Id$ | |||||
*/ | |||||
#include <jack/hardware.h> | |||||
#include <jack/alsa_driver.h> | |||||
#include <jack/hammerfall.h> | |||||
#include <jack/error.h> | |||||
static void | |||||
set_control_id (snd_ctl_elem_id_t *ctl, const char *name) | |||||
{ | |||||
snd_ctl_elem_id_set_name (ctl, name); | |||||
snd_ctl_elem_id_set_numid (ctl, 0); | |||||
snd_ctl_elem_id_set_interface (ctl, SND_CTL_ELEM_IFACE_PCM); | |||||
snd_ctl_elem_id_set_device (ctl, 0); | |||||
snd_ctl_elem_id_set_subdevice (ctl, 0); | |||||
snd_ctl_elem_id_set_index (ctl, 0); | |||||
} | |||||
static void | |||||
hammerfall_broadcast_channel_status_change (hammerfall_t *h, int lock, int sync, channel_t lowchn, channel_t highchn) | |||||
{ | |||||
channel_t chn; | |||||
ClockSyncStatus status = 0; | |||||
if (lock) { | |||||
status |= Lock; | |||||
} else { | |||||
status |= NoLock; | |||||
} | |||||
if (sync) { | |||||
status |= Sync; | |||||
} else { | |||||
status |= NoSync; | |||||
} | |||||
for (chn = lowchn; chn < highchn; chn++) { | |||||
alsa_driver_set_clock_sync_status (h->driver, chn, status); | |||||
} | |||||
} | |||||
static void | |||||
hammerfall_check_sync_state (hammerfall_t *h, int val, int adat_id) | |||||
{ | |||||
int lock; | |||||
int sync; | |||||
/* S/PDIF channel is always locked and synced, but we only | |||||
need tell people once that this is TRUE. | |||||
XXX - maybe need to make sure that the rate matches our | |||||
idea of the current rate ? | |||||
*/ | |||||
if (!h->said_that_spdif_is_fine) { | |||||
ClockSyncStatus status; | |||||
status = Lock|Sync; | |||||
/* XXX broken! fix for hammerfall light ! */ | |||||
alsa_driver_set_clock_sync_status (h->driver, 24, status); | |||||
alsa_driver_set_clock_sync_status (h->driver, 25, status); | |||||
h->said_that_spdif_is_fine = TRUE; | |||||
} | |||||
lock = (val & 0x1) ? TRUE : FALSE; | |||||
sync = (val & 0x2) ? TRUE : FALSE; | |||||
if (h->lock_status[adat_id] != lock || | |||||
h->sync_status[adat_id] != sync) { | |||||
hammerfall_broadcast_channel_status_change (h, lock, sync, adat_id*8, (adat_id*8)+8); | |||||
} | |||||
h->lock_status[adat_id] = lock; | |||||
h->sync_status[adat_id] = sync; | |||||
} | |||||
static void | |||||
hammerfall_check_sync (hammerfall_t *h, snd_ctl_elem_value_t *ctl) | |||||
{ | |||||
const char *name; | |||||
int val; | |||||
snd_ctl_elem_id_t *ctl_id; | |||||
printf ("check sync\n"); | |||||
snd_ctl_elem_id_alloca (&ctl_id); | |||||
snd_ctl_elem_value_get_id (ctl, ctl_id); | |||||
name = snd_ctl_elem_id_get_name (ctl_id); | |||||
if (strcmp (name, "ADAT1 Sync Check") == 0) { | |||||
val = snd_ctl_elem_value_get_enumerated (ctl, 0); | |||||
hammerfall_check_sync_state (h, val, 0); | |||||
} else if (strcmp (name, "ADAT2 Sync Check") == 0) { | |||||
val = snd_ctl_elem_value_get_enumerated (ctl, 0); | |||||
hammerfall_check_sync_state (h, val, 1); | |||||
} else if (strcmp (name, "ADAT3 Sync Check") == 0) { | |||||
val = snd_ctl_elem_value_get_enumerated (ctl, 0); | |||||
hammerfall_check_sync_state (h, val, 2); | |||||
} else { | |||||
jack_error ("Hammerfall: unknown control \"%s\"", name); | |||||
} | |||||
} | |||||
static int | |||||
hammerfall_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask) | |||||
{ | |||||
hammerfall_t *h = (hammerfall_t *) hw->private; | |||||
snd_ctl_elem_value_t *ctl; | |||||
snd_ctl_elem_id_t *ctl_id; | |||||
int err; | |||||
int i; | |||||
snd_ctl_elem_value_alloca (&ctl); | |||||
snd_ctl_elem_id_alloca (&ctl_id); | |||||
set_control_id (ctl_id, "Channels Thru"); | |||||
snd_ctl_elem_value_set_id (ctl, ctl_id); | |||||
for (i = 0; i < 26; i++) { | |||||
snd_ctl_elem_value_set_integer (ctl, i, (mask & (1<<i)) ? 1 : 0); | |||||
} | |||||
if ((err = snd_ctl_elem_write (h->driver->ctl_handle, ctl)) != 0) { | |||||
jack_error ("ALSA/Hammerfall: cannot set input monitoring (%s)", snd_strerror (err)); | |||||
return -1; | |||||
} | |||||
hw->input_monitor_mask = mask; | |||||
return 0; | |||||
} | |||||
static int | |||||
hammerfall_change_sample_clock (jack_hardware_t *hw, SampleClockMode mode) | |||||
{ | |||||
hammerfall_t *h = (hammerfall_t *) hw->private; | |||||
snd_ctl_elem_value_t *ctl; | |||||
snd_ctl_elem_id_t *ctl_id; | |||||
int err; | |||||
snd_ctl_elem_value_alloca (&ctl); | |||||
snd_ctl_elem_id_alloca (&ctl_id); | |||||
set_control_id (ctl_id, "Sync Mode"); | |||||
snd_ctl_elem_value_set_id (ctl, ctl_id); | |||||
switch (mode) { | |||||
case AutoSync: | |||||
snd_ctl_elem_value_set_enumerated (ctl, 0, 0); | |||||
break; | |||||
case ClockMaster: | |||||
snd_ctl_elem_value_set_enumerated (ctl, 0, 1); | |||||
break; | |||||
case WordClock: | |||||
snd_ctl_elem_value_set_enumerated (ctl, 0, 2); | |||||
break; | |||||
} | |||||
if ((err = snd_ctl_elem_write (h->driver->ctl_handle, ctl)) < 0) { | |||||
jack_error ("ALSA-Hammerfall: cannot set clock mode"); | |||||
} | |||||
return 0; | |||||
} | |||||
static void | |||||
hammerfall_release (jack_hardware_t *hw) | |||||
{ | |||||
hammerfall_t *h = (hammerfall_t *) hw->private; | |||||
void *status; | |||||
if (h == 0) { | |||||
return; | |||||
} | |||||
pthread_cancel (h->monitor_thread); | |||||
pthread_join (h->monitor_thread, &status); | |||||
free (h); | |||||
} | |||||
static void * | |||||
hammerfall_monitor_controls (void *arg) | |||||
{ | |||||
jack_hardware_t *hw = (jack_hardware_t *) arg; | |||||
hammerfall_t *h = (hammerfall_t *) hw->private; | |||||
snd_ctl_elem_id_t *switch_id[3]; | |||||
snd_ctl_elem_value_t *sw[3]; | |||||
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | |||||
snd_ctl_elem_id_malloc (&switch_id[0]); | |||||
snd_ctl_elem_id_malloc (&switch_id[1]); | |||||
snd_ctl_elem_id_malloc (&switch_id[2]); | |||||
snd_ctl_elem_value_malloc (&sw[0]); | |||||
snd_ctl_elem_value_malloc (&sw[1]); | |||||
snd_ctl_elem_value_malloc (&sw[2]); | |||||
set_control_id (switch_id[0], "ADAT1 Sync Check"); | |||||
set_control_id (switch_id[1], "ADAT2 Sync Check"); | |||||
set_control_id (switch_id[2], "ADAT3 Sync Check"); | |||||
snd_ctl_elem_value_set_id (sw[0], switch_id[0]); | |||||
snd_ctl_elem_value_set_id (sw[1], switch_id[1]); | |||||
snd_ctl_elem_value_set_id (sw[2], switch_id[2]); | |||||
while (1) { | |||||
if (snd_ctl_elem_read (h->driver->ctl_handle, sw[0])) { | |||||
jack_error ("cannot read control switch 0 ..."); | |||||
} | |||||
hammerfall_check_sync (h, sw[0]); | |||||
if (snd_ctl_elem_read (h->driver->ctl_handle, sw[1])) { | |||||
jack_error ("cannot read control switch 0 ..."); | |||||
} | |||||
hammerfall_check_sync (h, sw[1]); | |||||
if (snd_ctl_elem_read (h->driver->ctl_handle, sw[2])) { | |||||
jack_error ("cannot read control switch 0 ..."); | |||||
} | |||||
hammerfall_check_sync (h, sw[2]); | |||||
if (nanosleep (&h->monitor_interval, 0)) { | |||||
break; | |||||
} | |||||
} | |||||
pthread_exit (0); | |||||
} | |||||
jack_hardware_t * | |||||
jack_alsa_hammerfall_hw_new (alsa_driver_t *driver) | |||||
{ | |||||
jack_hardware_t *hw; | |||||
hammerfall_t *h; | |||||
hw = (jack_hardware_t *) malloc (sizeof (jack_hardware_t)); | |||||
hw->capabilities = Cap_HardwareMonitoring|Cap_AutoSync|Cap_WordClock|Cap_ClockMaster|Cap_ClockLockReporting; | |||||
hw->input_monitor_mask = 0; | |||||
hw->private = 0; | |||||
hw->set_input_monitor_mask = hammerfall_set_input_monitor_mask; | |||||
hw->change_sample_clock = hammerfall_change_sample_clock; | |||||
hw->release = hammerfall_release; | |||||
h = (hammerfall_t *) malloc (sizeof (hammerfall_t)); | |||||
h->lock_status[0] = FALSE; | |||||
h->sync_status[0] = FALSE; | |||||
h->lock_status[1] = FALSE; | |||||
h->sync_status[1] = FALSE; | |||||
h->lock_status[2] = FALSE; | |||||
h->sync_status[2] = FALSE; | |||||
h->said_that_spdif_is_fine = FALSE; | |||||
h->driver = driver; | |||||
h->monitor_interval.tv_sec = 1; | |||||
h->monitor_interval.tv_nsec = 0; | |||||
hw->private = h; | |||||
#if 0 | |||||
if (pthread_create (&h->monitor_thread, 0, hammerfall_monitor_controls, hw)) { | |||||
jack_error ("ALSA/Hammerfall: cannot create sync monitor thread"); | |||||
} | |||||
#endif | |||||
return hw; | |||||
} |
@@ -1,152 +0,0 @@ | |||||
/* | |||||
Copyright (C) 2002 Anthony Van Groningen | |||||
Parts based on source code taken from the | |||||
"Env24 chipset (ICE1712) control utility" that is | |||||
Copyright (C) 2000 by Jaroslav Kysela <perex@suse.cz> | |||||
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/hardware.h> | |||||
#include <jack/alsa_driver.h> | |||||
#include <jack/ice1712.h> | |||||
#include <jack/error.h> | |||||
static int | |||||
ice1712_hw_monitor_toggle(jack_hardware_t *hw, int idx, int onoff) | |||||
{ | |||||
ice1712_t *h = (ice1712_t *) hw->private; | |||||
snd_ctl_elem_value_t *val; | |||||
int err; | |||||
snd_ctl_elem_value_alloca (&val); | |||||
snd_ctl_elem_value_set_interface (val, SND_CTL_ELEM_IFACE_MIXER); | |||||
if (idx >= 8) { | |||||
snd_ctl_elem_value_set_name (val, SPDIF_PLAYBACK_ROUTE_NAME); | |||||
snd_ctl_elem_value_set_index (val, idx - 8); | |||||
} else { | |||||
snd_ctl_elem_value_set_name (val, ANALOG_PLAYBACK_ROUTE_NAME); | |||||
snd_ctl_elem_value_set_index (val, idx); | |||||
} | |||||
if (onoff) { | |||||
snd_ctl_elem_value_set_enumerated (val, 0, idx + 1); | |||||
} else { | |||||
snd_ctl_elem_value_set_enumerated (val, 0, 0); | |||||
} | |||||
if ((err = snd_ctl_elem_write (h->driver->ctl_handle, val)) != 0) { | |||||
jack_error ("ALSA/ICE1712: (%d) cannot set input monitoring (%s)", | |||||
idx,snd_strerror (err)); | |||||
return -1; | |||||
} | |||||
return 0; | |||||
} | |||||
static int | |||||
ice1712_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask) | |||||
{ | |||||
int idx; | |||||
ice1712_t *h = (ice1712_t *) hw->private; | |||||
for (idx = 0; idx < 10; idx++) { | |||||
if (h->active_channels & (1<<idx)) { | |||||
ice1712_hw_monitor_toggle (hw, idx, mask & (1<<idx) ? 1 : 0); | |||||
} | |||||
} | |||||
hw->input_monitor_mask = mask; | |||||
return 0; | |||||
} | |||||
static int | |||||
ice1712_change_sample_clock (jack_hardware_t *hw, SampleClockMode mode) | |||||
{ | |||||
return -1; | |||||
} | |||||
static void | |||||
ice1712_release (jack_hardware_t *hw) | |||||
{ | |||||
return; | |||||
} | |||||
jack_hardware_t * | |||||
jack_alsa_ice1712_hw_new (alsa_driver_t *driver) | |||||
{ | |||||
jack_hardware_t *hw; | |||||
ice1712_t *h; | |||||
snd_ctl_elem_value_t *val; | |||||
int err; | |||||
hw = (jack_hardware_t *) malloc (sizeof (jack_hardware_t)); | |||||
hw->capabilities = Cap_HardwareMonitoring; | |||||
hw->input_monitor_mask = 0; | |||||
hw->private = 0; | |||||
hw->set_input_monitor_mask = ice1712_set_input_monitor_mask; | |||||
hw->change_sample_clock = ice1712_change_sample_clock; | |||||
hw->release = ice1712_release; | |||||
h = (ice1712_t *) malloc (sizeof (ice1712_t)); | |||||
h->driver = driver; | |||||
/* Get the EEPROM (adopted from envy24control) */ | |||||
h->eeprom = (ice1712_eeprom_t *) malloc (sizeof (ice1712_eeprom_t)); | |||||
snd_ctl_elem_value_alloca (&val); | |||||
snd_ctl_elem_value_set_interface (val, SND_CTL_ELEM_IFACE_CARD); | |||||
snd_ctl_elem_value_set_name (val, "ICE1712 EEPROM"); | |||||
if ((err = snd_ctl_elem_read (driver->ctl_handle, val)) < 0) { | |||||
jack_error( "ALSA/ICE1712: Unable to read EEPROM contents (%s)\n", snd_strerror (err)); | |||||
/* Recover? */ | |||||
} | |||||
memcpy(h->eeprom, snd_ctl_elem_value_get_bytes(val), 32); | |||||
/* determine number of pro ADC's. We're asumming that there is at least one stereo pair. | |||||
Should check this first, but how? */ | |||||
switch((h->eeprom->codec & 0xCU) >> 2) { | |||||
case 0: | |||||
h->active_channels = 0x3U; | |||||
break; | |||||
case 1: | |||||
h->active_channels = 0xfU; | |||||
break; | |||||
case 2: | |||||
h->active_channels = 0x3fU; | |||||
break; | |||||
case 3: | |||||
h->active_channels = 0xffU; | |||||
break; | |||||
} | |||||
/* check for SPDIF In's */ | |||||
if (h->eeprom->spdif & 0x1U) { | |||||
h->active_channels |= 0x300U; | |||||
} | |||||
hw->private = h; | |||||
return hw; | |||||
} |
@@ -1,217 +0,0 @@ | |||||
/* | |||||
* Copyright (C) 2001 Steve Harris | |||||
* | |||||
* This program is free software; you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation; either version 2 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with this program; if not, write to the Free Software | |||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
* | |||||
* $Id$ | |||||
*/ | |||||
#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; | |||||
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"; | |||||
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_new("impulse_grabber")) == 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 = (int)(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 (jack_connect (client, "alsa_pcm:in_1", jack_port_name (input_port))) { | |||||
fprintf (stderr, "cannot connect input ports\n"); | |||||
} | |||||
if (jack_connect (client, jack_port_name (output_port), "alsa_pcm:out_1")) { | |||||
fprintf (stderr, "cannot connect output ports\n"); | |||||
} | |||||
/* 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); | |||||
} |
@@ -1,445 +0,0 @@ | |||||
/* | |||||
Copyright (C) 2001 Paul Davis | |||||
This program is free software; you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation; either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program; if not, write to the Free Software | |||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
$Id$ | |||||
*/ | |||||
#include <stdio.h> | |||||
#include <signal.h> | |||||
#include <getopt.h> | |||||
#include <sys/types.h> | |||||
#include <sys/shm.h> | |||||
#include <string.h> | |||||
#include <errno.h> | |||||
#include <wait.h> | |||||
#include <jack/engine.h> | |||||
#include <jack/internal.h> | |||||
#include <jack/driver.h> | |||||
static sigset_t signals; | |||||
static jack_engine_t *engine = 0; | |||||
static int jackd_pid; | |||||
static int realtime = 0; | |||||
static int realtime_priority = 10; | |||||
static int with_fork = 1; | |||||
static int verbose = 0; | |||||
static int asio_mode = 0; | |||||
typedef struct { | |||||
pid_t pid; | |||||
int argc; | |||||
char **argv; | |||||
} waiter_arg_t; | |||||
#define ILOWER 0 | |||||
#define IRANGE 3000 | |||||
int wait_times[IRANGE]; | |||||
int unders = 0; | |||||
int overs = 0; | |||||
int max_over = 0; | |||||
int min_under = INT_MAX; | |||||
#define WRANGE 3000 | |||||
int work_times[WRANGE]; | |||||
int work_overs = 0; | |||||
int work_max = 0; | |||||
void | |||||
store_work_time (int howlong) | |||||
{ | |||||
if (howlong < WRANGE) { | |||||
work_times[howlong]++; | |||||
} else { | |||||
work_overs++; | |||||
} | |||||
if (work_max < howlong) { | |||||
work_max = howlong; | |||||
} | |||||
} | |||||
void | |||||
show_work_times () | |||||
{ | |||||
int i; | |||||
for (i = 0; i < WRANGE; ++i) { | |||||
printf ("%d %d\n", i, work_times[i]); | |||||
} | |||||
printf ("work overs = %d\nmax = %d\n", work_overs, work_max); | |||||
} | |||||
void | |||||
store_wait_time (int interval) | |||||
{ | |||||
if (interval < ILOWER) { | |||||
unders++; | |||||
} else if (interval >= ILOWER + IRANGE) { | |||||
overs++; | |||||
} else { | |||||
wait_times[interval-ILOWER]++; | |||||
} | |||||
if (interval > max_over) { | |||||
max_over = interval; | |||||
} | |||||
if (interval < min_under) { | |||||
min_under = interval; | |||||
} | |||||
} | |||||
void | |||||
show_wait_times () | |||||
{ | |||||
int i; | |||||
for (i = 0; i < IRANGE; i++) { | |||||
printf ("%d %d\n", i+ILOWER, wait_times[i]); | |||||
} | |||||
printf ("unders: %d\novers: %d\n", unders, overs); | |||||
printf ("max: %d\nmin: %d\n", max_over, min_under); | |||||
} | |||||
static void | |||||
signal_handler (int sig) | |||||
{ | |||||
fprintf (stderr, "jackd: signal %d received\n", sig); | |||||
kill (jackd_pid, SIGTERM); | |||||
} | |||||
static void | |||||
posix_me_harder (void) | |||||
{ | |||||
/* what's this for? | |||||
POSIX says that signals are delivered like this: | |||||
* if a thread has blocked that signal, it is not | |||||
a candidate to receive the signal. | |||||
* of all threads not blocking the signal, pick | |||||
one at random, and deliver the signal. | |||||
this means that a simple-minded multi-threaded | |||||
program can expect to get POSIX signals delivered | |||||
randomly to any one of its threads, | |||||
here, we block all signals that we think we | |||||
might receive and want to catch. all "child" | |||||
threads will inherit this setting. if we | |||||
create a thread that calls sigwait() on the | |||||
same set of signals, implicitly unblocking | |||||
all those signals. any of those signals that | |||||
are delivered to the process will be delivered | |||||
to that thread, and that thread alone. this | |||||
makes cleanup for a signal-driven exit much | |||||
easier, since we know which thread is doing | |||||
it and more importantly, we are free to | |||||
call async-unsafe functions, because the | |||||
code is executing in normal thread context | |||||
after a return from sigwait(). | |||||
*/ | |||||
sigemptyset (&signals); | |||||
sigaddset(&signals, SIGHUP); | |||||
sigaddset(&signals, SIGINT); | |||||
sigaddset(&signals, SIGQUIT); | |||||
sigaddset(&signals, SIGILL); | |||||
sigaddset(&signals, SIGTRAP); | |||||
sigaddset(&signals, SIGABRT); | |||||
sigaddset(&signals, SIGIOT); | |||||
sigaddset(&signals, SIGFPE); | |||||
sigaddset(&signals, SIGPIPE); | |||||
sigaddset(&signals, SIGTERM); | |||||
sigaddset(&signals, SIGUSR1); | |||||
/* this can make debugging a pain, but it also makes | |||||
segv-exits cleanup_files after themselves rather than | |||||
leaving the audio thread active. i still | |||||
find it truly wierd that _exit() or whatever is done | |||||
by the default SIGSEGV handler does not | |||||
cancel all threads in a process, but what | |||||
else can we do? | |||||
*/ | |||||
sigaddset(&signals, SIGSEGV); | |||||
/* all child threads will inherit this mask */ | |||||
pthread_sigmask (SIG_BLOCK, &signals, 0); | |||||
} | |||||
static void * | |||||
jack_engine_waiter_thread (void *arg) | |||||
{ | |||||
waiter_arg_t *warg = (waiter_arg_t *) arg; | |||||
jack_driver_t *driver; | |||||
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | |||||
if ((engine = jack_engine_new (realtime, realtime_priority, verbose)) == 0) { | |||||
fprintf (stderr, "cannot create engine\n"); | |||||
kill (warg->pid, SIGTERM); | |||||
return 0; | |||||
} | |||||
if (warg->argc) { | |||||
if ((driver = jack_driver_load (warg->argc, warg->argv)) == 0) { | |||||
fprintf (stderr, "cannot load driver module %s\n", warg->argv[0]); | |||||
kill (warg->pid, SIGTERM); | |||||
return 0; | |||||
} | |||||
jack_use_driver (engine, driver); | |||||
} | |||||
if (asio_mode) { | |||||
jack_set_asio_mode (engine, TRUE); | |||||
} | |||||
if (jack_run (engine)) { | |||||
fprintf (stderr, "cannot start main JACK thread\n"); | |||||
kill (warg->pid, SIGTERM); | |||||
return 0; | |||||
} | |||||
jack_wait (engine); | |||||
fprintf (stderr, "telling signal thread that the engine is done\n"); | |||||
kill (warg->pid, SIGHUP); | |||||
return 0; /* nobody cares what this returns */ | |||||
} | |||||
static void | |||||
jack_main (int argc, char **argv) | |||||
{ | |||||
int sig; | |||||
pthread_t waiter_thread; | |||||
waiter_arg_t warg; | |||||
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | |||||
posix_me_harder (); | |||||
/* what we'd really like to do here is to be able to | |||||
wait for either the engine to stop or a POSIX signal, | |||||
whichever arrives sooner. but there is no mechanism | |||||
to do that, so instead we create a thread to wait | |||||
for the engine to finish, and here we stop and wait | |||||
for any (reasonably likely) POSIX signal. | |||||
if the engine finishes first, the waiter thread will | |||||
tell us about it via a signal. | |||||
if a signal arrives, we'll stop the engine and then | |||||
exit. | |||||
in normal operation, our parent process will be waiting | |||||
for us and will cleanup. | |||||
*/ | |||||
warg.pid = getpid(); | |||||
warg.argc = argc; | |||||
warg.argv = argv; | |||||
if (pthread_create (&waiter_thread, 0, jack_engine_waiter_thread, &warg)) { | |||||
fprintf (stderr, "jackd: cannot create engine waiting thread\n"); | |||||
return; | |||||
} | |||||
/* Note: normal operation has with_fork == 1 */ | |||||
if (with_fork) { | |||||
/* let the parent handle SIGINT */ | |||||
sigdelset (&signals, SIGINT); | |||||
} | |||||
if (verbose) { | |||||
fprintf (stderr, "%d waiting for signals\n", getpid()); | |||||
} | |||||
while(1) { | |||||
sigwait (&signals, &sig); | |||||
printf ("jack main caught signal %d\n", sig); | |||||
if (sig == SIGUSR1) { | |||||
jack_dump_configuration(engine, 1); | |||||
} else { | |||||
/* continue to kill engine */ | |||||
break; | |||||
} | |||||
} | |||||
pthread_cancel (waiter_thread); | |||||
jack_engine_delete (engine); | |||||
return; | |||||
} | |||||
static void usage () | |||||
{ | |||||
fprintf (stderr, "\ | |||||
usage: jackd [ --asio OR -a ] | |||||
[ --realtime OR -R [ --realtime-priority OR -P priority ] ] | |||||
[ --verbose OR -v ] | |||||
[ --getcap OR -g capability-program-name ] | |||||
[ --tmpdir OR -D directory-for-temporary-files ] | |||||
-d driver [ ... driver args ... ] | |||||
"); | |||||
} | |||||
int | |||||
main (int argc, char *argv[]) | |||||
{ | |||||
const char *options = "ad:D:P:vhRFl:"; | |||||
struct option long_options[] = | |||||
{ | |||||
{ "asio", 0, 0, 'a' }, | |||||
{ "driver", 1, 0, 'd' }, | |||||
{ "tmpdir", 1, 0, 'D' }, | |||||
{ "getcap", 1, 0, 'g' }, | |||||
{ "verbose", 0, 0, 'v' }, | |||||
{ "help", 0, 0, 'h' }, | |||||
{ "realtime", 0, 0, 'R' }, | |||||
{ "realtime-priority", 1, 0, 'P' }, | |||||
{ "spoon", 0, 0, 'F' }, | |||||
{ 0, 0, 0, 0 } | |||||
}; | |||||
int option_index; | |||||
int opt; | |||||
int seen_driver = 0; | |||||
char *driver_name = 0; | |||||
char *getcap_name = 0; | |||||
char **driver_args = 0; | |||||
int driver_nargs = 1; | |||||
int i; | |||||
opterr = 0; | |||||
while (!seen_driver && (opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) { | |||||
switch (opt) { | |||||
case 'a': | |||||
asio_mode = TRUE; | |||||
break; | |||||
case 'D': | |||||
jack_set_temp_dir (optarg); | |||||
break; | |||||
case 'd': | |||||
seen_driver = 1; | |||||
driver_name = optarg; | |||||
break; | |||||
case 'g': | |||||
getcap_name = optarg; | |||||
break; | |||||
case 'v': | |||||
verbose = 1; | |||||
break; | |||||
case 'F': | |||||
with_fork = 0; | |||||
break; | |||||
case 'P': | |||||
realtime_priority = atoi (optarg); | |||||
break; | |||||
case 'R': | |||||
realtime = 1; | |||||
break; | |||||
default: | |||||
fprintf (stderr, "unknown option character %c\n", optopt); | |||||
/*fallthru*/ | |||||
case 'h': | |||||
usage(); | |||||
return -1; | |||||
} | |||||
} | |||||
if (!seen_driver) { | |||||
usage (); | |||||
exit (1); | |||||
} | |||||
if (optind < argc) { | |||||
driver_nargs = 1 + argc - optind; | |||||
} else { | |||||
driver_nargs = 1; | |||||
} | |||||
driver_args = (char **) malloc (sizeof (char *) * driver_nargs); | |||||
driver_args[0] = driver_name; | |||||
for (i = 1; i < driver_nargs; i++) { | |||||
driver_args[i] = argv[optind++]; | |||||
} | |||||
printf ( "jackd " VERSION "\n" | |||||
"Copyright 2001-2002 Paul Davis and others.\n" | |||||
"jackd comes with ABSOLUTELY NO WARRANTY\n" | |||||
"This is free software, and you are welcome to redistribute it\n" | |||||
"under certain conditions; see the file COPYING for details\n\n"); | |||||
/* get real-time capabilities for this process, we should check for errors */ | |||||
if (getcap_name) system (getcap_name); | |||||
if (!with_fork) { | |||||
/* This is really here so that we can run gdb easily */ | |||||
jack_main (driver_nargs, driver_args); | |||||
} else { | |||||
int pid = fork (); | |||||
if (pid < 0) { | |||||
fprintf (stderr, "could not fork jack server (%s)", strerror (errno)); | |||||
exit (1); | |||||
} else if (pid == 0) { | |||||
jack_main (driver_nargs, driver_args); | |||||
} else { | |||||
jackd_pid = pid; | |||||
signal (SIGHUP, signal_handler); | |||||
signal (SIGINT, signal_handler); | |||||
signal (SIGQUIT, signal_handler); | |||||
signal (SIGTERM, signal_handler); | |||||
waitpid (pid, NULL, 0); | |||||
} | |||||
} | |||||
jack_cleanup_shm (); | |||||
jack_cleanup_files (); | |||||
return 0; | |||||
} |
@@ -1,459 +0,0 @@ | |||||
/* | |||||
Copyright (C) 2000 Paul Davis | |||||
This program is free software; you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation; either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program; if not, write to the Free Software | |||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
$Id$ | |||||
*/ | |||||
#include <stdio.h> | |||||
#include <string.h> | |||||
#include <math.h> | |||||
#include <memory.h> | |||||
#include <stdlib.h> | |||||
#include <limits.h> | |||||
#include <jack/memops.h> | |||||
#define SAMPLE_MAX_24BIT 8388607.0f | |||||
#define SAMPLE_MAX_16BIT 32767.0f | |||||
/* Round float to int (can't go in memops.h otherwise it gets multiply | |||||
defined) */ | |||||
inline int f_round(float f) { | |||||
f += (3<<22); | |||||
return *((int*)&f) - 0x4b400000; | |||||
} | |||||
/* XXX we could use rint(), but for now we'll accept whatever default | |||||
floating-point => int conversion the compiler provides. | |||||
*/ | |||||
void sample_move_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) | |||||
{ | |||||
long long y; | |||||
while (nsamples--) { | |||||
y = (long long)(*src * SAMPLE_MAX_24BIT) << 8; | |||||
if (y > INT_MAX) { | |||||
*((int *) dst) = INT_MAX; | |||||
} else if (y < INT_MIN) { | |||||
*((int *) dst) = INT_MIN; | |||||
} else { | |||||
*((int *) dst) = (int)y; | |||||
} | |||||
dst += dst_skip; | |||||
src++; | |||||
} | |||||
} | |||||
void sample_move_dS_s32u24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) | |||||
{ | |||||
/* ALERT: signed sign-extension portability !!! */ | |||||
while (nsamples--) { | |||||
*dst = (*((int *) src) >> 8) / SAMPLE_MAX_24BIT; | |||||
dst++; | |||||
src += src_skip; | |||||
} | |||||
} | |||||
void sample_move_dither_rect_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) | |||||
{ | |||||
/* ALERT: signed sign-extension portability !!! */ | |||||
jack_default_audio_sample_t x; | |||||
long long y; | |||||
while (nsamples--) { | |||||
x = *src * SAMPLE_MAX_16BIT; | |||||
x -= (float)rand() / (float)RAND_MAX; | |||||
y = (long long)f_round(x); | |||||
y <<= 16; | |||||
if (y > INT_MAX) { | |||||
*((int *) dst) = INT_MAX; | |||||
} else if (y < INT_MIN) { | |||||
*((int *) dst) = INT_MIN; | |||||
} else { | |||||
*((int *) dst) = (int)y; | |||||
} | |||||
dst += dst_skip; | |||||
src++; | |||||
} | |||||
} | |||||
void sample_move_dither_tri_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) | |||||
{ | |||||
jack_default_audio_sample_t x; | |||||
float r; | |||||
float rm1 = state->rm1; | |||||
long long y; | |||||
while (nsamples--) { | |||||
x = *src * (float)SAMPLE_MAX_16BIT; | |||||
r = 2.0f * (float)rand() / (float)RAND_MAX - 1.0f; | |||||
x += r - rm1; | |||||
rm1 = r; | |||||
/* swh: This could be some inline asm on x86 */ | |||||
y = (long long)f_round(x); | |||||
y <<= 16; | |||||
if (y > INT_MAX) { | |||||
*((int *) dst) = INT_MAX; | |||||
} else if (y < INT_MIN) { | |||||
*((int *) dst) = INT_MIN; | |||||
} else { | |||||
*((int *) dst) = (int)y; | |||||
} | |||||
dst += dst_skip; | |||||
src++; | |||||
} | |||||
state->rm1 = rm1; | |||||
} | |||||
void sample_move_dither_shaped_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) | |||||
{ | |||||
jack_default_audio_sample_t x; | |||||
jack_default_audio_sample_t xe; /* the innput sample - filtered error */ | |||||
jack_default_audio_sample_t xp; /* x' */ | |||||
float r; | |||||
float rm1 = state->rm1; | |||||
unsigned int idx = state->idx; | |||||
long long y; | |||||
while (nsamples--) { | |||||
x = *src * (float)SAMPLE_MAX_16BIT; | |||||
r = 2.0f * (float)rand() / (float)RAND_MAX - 1.0f; | |||||
/* Filter the error with Lipshitz's minimally audible FIR: | |||||
[2.033 -2.165 1.959 -1.590 0.6149] */ | |||||
xe = x | |||||
- state->e[idx] * 2.033f | |||||
+ state->e[(idx - 1) & DITHER_BUF_MASK] * 2.165f | |||||
- state->e[(idx - 2) & DITHER_BUF_MASK] * 1.959f | |||||
+ state->e[(idx - 3) & DITHER_BUF_MASK] * 1.590f | |||||
- state->e[(idx - 4) & DITHER_BUF_MASK] * 0.6149f; | |||||
xp = xe + r - rm1; | |||||
rm1 = r; | |||||
/* This could be some inline asm on x86 */ | |||||
y = (long long)f_round(xp); | |||||
/* Intrinsic z^-1 delay */ | |||||
idx = (idx + 1) & DITHER_BUF_MASK; | |||||
state->e[idx] = y - xe; | |||||
y <<= 16; | |||||
if (y > INT_MAX) { | |||||
*((int *) dst) = INT_MAX; | |||||
} else if (y < INT_MIN) { | |||||
*((int *) dst) = INT_MIN; | |||||
} else { | |||||
*((int *) dst) = (int)y; | |||||
} | |||||
dst += dst_skip; | |||||
src++; | |||||
} | |||||
state->rm1 = rm1; | |||||
state->idx = idx; | |||||
} | |||||
void sample_move_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) | |||||
{ | |||||
jack_default_audio_sample_t val; | |||||
/* ALERT: signed sign-extension portability !!! */ | |||||
/* XXX good to use x86 assembler here, since float->short | |||||
sucks that h/w. | |||||
*/ | |||||
while (nsamples--) { | |||||
val = *src; | |||||
if (val > 1.0f) { | |||||
*((short *)dst) = SHRT_MAX; | |||||
} else if (val < -1.0f) { | |||||
*((short *)dst) = SHRT_MIN; | |||||
} else { | |||||
*((short *) dst) = (short) (val * SAMPLE_MAX_16BIT); | |||||
} | |||||
dst += dst_skip; | |||||
src++; | |||||
} | |||||
} | |||||
void sample_move_dither_rect_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) | |||||
{ | |||||
jack_default_audio_sample_t val; | |||||
int tmp; | |||||
while (nsamples--) { | |||||
val = *src * (float)SAMPLE_MAX_16BIT; | |||||
val -= (float)rand() / (float)RAND_MAX; | |||||
/* swh: This could be some inline asm on x86 */ | |||||
tmp = f_round(val); | |||||
if (tmp > SHRT_MAX) { | |||||
*((short *)dst) = SHRT_MAX; | |||||
} else if (tmp < SHRT_MIN) { | |||||
*((short *)dst) = SHRT_MIN; | |||||
} else { | |||||
*((short *) dst) = (short)tmp; | |||||
} | |||||
dst += dst_skip; | |||||
src++; | |||||
} | |||||
} | |||||
void sample_move_dither_tri_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) | |||||
{ | |||||
jack_default_audio_sample_t x; | |||||
float r; | |||||
float rm1 = state->rm1; | |||||
int y; | |||||
while (nsamples--) { | |||||
x = *src * (float)SAMPLE_MAX_16BIT; | |||||
r = 2.0f * (float)rand() / (float)RAND_MAX - 1.0f; | |||||
x += r - rm1; | |||||
rm1 = r; | |||||
/* swh: This could be some inline asm on x86 */ | |||||
y = f_round(x); | |||||
if (y > SHRT_MAX) { | |||||
*((short *)dst) = SHRT_MAX; | |||||
} else if (y < SHRT_MIN) { | |||||
*((short *)dst) = SHRT_MIN; | |||||
} else { | |||||
*((short *) dst) = (short)y; | |||||
} | |||||
dst += dst_skip; | |||||
src++; | |||||
} | |||||
state->rm1 = rm1; | |||||
} | |||||
void sample_move_dither_shaped_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) | |||||
{ | |||||
jack_default_audio_sample_t x; | |||||
jack_default_audio_sample_t xe; /* the innput sample - filtered error */ | |||||
jack_default_audio_sample_t xp; /* x' */ | |||||
float r; | |||||
float rm1 = state->rm1; | |||||
unsigned int idx = state->idx; | |||||
int y; | |||||
while (nsamples--) { | |||||
x = *src * (float)SAMPLE_MAX_16BIT; | |||||
r = 2.0f * (float)rand() / (float)RAND_MAX - 1.0f; | |||||
/* Filter the error with Lipshitz's minimally audible FIR: | |||||
[2.033 -2.165 1.959 -1.590 0.6149] */ | |||||
xe = x | |||||
- state->e[idx] * 2.033f | |||||
+ state->e[(idx - 1) & DITHER_BUF_MASK] * 2.165f | |||||
- state->e[(idx - 2) & DITHER_BUF_MASK] * 1.959f | |||||
+ state->e[(idx - 3) & DITHER_BUF_MASK] * 1.590f | |||||
- state->e[(idx - 4) & DITHER_BUF_MASK] * 0.6149f; | |||||
xp = xe + r - rm1; | |||||
rm1 = r; | |||||
/* This could be some inline asm on x86 */ | |||||
y = f_round(xp); | |||||
/* Intrinsic z^-1 delay */ | |||||
idx = (idx + 1) & DITHER_BUF_MASK; | |||||
state->e[idx] = y - xe; | |||||
if (y > SHRT_MAX) { | |||||
*((short *)dst) = SHRT_MAX; | |||||
} else if (y < SHRT_MIN) { | |||||
*((short *)dst) = SHRT_MIN; | |||||
} else { | |||||
*((short *) dst) = (short)y; | |||||
} | |||||
dst += dst_skip; | |||||
src++; | |||||
} | |||||
state->rm1 = rm1; | |||||
state->idx = idx; | |||||
} | |||||
void sample_move_dS_s16 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) | |||||
{ | |||||
/* ALERT: signed sign-extension portability !!! */ | |||||
while (nsamples--) { | |||||
*dst = (*((short *) src)) / SAMPLE_MAX_16BIT; | |||||
dst++; | |||||
src += src_skip; | |||||
} | |||||
} | |||||
void sample_merge_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) | |||||
{ | |||||
short val; | |||||
/* ALERT: signed sign-extension portability !!! */ | |||||
while (nsamples--) { | |||||
val = (short) (*src * SAMPLE_MAX_16BIT); | |||||
if (val > SHRT_MAX - *((short *) dst)) { | |||||
*((short *)dst) = SHRT_MAX; | |||||
} else if (val < SHRT_MIN - *((short *) dst)) { | |||||
*((short *)dst) = SHRT_MIN; | |||||
} else { | |||||
*((short *) dst) += val; | |||||
} | |||||
dst += dst_skip; | |||||
src++; | |||||
} | |||||
} | |||||
void sample_merge_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) | |||||
{ | |||||
/* ALERT: signed sign-extension portability !!! */ | |||||
while (nsamples--) { | |||||
*((int *) dst) += (((int) (*src * SAMPLE_MAX_24BIT)) << 8); | |||||
dst += dst_skip; | |||||
src++; | |||||
} | |||||
} | |||||
void memset_interleave (char *dst, char val, unsigned long bytes, | |||||
unsigned long unit_bytes, | |||||
unsigned long skip_bytes) | |||||
{ | |||||
switch (unit_bytes) { | |||||
case 1: | |||||
while (bytes--) { | |||||
*dst = val; | |||||
dst += skip_bytes; | |||||
} | |||||
break; | |||||
case 2: | |||||
while (bytes) { | |||||
*((short *) dst) = (short) val; | |||||
dst += skip_bytes; | |||||
bytes -= 2; | |||||
} | |||||
break; | |||||
case 4: | |||||
while (bytes) { | |||||
*((int *) dst) = (int) val; | |||||
dst += skip_bytes; | |||||
bytes -= 4; | |||||
} | |||||
break; | |||||
} | |||||
} | |||||
/* COPY FUNCTIONS: used to move data from an input channel to an | |||||
output channel. Note that we assume that the skip distance | |||||
is the same for both channels. This is completely fine | |||||
unless the input and output were on different audio interfaces that | |||||
were interleaved differently. We don't try to handle that. | |||||
*/ | |||||
void | |||||
memcpy_fake (char *dst, char *src, unsigned long src_bytes, unsigned long foo, unsigned long bar) | |||||
{ | |||||
memcpy (dst, src, src_bytes); | |||||
} | |||||
void | |||||
merge_memcpy_d16_s16 (char *dst, char *src, unsigned long src_bytes, | |||||
unsigned long dst_skip_bytes, unsigned long src_skip_bytes) | |||||
{ | |||||
while (src_bytes) { | |||||
*((short *) dst) += *((short *) src); | |||||
dst += 2; | |||||
src += 2; | |||||
src_bytes -= 2; | |||||
} | |||||
} | |||||
void | |||||
merge_memcpy_d32_s32 (char *dst, char *src, unsigned long src_bytes, | |||||
unsigned long dst_skip_bytes, unsigned long src_skip_bytes) | |||||
{ | |||||
while (src_bytes) { | |||||
*((int *) dst) += *((int *) src); | |||||
dst += 4; | |||||
src += 4; | |||||
src_bytes -= 4; | |||||
} | |||||
} | |||||
void | |||||
merge_memcpy_interleave_d16_s16 (char *dst, char *src, unsigned long src_bytes, | |||||
unsigned long dst_skip_bytes, unsigned long src_skip_bytes) | |||||
{ | |||||
while (src_bytes) { | |||||
*((short *) dst) += *((short *) src); | |||||
dst += dst_skip_bytes; | |||||
src += src_skip_bytes; | |||||
src_bytes -= 2; | |||||
} | |||||
} | |||||
void | |||||
merge_memcpy_interleave_d32_s32 (char *dst, char *src, unsigned long src_bytes, | |||||
unsigned long dst_skip_bytes, unsigned long src_skip_bytes) | |||||
{ | |||||
while (src_bytes) { | |||||
*((int *) dst) += *((int *) src); | |||||
dst += dst_skip_bytes; | |||||
src += src_skip_bytes; | |||||
src_bytes -= 4; | |||||
} | |||||
} | |||||
void | |||||
memcpy_interleave_d16_s16 (char *dst, char *src, unsigned long src_bytes, | |||||
unsigned long dst_skip_bytes, unsigned long src_skip_bytes) | |||||
{ | |||||
while (src_bytes) { | |||||
*((short *) dst) = *((short *) src); | |||||
dst += dst_skip_bytes; | |||||
src += src_skip_bytes; | |||||
src_bytes -= 2; | |||||
} | |||||
} | |||||
void | |||||
memcpy_interleave_d32_s32 (char *dst, char *src, unsigned long src_bytes, | |||||
unsigned long dst_skip_bytes, unsigned long src_skip_bytes) | |||||
{ | |||||
while (src_bytes) { | |||||
*((int *) dst) = *((int *) src); | |||||
dst += dst_skip_bytes; | |||||
src += src_skip_bytes; | |||||
src_bytes -= 4; | |||||
} | |||||
} |
@@ -1,30 +0,0 @@ | |||||
#include <stdio.h> | |||||
#include <unistd.h> | |||||
#include <jack/jack.h> | |||||
#define TRUE 1 | |||||
#define FALSE 0 | |||||
int | |||||
main (int argc, char *argv[]) | |||||
{ | |||||
jack_client_t *client; | |||||
if ((client = jack_client_new ("input monitoring")) == 0) { | |||||
fprintf (stderr, "jack server not running?\n"); | |||||
return 1; | |||||
} | |||||
if (jack_port_request_monitor_by_name (client, "alsa_pcm:in_1", TRUE)) { | |||||
fprintf (stderr, "could not enable monitoring for in_1\n"); | |||||
} | |||||
sleep (30); | |||||
if (jack_port_request_monitor_by_name (client, "alsa_pcm:in_1", FALSE)) { | |||||
fprintf (stderr, "could not disable monitoring for in_1\n"); | |||||
} | |||||
jack_client_close (client); | |||||
exit (0); | |||||
} | |||||
@@ -1,37 +0,0 @@ | |||||
/* | |||||
Copyright (C) 2001 Paul Davis | |||||
This program is free software; you can redistribute it and/or modify | |||||
it under the terms of the GNU Lesser General Public License as published by | |||||
the Free Software Foundation; either version 2.1 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU Lesser General Public License for more details. | |||||
You should have received a copy of the GNU Lesser General Public License | |||||
along with this program; if not, write to the Free Software | |||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||||
$Id$ | |||||
*/ | |||||
#include <stdlib.h> | |||||
#include <jack/pool.h> | |||||
void * | |||||
jack_pool_alloc (size_t bytes) | |||||
{ | |||||
/* XXX need RT-pool based allocator here */ | |||||
return malloc (bytes); | |||||
} | |||||
void | |||||
jack_pool_release (void *ptr) | |||||
{ | |||||
free (ptr); | |||||
} |
@@ -1,128 +0,0 @@ | |||||
#include <stdio.h> | |||||
#include <errno.h> | |||||
#include <unistd.h> | |||||
#include <jack/jack.h> | |||||
jack_port_t *input_port; | |||||
jack_port_t *output_port; | |||||
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); | |||||
memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes); | |||||
return 0; | |||||
} | |||||
int | |||||
bufsize (jack_nframes_t nframes, void *arg) | |||||
{ | |||||
printf ("the maximum buffer size is now %lu\n", nframes); | |||||
return 0; | |||||
} | |||||
int | |||||
srate (jack_nframes_t nframes, void *arg) | |||||
{ | |||||
printf ("the sample rate is now %lu/sec\n", nframes); | |||||
return 0; | |||||
} | |||||
void | |||||
jack_shutdown (void *arg) | |||||
{ | |||||
exit (1); | |||||
} | |||||
int | |||||
main (int argc, char *argv[]) | |||||
{ | |||||
jack_client_t *client; | |||||
if (argc < 2) { | |||||
fprintf (stderr, "usage: jack_simple_client <name>\n"); | |||||
return 1; | |||||
} | |||||
/* try to become a client of the JACK server */ | |||||
if ((client = jack_client_new (argv[1])) == 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 `bufsize()' whenever | |||||
the maximum number of frames that will be passed | |||||
to `process()' changes | |||||
*/ | |||||
jack_set_buffer_size_callback (client, bufsize, 0); | |||||
/* tell the JACK server to call `srate()' whenever | |||||
the sample rate of the system changes. | |||||
*/ | |||||
jack_set_sample_rate_callback (client, srate, 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. | |||||
*/ | |||||
printf ("engine sample rate: %lu\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); | |||||
/* 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, because we can't allow | |||||
connections to be made to clients that aren't | |||||
running. | |||||
*/ | |||||
if (jack_connect (client, "alsa_pcm:in_1", jack_port_name (input_port))) { | |||||
fprintf (stderr, "cannot connect input ports\n"); | |||||
} | |||||
if (jack_connect (client, jack_port_name (output_port), "alsa_pcm:out_1")) { | |||||
fprintf (stderr, "cannot connect output ports\n"); | |||||
} | |||||
/* Since this is just a toy, run for a few seconds, then finish */ | |||||
sleep (10); | |||||
jack_client_close (client); | |||||
exit (0); | |||||
} | |||||