From a321c5d3e0f73f3652f959f3b1fd15c77a7b52f5 Mon Sep 17 00:00:00 2001 From: pbd Date: Wed, 6 Mar 2002 18:38:03 +0000 Subject: [PATCH] remove cleanup thread, add dither code from steve harris git-svn-id: svn+ssh://jackaudio.org/trunk/jack@145 0c269be4-1314-0410-8aa9-9f06e86f4224 --- alsa_driver.c | 57 +++++++++++++++++++++++++---- client.c | 5 ++- configure.in | 4 +-- engine.c | 90 ++++++++++++++++++---------------------------- jack/alsa_driver.h | 9 +++-- jack/engine.h | 1 - jack/memops.h | 13 +++---- jack/types.h | 17 +++++++++ memops.c | 86 +++++++++++++++++++++++++++++++++++++++++--- 9 files changed, 202 insertions(+), 80 deletions(-) diff --git a/alsa_driver.c b/alsa_driver.c index 19bc12f..3ec91dd 100644 --- a/alsa_driver.c +++ b/alsa_driver.c @@ -54,6 +54,11 @@ alsa_driver_release_channel_dependent_memory (alsa_driver_t *driver) free (driver->silent); driver->silent = 0; } + + if (driver->dither_state) { + free (driver->dither_state); + driver->dither_state = 0; + } } static int @@ -150,12 +155,27 @@ alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) driver->channel_copy = memcpy_fake; } - if (driver->dither) { + switch (driver->dither) { + case Rectangular: printf("Rectangular dithering at 16 bits\n"); driver->write_via_copy = sample_move_dither_rect_d16_sS; - } else { + break; + + case Triangular: + printf("Triangular dithering at 16 bits\n"); + driver->write_via_copy = sample_move_dither_tri_d16_sS; + break; + + case Shaped: + printf("Noise-shaped dithering at 16 bits\n"); + driver->write_via_copy = sample_move_dither_shaped_d16_sS; + break; + + default: driver->write_via_copy = sample_move_d16_sS; + break; } + driver->read_via_copy = sample_move_dS_s16; break; @@ -463,6 +483,8 @@ alsa_driver_set_parameters (alsa_driver_t *driver, nframes_t frames_per_cycle, n for (chn = 0; chn < driver->playback_nchannels; chn++) { driver->channel_done_bits |= (1<dither_state = (dither_state_t *) calloc ( driver->playback_nchannels, sizeof (dither_state_t)); } if (driver->capture_handle) { @@ -995,14 +1017,17 @@ alsa_driver_process (alsa_driver_t *driver, nframes_t nframes) /* now move data from ports to channels */ for (chn = 0, node = driver->playback_ports; node; node = g_slist_next (node), chn++) { - + sample_t *buf; + jack_port_t *port = (jack_port_t *) node->data; if (!jack_port_connected (port)) { continue; } + + buf = jack_port_get_buffer (port, contiguous); - alsa_driver_write_to_channel (driver, chn, jack_port_get_buffer (port, contiguous), contiguous); + alsa_driver_write_to_channel (driver, chn, buf, contiguous); } } @@ -1256,7 +1281,7 @@ alsa_driver_new (char *name, char *alsa_device, int hw_monitoring, int capturing, int playing, - int dither) + DitherAlgorithm dither) { int err; @@ -1456,6 +1481,7 @@ alsa PCM driver args: -D (duplex, default: yes) -C (capture, default: duplex) -P (playback, default: duplex) + -z[r|t|s|-] (dither, rect|tri|shaped|off, default: off) "); } @@ -1469,7 +1495,7 @@ driver_initialize (int argc, char **argv) int hw_monitoring = FALSE; int capture = FALSE; int playback = FALSE; - int dither = FALSE; + DitherAlgorithm dither = None; int i; /* grrrr ... getopt() cannot be called in more than one "loop" @@ -1518,7 +1544,24 @@ driver_initialize (int argc, char **argv) break; case 'z': - dither = TRUE; + switch (argv[i][2]) { + case '-': + dither = None; + break; + + case 'r': + dither = Rectangular; + break; + + case 's': + dither = Shaped; + break; + + case 't': + default: + dither = Triangular; + break; + } break; default: diff --git a/client.c b/client.c index 6dacf76..77388a0 100644 --- a/client.c +++ b/client.c @@ -1203,6 +1203,9 @@ jack_port_get_buffer (jack_port_t *port, nframes_t nframes) the buffer of the connected (output) port. */ + printf ("get buffer for port %s is at offset %d\n", port->shared->name, + ((jack_port_t *) node->data)->shared->offset); + return jack_port_buffer (((jack_port_t *) node->data)); } @@ -1597,7 +1600,7 @@ jack_audio_port_mixdown (jack_port_t *port, nframes_t nframes) node = port->connections; input = (jack_port_t *) node->data; buffer = jack_port_buffer (port); - + memcpy (buffer, jack_port_buffer (input), sizeof (sample_t) * nframes); for (node = g_slist_next (node); node; node = g_slist_next (node)) { diff --git a/configure.in b/configure.in index b373060..8762c26 100644 --- a/configure.in +++ b/configure.in @@ -4,7 +4,7 @@ AC_INIT(client.c) AC_CONFIG_AUX_DIR(.) JACK_MAJOR_VERSION=0 -JACK_MINOR_VERSION=19 +JACK_MINOR_VERSION=20 JACK_MICRO_VERSION=0 BETA= @@ -31,7 +31,7 @@ JACK_OPT_CFLAGS="-D_REENTRANT -O6 -Wall -fomit-frame-pointer -ffast-math -fstren AC_ARG_ENABLE(optimize, [ --enable-optimize ask the compiler for its best optimizations.], - [ if test "x$enable_optimize" != "xno" ; then JACK_CFLAGS="$JACK_OPT_CFLAGS" ; fi ]) + [ if test "x$enable_optimize" != "xno" ; then CFLAGS="$JACK_OPT_CFLAGS" ; fi ]) AC_SUBST(JACK_CFLAGS) diff --git a/engine.c b/engine.c index 637b8b6..c07ec5b 100644 --- a/engine.c +++ b/engine.c @@ -520,48 +520,6 @@ jack_process (jack_engine_t *engine, nframes_t nframes) return engine->process_errors > 0; } -static void * -jack_cleanup_clients (void *arg) -{ - jack_engine_t *engine = (jack_engine_t *) arg; - jack_client_internal_t *client; - GSList *node, *tmp; - int need_sort = FALSE; - - jack_lock_graph (engine); - - /* remove all dead clients */ - - for (node = engine->clients; node; ) { - - tmp = g_slist_next (node); - - client = (jack_client_internal_t *) node->data; - - if (client->error) { - - if (engine->verbose) { - fprintf (stderr, "removing failed client %s (errors: %d)\n", - client->control->name, client->error); - } - - jack_remove_client (engine, (jack_client_internal_t *) node->data); - need_sort = TRUE; - } - - node = tmp; - } - - if (need_sort) { - jack_sort_graph (engine); - } - - jack_unlock_graph (engine); - pthread_mutex_unlock (&engine->cleanup_lock); - - return NULL; -} - static int jack_engine_post_process (jack_engine_t *engine) { @@ -579,10 +537,6 @@ jack_engine_post_process (jack_engine_t *engine) client = (jack_client_internal_t *) node->data; ctl = client->control; - if (engine->verbose) { - fprintf (stderr, "client %s state = %s\n", ctl->name, client_state_names[ctl->state]); - } - if (ctl->timed_out || (ctl->state > NotTriggered && ctl->state != Finished)) { client->error++; } @@ -592,20 +546,40 @@ jack_engine_post_process (jack_engine_t *engine) } } - jack_unlock_graph (engine); - if (need_remove) { - /* only one thread is allowed to run cleanup at a time. if - one is already underway, don't bother starting another. - */ + GSList *tmp; + int need_sort = FALSE; + + /* remove all dead clients */ - if (pthread_mutex_trylock (&engine->cleanup_lock) == 0) { - pthread_t cleanup_thread; - pthread_create (&cleanup_thread, NULL, jack_cleanup_clients, engine); + for (node = engine->clients; node; ) { + + tmp = g_slist_next (node); + + client = (jack_client_internal_t *) node->data; + + if (client->error) { + + if (engine->verbose) { + fprintf (stderr, "removing failed client %s state = %s\n", + client->control->name, client_state_names[client->control->state]); + } + + jack_remove_client (engine, (jack_client_internal_t *) node->data); + need_sort = TRUE; + } + + node = tmp; + } + + if (need_sort) { + jack_sort_graph (engine); } } + jack_unlock_graph (engine); + return 0; } @@ -1152,7 +1126,6 @@ jack_engine_new (int realtime, int rtpriority, int verbose) engine->asio_mode = FALSE; pthread_mutex_init (&engine->client_lock, 0); - pthread_mutex_init (&engine->cleanup_lock, 0); pthread_mutex_init (&engine->buffer_lock, 0); pthread_mutex_init (&engine->port_lock, 0); @@ -2563,6 +2536,13 @@ jack_port_assign_buffer (jack_engine_t *engine, jack_port_internal_t *port) break; } } + + if (engine->verbose) { + fprintf (stderr, "port %s assigned buffer in shm key 0x%x at offset %d\n", + port->shared->name, + port->shared->shm_key, + port->shared->offset); + } if (port->shared->shm_key >= 0) { engine->port_buffer_freelist = g_slist_remove (engine->port_buffer_freelist, bi); diff --git a/jack/alsa_driver.h b/jack/alsa_driver.h index 80385b6..bd0b903 100644 --- a/jack/alsa_driver.h +++ b/jack/alsa_driver.h @@ -34,7 +34,8 @@ typedef void (*ReadCopyFunction) (sample_t *dst, char *src, unsigned long src_skip_bytes); typedef void (*WriteCopyFunction) (char *dst, sample_t *src, unsigned long src_bytes, - unsigned long dst_skip_bytes); + unsigned long dst_skip_bytes, + dither_state_t *state); typedef void (*CopyCopyFunction) (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, @@ -102,7 +103,8 @@ typedef struct { WriteCopyFunction write_via_copy; CopyCopyFunction channel_copy; - int dither; + int dither; + dither_state_t *dither_state; SampleClockMode clock_mode; GSList *clock_sync_listeners; @@ -161,7 +163,8 @@ static __inline__ void alsa_driver_write_to_channel (alsa_driver_t *driver, driver->write_via_copy (driver->playback_addr[channel], buf, nsamples, - driver->playback_interleave_skip); + driver->playback_interleave_skip, + driver->dither_state+channel); alsa_driver_mark_channel_done (driver, channel); } diff --git a/jack/engine.h b/jack/engine.h index f8080de..4e343c1 100644 --- a/jack/engine.h +++ b/jack/engine.h @@ -38,7 +38,6 @@ struct _jack_engine { void (*process_unlock)(struct _jack_engine *); int (*post_process)(struct _jack_engine *); pthread_mutex_t client_lock; - pthread_mutex_t cleanup_lock; pthread_mutex_t buffer_lock; pthread_mutex_t port_lock; int process_errors; diff --git a/jack/memops.h b/jack/memops.h index 3c5cd3e..f67d7f1 100644 --- a/jack/memops.h +++ b/jack/memops.h @@ -23,17 +23,18 @@ #include -void sample_move_d32u24_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip); -void sample_move_d16_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip); +void sample_move_d32u24_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_d16_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); -void sample_move_dither_rect_d16_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip); +void sample_move_dither_rect_d16_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_tri_d16_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_shaped_d16_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); void sample_move_dS_s32u24 (sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); void sample_move_dS_s16 (sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); - -void sample_merge_d16_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip); -void sample_merge_d32u24_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip); +void sample_merge_d16_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_merge_d32u24_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); static __inline__ void sample_merge (sample_t *dst, sample_t *src, unsigned long cnt) diff --git a/jack/types.h b/jack/types.h index ed80d70..b66295d 100644 --- a/jack/types.h +++ b/jack/types.h @@ -70,4 +70,21 @@ typedef enum { NoSync = 0x8 } ClockSyncStatus; +typedef enum { + None, + Rectangular, + Triangular, + Shaped +} DitherAlgorithm; + +#define DITHER_BUF_SIZE 8 +#define DITHER_BUF_MASK 7 + +typedef struct { + unsigned int depth; + float rm1; + unsigned int idx; + float e[DITHER_BUF_SIZE]; +} dither_state_t; + #endif /* __jack_engine_types_h__ */ diff --git a/memops.c b/memops.c index a7fafd1..484f084 100644 --- a/memops.c +++ b/memops.c @@ -41,7 +41,7 @@ inline int f_round(float f) { floating-point => int conversion the compiler provides. */ -void sample_move_d32u24_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip) +void sample_move_d32u24_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { /* ALERT: signed sign-extension portability !!! */ @@ -64,7 +64,7 @@ void sample_move_dS_s32u24 (sample_t *dst, char *src, unsigned long nsamples, un } } -void sample_move_d16_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip) +void sample_move_d16_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { sample_t val; @@ -89,7 +89,7 @@ void sample_move_d16_sS (char *dst, sample_t *src, unsigned long nsamples, unsi } } -void sample_move_dither_rect_d16_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip) +void sample_move_dither_rect_d16_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { sample_t val; @@ -112,6 +112,82 @@ void sample_move_dither_rect_d16_sS (char *dst, sample_t *src, unsigned long ns } } +void sample_move_dither_tri_d16_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) + +{ + 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, sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) + +{ + sample_t x; + sample_t xe; /* the innput sample - filtered error */ + 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 (sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) { @@ -123,7 +199,7 @@ void sample_move_dS_s16 (sample_t *dst, char *src, unsigned long nsamples, unsig } } -void sample_merge_d16_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip) +void sample_merge_d16_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { short val; @@ -144,7 +220,7 @@ void sample_merge_d16_sS (char *dst, sample_t *src, unsigned long nsamples, uns } } -void sample_merge_d32u24_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip) +void sample_merge_d32u24_sS (char *dst, sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { /* ALERT: signed sign-extension portability !!! */