From c07889f2d855d936b820e7650169e7f7a206c741 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Mon, 9 Jun 2025 03:19:06 +0800 Subject: [PATCH 13/19] viz.c: blockless dispatch --- include/deadbeef/deadbeef.h | 4 +- src/viz.c | 181 ++++++++++++++++++++++-------------- 2 files changed, 113 insertions(+), 72 deletions(-) diff --git a/include/deadbeef/deadbeef.h b/include/deadbeef/deadbeef.h index a11f2bd26..9faea357d 100644 --- a/include/deadbeef/deadbeef.h +++ b/include/deadbeef/deadbeef.h @@ -1407,7 +1407,7 @@ typedef struct { /// Incoming waveform data can be arbitrary size. /// Samples are stored in interleaved layout. /// @param ctx Unique pointer identifying your listener. - void (*vis_waveform_listen) (void *ctx, void (*callback)(void *ctx, const ddb_audio_data_t *data)); + void (*vis_waveform_listen) (void *ctx, void (*callback)(void *ctx, ddb_audio_data_t *data)); /// Unregister from getting visualization wave data. /// @param ctx The pointer used with the matching @c vis_waveform_listen call. @@ -1415,7 +1415,7 @@ typedef struct { /// This method does nothing starting with API 1.15. /// Please use @c vis_spectrum_listen2 instead. - void (*vis_spectrum_listen) (void *ctx, void (*callback)(void *ctx, const ddb_audio_data_t *data)) DEPRECATED_115; + void (*vis_spectrum_listen) (void *ctx, void (*callback)(void *ctx, ddb_audio_data_t *data)) DEPRECATED_115; void (*vis_spectrum_unlisten) (void *ctx); diff --git a/src/viz.c b/src/viz.c index cfb24cc55..dc692fbe1 100644 --- a/src/viz.c +++ b/src/viz.c @@ -84,52 +84,77 @@ viz_free (void) { _free_buffers(); } -void -viz_waveform_listen (void *ctx, void (*callback)(void *ctx, const ddb_audio_data_t *data)) { - dispatch_sync(sync_queue, ^{ - wavedata_listener_t *l = malloc (sizeof (wavedata_listener_t)); - memset (l, 0, sizeof (wavedata_listener_t)); - l->ctx = ctx; - l->callback = callback; - l->next = waveform_listeners; - waveform_listeners = l; - }); +typedef struct { + void *ctx; + void (*callback)(void *ctx, const ddb_audio_data_t *data); +} viz_waveform_listen_args_t; + +static void viz_waveform_listen_f(void *p) { + viz_waveform_listen_args_t *args = p; + wavedata_listener_t *l = malloc(sizeof(wavedata_listener_t)); + memset(l, 0, sizeof(wavedata_listener_t)); + l->ctx = args->ctx; + l->callback = args->callback; + l->next = waveform_listeners; + waveform_listeners = l; } void -viz_waveform_unlisten (void *ctx) { - dispatch_sync(sync_queue, ^{ - wavedata_listener_t *l, *prev = NULL; - for (l = waveform_listeners; l; prev = l, l = l->next) { - if (l->ctx == ctx) { - if (prev) { - prev->next = l->next; - } - else { - waveform_listeners = l->next; - } - free (l); - break; +viz_waveform_listen(void *ctx, void (*callback)(void *ctx, const ddb_audio_data_t *data)) { + viz_waveform_listen_args_t args = { ctx, callback }; + dispatch_sync_f(sync_queue, &args, viz_waveform_listen_f); +} + +typedef struct { + void *ctx; +} viz_waveform_unlisten_args_t; + +static void viz_waveform_unlisten_f(void *p) { + void *ctx = ((viz_waveform_unlisten_args_t *)p)->ctx; + wavedata_listener_t *l, *prev = NULL; + for (l = waveform_listeners; l; prev = l, l = l->next) { + if (l->ctx == ctx) { + if (prev) { + prev->next = l->next; + } + else { + waveform_listeners = l->next; } + free(l); + break; } - }); + } +} + +void +viz_waveform_unlisten(void *ctx) { + viz_waveform_unlisten_args_t args = { ctx }; + dispatch_sync_f(sync_queue, &args, viz_waveform_unlisten_f); } void viz_spectrum_listen (void *ctx, void (*callback)(void *ctx, const ddb_audio_data_t *data)) { - dispatch_sync(sync_queue, ^{ - wavedata_listener_t *l = malloc (sizeof (wavedata_listener_t)); - memset (l, 0, sizeof (wavedata_listener_t)); - l->ctx = ctx; - l->callback = callback; + typedef struct { + void *ctx; + void (*callback)(void *ctx, const ddb_audio_data_t *data); + } spec_listen_args_t; + static void spec_listen_f(void *p) { + spec_listen_args_t *args = p; + wavedata_listener_t *l = malloc(sizeof(wavedata_listener_t)); + memset(l, 0, sizeof(wavedata_listener_t)); + l->ctx = args->ctx; + l->callback = args->callback; l->next = spectrum_listeners; spectrum_listeners = l; - }); + } + spec_listen_args_t args = { ctx, callback }; + dispatch_sync_f(sync_queue, &args, spec_listen_f); } void viz_spectrum_unlisten (void *ctx) { - dispatch_sync(sync_queue, ^{ + static void spec_unlisten_f(void *p) { + void *ctx = p; wavedata_listener_t *l, *prev = NULL; for (l = spectrum_listeners; l; prev = l, l = l->next) { if (l->ctx == ctx) { @@ -139,35 +164,65 @@ viz_spectrum_unlisten (void *ctx) { else { spectrum_listeners = l->next; } - free (l); + free(l); break; } } - }); + } + dispatch_sync_f(sync_queue, ctx, spec_unlisten_f); } void -viz_reset (void) { - dispatch_sync(sync_queue, ^{ +viz_reset(void) { + static void reset_f(void *p) { + (void)p; _need_reset = 1; - }); + } + dispatch_sync_f(sync_queue, NULL, reset_f); } void viz_process (char * restrict _bytes, int _bytes_size, DB_output_t *output, int fft_size, int wave_size) { - dispatch_sync(sync_queue, ^{ + typedef struct { + char *bytes; + int bytes_size; + DB_output_t *output; + int fft_size; + int wave_size; + } viz_process_args_t; + typedef struct { + ddb_audio_data_t *waveform_data; + float *data; + ddb_waveformat_t *out_fmt; + } viz_process_async_args_t; + static void viz_process_async_f(void *p) { + viz_process_async_args_t *args = p; + for (wavedata_listener_t *l = waveform_listeners; l; l = l->next) { + l->callback(l->ctx, args->waveform_data); + } + free(args->data); + free(args->out_fmt); + free(args->waveform_data); + free(args); + } + static void viz_process_sync_f(void *p) { + viz_process_args_t *args = p; + char *bytes = args->bytes; + int _bytes_size = args->bytes_size; + DB_output_t *output = args->output; + int fft_size = args->fft_size; + int wave_size = args->wave_size; + _init_buffers(fft_size); if (!waveform_listeners && !spectrum_listeners) { return; } - char *bytes = _bytes; if (output->fmt.flags & DDB_WAVEFORMAT_FLAG_IS_DOP) { bytes = NULL; } - - // convert to float - ddb_waveformat_t *out_fmt = calloc (1, sizeof (ddb_waveformat_t)); + + ddb_waveformat_t *out_fmt = calloc(1, sizeof(ddb_waveformat_t)); out_fmt->bps = 32; out_fmt->channels = output->fmt.channels; out_fmt->samplerate = output->fmt.samplerate; @@ -175,20 +230,14 @@ viz_process (char * restrict _bytes, int _bytes_size, DB_output_t *output, int f out_fmt->is_float = 1; const int fft_nframes = fft_size * 2; - - // calculate the size which can fit either the FFT input, or the wave data. const int output_nframes = fft_nframes > wave_size ? fft_nframes : wave_size; - - const int final_output_size = output_nframes * out_fmt->channels * sizeof (float); + const int final_output_size = output_nframes * out_fmt->channels * sizeof(float); const int final_input_size = output_nframes * output->fmt.channels * (output->fmt.bps/8); float *data = calloc(1, final_output_size); if (bytes != NULL) { - // take only as much bytes as we have available. const int convert_size = _bytes_size < final_input_size ? _bytes_size : final_input_size; - - // After this runs, we'll have a buffer with enough samples for FFT, padded with 0s if needed. - pcm_convert (&output->fmt, bytes, out_fmt, (char *)data, convert_size); + pcm_convert(&output->fmt, bytes, out_fmt, (char *)data, convert_size); } ddb_audio_data_t *waveform_data = calloc(1, sizeof(ddb_audio_data_t)); @@ -197,16 +246,14 @@ viz_process (char * restrict _bytes, int _bytes_size, DB_output_t *output, int f waveform_data->nframes = wave_size; if (_need_reset || out_fmt->channels != audio_data_channels || !spectrum_listeners) { - // reset audio_data_channels = out_fmt->channels; - memset (_freq_data, 0, sizeof (float) * _fft_size * DDB_FREQ_MAX_CHANNELS); - memset (_audio_data, 0, sizeof (float) * _fft_size * 2 * DDB_FREQ_MAX_CHANNELS); + memset(_freq_data, 0, sizeof(float) * _fft_size * DDB_FREQ_MAX_CHANNELS); + memset(_audio_data, 0, sizeof(float) * _fft_size * 2 * DDB_FREQ_MAX_CHANNELS); _need_reset = 0; } if (spectrum_listeners) { - // convert samples in planar layout - assert (fft_nframes == _fft_size * 2); + assert(fft_nframes == _fft_size * 2); for (int c = 0; c < audio_data_channels; c++) { float *channel = &_audio_data[_fft_size * 2 * c]; for (int s = 0; s < fft_nframes; s++) { @@ -214,10 +261,9 @@ viz_process (char * restrict _bytes, int _bytes_size, DB_output_t *output, int f } } - // calc fft if (_audio_data != NULL) { for (int c = 0; c < audio_data_channels; c++) { - fft_calculate (&_audio_data[_fft_size * 2 * c], &_freq_data[_fft_size * c], _fft_size); + fft_calculate(&_audio_data[_fft_size * 2 * c], &_freq_data[_fft_size * c], _fft_size); } } ddb_audio_data_t spectrum_data = { @@ -226,21 +272,16 @@ viz_process (char * restrict _bytes, int _bytes_size, DB_output_t *output, int f .nframes = _fft_size }; for (wavedata_listener_t *l = spectrum_listeners; l; l = l->next) { - l->callback (l->ctx, &spectrum_data); + l->callback(l->ctx, &spectrum_data); } } - // Pass to async queue for processing and callbacks - dispatch_async (process_queue, ^{ - for (wavedata_listener_t *l = waveform_listeners; l; l = l->next) { - l->callback (l->ctx, waveform_data); - } - - free (data); - free (out_fmt); - free (waveform_data); - }); - - }); + viz_process_async_args_t *async_args = malloc(sizeof(viz_process_async_args_t)); + async_args->waveform_data = waveform_data; + async_args->data = data; + async_args->out_fmt = out_fmt; + dispatch_async_f(process_queue, async_args, viz_process_async_f); + } + viz_process_args_t args = { _bytes, _bytes_size, output, fft_size, wave_size }; + dispatch_sync_f(sync_queue, &args, viz_process_sync_f); } - -- 2.49.0