diff options
-rw-r--r-- | gst/spectrum/gstspectrum.c | 167 | ||||
-rw-r--r-- | gst/spectrum/gstspectrum.h | 4 | ||||
-rw-r--r-- | tests/examples/spectrum/demo-osssrc.c | 51 |
3 files changed, 131 insertions, 91 deletions
diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c index 4f01ceff..12762c58 100644 --- a/gst/spectrum/gstspectrum.c +++ b/gst/spectrum/gstspectrum.c @@ -1,5 +1,6 @@ /* GStreamer * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> + * <2006> Stefan Kost <ensonic@users.sf.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,12 +25,33 @@ #include "gstspectrum.h" +GST_DEBUG_CATEGORY_STATIC (gst_spectrum_debug); +#define GST_CAT_DEFAULT gst_spectrum_debug + /* elementfactory information */ static const GstElementDetails gst_spectrum_details = GST_ELEMENT_DETAILS ("Spectrum analyzer", "Filter/Analyzer/Audio", "Run an FFT on the audio signal, output spectrum data", - "Erik Walthinsen <omega@cse.ogi.edu>"); + "Erik Walthinsen <omega@cse.ogi.edu>," + "Stefan Kost <ensonic@users.sf.net>"); + +static GstStaticPadTemplate sink_template_factory = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw-int, " + "rate = (int) [ 1, MAX ], " + "channels = (int) 1, " + "endianness = (int) BYTE_ORDER, " + "width = (int) 16, " "depth = (int) 16, " "signed = (boolean) true") + ); + +static GstStaticPadTemplate src_template_factory = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); /* Spectrum signals and args */ enum @@ -48,18 +70,17 @@ enum static void gst_spectrum_base_init (gpointer g_class); static void gst_spectrum_class_init (GstSpectrumClass * klass); static void gst_spectrum_init (GstSpectrum * spectrum); - +static void gst_spectrum_dispose (GObject * object); static void gst_spectrum_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_spectrum_chain (GstPad * pad, GstData * _data); +static GstFlowReturn gst_spectrum_chain (GstPad * pad, GstBuffer * buffer); #define fixed short -int gst_spectrum_fix_fft (fixed fr[], fixed fi[], int m, int inverse); -void gst_spectrum_fix_loud (fixed loud[], fixed fr[], fixed fi[], int n, +extern int gst_spectrum_fix_fft (fixed fr[], fixed fi[], int m, int inverse); +extern void gst_spectrum_fix_loud (fixed loud[], fixed fr[], fixed fi[], int n, int scale_shift); -void gst_spectrum_window (fixed fr[], int n); - +extern void gst_spectrum_window (fixed fr[], int n); static GstElementClass *parent_class = NULL; @@ -83,9 +104,10 @@ gst_spectrum_get_type (void) (GInstanceInitFunc) gst_spectrum_init, }; - spectrum_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstSpectrum", &spectrum_info, - 0); + spectrum_type = g_type_register_static (GST_TYPE_ELEMENT, "GstSpectrum", + &spectrum_info, 0); + GST_DEBUG_CATEGORY_INIT (gst_spectrum_debug, "spectrum", 0, + "audio spectrum analyser element"); } return spectrum_type; } @@ -95,113 +117,128 @@ gst_spectrum_base_init (gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_template_factory)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_template_factory)); gst_element_class_set_details (element_class, &gst_spectrum_details); } + static void gst_spectrum_class_init (GstSpectrumClass * klass) { - GObjectClass *gobject_class; - - gobject_class = (GObjectClass *) klass; + GObjectClass *gobject_class = (GObjectClass *) klass; parent_class = g_type_class_peek_parent (klass); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_WIDTH, g_param_spec_int ("width", "width", "width", G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE)); /* CHECKME */ - gobject_class->set_property = gst_spectrum_set_property; + gobject_class->dispose = gst_spectrum_dispose; + + g_object_class_install_property (gobject_class, ARG_WIDTH, + g_param_spec_int ("width", "width", "width", + G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE)); + } static void gst_spectrum_init (GstSpectrum * spectrum) { - spectrum->sinkpad = gst_pad_new ("sink", GST_PAD_SINK); + spectrum->sinkpad = + gst_pad_new_from_static_template (&sink_template_factory, "sink"); gst_element_add_pad (GST_ELEMENT (spectrum), spectrum->sinkpad); gst_pad_set_chain_function (spectrum->sinkpad, gst_spectrum_chain); - spectrum->srcpad = gst_pad_new ("src", GST_PAD_SRC); + + spectrum->srcpad = + gst_pad_new_from_static_template (&src_template_factory, "src"); gst_element_add_pad (GST_ELEMENT (spectrum), spectrum->srcpad); spectrum->width = 75; + spectrum->base = 8; + spectrum->len = 1024; + + spectrum->loud = g_malloc (spectrum->len * sizeof (gint16)); + spectrum->im = g_malloc (spectrum->len * sizeof (gint16)); + memset (spectrum->im, 0, spectrum->len * sizeof (gint16)); + spectrum->re = g_malloc (spectrum->len * sizeof (gint16)); + memset (spectrum->re, 0, spectrum->len * sizeof (gint16)); +} + +static void +gst_spectrum_dispose (GObject * object) +{ + GstSpectrum *spectrum = GST_SPECTRUM (object); + + g_free (spectrum->re); + g_free (spectrum->im); + g_free (spectrum->loud); + + G_OBJECT_CLASS (parent_class)->dispose (object); } static void gst_spectrum_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - GstSpectrum *spectrum; - - g_return_if_fail (GST_IS_SPECTRUM (object)); - spectrum = GST_SPECTRUM (object); + GstSpectrum *spectrum = GST_SPECTRUM (object); switch (prop_id) { case ARG_WIDTH: spectrum->width = g_value_get_int (value); break; default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } -static void -gst_spectrum_chain (GstPad * pad, GstData * _data) +static GstFlowReturn +gst_spectrum_chain (GstPad * pad, GstBuffer * buffer) { - GstBuffer *buf = GST_BUFFER (_data); GstSpectrum *spectrum; - gint spec_base, spec_len; - gint16 *re, *im, *loud; gint16 *samples; - gint step, pos, i; + gint step, pos, num, i; guchar *spect; GstBuffer *newbuf; - g_return_if_fail (pad != NULL); - g_return_if_fail (GST_IS_PAD (pad)); - g_return_if_fail (buf != NULL); - spectrum = GST_SPECTRUM (GST_OBJECT_PARENT (pad)); + samples = (gint16 *) GST_BUFFER_DATA (buffer); + + GST_LOG ("buffer-size = %ld", GST_BUFFER_SIZE (buffer)); + + /* FIXME:need a gst_adapter */ + num = GST_BUFFER_SIZE (buffer) / 2; + num = MIN (num, spectrum->len); + + for (i = 0; i < num; i++) + spectrum->re[i] = (samples[(i * 2)] + samples[(i * 2) + 1]) >> 1; + + gst_spectrum_window (spectrum->re, spectrum->len); + gst_spectrum_fix_fft (spectrum->re, spectrum->im, spectrum->base, FALSE); + gst_spectrum_fix_loud (spectrum->loud, spectrum->re, spectrum->im, + spectrum->len, 0); - samples = (gint16 *) GST_BUFFER_DATA (buf); - - spec_base = 8; - spec_len = 1024; - - im = g_malloc (spec_len * sizeof (gint16)); - g_return_if_fail (im != NULL); - loud = g_malloc (spec_len * sizeof (gint16)); - g_return_if_fail (loud != NULL); - - memset (im, 0, spec_len * sizeof (gint16)); - /*if (spectrum->meta->channels == 2) { */ - re = g_malloc (spec_len * sizeof (gint16)); - for (i = 0; i < spec_len; i++) - re[i] = (samples[(i * 2)] + samples[(i * 2) + 1]) >> 1; - /*} else */ - /* re = samples; */ - gst_spectrum_window (re, spec_len); - gst_spectrum_fix_fft (re, im, spec_base, FALSE); - gst_spectrum_fix_loud (loud, re, im, spec_len, 0); - if (re != samples) - g_free (re); - g_free (im); - step = spec_len / (spectrum->width * 2); + /* resample to requested width */ + step = spectrum->len / (spectrum->width * 4); /* <-- shouldn't this be 2 instead of 4? */ spect = (guchar *) g_malloc (spectrum->width); for (i = 0, pos = 0; i < spectrum->width; i++, pos += step) { - if (loud[pos] > -60) - spect[i] = (loud[pos] + 60) / 2; - else + /* > -60 db? */ + if (spectrum->loud[pos] > -60) { + spect[i] = spectrum->loud[pos] + 60; + /* + if (spect[i] > 15); + spect[i] = 15; + */ + } else + /* treat as silence */ spect[i] = 0; -/* if (spect[i] > 15); */ -/* spect[i] = 15; */ } - g_free (loud); - gst_buffer_unref (buf); -/* g_free(samples); */ + gst_buffer_unref (buffer); newbuf = gst_buffer_new (); - g_return_if_fail (newbuf != NULL); GST_BUFFER_DATA (newbuf) = spect; GST_BUFFER_SIZE (newbuf) = spectrum->width; - gst_pad_push (spectrum->srcpad, GST_DATA (newbuf)); + return gst_pad_push (spectrum->srcpad, newbuf); } static gboolean diff --git a/gst/spectrum/gstspectrum.h b/gst/spectrum/gstspectrum.h index 8cc546ec..2dbc2242 100644 --- a/gst/spectrum/gstspectrum.h +++ b/gst/spectrum/gstspectrum.h @@ -39,7 +39,7 @@ extern "C" { #define GST_IS_SPECTRUM(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPECTRUM)) #define GST_IS_SPECTRUM_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPECTRUM)) + (G_TYPE_CHECK_CLASS_TYPE((obj),GST_TYPE_SPECTRUM)) typedef struct _GstSpectrum GstSpectrum; typedef struct _GstSpectrumClass GstSpectrumClass; @@ -50,6 +50,8 @@ struct _GstSpectrum { GstPad *sinkpad,*srcpad; gint width; + gint base, len; + gint16 *re, *im, *loud; }; struct _GstSpectrumClass { diff --git a/tests/examples/spectrum/demo-osssrc.c b/tests/examples/spectrum/demo-osssrc.c index b51e8c2a..9bdb93f7 100644 --- a/tests/examples/spectrum/demo-osssrc.c +++ b/tests/examples/spectrum/demo-osssrc.c @@ -4,26 +4,26 @@ #include <gst/gst.h> #include <gtk/gtk.h> -extern gboolean _gst_plugin_spew; - -gboolean idle_func (gpointer data); +#define DEFAULT_AUDIOSRC "alsasrc" +#define SPECT_BANDS 256 GtkWidget *drawingarea; -void +static void spectrum_chain (GstElement * sink, GstBuffer * buf, GstPad * pad, gpointer unused) { gint i; guchar *data = buf->data; - GdkRectangle rect = { 0, 0, GST_BUFFER_SIZE (buf), 25 }; + gint width = GST_BUFFER_SIZE (buf); + GdkRectangle rect = { 0, 0, width, 50 }; gdk_window_begin_paint_rect (drawingarea->window, &rect); gdk_draw_rectangle (drawingarea->window, drawingarea->style->black_gc, - TRUE, 0, 0, GST_BUFFER_SIZE (buf), 25); - for (i = 0; i < GST_BUFFER_SIZE (buf); i++) { + TRUE, 0, 0, width, 50); + for (i = 0; i < width; i++) { gdk_draw_rectangle (drawingarea->window, drawingarea->style->white_gc, - TRUE, i, 32 - data[i], 1, data[i]); + TRUE, i, 64 - data[i], 1, data[i]); } gdk_window_end_paint (drawingarea->window); } @@ -32,7 +32,7 @@ int main (int argc, char *argv[]) { GstElement *bin; - GstElement *src, *spectrum, *sink; + GstElement *src, *conv, *spectrum, *sink; GtkWidget *appwindow; @@ -42,34 +42,35 @@ main (int argc, char *argv[]) bin = gst_pipeline_new ("bin"); src = gst_element_factory_make (DEFAULT_AUDIOSRC, "src"); - g_object_set (G_OBJECT (src), "buffersize", (gulong) 1024, NULL); + g_object_set (G_OBJECT (src), "blocksize", (gulong) 1024 * 2, NULL); + + conv = gst_element_factory_make ("audioconvert", "conv"); + spectrum = gst_element_factory_make ("spectrum", "spectrum"); - g_object_set (G_OBJECT (spectrum), "width", 256, NULL); + g_object_set (G_OBJECT (spectrum), "width", SPECT_BANDS, NULL); + sink = gst_element_factory_make ("fakesink", "sink"); g_object_set (G_OBJECT (sink), "signal-handoffs", TRUE, NULL); + g_signal_connect (sink, "handoff", G_CALLBACK (spectrum_chain), NULL); - gst_bin_add_many (GST_BIN (bin), src, spectrum, sink, NULL); - gst_element_link_many (src, spectrum, sink, NULL); + gst_bin_add_many (GST_BIN (bin), src, conv, spectrum, sink, NULL); + if (!gst_element_link_many (src, conv, spectrum, sink, NULL)) { + fprintf (stderr, "cant link elements\n"); + exit (1); + } appwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); drawingarea = gtk_drawing_area_new (); - gtk_drawing_area_size (GTK_DRAWING_AREA (drawingarea), 256, 32); + gtk_drawing_area_size (GTK_DRAWING_AREA (drawingarea), SPECT_BANDS, 64); gtk_container_add (GTK_CONTAINER (appwindow), drawingarea); gtk_widget_show_all (appwindow); - gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING); - - g_idle_add (idle_func, bin); - + gst_element_set_state (bin, GST_STATE_PLAYING); gtk_main (); + gst_element_set_state (bin, GST_STATE_NULL); - return 0; -} - + gst_object_unref (bin); -gboolean -idle_func (gpointer data) -{ - return gst_bin_iterate (data); + return 0; } |