gst/spectrum/Makefile.am: Link to base libraries
authorStefan Kost <ensonic@users.sourceforge.net>
Sun, 21 May 2006 16:23:23 +0000 (16:23 +0000)
committerStefan Kost <ensonic@users.sourceforge.net>
Sun, 21 May 2006 16:23:23 +0000 (16:23 +0000)
Original commit message from CVS:
* gst/spectrum/Makefile.am:
Link to base libraries
* gst/spectrum/demo-osssrc.c: (main):
use new threshhold property
* gst/spectrum/gstspectrum.c: (gst_spectrum_class_init),
(gst_spectrum_init), (gst_spectrum_dispose),
(gst_spectrum_set_property), (gst_spectrum_set_sink_caps),
(gst_spectrum_get_sink_caps), (gst_spectrum_chain),
(gst_spectrum_change_state):
* gst/spectrum/gstspectrum.h:
Use gst_adapter, support multiple-channels, add threshold property for
result, add docs, fix resulting spectrum range (was including mirrored
results)

ChangeLog
gst/spectrum/Makefile.am
gst/spectrum/demo-osssrc.c
gst/spectrum/gstspectrum.c
gst/spectrum/gstspectrum.h

index 12a060a..7323304 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,23 @@
 2006-05-21  Stefan Kost  <ensonic@users.sf.net>
 
+       * gst/spectrum/Makefile.am:
+        Link to base libraries
+        
+       * gst/spectrum/demo-osssrc.c: (main):
+        use new threshhold property
+        
+       * gst/spectrum/gstspectrum.c: (gst_spectrum_class_init),
+       (gst_spectrum_init), (gst_spectrum_dispose),
+       (gst_spectrum_set_property), (gst_spectrum_set_sink_caps),
+       (gst_spectrum_get_sink_caps), (gst_spectrum_chain),
+       (gst_spectrum_change_state):
+       * gst/spectrum/gstspectrum.h:
+        Use gst_adapter, support multiple-channels, add threshold property for
+        result, add docs, fix resulting spectrum range (was including mirrored
+        results)
+
+2006-05-21  Stefan Kost  <ensonic@users.sf.net>
+
        * configure.ac:
        * gst/spectrum/demo-osssrc.c: (spectrum_chain), (main):
        * gst/spectrum/fix_fft.c: (gst_spectrum_fix_dot):
index f86107d..a6341cf 100644 (file)
@@ -2,8 +2,8 @@
 plugin_LTLIBRARIES = libgstspectrum.la
 
 libgstspectrum_la_SOURCES = gstspectrum.c fix_fft.c
-libgstspectrum_la_CFLAGS = $(GST_CFLAGS)
-libgstspectrum_la_LIBADD =
+libgstspectrum_la_CFLAGS = $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstspectrum_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS)
 libgstspectrum_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 
 noinst_HEADERS = gstspectrum.h
@@ -13,7 +13,7 @@ noinst_PROGRAMS = demo-osssrc
 endif
 
 demo_osssrc_SOURCES = demo-osssrc.c
-demo_osssrc_CFLAGS  = $(GST_CFLAGS) $(GTK_CFLAGS)
-demo_osssrc_LDFLAGS = $(GST_LIBS) $(GTK_LIBS)
+demo_osssrc_CFLAGS  = $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GTK_CFLAGS)
+demo_osssrc_LDFLAGS = $(GST_BASE_LIBS) $(GST_LIBS) $(GTK_LIBS)
 
 EXTRA_DIST = README
index 9bdb93f..7f858ea 100644 (file)
@@ -32,7 +32,7 @@ int
 main (int argc, char *argv[])
 {
   GstElement *bin;
-  GstElement *src, *conv, *spectrum, *sink;
+  GstElement *src, *spectrum, *sink;
 
   GtkWidget *appwindow;
 
@@ -44,18 +44,17 @@ main (int argc, char *argv[])
   src = gst_element_factory_make (DEFAULT_AUDIOSRC, "src");
   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", SPECT_BANDS, NULL);
+  g_object_set (G_OBJECT (spectrum), "width", SPECT_BANDS, "threshold", -80,
+      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, conv, spectrum, sink, NULL);
-  if (!gst_element_link_many (src, conv, spectrum, sink, NULL)) {
+  gst_bin_add_many (GST_BIN (bin), src, spectrum, sink, NULL);
+  if (!gst_element_link_many (src, spectrum, sink, NULL)) {
     fprintf (stderr, "cant link elements\n");
     exit (1);
   }
index 12762c5..37861f6 100644 (file)
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+/**
+ * SECTION:element-spectrum
+ *
+ * <refsect2>
+ * The Spectrum element analyzes the frequency spectrum of an audio signal.
+ * Analysis results are send as outgoing buffers.
+ * The buffer contains a guint8 value per frequency band.
+ * A value of 0 maps to the threshold property.
+ *
+ * It cannot be used with the gst-launch command in a sensible way. Instead the
+ * included demo shows how to use it.
+ *
+ * Last reviewed on 2006-05-21 (0.10.3)
+ */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -42,7 +56,7 @@ GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS ("audio/x-raw-int, "
         "rate = (int) [ 1, MAX ], "
-        "channels = (int) 1, "
+        "channels = (int) [1, MAX], "
         "endianness = (int) BYTE_ORDER, "
         "width = (int) 16, " "depth = (int) 16, " "signed = (boolean) true")
     );
@@ -63,7 +77,8 @@ enum
 enum
 {
   ARG_0,
-  ARG_WIDTH
+  ARG_WIDTH,
+  ARG_THRESHOLD
 };
 
 
@@ -74,7 +89,11 @@ static void gst_spectrum_dispose (GObject * object);
 static void gst_spectrum_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
 
+static gboolean gst_spectrum_set_sink_caps (GstPad * pad, GstCaps * caps);
+static GstCaps *gst_spectrum_get_sink_caps (GstPad * pad);
 static GstFlowReturn gst_spectrum_chain (GstPad * pad, GstBuffer * buffer);
+static GstStateChangeReturn gst_spectrum_change_state (GstElement * element,
+    GstStateChange transition);
 
 #define fixed short
 extern int gst_spectrum_fix_fft (fixed fr[], fixed fi[], int m, int inverse);
@@ -127,16 +146,24 @@ gst_spectrum_base_init (gpointer g_class)
 static void
 gst_spectrum_class_init (GstSpectrumClass * klass)
 {
-  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *element = GST_ELEMENT_CLASS (klass);
 
   parent_class = g_type_class_peek_parent (klass);
 
   gobject_class->set_property = gst_spectrum_set_property;
   gobject_class->dispose = gst_spectrum_dispose;
 
+  element->change_state = gst_spectrum_change_state;
+
   g_object_class_install_property (gobject_class, ARG_WIDTH,
-      g_param_spec_int ("width", "width", "width",
-          G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE));
+      g_param_spec_uint ("width", "width", "number of frequency bands",
+          0, G_MAXUINT, 0, G_PARAM_WRITABLE));
+
+  g_object_class_install_property (gobject_class, ARG_THRESHOLD,
+      g_param_spec_int ("threshold", "threshold",
+          "db threshold for result, maps to 0", G_MININT, 0, -60,
+          G_PARAM_WRITABLE));
 
 }
 
@@ -145,16 +172,20 @@ gst_spectrum_init (GstSpectrum * spectrum)
 {
   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);
+  gst_pad_set_setcaps_function (spectrum->sinkpad, gst_spectrum_set_sink_caps);
+  gst_pad_set_getcaps_function (spectrum->sinkpad, gst_spectrum_get_sink_caps);
+  gst_element_add_pad (GST_ELEMENT (spectrum), spectrum->sinkpad);
 
   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->adapter = gst_adapter_new ();
+
+  spectrum->width = 128;
+  spectrum->base = 9;
+  spectrum->len = 1024;         /* 2 ^ (base+1) */
 
   spectrum->loud = g_malloc (spectrum->len * sizeof (gint16));
   spectrum->im = g_malloc (spectrum->len * sizeof (gint16));
@@ -168,6 +199,11 @@ gst_spectrum_dispose (GObject * object)
 {
   GstSpectrum *spectrum = GST_SPECTRUM (object);
 
+  if (spectrum->adapter) {
+    g_object_unref (spectrum->adapter);
+    spectrum->adapter = NULL;
+  }
+
   g_free (spectrum->re);
   g_free (spectrum->im);
   g_free (spectrum->loud);
@@ -183,7 +219,10 @@ gst_spectrum_set_property (GObject * object, guint prop_id,
 
   switch (prop_id) {
     case ARG_WIDTH:
-      spectrum->width = g_value_get_int (value);
+      spectrum->width = g_value_get_uint (value);
+      break;
+    case ARG_THRESHOLD:
+      spectrum->threshold = g_value_get_int (value);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -191,56 +230,135 @@ gst_spectrum_set_property (GObject * object, guint prop_id,
   }
 }
 
+static gboolean
+gst_spectrum_set_sink_caps (GstPad * pad, GstCaps * caps)
+{
+  GstSpectrum *spectrum = GST_SPECTRUM (gst_pad_get_parent (pad));
+  GstStructure *structure = gst_caps_get_structure (caps, 0);
+  gboolean ret;
+
+  ret = gst_structure_get_int (structure, "channels", &spectrum->channels);
+  GST_INFO ("Got channels = %d", spectrum->channels);
+
+  gst_object_unref (spectrum);
+
+  return ret;
+}
+
+static GstCaps *
+gst_spectrum_get_sink_caps (GstPad * pad)
+{
+  GstSpectrum *spectrum = GST_SPECTRUM (gst_pad_get_parent (pad));
+  GstCaps *res;
+  GstStructure *structure;
+
+  res = gst_caps_copy (gst_pad_get_pad_template_caps (spectrum->sinkpad));
+  if (spectrum->channels) {
+    structure = gst_caps_get_structure (res, 0);
+    gst_structure_set (structure, "channels", G_TYPE_INT, spectrum->channels,
+        NULL);
+    GST_INFO ("Fixate channels = %d", spectrum->channels);
+  }
+  gst_object_unref (spectrum);
+  return res;
+}
+
 static GstFlowReturn
 gst_spectrum_chain (GstPad * pad, GstBuffer * buffer)
 {
-  GstSpectrum *spectrum;
+  GstSpectrum *spectrum = GST_SPECTRUM (gst_pad_get_parent (pad));
   gint16 *samples;
-  gint step, pos, num, i;
+  gint wanted;
+  gint i, j, k;
+  gint32 acc;
+  gfloat pos, step;
   guchar *spect;
-  GstBuffer *newbuf;
-
-  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);
-
-  /* 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) {
-    /* > -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;
+  GstBuffer *outbuf;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  gst_adapter_push (spectrum->adapter, buffer);
+  /* required number of bytes */
+  wanted = spectrum->channels * spectrum->len * 2;
+  /* FIXME: 4.0 was 2.0 before, but that include the mirrored spectrum */
+  step = (gfloat) spectrum->len / (spectrum->width * 4.0);
+
+  while (gst_adapter_available (spectrum->adapter) > wanted &&
+      (ret == GST_FLOW_OK)) {
+
+    samples = (gint16 *) gst_adapter_take (spectrum->adapter, wanted);
+
+    for (i = 0, j = 0; i < spectrum->len; i++) {
+      for (k = 0, acc = 0; k < spectrum->channels; k++)
+        acc += samples[j++];
+      spectrum->re[i] = (gint16) (acc / spectrum->channels);
+    }
+
+    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);
+
+    ret = gst_pad_alloc_buffer_and_set_caps (spectrum->srcpad,
+        GST_BUFFER_OFFSET_NONE, spectrum->width,
+        GST_PAD_CAPS (spectrum->srcpad), &outbuf);
+
+    /* resample to requested width */
+    spect = GST_BUFFER_DATA (outbuf);
+    for (i = 0, pos = 0.0; i < spectrum->width; i++, pos += step) {
+      /* > -60 db? FIXME: make this a gobject property */
+      if (spectrum->loud[(gint) pos] > spectrum->threshold) {
+        spect[i] = spectrum->loud[(gint) pos] - spectrum->threshold;
+        /*
+           if (spect[i] > 15);
+           spect[i] = 15;
+         */
+      } else
+        /* treat as silence */
+        spect[i] = 0;
+    }
+
+    ret = gst_pad_push (spectrum->srcpad, outbuf);
   }
-  gst_buffer_unref (buffer);
 
-  newbuf = gst_buffer_new ();
-  GST_BUFFER_DATA (newbuf) = spect;
-  GST_BUFFER_SIZE (newbuf) = spectrum->width;
+  gst_object_unref (spectrum);
+  return ret;
+}
+
+static GstStateChangeReturn
+gst_spectrum_change_state (GstElement * element, GstStateChange transition)
+{
+  GstSpectrum *spectrum = GST_SPECTRUM (element);
+  GstStateChangeReturn ret;
 
-  return gst_pad_push (spectrum->srcpad, newbuf);
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_adapter_clear (spectrum->adapter);
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+
+  return ret;
 }
 
+
 static gboolean
 plugin_init (GstPlugin * plugin)
 {
index 2dbc224..8e53678 100644 (file)
 
 
 #include <gst/gst.h>
-
+#include <gst/base/gstadapter.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 
 
-#define GST_TYPE_SPECTRUM \
-  (gst_spectrum_get_type())
-#define GST_SPECTRUM(obj) \
-  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPECTRUM,GstSpectrum))
-#define GST_SPECTRUM_CLASS(klass) \
-  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPECTRUM,GstSpectrum))
-#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((obj),GST_TYPE_SPECTRUM))
+#define GST_TYPE_SPECTRUM            (gst_spectrum_get_type())
+#define GST_SPECTRUM(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPECTRUM,GstSpectrum))
+#define GST_IS_SPECTRUM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPECTRUM))
+#define GST_SPECTRUM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_SPECTRUM,GstSpectrum))
+#define GST_IS_SPECTRUM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_SPECTRUM))
 
 typedef struct _GstSpectrum GstSpectrum;
 typedef struct _GstSpectrumClass GstSpectrumClass;
@@ -48,8 +43,13 @@ struct _GstSpectrum {
   GstElement element;
 
   GstPad *sinkpad,*srcpad;
+  GstAdapter *adapter;
+
+  /* properties */
+  guint width;
+  gint threshold;
 
-  gint width;
+  gint channels;
   gint base, len;
   gint16 *re, *im, *loud;
 };