summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alexey Yakovenko <waker@users.sourceforge.net>2013-11-01 21:41:14 +0100
committerGravatar Alexey Yakovenko <waker@users.sourceforge.net>2013-11-01 21:41:14 +0100
commit87a915f831fa97cec0e7c061345c6bd1223decd3 (patch)
treebcc52abe2498a37551f5eca64029ae670a34e1b5
parentf30a353184a725089ec3f775632f22802e296e89 (diff)
improved vis API
-rw-r--r--deadbeef.h37
-rw-r--r--plugins.c6
-rw-r--r--plugins/gtkui/widgets.c28
-rw-r--r--streamer.c115
-rw-r--r--streamer.h10
5 files changed, 123 insertions, 73 deletions
diff --git a/deadbeef.h b/deadbeef.h
index 132770d4..c9883af6 100644
--- a/deadbeef.h
+++ b/deadbeef.h
@@ -322,17 +322,6 @@ enum ddb_sort_order_t {
DDB_SORT_RANDOM, // available since API 1.3
};
-// since 1.5
-enum ddb_audio_data_type_t {
- DDB_AUDIO_WAVEFORM,
- DDB_AUDIO_FREQ,
-};
-
-// audio memory constants
-// since 1.5
-#define DDB_FREQ_BANDS 256
-#define DDB_FREQ_MAX_CHANNELS 9
-
// typecasting macros
#define DB_PLUGIN(x) ((DB_plugin_t *)(x))
#define DB_CALLBACK(x) ((DB_callback_t)(x))
@@ -358,6 +347,15 @@ typedef struct {
int is_bigendian;
} ddb_waveformat_t;
+// since 1.5
+#define DDB_FREQ_BANDS 256
+#define DDB_FREQ_MAX_CHANNELS 9
+typedef struct {
+ const ddb_waveformat_t *fmt;
+ const float *data;
+ int nframes;
+} ddb_audio_data_t;
+
// forward decl for plugin struct
struct DB_plugin_s;
@@ -824,12 +822,19 @@ typedef struct {
// register/unregister for getting continuous wave data
// mainly for visualization
// ctx must be unique
- // type is one of DDB_AUDIO_WAVEFORM and DDB_AUDIO_FREQ
- // the waveform can be arbitrary large;
- // freq data size is always DDB_FREQ_BANDS
- void (*register_continuous_wavedata_listener) (void *ctx, int type, void (*callback)(void *ctx, int type, ddb_waveformat_t *fmt, const float *data, int nsamples));
+ // the waveform data can be arbitrary size
+ // the samples are interleaved
+ void (*vis_waveform_listen) (void *ctx, void (*callback)(void *ctx, ddb_audio_data_t *data));
+ void (*vis_waveform_unlisten) (void *ctx);
- void (*unregister_continuous_wavedata_listener) (void *ctx, int type);
+ // register/unregister for getting continuous spectrum (frequency domain) data
+ // mainly for visualization
+ // ctx must be unique
+ // the data always contains DDB_FREQ_BANDS frames
+ // max number of channels is DDB_FREQ_MAX_CHANNELS
+ // the samples are non-interleaved
+ void (*vis_spectrum_listen) (void *ctx, void (*callback)(void *ctx, ddb_audio_data_t *data));
+ void (*vis_spectrum_unlisten) (void *ctx);
// this is useful to mute/unmute audio, and query the muted status, from
// plugins, without touching the volume control
diff --git a/plugins.c b/plugins.c
index b8f10e02..dcc02df5 100644
--- a/plugins.c
+++ b/plugins.c
@@ -341,8 +341,10 @@ static DB_functions_t deadbeef_api = {
.plt_get_meta = (int (*) (ddb_playlist_t *handle, const char *key, char *val, int size))plt_get_meta,
.pl_meta_exists = (int (*) (DB_playItem_t *it, const char *key))pl_meta_exists,
// ******* new 1.5 APIs ********
- .register_continuous_wavedata_listener = register_continuous_wavedata_listener,
- .unregister_continuous_wavedata_listener = unregister_continuous_wavedata_listener,
+ .vis_waveform_listen = vis_waveform_listen,
+ .vis_waveform_unlisten = vis_waveform_unlisten,
+ .vis_spectrum_listen = vis_spectrum_listen,
+ .vis_spectrum_unlisten = vis_spectrum_unlisten,
.audio_set_mute = audio_set_mute,
.audio_is_mute = audio_is_mute,
.background_job_increment = background_job_increment,
diff --git a/plugins/gtkui/widgets.c b/plugins/gtkui/widgets.c
index 45b7554f..4a676c4b 100644
--- a/plugins/gtkui/widgets.c
+++ b/plugins/gtkui/widgets.c
@@ -157,7 +157,7 @@ typedef struct {
#if USE_OPENGL
GdkGLContext *glcontext;
#endif
- float data[DDB_FREQ_BANDS];
+ float data[DDB_FREQ_BANDS * DDB_FREQ_MAX_CHANNELS];
float xscale[MAX_BANDS + 1];
int bars[MAX_BANDS + 1];
int delay[MAX_BANDS + 1];
@@ -2253,7 +2253,7 @@ w_coverart_create (void) {
void
w_scope_destroy (ddb_gtkui_widget_t *w) {
w_scope_t *s = (w_scope_t *)w;
- deadbeef->unregister_continuous_wavedata_listener (w, DDB_AUDIO_WAVEFORM);
+ deadbeef->vis_waveform_unlisten (w);
if (s->drawtimer) {
g_source_remove (s->drawtimer);
s->drawtimer = 0;
@@ -2286,7 +2286,7 @@ w_scope_draw_cb (void *data) {
}
static void
-scope_wavedata_listener (void *ctx, int type, ddb_waveformat_t *fmt, const float *data, int in_samples) {
+scope_wavedata_listener (void *ctx, ddb_audio_data_t *data) {
w_scope_t *w = ctx;
if (w->nsamples != w->resized) {
deadbeef->mutex_lock (w->mutex);
@@ -2310,8 +2310,8 @@ scope_wavedata_listener (void *ctx, int type, ddb_waveformat_t *fmt, const float
if (w->samples) {
// append
- int nsamples = in_samples / fmt->channels;
- float ratio = fmt->samplerate / 44100.f;
+ int nsamples = data->nframes / data->fmt->channels;
+ float ratio = data->fmt->samplerate / 44100.f;
int size = nsamples / ratio;
int sz = min (w->nsamples, size);
@@ -2320,11 +2320,11 @@ scope_wavedata_listener (void *ctx, int type, ddb_waveformat_t *fmt, const float
memmove (w->samples, w->samples + sz, n * sizeof (float));
float pos = 0;
for (int i = 0; i < sz && pos < nsamples; i++, pos += ratio) {
- w->samples[n + i] = data[ftoi(pos * fmt->channels) * fmt->channels + 0];
- for (int j = 1; j < fmt->channels; j++) {
- w->samples[n + i] += data[ftoi(pos * fmt->channels) * fmt->channels + j];
+ w->samples[n + i] = data->data[ftoi(pos * data->fmt->channels) * data->fmt->channels + 0];
+ for (int j = 1; j < data->fmt->channels; j++) {
+ w->samples[n + i] += data->data[ftoi(pos * data->fmt->channels) * data->fmt->channels + j];
}
- w->samples[n+i] /= fmt->channels;
+ w->samples[n+i] /= data->fmt->channels;
}
}
}
@@ -2518,7 +2518,7 @@ w_scope_create (void) {
#endif
g_signal_connect_after (G_OBJECT (w->drawarea), "realize", G_CALLBACK (scope_realize), w);
w_override_signals (w->base.widget, w);
- deadbeef->register_continuous_wavedata_listener (w, DDB_AUDIO_WAVEFORM, scope_wavedata_listener);
+ deadbeef->vis_waveform_listen(w, scope_wavedata_listener);
return (ddb_gtkui_widget_t *)w;
}
@@ -2526,6 +2526,7 @@ w_scope_create (void) {
void
w_spectrum_destroy (ddb_gtkui_widget_t *w) {
w_spectrum_t *s = (w_spectrum_t *)w;
+ deadbeef->vis_spectrum_unlisten (w);
if (s->drawtimer) {
g_source_remove (s->drawtimer);
s->drawtimer = 0;
@@ -2535,7 +2536,6 @@ w_spectrum_destroy (ddb_gtkui_widget_t *w) {
gdk_gl_context_destroy (s->glcontext);
s->glcontext = NULL;
}
- deadbeef->unregister_continuous_wavedata_listener (w, DDB_AUDIO_FREQ);
#endif
}
@@ -2556,9 +2556,9 @@ static void calculate_bands(w_spectrum_t *w, int bands)
}
static void
-spectrum_audio_listener (void *ctx, int type, ddb_waveformat_t *fmt, const float *data, int nsamples) {
+spectrum_audio_listener (void *ctx, ddb_audio_data_t *data) {
w_spectrum_t *w = ctx;
- memcpy (w->data, data, DDB_FREQ_BANDS * sizeof (float));
+ memcpy (w->data, data->data, DDB_FREQ_BANDS * sizeof (float));
}
static gboolean
@@ -2739,7 +2739,7 @@ w_spectrum_create (void) {
#endif
g_signal_connect_after (G_OBJECT (w->drawarea), "realize", G_CALLBACK (spectrum_realize), w);
w_override_signals (w->base.widget, w);
- deadbeef->register_continuous_wavedata_listener (w, DDB_AUDIO_FREQ, spectrum_audio_listener);
+ deadbeef->vis_spectrum_listen (w, spectrum_audio_listener);
return (ddb_gtkui_widget_t *)w;
}
diff --git a/streamer.c b/streamer.c
index 5cba5211..617e3578 100644
--- a/streamer.c
+++ b/streamer.c
@@ -147,12 +147,12 @@ static struct handler_s *handler;
// visualization stuff
typedef struct wavedata_listener_s {
void *ctx;
- int type;
- void (*callback)(void *ctx, int type, ddb_waveformat_t *fmt, const float *data, int nsamples);
+ void (*callback)(void *ctx, ddb_audio_data_t *data);
struct wavedata_listener_s *next;
} wavedata_listener_t;
-static wavedata_listener_t *wavedata_listeners;
+static wavedata_listener_t *waveform_listeners;
+static wavedata_listener_t *spectrum_listeners;
#if DETECT_PL_LOCK_RC
volatile pthread_t streamer_lock_tid = 0;
@@ -2282,7 +2282,7 @@ streamer_read (char *bytes, int size) {
printf ("streamer_read took %d ms\n", ms);
#endif
- if (wavedata_listeners) {
+ if (waveform_listeners || spectrum_listeners) {
int in_frame_size = (output->fmt.bps >> 3) * output->fmt.channels;
int in_frames = sz / in_frame_size;
ddb_waveformat_t out_fmt = {
@@ -2296,44 +2296,51 @@ streamer_read (char *bytes, int size) {
float temp_audio_data[in_frames * out_fmt.channels];
pcm_convert (&output->fmt, bytes, &out_fmt, (char *)temp_audio_data, sz);
+ ddb_audio_data_t data;
+ data.fmt = &out_fmt;
+ data.data = temp_audio_data;
+ data.nframes = in_frames;
mutex_lock (wdl_mutex);
- for (wavedata_listener_t *l = wavedata_listeners; l; l = l->next) {
- if (l->type == DDB_AUDIO_WAVEFORM) {
- l->callback (l->ctx, l->type, &out_fmt, temp_audio_data, in_frames);
- }
+ for (wavedata_listener_t *l = waveform_listeners; l; l = l->next) {
+ l->callback (l->ctx, &data);
}
mutex_unlock (wdl_mutex);
- if (out_fmt.channels != audio_data_channels) {
+ if (out_fmt.channels != audio_data_channels || !spectrum_listeners) {
audio_data_fill = 0;
audio_data_channels = out_fmt.channels;
}
- int remaining = in_frames;
- do {
- int sz = DDB_FREQ_BANDS-audio_data_fill;
- sz = min (sz, remaining);
- for (int c = 0; c < audio_data_channels; c++) {
- for (int s = 0; s < sz; s++) {
- audio_data[DDB_FREQ_BANDS * c + audio_data_fill + s] = temp_audio_data[(in_frames-remaining + s) * audio_data_channels + c];
- }
- }
-// memcpy (&audio_data[audio_data_fill], &temp_audio_data[in_frames-remaining], sz * sizeof (float));
- audio_data_fill += sz;
- remaining -= sz;
- if (audio_data_fill == DDB_FREQ_BANDS) {
+
+ if (spectrum_listeners) {
+ int remaining = in_frames;
+ do {
+ int sz = DDB_FREQ_BANDS-audio_data_fill;
+ sz = min (sz, remaining);
for (int c = 0; c < audio_data_channels; c++) {
- calc_freq (&audio_data[DDB_FREQ_BANDS * c], &freq_data[DDB_FREQ_BANDS * c]);
+ for (int s = 0; s < sz; s++) {
+ audio_data[DDB_FREQ_BANDS * c + audio_data_fill + s] = temp_audio_data[(in_frames-remaining + s) * audio_data_channels + c];
+ }
}
- mutex_lock (wdl_mutex);
- for (wavedata_listener_t *l = wavedata_listeners; l; l = l->next) {
- if (l->type == DDB_AUDIO_FREQ) {
- l->callback (l->ctx, l->type, &out_fmt, freq_data, DDB_FREQ_BANDS);
+ // memcpy (&audio_data[audio_data_fill], &temp_audio_data[in_frames-remaining], sz * sizeof (float));
+ audio_data_fill += sz;
+ remaining -= sz;
+ if (audio_data_fill == DDB_FREQ_BANDS) {
+ for (int c = 0; c < audio_data_channels; c++) {
+ calc_freq (&audio_data[DDB_FREQ_BANDS * c], &freq_data[DDB_FREQ_BANDS * c]);
+ }
+ ddb_audio_data_t data;
+ data.fmt = &out_fmt;
+ data.data = freq_data;
+ data.nframes = DDB_FREQ_BANDS;
+ mutex_lock (wdl_mutex);
+ for (wavedata_listener_t *l = spectrum_listeners; l; l = l->next) {
+ l->callback (l->ctx, &data);
}
+ mutex_unlock (wdl_mutex);
+ audio_data_fill = 0;
}
- mutex_unlock (wdl_mutex);
- audio_data_fill = 0;
- }
- } while (remaining > 0);
+ } while (remaining > 0);
+ }
}
if (!output->has_volume) {
@@ -2607,29 +2614,59 @@ streamer_notify_order_changed (int prev_order, int new_order) {
}
void
-register_continuous_wavedata_listener (void *ctx, int type, void (*callback)(void *ctx, int type, ddb_waveformat_t *fmt, const float *data, int nsamples)) {
+vis_waveform_listen (void *ctx, void (*callback)(void *ctx, ddb_audio_data_t *data)) {
+ mutex_lock (wdl_mutex);
+ 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;
+ mutex_unlock (wdl_mutex);
+}
+
+void
+vis_waveform_unlisten (void *ctx) {
+ mutex_lock (wdl_mutex);
+ 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;
+ }
+ }
+ mutex_unlock (wdl_mutex);
+}
+
+void
+vis_spectrum_listen (void *ctx, void (*callback)(void *ctx, ddb_audio_data_t *data)) {
mutex_lock (wdl_mutex);
wavedata_listener_t *l = malloc (sizeof (wavedata_listener_t));
memset (l, 0, sizeof (wavedata_listener_t));
l->ctx = ctx;
- l->type = type;
l->callback = callback;
- l->next = wavedata_listeners;
- wavedata_listeners = l;
+ l->next = spectrum_listeners;
+ spectrum_listeners = l;
mutex_unlock (wdl_mutex);
}
void
-unregister_continuous_wavedata_listener (void *ctx, int type) {
+vis_spectrum_unlisten (void *ctx) {
mutex_lock (wdl_mutex);
wavedata_listener_t *l, *prev = NULL;
- for (l = wavedata_listeners; l; prev = l, l = l->next) {
- if (l->ctx == ctx && l->type == type) {
+ for (l = spectrum_listeners; l; prev = l, l = l->next) {
+ if (l->ctx == ctx) {
if (prev) {
prev->next = l->next;
}
else {
- wavedata_listeners = l->next;
+ spectrum_listeners = l->next;
}
free (l);
break;
diff --git a/streamer.h b/streamer.h
index fd45662b..5bbfd9b1 100644
--- a/streamer.h
+++ b/streamer.h
@@ -149,9 +149,15 @@ struct handler_s *
streamer_get_handler (void);
void
-register_continuous_wavedata_listener (void *ctx, int type, void (*callback)(void *ctx, int type, ddb_waveformat_t *fmt, const float *data, int nsamples));
+vis_waveform_listen (void *ctx, void (*callback)(void *ctx, ddb_audio_data_t *data));
void
-unregister_continuous_wavedata_listener (void *ctx, int type);
+vis_waveform_unlisten (void *ctx);
+
+void
+vis_spectrum_listen (void *ctx, void (*callback)(void *ctx, ddb_audio_data_t *data));
+
+void
+vis_spectrum_unlisten (void *ctx);
#endif // __STREAMER_H