From f139113e3e122b297e0fcf6cd18aefdfebccf576 Mon Sep 17 00:00:00 2001 From: pbd Date: Mon, 16 Sep 2002 16:35:51 +0000 Subject: [PATCH] fix configure for libsndfile, add 3 new sample clients, fix problems with removing dead clients, change timebase to use pending model git-svn-id: svn+ssh://jackaudio.org/trunk/jack@245 0c269be4-1314-0410-8aa9-9f06e86f4224 --- Makefile.am | 2 +- configure.in | 17 +-- drivers/alsa/alsa_driver.c | 2 +- example-clients/Makefile.am | 16 +++ example-clients/lsp.c | 30 +++++ example-clients/metro.c | 242 ++++++++++++++++++++++++++++++++++++ example-clients/showtime.c | 85 +++++++++++++ jack/internal.h | 8 +- jackd/engine.c | 34 +++-- jackd/jackd.c | 4 + libjack/client.c | 16 +-- 11 files changed, 422 insertions(+), 34 deletions(-) create mode 100644 example-clients/lsp.c create mode 100644 example-clients/metro.c create mode 100644 example-clients/showtime.c diff --git a/Makefile.am b/Makefile.am index fc8cded..82c7802 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,7 @@ MAINTAINERCLEANFILES = Makefile.in aclocal.m4 configure config.h.in \ stamp-h.in config.log config.cache \ config.guess mkinstalldirs config.status \ missing install-sh config.sub ltconfig \ - ltmain.sh acinclude.m4 + ltmain.sh if HAVE_DOXYGEN DOC_DIR = doc diff --git a/configure.in b/configure.in index a0f45a9..858aa46 100644 --- a/configure.in +++ b/configure.in @@ -4,8 +4,8 @@ AC_INIT(jackd/jackd.c) AC_CONFIG_AUX_DIR(.) JACK_MAJOR_VERSION=0 -JACK_MINOR_VERSION=37 -JACK_MICRO_VERSION=2 +JACK_MINOR_VERSION=38 +JACK_MICRO_VERSION=0 BETA= @@ -162,15 +162,10 @@ if test $HAVE_FLTK = "false"; then AC_MSG_WARN([*** no fltk found, the fltk example client will not be built]) fi -AC_CHECK_LIB(sndfile,main, - [AC_CHECK_HEADER(sndfile.h, - [HAVE_SNDFILE=true], - [HAVE_SNDFILE=false] - )], - [HAVE_SNDFILE=false] -) -if test $HAVE_SNDFILE = "false"; then - AC_MSG_WARN([*** no libsndfile found, the jackrec example client will not be built]) +HAVE_SNDFILE= +PKG_CHECK_MODULES(SNDFILE, sndfile >= 1.0,[HAVE_SNDFILE=true], [true]) +if test x$HAVE_SNDFILE = x; then + AC_MSG_WARN([*** the jackrec example client will not be built]) fi # you need doxygen to make dist. diff --git a/drivers/alsa/alsa_driver.c b/drivers/alsa/alsa_driver.c index 71e4f93..295bb8d 100644 --- a/drivers/alsa/alsa_driver.c +++ b/drivers/alsa/alsa_driver.c @@ -867,7 +867,7 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float *delay } driver->poll_last = poll_ret; driver->poll_next = poll_ret + (unsigned long long) floor ((driver->period_usecs * driver->cpu_mhz)); - driver->engine->control->time.cycles = get_cycles(); + driver->engine->control->current_time.cycles = get_cycles(); } /* check to see if it was the extra FD that caused us to return from poll diff --git a/example-clients/Makefile.am b/example-clients/Makefile.am index 7828f7d..6dd575d 100644 --- a/example-clients/Makefile.am +++ b/example-clients/Makefile.am @@ -30,6 +30,9 @@ bin_PROGRAMS = jack_simple_client \ jack_cache_killer \ jack_connect \ jack_disconnect \ + jack_metro \ + jack_showtime \ + jack_lsp \ $(FLTK_CLIENT) $(JACKREC) AM_CFLAGS = -I.. $(JACK_CFLAGS) $(GLIB_CFLAGS) @@ -55,6 +58,19 @@ jack_cache_killer_SOURCES = cache_killer.c jack_cache_killer_LDFLAGS = -ldl -lpthread jack_cache_killer_LDADD = ../libjack/libjack.la +jack_metro_SOURCES = metro.c +jack_metro_LDFLAGS = -ldl -lpthread +jack_metro_LDADD = ../libjack/libjack.la + +jack_lsp_SOURCES = lsp.c +jack_lsp_LDFLAGS = -ldl -lpthread +jack_lsp_LDADD = ../libjack/libjack.la + +jack_showtime_SOURCES = showtime.c +jack_showtime_LDFLAGS = -ldl -lpthread +jack_showtime_LDADD = ../libjack/libjack.la + + if HAVE_FLTK jack_fltk_client_SOURCES = fltk_client.cc jack_fltk_client_LDFLAGS = -L/usr/X11R6/lib -lfltk -lX11 -lXext -ldl -lpthread diff --git a/example-clients/lsp.c b/example-clients/lsp.c new file mode 100644 index 0000000..782d97e --- /dev/null +++ b/example-clients/lsp.c @@ -0,0 +1,30 @@ +#include +#include + +#include + +int +main (int argc, char *argv[]) + +{ + jack_client_t *client; + const char **ports; + int i; + + /* try to become a client of the JACK server */ + + if ((client = jack_client_new ("lsp")) == 0) { + fprintf (stderr, "jack server not running?\n"); + return 1; + } + + ports = jack_get_ports (client, NULL, NULL, 0); + + for (i = 0; ports[i]; ++i) { + printf ("%s\n", ports[i]); + } + + jack_client_close (client); + exit (0); +} + diff --git a/example-clients/metro.c b/example-clients/metro.c new file mode 100644 index 0000000..31f5c2b --- /dev/null +++ b/example-clients/metro.c @@ -0,0 +1,242 @@ +/* + 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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 pos = 0; + +void +usage () + +{ + fprintf (stderr, "\ +usage: jack_metro + [ --frequency OR -f frequency (in Hz) ] + [ --amplitude OR -A maximum amplitude (between 0 and 1) ] + [ --duration OR -D duration (in ms) ] + [ --attack OR -a attack (in percent of duration) ] + [ --decay OR -d decay (in percent of duration) ] + [ --name OR -n jack name for metronome client ] + --bpm OR -b beats per minute +"); +} + +int +process (jack_nframes_t nframes, void *arg) +{ + sample_t *buffer = (sample_t *) jack_port_get_buffer(output_port, nframes); + jack_nframes_t frames_left = nframes; + + while (wave_length - pos < frames_left) { + memcpy (buffer + (nframes - frames_left), wave + pos, sizeof (sample_t) * (wave_length - pos)); + frames_left -= wave_length - pos; + pos = 0; + } + if (frames_left > 0) { + memcpy (buffer + (nframes - frames_left), wave + pos, sizeof (sample_t) * frames_left); + pos += frames_left; + } + return 0; +} + +int +buffer_size_change () { + printf("Buffer size has changed! Exiting...\n"); + exit(-1); +} + +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; + + const char *options = "f:A:D:a:d:b:n:hv"; + 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'}, + {"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 = %lu\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"); + fprintf (stderr, "bpm = %lu\n", bpm); + break; + case 'n': + client_name = (char *) malloc (strlen (optarg) * sizeof (char)); + strcpy (client_name, optarg); + break; + case 'v': + verbose = 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_new (client_name)) == 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 = %lu, wave length = %lu\n", tone_length, wave_length); + return -1; + } + if (attack_length + decay_length > 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 < tone_length - decay_length; i++) { + amp[i] = max_amp; + } + for (i = tone_length - decay_length; i < tone_length; i++) { + amp[i] = - max_amp * (i - (double) tone_length) / ((double) decay_length); + } + for (i = 0; i < tone_length; i++) { + wave[i] = amp[i] * sin (scale * i); + } + for (i = tone_length; i < wave_length; i++) { + wave[i] = 0; + } + + if (jack_activate (client)) { + fprintf (stderr, "cannot activate client"); + return 1; + } + + if (verbose) { + } + + while (1) { + sleep(1); + }; + +} diff --git a/example-clients/showtime.c b/example-clients/showtime.c new file mode 100644 index 0000000..36e9db8 --- /dev/null +++ b/example-clients/showtime.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include + +#include +#include + +jack_client_t *client; +jack_transport_info_t now; + +void +showtime () +{ + jack_transport_info_t current = now; + printf ("frame: %lu state: %d loop: %lu-%lu\n", current.position, current.state, current.loop_start, current.loop_end); +} + +int +process (jack_nframes_t nframes, void *arg) +{ + now.valid = JackTransportState|JackTransportPosition|JackTransportLoop; + jack_get_transport_info (client, &now); + return 0; +} + +void +jack_shutdown (void *arg) +{ + exit (1); +} + +void +signal_handler (int sig) +{ + fprintf (stderr, "signal received, exiting ...\n"); + jack_client_close (client); + exit (0); +} + +int +main (int argc, char *argv[]) + +{ + /* try to become a client of the JACK server */ + + if ((client = jack_client_new ("showtime")) == 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 `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 that we are ready to roll */ + + if (jack_activate (client)) { + fprintf (stderr, "cannot activate client"); + return 1; + } + + while (1) { + usleep (100000); + showtime (); + } + + jack_client_close (client); + exit (0); +} + diff --git a/jack/internal.h b/jack/internal.h index 28c41fd..15da4fb 100644 --- a/jack/internal.h +++ b/jack/internal.h @@ -92,10 +92,11 @@ typedef struct { typedef struct { - jack_time_info_t time; + jack_time_info_t current_time; + jack_time_info_t pending_time; jack_frame_timer_t frame_timer; int in_process; - jack_nframes_t frames_at_cycle_start; + jack_nframes_t frames_at_cycle_start; pid_t engine_pid; unsigned long buffer_size; char real_time; @@ -103,8 +104,9 @@ typedef struct { int has_capabilities; float cpu_load; unsigned long port_max; - jack_port_shared_t ports[0]; int engine_ok; + jack_port_shared_t ports[0]; + } jack_control_t; typedef enum { diff --git a/jackd/engine.c b/jackd/engine.c index e1cd44d..4ac89df 100644 --- a/jackd/engine.c +++ b/jackd/engine.c @@ -411,9 +411,9 @@ jack_set_buffer_size (jack_engine_t *engine, jack_nframes_t nframes) static int jack_set_sample_rate (jack_engine_t *engine, jack_nframes_t nframes) - { - engine->control->time.frame_rate = nframes; + engine->control->current_time.frame_rate = nframes; + engine->control->pending_time.frame_rate = nframes; return 0; } @@ -593,6 +593,11 @@ jack_engine_post_process (jack_engine_t *engine) jack_lock_graph (engine); + /* update timebase */ + + engine->control->pending_time.cycles = engine->control->current_time.cycles; + engine->control->current_time = engine->control->pending_time; + /* find any clients that need removal due to timeouts, etc. */ for (node = engine->clients; node; node = g_slist_next (node) ) { @@ -600,7 +605,7 @@ jack_engine_post_process (jack_engine_t *engine) client = (jack_client_internal_t *) node->data; ctl = client->control; - if (ctl->timed_out || (ctl->state > NotTriggered && ctl->state != Finished)) { + if (ctl->state > NotTriggered && ctl->state != Finished && ctl->timed_out++) { client->error = TRUE; } @@ -625,8 +630,9 @@ jack_engine_post_process (jack_engine_t *engine) if (client->error) { if (engine->verbose) { - fprintf (stderr, "removing failed client %s state = %s\n", - client->control->name, client_state_names[client->control->state]); + fprintf (stderr, "removing failed client %s state = %s errors = %d\n", + client->control->name, client_state_names[client->control->state], + client->error); } jack_remove_client (engine, (jack_client_internal_t *) node->data); @@ -1039,7 +1045,10 @@ jack_client_deactivate (jack_engine_t *engine, jack_client_id_t id) if (client == engine->timebase_client) { engine->timebase_client = 0; - engine->control->time.frame = 0; + engine->control->current_time.frame = 0; + engine->control->pending_time.frame = 0; + engine->control->current_time.transport_state = JackTransportStopped; + engine->control->pending_time.transport_state = JackTransportStopped; } for (portnode = client->ports; portnode; portnode = g_slist_next (portnode)) { @@ -1408,8 +1417,10 @@ jack_engine_new (int realtime, int rtpriority, int verbose) engine->control->cpu_load = 0; engine->control->buffer_size = 0; - engine->control->time.frame_rate = 0; - engine->control->time.frame = 0; + engine->control->current_time.frame_rate = 0; + engine->control->current_time.frame = 0; + engine->control->pending_time.frame_rate = 0; + engine->control->pending_time.frame = 0; engine->control->in_process = 0; engine->control->has_capabilities = 0; @@ -1675,7 +1686,7 @@ jack_main_thread (void *arg) /* store the execution time for later averaging */ engine->rolling_client_usecs[engine->rolling_client_usecs_index++] = - (float) (cycle_end - engine->control->time.cycles) / engine->cpu_mhz; + (float) (cycle_end - engine->control->current_time.cycles) / engine->cpu_mhz; if (engine->rolling_client_usecs_index >= JACK_ENGINE_ROLLING_COUNT) { engine->rolling_client_usecs_index = 0; @@ -1882,7 +1893,10 @@ jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client) if (client == engine->timebase_client) { engine->timebase_client = 0; - engine->control->time.frame = 0; + engine->control->current_time.frame = 0; + engine->control->pending_time.frame = 0; + engine->control->current_time.transport_state = JackTransportStopped; + engine->control->pending_time.transport_state = JackTransportStopped; } jack_client_disconnect (engine, client); diff --git a/jackd/jackd.c b/jackd/jackd.c index 14981ba..c5b27d0 100644 --- a/jackd/jackd.c +++ b/jackd/jackd.c @@ -214,6 +214,8 @@ jack_engine_waiter_thread (void *arg) } if (warg->argc) { + + fprintf (stderr, "loading driver ..\n"); if ((driver = jack_driver_load (warg->argc, warg->argv)) == 0) { fprintf (stderr, "cannot load driver module %s\n", warg->argv[0]); @@ -228,6 +230,8 @@ jack_engine_waiter_thread (void *arg) jack_set_asio_mode (engine, TRUE); } + fprintf (stderr, "starting engine\n"); + if (jack_run (engine)) { fprintf (stderr, "cannot start main JACK thread\n"); kill (warg->pid, SIGTERM); diff --git a/libjack/client.c b/libjack/client.c index 6870eb4..3b1f3cb 100644 --- a/libjack/client.c +++ b/libjack/client.c @@ -1100,7 +1100,7 @@ unsigned long jack_get_buffer_size (jack_client_t *client) unsigned long jack_get_sample_rate (jack_client_t *client) { - return client->engine->time.frame_rate; + return client->engine->current_time.frame_rate; } static jack_port_t * @@ -1513,7 +1513,7 @@ jack_set_sample_rate_callback (jack_client_t *client, JackSampleRateCallback cal /* Now invoke it */ - callback (client->engine->time.frame_rate, arg); + callback (client->engine->current_time.frame_rate, arg); return 0; } @@ -1780,8 +1780,8 @@ jack_frames_since_cycle_start (const jack_client_t *client) { float usecs; - usecs = (float) (get_cycles() - client->engine->time.cycles) / client->cpu_mhz; - return (jack_nframes_t) floor ((((float) client->engine->time.frame_rate) / 1000000.0f) * usecs); + usecs = (float) (get_cycles() - client->engine->current_time.cycles) / client->cpu_mhz; + return (jack_nframes_t) floor ((((float) client->engine->current_time.frame_rate) / 1000000.0f) * usecs); } jack_nframes_t @@ -1794,7 +1794,7 @@ jack_frame_time (const jack_client_t *client) jack_read_frame_time (client, ¤t); usecs = (float) (get_cycles() - current.stamp) / client->cpu_mhz; - elapsed = (jack_nframes_t) floor ((((float) client->engine->time.frame_rate) / 1000000.0f) * usecs); + elapsed = (jack_nframes_t) floor ((((float) client->engine->current_time.frame_rate) / 1000000.0f) * usecs); return current.frames + elapsed; } @@ -1940,8 +1940,8 @@ int jack_get_transport_info (jack_client_t *client, jack_transport_info_t *info) { - jack_time_info_t *time_info = &client->engine->time; - + jack_time_info_t *time_info = &client->engine->current_time; + if (info->valid & JackTransportState) { info->state = time_info->transport_state; } @@ -1962,7 +1962,7 @@ int jack_set_transport_info (jack_client_t *client, jack_transport_info_t *info) { - jack_time_info_t *time_info = &client->engine->time; + jack_time_info_t *time_info = &client->engine->pending_time; if (info->valid & JackTransportState) { time_info->transport_state = info->state;