From 78bb0de6e9ee0e72193df5eb6bb37a3f5f3b4e7a Mon Sep 17 00:00:00 2001 From: Oschowa Date: Thu, 3 Dec 2020 21:12:04 +0100 Subject: [PATCH] (Audio/JACK) Deinterleave in the process callback This allows us to avoid the extra copy to the deinterleave buffer and lets us use only a single jack ringbuffer. --- audio/drivers/jack.c | 119 +++++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 61 deletions(-) diff --git a/audio/drivers/jack.c b/audio/drivers/jack.c index 3bc1591c47..f0729b385d 100644 --- a/audio/drivers/jack.c +++ b/audio/drivers/jack.c @@ -35,7 +35,7 @@ typedef struct jack { jack_client_t *client; jack_port_t *ports[2]; - jack_ringbuffer_t *buffer[2]; + jack_ringbuffer_t *buffer; #ifdef HAVE_THREADS scond_t *cond; slock_t *cond_lock; @@ -46,11 +46,33 @@ typedef struct jack bool is_paused; } jack_t; +static size_t read_deinterleaved(float *dst[2], jack_nframes_t dst_offset, + jack_ringbuffer_data_t buf, jack_nframes_t nframes) +{ + int i; + jack_nframes_t j, frames_avail; + const float *src = (const float *)buf.buf; + + if (nframes <= 0) + return 0; + + frames_avail = FRAMES(buf.len); + nframes = nframes < frames_avail ? nframes : frames_avail; + + for (j = 0; j < nframes; j++) + for (i = 0; i < 2; i++) + dst[i][dst_offset + j] = *src++; + + return nframes; +} + static int process_cb(jack_nframes_t nframes, void *data) { int i; - jack_nframes_t avail[2], min_avail; + jack_nframes_t read = 0; jack_t *jd = (jack_t*)data; + jack_ringbuffer_data_t buf[2]; + float *dst[2]; if (nframes <= 0) { @@ -60,23 +82,20 @@ static int process_cb(jack_nframes_t nframes, void *data) return 0; } - avail[0] = jack_ringbuffer_read_space(jd->buffer[0]); - avail[1] = jack_ringbuffer_read_space(jd->buffer[1]); - min_avail = ((avail[0] < avail[1]) ? avail[0] : avail[1]) / sizeof(jack_default_audio_sample_t); + for (i = 0; i < 2; i++) + dst[i] = (float *)jack_port_get_buffer(jd->ports[i], nframes); - if (min_avail > nframes) - min_avail = nframes; + jack_ringbuffer_get_read_vector(jd->buffer, buf); for (i = 0; i < 2; i++) - { - jack_nframes_t f; - jack_default_audio_sample_t *out = (jack_default_audio_sample_t*)jack_port_get_buffer(jd->ports[i], nframes); + read += read_deinterleaved(dst, read, buf[i], nframes - read); - jack_ringbuffer_read(jd->buffer[i], (char*)out, min_avail * sizeof(jack_default_audio_sample_t)); + jack_ringbuffer_read_advance(jd->buffer, read * sizeof(float) * 2); + + for (; read < nframes; read++) + for (i = 0; i < 2; i++) + dst[i][read] = 0.0f; - for (f = min_avail; f < nframes; f++) - out[f] = 0.0f; - } #ifdef HAVE_THREADS scond_signal(jd->cond); #endif @@ -193,14 +212,12 @@ static void *ja_init(const char *device, jd->buffer_size = bufsize; RARCH_LOG("[JACK]: Internal buffer size: %d frames.\n", (int)(bufsize / sizeof(jack_default_audio_sample_t))); - for (i = 0; i < 2; i++) + + jd->buffer = jack_ringbuffer_create(bufsize); + if (!jd->buffer) { - jd->buffer[i] = jack_ringbuffer_create(bufsize); - if (!jd->buffer[i]) - { - RARCH_ERR("[JACK]: Failed to create buffers.\n"); - goto error; - } + RARCH_ERR("[JACK]: Failed to create buffers.\n"); + goto error; } parsed = parse_ports(dest_ports, jports); @@ -235,43 +252,31 @@ error: return NULL; } -static size_t write_buffer(jack_t *jd, const float *buf, size_t size) +static ssize_t ja_write(void *data, const void *buf_, size_t size) { - int i; - size_t j, written = 0; - jack_default_audio_sample_t out_deinterleaved_buffer[2][AUDIO_CHUNK_SIZE_NONBLOCKING * AUDIO_MAX_RATIO]; - size_t frames = FRAMES(size); + jack_t *jd = (jack_t*)data; + const char *buf = (const char *)buf_; + size_t written = 0; - /* Avoid buffer overflow if a DSP plugin generated a huge number of frames. */ - if (frames > AUDIO_CHUNK_SIZE_NONBLOCKING * AUDIO_MAX_RATIO) - frames = AUDIO_CHUNK_SIZE_NONBLOCKING * AUDIO_MAX_RATIO; - - for (i = 0; i < 2; i++) - for (j = 0; j < frames; j++) - out_deinterleaved_buffer[i][j] = buf[j * 2 + i]; - - while (written < frames) + while (size > 0) { - size_t avail[2], min_avail, write_frames; + size_t avail, to_write; + if (jd->shutdown) return 0; - avail[0] = jack_ringbuffer_write_space(jd->buffer[0]); - avail[1] = jack_ringbuffer_write_space(jd->buffer[1]); + avail = jack_ringbuffer_write_space(jd->buffer); - min_avail = avail[0] < avail[1] ? avail[0] : avail[1]; - min_avail /= sizeof(float); + to_write = size < avail ? size : avail; + /* make sure to only write multiples of the sample size */ + to_write = (to_write / sizeof(float)) * sizeof(float); - write_frames = frames - written > min_avail ? min_avail : frames - written; - - if (write_frames > 0) + if (to_write > 0) { - for (i = 0; i < 2; i++) - { - jack_ringbuffer_write(jd->buffer[i], (const char*)&out_deinterleaved_buffer[i][written], - write_frames * sizeof(jack_default_audio_sample_t)); - } - written += write_frames; + jack_ringbuffer_write(jd->buffer, buf, to_write); + buf += to_write; + size -= to_write; + written += to_write; } else if (!jd->nonblock) { @@ -286,14 +291,7 @@ static size_t write_buffer(jack_t *jd, const float *buf, size_t size) break; } - return written * sizeof(float) * 2; -} - -static ssize_t ja_write(void *data, const void *buf, size_t size) -{ - jack_t *jd = (jack_t*)data; - - return write_buffer(jd, (const float*)buf, size); + return written; } static bool ja_stop(void *data) @@ -340,9 +338,8 @@ static void ja_free(void *data) jack_client_close(jd->client); } - for (i = 0; i < 2; i++) - if (jd->buffer[i]) - jack_ringbuffer_free(jd->buffer[i]); + if (jd->buffer) + jack_ringbuffer_free(jd->buffer); #ifdef HAVE_THREADS if (jd->cond_lock) @@ -362,7 +359,7 @@ static bool ja_use_float(void *data) static size_t ja_write_avail(void *data) { jack_t *jd = (jack_t*)data; - return jack_ringbuffer_write_space(jd->buffer[0]); + return jack_ringbuffer_write_space(jd->buffer); } static size_t ja_buffer_size(void *data)