Initial port of the spectrum element

Original commit message from CVS:
* configure.ac:
* gst/spectrum/demo-osssrc.c: (spectrum_chain), (main):
* gst/spectrum/fix_fft.c: (gst_spectrum_fix_dot):
* gst/spectrum/gstspectrum.c: (gst_spectrum_get_type),
(gst_spectrum_base_init), (gst_spectrum_class_init),
(gst_spectrum_init), (gst_spectrum_dispose),
(gst_spectrum_set_property), (gst_spectrum_chain):
* gst/spectrum/gstspectrum.h:
Initial port of the spectrum element
This commit is contained in:
Stefan Kost 2006-05-20 22:42:15 +00:00
parent 4e5f3fae24
commit 0428d5cf5f
6 changed files with 331 additions and 249 deletions

View file

@ -1,3 +1,15 @@
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):
* gst/spectrum/gstspectrum.c: (gst_spectrum_get_type),
(gst_spectrum_base_init), (gst_spectrum_class_init),
(gst_spectrum_init), (gst_spectrum_dispose),
(gst_spectrum_set_property), (gst_spectrum_chain):
* gst/spectrum/gstspectrum.h:
Initial port of the spectrum element
2006-05-19 Edgard Lima <edgard.lima@indt.org.br>
* sys/v4l2/gstv4l2.c:

View file

@ -79,6 +79,7 @@ GST_PLUGINS_ALL="\
cdxaparse \
freeze \
modplug \
spectrum \
speed \
qtdemux \
xingheader \
@ -154,16 +155,41 @@ dnl uninstalled is selected preferentially -- see pkg-config(1)
GST_CHECK_GST($GST_MAJORMINOR, [$GST_REQ])
GST_CHECK_GST_BASE($GST_MAJORMINOR, [$GST_REQ])
GST_CHECK_GST_CHECK($GST_MAJORMINOR, [$GST_REQ], no)
GST_CHECK_GST_PLUGINS_BASE($GST_MAJORMINOR, [$GSTPB_REQ], no)
GSTPB_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-base-$GST_MAJORMINOR --variable pluginsdir`
AC_SUBST(GSTPB_PLUGINS_DIR)
AC_MSG_NOTICE(Using GStreamer Base Plugins in $GSTPB_PLUGINS_DIR)
dnl FIXME: get rid of this by making sure gstreamer-check brings it in
dnl check for "check", unit testing library/header
AM_PATH_CHECK(0.9.2, HAVE_CHECK=yes, HAVE_CHECK=no)
AM_CONDITIONAL(HAVE_CHECK, test "x$HAVE_CHECK" = "xyes")
GST_CHECK_GST_PLUGINS_BASE($GST_MAJORMINOR, [$GSTPB_REQ], no)
GSTPB_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-base-$GST_MAJORMINOR --variable pluginsdir`
AC_SUBST(GSTPB_PLUGINS_DIR)
AC_MSG_NOTICE(Using GStreamer Base Plugins in $GSTPB_PLUGINS_DIR)
dnl GTK is optional and used in examples
HAVE_GTK=NO
PKG_CHECK_MODULES(GTK2, gtk+-2.0 >= 2.2.0, HAVE_GTK_22=yes, HAVE_GTK_22=no)
if test "x$HAVE_GTK_22" = "xyes"; then
HAVE_GTK=yes
GTK_VERSION=`$PKG_CONFIG --variable=gtk_binary_version gtk+-2.0`
AC_SUBST(GTK_VERSION)
GTK_PREFIX=`$PKG_CONFIG --variable=prefix gdk-pixbuf-2.0`
AC_SUBST(GTK_BASE_DIR)
GDK_PIXBUF_LIBDIR=`$PKG_CONFIG --variable=libdir gdk-pixbuf-2.0`
GDK_PIXBUF_PREFIXDIR=`$PKG_CONFIG --variable=prefix gdk-pixbuf-2.0`
AC_SUBST(GTK_BASE_DIR)
else
PKG_CHECK_MODULES(GTK2, gtk+-2.0, HAVE_GTK_20=yes, HAVE_GTK_20=no)
fi
if test "x$HAVE_GTK_20" = "xyes"; then
HAVE_GTK=yes
fi
GTK_CFLAGS=$GTK2_CFLAGS
GTK_LIBS=$GTK2_LIBS
AC_SUBST(GTK_LIBS)
AC_SUBST(GTK_CFLAGS)
AC_SUBST(HAVE_GTK)
AM_CONDITIONAL(HAVE_GTK, test "x$HAVE_GTK" = "xyes")
dnl set license and copyright notice
GST_LICENSE="LGPL"
@ -679,6 +705,7 @@ gst/cdxaparse/Makefile
gst/freeze/Makefile
gst/modplug/Makefile
gst/modplug/libmodplug/Makefile
gst/spectrum/Makefile
gst/speed/Makefile
gst/qtdemux/Makefile
gst/tta/Makefile

View file

@ -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);
gst_object_unref (bin);
return 0;
}
gboolean
idle_func (gpointer data)
{
return gst_bin_iterate (data);
}

View file

@ -54,9 +54,6 @@
#define fixed short
/* FIX_MPY() - fixed-point multiplication macro.
This macro is a statement, not an expression (uses asm).
BEWARE: make sure _DX is not clobbered by evaluating (A) or DEST.
args are all of type fixed.
Scaling ensures that 32767*32767 = 32767. */
#define FIX_MPY(DEST,A,B) DEST = ((long)(A) * (long)(B))>>15
@ -65,8 +62,9 @@
#define LOG2_N_WAVE 10 /* log2(N_WAVE) */
#define N_LOUD 100 /* dimension of Loudampl[] */
extern fixed gst_spectrum_Sinewave[N_WAVE]; /* placed at end of this file for clarity */
extern fixed gst_spectrum_Loudampl[N_LOUD];
extern fixed const gst_spectrum_Sinewave[N_WAVE]; /* placed at end of this file for clarity */
extern fixed const gst_spectrum_Loudampl[N_LOUD];
static int gst_spectrum_db_from_ampl (fixed re, fixed im);
static fixed gst_spectrum_fix_mpy (fixed a, fixed b);
@ -221,7 +219,7 @@ gst_spectrum_fix_loud (fixed loud[], fixed fr[], fixed fi[], int n,
/* db_from_ampl() - find loudness (in dB) from
the complex amplitude.
*/
int
static int
gst_spectrum_db_from_ampl (fixed re, fixed im)
{
static long loud2[N_LOUD] = { 0 };
@ -250,17 +248,18 @@ gst_spectrum_db_from_ampl (fixed re, fixed im)
/*
fix_mpy() - fixed-point multiplication
*/
fixed
static fixed
gst_spectrum_fix_mpy (fixed a, fixed b)
{
FIX_MPY (a, a, b);
return a;
}
#if 0
/*
iscale() - scale an integer value by (numer/denom)
*/
int
static int
gst_spectrum_iscale (int value, int numer, int denom)
{
return (long) value *(long) numer / (long) denom;
@ -269,14 +268,15 @@ gst_spectrum_iscale (int value, int numer, int denom)
/*
fix_dot() - dot product of two fixed arrays
*/
fixed
static fixed
gst_spectrum_fix_dot (fixed * hpa, fixed * pb, int n)
{
fixed *pa = hpa; /* FIXME */
long sum;
register fixed a, b;
/* seg = FP_SEG(hpa);
/*
seg = FP_SEG(hpa);
off = FP_OFF(hpa);
seg += off>>4;
off &= 0x000F;
@ -298,11 +298,12 @@ gst_spectrum_fix_dot (fixed * hpa, fixed * pb, int n)
return (fixed) sum;
}
#endif
#if N_WAVE != 1024
ERROR:N_WAVE != 1024
#endif
fixed gst_spectrum_Sinewave[1024] = {
fixed const gst_spectrum_Sinewave[1024] = {
0, 201, 402, 603, 804, 1005, 1206, 1406,
1607, 1808, 2009, 2209, 2410, 2610, 2811, 3011,
3211, 3411, 3611, 3811, 4011, 4210, 4409, 4608,
@ -431,12 +432,13 @@ ERROR:N_WAVE != 1024
-6392, -6195, -5997, -5799, -5601, -5403, -5205, -5006,
-4807, -4608, -4409, -4210, -4011, -3811, -3611, -3411,
-3211, -3011, -2811, -2610, -2410, -2209, -2009, -1808,
-1607, -1406, -1206, -1005, -804, -603, -402, -201,};
-1607, -1406, -1206, -1005, -804, -603, -402, -201,
};
#if N_LOUD != 100
ERROR:N_LOUD != 100
#endif
fixed gst_spectrum_Loudampl[100] = {
fixed const gst_spectrum_Loudampl[100] = {
32767, 29203, 26027, 23197, 20674, 18426, 16422, 14636,
13044, 11626, 10361, 9234, 8230, 7335, 6537, 5826,
5193, 4628, 4125, 3676, 3276, 2920, 2602, 2319,
@ -447,4 +449,5 @@ ERROR:N_LOUD != 100
51, 46, 41, 36, 32, 29, 26, 23,
20, 18, 16, 14, 13, 11, 10, 9,
8, 7, 6, 5, 5, 4, 4, 3,
3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};

View file

@ -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);
samples = (gint16 *) GST_BUFFER_DATA (buf);
GST_LOG ("buffer-size = %ld", GST_BUFFER_SIZE (buffer));
spec_base = 8;
spec_len = 1024;
/* FIXME:need a gst_adapter */
num = GST_BUFFER_SIZE (buffer) / 2;
num = MIN (num, spectrum->len);
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);
for (i = 0; i < num; i++)
spectrum->re[i] = (samples[(i * 2)] + samples[(i * 2) + 1]) >> 1;
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);
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) {
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

View file

@ -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 {