summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deadbeef.h17
-rw-r--r--fft.c14
-rw-r--r--plugins.c1
-rw-r--r--plugins/gtkui/widgets.c21
-rw-r--r--streamer.c67
-rw-r--r--streamer.h4
6 files changed, 61 insertions, 63 deletions
diff --git a/deadbeef.h b/deadbeef.h
index 1ea892ab..f5ea79e4 100644
--- a/deadbeef.h
+++ b/deadbeef.h
@@ -330,7 +330,7 @@ enum ddb_audio_data_type_t {
// audio memory constants
// since 1.5
-#define DDB_AUDIO_MEMORY_FRAMES 256
+#define DDB_FREQ_BANDS 256
// typecasting macros
#define DB_PLUGIN(x) ((DB_plugin_t *)(x))
@@ -820,18 +820,15 @@ typedef struct {
int (*pl_meta_exists) (DB_playItem_t *it, const char *key);
// ******* new 1.5 APIs *******
- // access real-time audio data (e.g. for visualization)
- // returns data size in bytes
- // fmt and data will be filled with last bytes that came to the output plugin
- // data size must be float[DDB_AUDIO_MEMORY_FRAMES]
- // type is one of DDB_AUDIO_WAVEFORM and DDB_AUDIO_FREQ
- void (*audio_get_waveform_data) (int type, float *data);
-
// register/unregister for getting continuous wave data
// mainly for visualization
// ctx must be unique
- void (*register_continuous_wavedata_listener) (void *ctx, void (*callback)(void *ctx, ddb_waveformat_t *fmt, const float *data, int nsamples));
- void (*unregister_continuous_wavedata_listener) (void *ctx);
+ // 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));
+
+ void (*unregister_continuous_wavedata_listener) (void *ctx, int type);
// this is useful to mute/unmute audio, and query the muted status, from
// plugins, without touching the volume control
diff --git a/fft.c b/fft.c
index 7b6a3a75..59d36e91 100644
--- a/fft.c
+++ b/fft.c
@@ -27,9 +27,9 @@
#include <math.h>
#include <complex.h>
-static float hamming[DDB_AUDIO_MEMORY_FRAMES]; /* hamming window, scaled to sum to 1 */
-static int reversed[DDB_AUDIO_MEMORY_FRAMES]; /* bit-reversal table */
-static float complex roots[DDB_AUDIO_MEMORY_FRAMES / 2]; /* N-th roots of unity */
+static float hamming[DDB_FREQ_BANDS]; /* hamming window, scaled to sum to 1 */
+static int reversed[DDB_FREQ_BANDS]; /* bit-reversal table */
+static float complex roots[DDB_FREQ_BANDS / 2]; /* N-th roots of unity */
static int generated = 0;
static float LOGN; /* log N (base 2) */
@@ -59,7 +59,7 @@ static void generate_tables (void)
if (generated)
return;
- const int N = DDB_AUDIO_MEMORY_FRAMES;
+ const int N = DDB_FREQ_BANDS;
LOGN = log2(N);
for (int n = 0; n < N; n ++)
hamming[n] = 1 - 0.85 * cosf (2 * M_PI * n / N);
@@ -71,9 +71,9 @@ static void generate_tables (void)
generated = 1;
}
-static void do_fft (float complex a[DDB_AUDIO_MEMORY_FRAMES])
+static void do_fft (float complex a[DDB_FREQ_BANDS])
{
- const int N = DDB_AUDIO_MEMORY_FRAMES;
+ const int N = DDB_FREQ_BANDS;
int half = 1; /* (2^s)/2 */
int inv = N / 2; /* N/(2^s) */
@@ -104,7 +104,7 @@ calc_freq (float *data, float *freq) {
// fft code shamelessly stolen from audacious
// thanks, John
- int N = DDB_AUDIO_MEMORY_FRAMES;
+ int N = DDB_FREQ_BANDS;
float complex a[N];
for (int n = 0; n < N; n ++) {
a[reversed[n]] = data[n] * hamming[n];
diff --git a/plugins.c b/plugins.c
index 8b6d3ff9..b8f10e02 100644
--- a/plugins.c
+++ b/plugins.c
@@ -341,7 +341,6 @@ 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 ********
- .audio_get_waveform_data = audio_get_waveform_data,
.register_continuous_wavedata_listener = register_continuous_wavedata_listener,
.unregister_continuous_wavedata_listener = unregister_continuous_wavedata_listener,
.audio_set_mute = audio_set_mute,
diff --git a/plugins/gtkui/widgets.c b/plugins/gtkui/widgets.c
index 5132689c..e487bf29 100644
--- a/plugins/gtkui/widgets.c
+++ b/plugins/gtkui/widgets.c
@@ -146,6 +146,7 @@ typedef struct {
#if USE_OPENGL
GdkGLContext *glcontext;
#endif
+ float data[DDB_FREQ_BANDS];
} w_spectrum_t;
typedef struct {
@@ -2236,7 +2237,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);
+ deadbeef->unregister_continuous_wavedata_listener (w, DDB_AUDIO_WAVEFORM);
if (s->drawtimer) {
g_source_remove (s->drawtimer);
s->drawtimer = 0;
@@ -2261,7 +2262,7 @@ w_scope_draw_cb (void *data) {
}
static void
-scope_wavedata_listener (void *ctx, ddb_waveformat_t *fmt, const float *data, int in_samples) {
+scope_wavedata_listener (void *ctx, int type, ddb_waveformat_t *fmt, const float *data, int in_samples) {
w_scope_t *w = ctx;
if (w->samples) {
// append
@@ -2445,7 +2446,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, scope_wavedata_listener);
+ deadbeef->register_continuous_wavedata_listener (w, DDB_AUDIO_WAVEFORM, scope_wavedata_listener);
return (ddb_gtkui_widget_t *)w;
}
@@ -2462,6 +2463,7 @@ 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
}
@@ -2474,7 +2476,7 @@ w_spectrum_draw_cb (void *data) {
// spectrum analyzer based on cairo-spectrum from audacious
// Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org>
-#define MAX_BANDS DDB_AUDIO_MEMORY_FRAMES
+#define MAX_BANDS DDB_FREQ_BANDS
#define VIS_DELAY 1
#define VIS_DELAY_PEAK 10
#define VIS_FALLOFF 1
@@ -2494,12 +2496,16 @@ static void calculate_bands(int bands)
xscale[i] = powf((float)(MAX_BANDS+1), ((float) i / (float) bands)) - 1;
}
+static void
+spectrum_audio_listener (void *ctx, int type, ddb_waveformat_t *fmt, const float *data, int nsamples) {
+ w_spectrum_t *w = ctx;
+ memcpy (w->data, data, DDB_FREQ_BANDS * sizeof (float));
+}
+
static gboolean
spectrum_draw (GtkWidget *widget, cairo_t *cr, gpointer user_data) {
w_spectrum_t *w = user_data;
- float data[DDB_AUDIO_MEMORY_FRAMES];
- float *freq = data;
- deadbeef->audio_get_waveform_data (DDB_AUDIO_FREQ, data);
+ float *freq = w->data;
GtkAllocation a;
gtk_widget_get_allocation (widget, &a);
@@ -2675,6 +2681,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);
return (ddb_gtkui_widget_t *)w;
}
diff --git a/streamer.c b/streamer.c
index 674f3517..694b587f 100644
--- a/streamer.c
+++ b/streamer.c
@@ -105,7 +105,6 @@ static char streambuffer[STREAM_BUFFER_SIZE];
static int bytes_until_next_song = 0;
static uintptr_t mutex;
static uintptr_t decodemutex;
-static uintptr_t audio_mem_mutex;
static int nextsong = -1;
static int nextsong_pstate = -1;
static int badsong = -1;
@@ -136,8 +135,9 @@ static int streamer_buffering;
static DB_FILE *streamer_file;
// for vis plugins
-static float freq_data[DDB_AUDIO_MEMORY_FRAMES];
-static float audio_data[DDB_AUDIO_MEMORY_FRAMES];
+static float freq_data[DDB_FREQ_BANDS];
+static float audio_data[DDB_FREQ_BANDS];
+static int audio_data_fill = 0;
// message queue
static struct handler_s *handler;
@@ -145,7 +145,8 @@ static struct handler_s *handler;
// visualization stuff
typedef struct wavedata_listener_s {
void *ctx;
- void (*callback)(void *ctx, ddb_waveformat_t *fmt, const float *data, int nsamples);
+ int type;
+ void (*callback)(void *ctx, int type, ddb_waveformat_t *fmt, const float *data, int nsamples);
struct wavedata_listener_s *next;
} wavedata_listener_t;
@@ -1889,7 +1890,6 @@ streamer_init (void) {
#endif
mutex = mutex_create ();
decodemutex = mutex_create ();
- audio_mem_mutex = mutex_create ();
ringbuf_init (&streamer_ringbuf, streambuffer, STREAM_BUFFER_SIZE);
@@ -1939,8 +1939,6 @@ streamer_free (void) {
decodemutex = 0;
mutex_free (mutex);
mutex = 0;
- mutex_free (audio_mem_mutex);
- audio_mem_mutex = 0;
streamer_dsp_chain_save();
@@ -2280,7 +2278,6 @@ streamer_read (char *bytes, int size) {
#endif
if (wavedata_listeners) {
- mutex_lock (audio_mem_mutex);
int in_frame_size = (output->fmt.bps >> 3) * output->fmt.channels;
int in_frames = sz / in_frame_size;
ddb_waveformat_t out_fmt = {
@@ -2294,20 +2291,29 @@ 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);
- if (in_frames < DDB_AUDIO_MEMORY_FRAMES) {
- memmove (audio_data, audio_data + in_frames, (DDB_AUDIO_MEMORY_FRAMES-in_frames)*sizeof (float));
- memcpy (audio_data + DDB_AUDIO_MEMORY_FRAMES - in_frames, temp_audio_data, sz);
- }
- else {
- memcpy (audio_data, temp_audio_data, DDB_AUDIO_MEMORY_FRAMES * in_frame_size);
- }
-
for (wavedata_listener_t *l = wavedata_listeners; l; l = l->next) {
- l->callback (l->ctx, &out_fmt, temp_audio_data, in_frames);
- }
-
- calc_freq (audio_data, freq_data);
- mutex_unlock (audio_mem_mutex);
+ if (l->type == DDB_AUDIO_WAVEFORM) {
+ l->callback (l->ctx, l->type, &out_fmt, temp_audio_data, in_frames);
+ }
+ }
+
+ int remaining = in_frames;
+ do {
+ int sz = DDB_FREQ_BANDS-audio_data_fill;
+ sz = min (sz, remaining);
+ 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) {
+ calc_freq (audio_data, freq_data);
+ 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);
+ }
+ }
+ audio_data_fill = 0;
+ }
+ } while (remaining > 0);
}
if (!output->has_volume) {
@@ -2581,31 +2587,20 @@ streamer_notify_order_changed (int prev_order, int new_order) {
}
void
-audio_get_waveform_data (int type, float *data) {
- DB_output_t *output = plug_get_output ();
- if (!audio_mem_mutex || !output || output->state () == OUTPUT_STATE_STOPPED) {
- memset (data, 0, sizeof (audio_data));
- return;
- }
- mutex_lock (audio_mem_mutex);
- memcpy (data, type == DDB_AUDIO_WAVEFORM ? audio_data : freq_data, sizeof (audio_data));
- mutex_unlock (audio_mem_mutex);
-}
-
-void
-register_continuous_wavedata_listener (void *ctx, void (*callback)(void *ctx, ddb_waveformat_t *fmt, const float *data, int nsamples)) {
+register_continuous_wavedata_listener (void *ctx, int type, void (*callback)(void *ctx, int type, ddb_waveformat_t *fmt, const float *data, int nsamples)) {
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;
}
void
-unregister_continuous_wavedata_listener (void *ctx) {
+unregister_continuous_wavedata_listener (void *ctx, int type) {
wavedata_listener_t *l, *prev = NULL;
- for (l = wavedata_listeners; l && l->ctx != ctx; prev = l, l = l->next);
+ for (l = wavedata_listeners; l && l->ctx != ctx && l->type != type; prev = l, l = l->next);
if (l) {
if (prev) {
prev->next = l->next;
diff --git a/streamer.h b/streamer.h
index 96acab9a..fd45662b 100644
--- a/streamer.h
+++ b/streamer.h
@@ -149,9 +149,9 @@ struct handler_s *
streamer_get_handler (void);
void
-register_continuous_wavedata_listener (void *ctx, void (*callback)(void *ctx, ddb_waveformat_t *fmt, const float *data, int nsamples));
+register_continuous_wavedata_listener (void *ctx, int type, void (*callback)(void *ctx, int type, ddb_waveformat_t *fmt, const float *data, int nsamples));
void
-unregister_continuous_wavedata_listener (void *ctx);
+unregister_continuous_wavedata_listener (void *ctx, int type);
#endif // __STREAMER_H