summaryrefslogtreecommitdiffstats
path: root/gst/level
diff options
context:
space:
mode:
authorThomas Vander Stichele <thomas@apestaart.org>2003-09-21 12:21:49 +0000
committerThomas Vander Stichele <thomas@apestaart.org>2003-09-21 12:21:49 +0000
commit1bb14f4e4864696d32bdbb24168a6b8d7e561753 (patch)
tree3c0144bc47002a73db98a1883049a271e6e340c7 /gst/level
parent6ecea15a25119e14d754450db283be5102645cb5 (diff)
reworked level plugin. It now does RMS, peak, and decay peak signaling per interleaved channel.
Original commit message from CVS: reworked level plugin. It now does RMS, peak, and decay peak signaling per interleaved channel.
Diffstat (limited to 'gst/level')
-rw-r--r--gst/level/Makefile.am24
-rw-r--r--gst/level/README24
-rw-r--r--gst/level/filter.func57
-rw-r--r--gst/level/gstlevel-marshal.list1
-rw-r--r--gst/level/gstlevel.c288
-rw-r--r--gst/level/gstlevel.h32
6 files changed, 317 insertions, 109 deletions
diff --git a/gst/level/Makefile.am b/gst/level/Makefile.am
index 507454d5..702b2cd6 100644
--- a/gst/level/Makefile.am
+++ b/gst/level/Makefile.am
@@ -1,11 +1,33 @@
plugin_LTLIBRARIES = libgstlevel.la
-libgstlevel_la_SOURCES = gstlevel.c
+libgstlevel_la_SOURCES = gstlevel.c gstlevel-marshal.c
libgstlevel_la_CFLAGS = $(GST_CFLAGS)
libgstlevel_la_LIBADD =
libgstlevel_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
noinst_HEADERS = gstlevel.h filter.func
+EXTRA_libgstlevel_la_SOURCES = gstlevel-marshal.list
+
+BUILT_SOURCES = \
+ gstlevel-marshal.c \
+ gstlevel-marshal.h
+
+gstlevel-marshal.h: gstlevel-marshal.list
+ glib-genmarshal --header --prefix=gstlevel_cclosure_marshal $(srcdir)/gstlevel-marshal.list > gstlevel-marshal.h.tmp
+ mv gstlevel-marshal.h.tmp gstlevel-marshal.h
+
+gstlevel-marshal.c: gstlevel-marshal.list
+ echo "#include \"glib.h\"" > gstlevel-marshal.c.tmp
+ echo "#include \"glib-object.h\"" >> gstlevel-marshal.c.tmp
+ echo "#include \"gstlevel-marshal.h\"" >> gstlevel-marshal.c.tmp
+ glib-genmarshal --body --prefix=gstlevel_cclosure_marshal $(srcdir)/gstlevel-marshal.list >> gstlevel-marshal.c.tmp
+ mv gstlevel-marshal.c.tmp gstlevel-marshal.c
+
+# Don't want the generated marshal files in the dist
+dist-hook:
+ rm -f $(distdir)/gstlevel-marshal.c
+ rm -f $(distdir)/gstlevel-marshal.h
+
EXTRA_DIST = README
diff --git a/gst/level/README b/gst/level/README
index c7dbf4ca..fffc69fa 100644
--- a/gst/level/README
+++ b/gst/level/README
@@ -1,11 +1,21 @@
level plugin by thomas <thomas@apestaart.org>
-basic level indicator; prints out RMS values averaged over the buffer of
-one iteration. Insert this into an audio/raw chain.
+this plugin signals:
+ - channel
+ - RMS level
+ - peak level
+ - decaying peak level
+over the given interval.
+
+This is useful for a VU meter display and for plotting out the signal graph.
+The VU meter can either display RMS, or display immediate peak level and
+have the falloff decaying peak level displayed as a line.
+
+The interval for signal emission, ttl of decay peak, and falloff of decay peak
+can all be set.
+
+The element only takes unsigned data in; it could be extended to signed as
+well, if separate fast chain functions are made that displaces the incoming
+data to its midpoint (ie, 0,65535 should be mapped to -32768, 32767)
-You can plot the level envelope of the track using gnuplot, example :
-tools/gstreamer-launch disksrc location=foo.wav ! parsewav ! level ! \
- fakesink silent=true > foo.level
-graph -T gif foo.level > foo.gif
-xview dark.gif
diff --git a/gst/level/filter.func b/gst/level/filter.func
index a530270d..eacecc66 100644
--- a/gst/level/filter.func
+++ b/gst/level/filter.func
@@ -1,45 +1,34 @@
+/* process one (interleaved) channel of incoming samples
+ * calculate square sum of samples
+ * normalize and return normalized Cumulative Square
+ * caller must assure num is a multiple of channels
+ * this filter only accepts signed audio data, so mid level is always 0
+ */
{
- guint j;
- double squaresum = 0.0;
- double RMS = 0.0;
- double RMS_dB = 0.0;
- static int threshold_dB = -80;
- static long int sample = 0;
- double timepoint;
+ register int j;
+ double squaresum = 0.0; /* square sum of the integer samples */
+ register double square = 0.0; /* Square */
+ register double PSS = 0.0; /* Peak Square Sample */
+
+ *CS = 0.0; /* Cumulative Square for this block */
+
+ gdouble normalizer = (double) (1 << resolution);
/*
* process data here
* input sample data enters in *in_data as 8 or 16 bit data
* samples for left and right channel are interleaved
+ * returns the Mean Square of the samples as a double between 0 and 1
*/
-/*
- for(j = 0; j < num_samples; j++) {
- out_data[j] = in_data[j];
- squaresum += in_data[j] * in_data[j];
- }
- RMS = sqrt (squaresum / (float) num_samples);
- printf ("RMS for this block : %f\n", RMS);
- RMS_dB = 20 * log (RMS / 32767);
- printf ("RMS in dB (for 16bit) : %f\n", RMS_dB);
-*/
- for(j = 0; j < num_samples; j++) {
- out_data[j] = in_data[j];
- squaresum += pow ((double) in_data[j] / 32767.0, 2);
- }
- RMS = sqrt (squaresum / (float) num_samples);
- RMS_dB = 10 * log (RMS);
- sample += num_samples;
- timepoint = sample / (44100.0 * 2);
-
- if (RMS_dB > (double) threshold_dB)
+ for (j = 0; j < num; j += channels)
{
-/* printf ("Reached %d dB at %f sec (%f dB)\n",
- threshold_dB, timepoint, RMS_dB);
-*/
- threshold_dB += 1;
+ square = (double) (in[j] * in[j]);
+ if (square > PSS) PSS = square;
+ squaresum += square;
}
-/* printf ("RMS in dB (for 16bit) : %f\n", RMS_dB); */
- printf ("%f s %f dB\n", timepoint, RMS_dB);
+ *peak = PSS / ((double) normalizer * (double) normalizer);
+
+ /* return normalized cumulative square */
+ *CS = squaresum / ((double) normalizer * (double) normalizer);
}
-
diff --git a/gst/level/gstlevel-marshal.list b/gst/level/gstlevel-marshal.list
new file mode 100644
index 00000000..d2ae97ea
--- /dev/null
+++ b/gst/level/gstlevel-marshal.list
@@ -0,0 +1 @@
+VOID:INT,DOUBLE,DOUBLE,DOUBLE
diff --git a/gst/level/gstlevel.c b/gst/level/gstlevel.c
index ad4f1b15..4fdfb0c7 100644
--- a/gst/level/gstlevel.c
+++ b/gst/level/gstlevel.c
@@ -1,6 +1,10 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
+ * gstlevel.c: signals RMS, peak and decaying peak levels
+ * Copyright (C) 2000,2001,2002,2003
+ * Thomas Vander Stichele <thomas at apestaart dot org>
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
@@ -17,34 +21,35 @@
* Boston, MA 02111-1307, USA.
*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
#include <gst/gst.h>
#include "gstlevel.h"
#include "math.h"
-#include <gst/audio/audio.h>
/* elementfactory information */
static GstElementDetails level_details = {
"Level",
"Filter/Audio/Analysis",
"LGPL",
- "RMS Level indicator for audio/raw",
+ "RMS/Peak/Decaying Peak Level signaller for audio/raw",
VERSION,
"Thomas <thomas@apestaart.org>",
- "(C) 2001",
+ "(C) 2001, 2003, 2003",
};
/* Filter signals and args */
enum {
/* FILL ME */
+ SIGNAL_LEVEL,
LAST_SIGNAL
};
enum {
- ARG_0
+ ARG_0,
+ ARG_SIGNAL_LEVEL,
+ ARG_SIGNAL_INTERVAL,
+ ARG_PEAK_TTL,
+ ARG_PEAK_FALLOFF
};
static GstPadTemplate*
@@ -59,11 +64,12 @@ level_src_factory (void)
GST_PAD_ALWAYS,
gst_caps_new (
"test_src",
- "audio/x-raw-int",
- GST_AUDIO_INT_PAD_TEMPLATE_PROPS
- ),
- NULL
- );
+ "audio/raw",
+ gst_props_new (
+ "channels", GST_PROPS_INT_RANGE (1, 2),
+ "signed", GST_PROPS_BOOLEAN (TRUE),
+ NULL)),
+ NULL);
}
return template;
}
@@ -80,11 +86,12 @@ level_sink_factory (void)
GST_PAD_ALWAYS,
gst_caps_new (
"test_src",
- "audio/x-raw-int",
- GST_AUDIO_INT_PAD_TEMPLATE_PROPS
- ),
- NULL
- );
+ "audio/raw",
+ gst_props_new (
+ "channels", GST_PROPS_INT_RANGE (1, 2),
+ "signed", GST_PROPS_BOOLEAN (TRUE),
+ NULL)),
+ NULL);
}
return template;
}
@@ -96,13 +103,9 @@ static void gst_level_set_property (GObject *object, guint prop_id, const GVa
static void gst_level_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
static void gst_level_chain (GstPad *pad, GstBuffer *buf);
-static void inline gst_level_fast_16bit_chain (gint16* data, gint16* out_data,
- guint numsamples);
-static void inline gst_level_fast_8bit_chain (gint8* data, gint8* out_data,
- guint numsamples);
static GstElementClass *parent_class = NULL;
-/*static guint gst_filter_signals[LAST_SIGNAL] = { 0 }; */
+static guint gst_filter_signals[LAST_SIGNAL] = { 0 };
GType
gst_level_get_type (void)
@@ -129,6 +132,8 @@ gst_level_connect (GstPad *pad, GstCaps *caps)
{
GstLevel *filter;
GstPad *otherpad;
+ GstPadLinkReturn res;
+ int i;
filter = GST_LEVEL (gst_pad_get_parent (pad));
g_return_val_if_fail (filter != NULL, GST_PAD_LINK_REFUSED);
@@ -137,73 +142,172 @@ gst_level_connect (GstPad *pad, GstCaps *caps)
if (GST_CAPS_IS_FIXED (caps))
{
- /*if ( !volume_parse_caps (filter, caps) || */
- return gst_pad_try_set_caps (otherpad, gst_caps_ref (caps));
+ /* yep, got them */
+ res = gst_pad_try_set_caps (otherpad, caps);
+ /* if ok, set filter */
+ if (res == GST_PAD_LINK_OK)
+ {
+ filter->num_samples = 0;
+ /* FIXME: error handling */
+ if (! gst_caps_get_int (caps, "rate", &(filter->rate)))
+ g_warning ("WARNING: level: Could not get rate from caps\n");
+ if (!gst_caps_get_int (caps, "width", &(filter->width)))
+ g_warning ("WARNING: level: Could not get width from caps\n");
+ if (!gst_caps_get_int (caps, "channels", &(filter->channels)))
+ g_warning ("WARNING: level: Could not get number of channels from caps\n");
+
+ /* allocate channel variable arrays */
+ if (filter->CS) g_free (filter->CS);
+ if (filter->peak) g_free (filter->peak);
+ if (filter->last_peak) g_free (filter->last_peak);
+ if (filter->decay_peak) g_free (filter->decay_peak);
+ if (filter->decay_peak_age) g_free (filter->decay_peak_age);
+ if (filter->MS) g_free (filter->MS);
+ if (filter->RMS_dB) g_free (filter->RMS_dB);
+ filter->CS = g_new (double, filter->channels);
+ filter->peak = g_new (double, filter->channels);
+ filter->last_peak = g_new (double, filter->channels);
+ filter->decay_peak = g_new (double, filter->channels);
+ filter->decay_peak_age = g_new (double, filter->channels);
+ filter->MS = g_new (double, filter->channels);
+ filter->RMS_dB = g_new (double, filter->channels);
+ for (i = 0; i < filter->channels; ++i)
+ {
+ filter->CS[i] = filter->peak[i] = filter->last_peak[i] =
+ filter->decay_peak[i] = filter->decay_peak_age[i] =
+ filter->MS[i] = filter->RMS_dB[i] = 0.0;
+ }
+ }
+ return res;
}
return GST_PAD_LINK_DELAYED;
}
+static void inline
+gst_level_fast_16bit_chain (gint16* in, guint num, gint channels,
+ gint resolution, double *CS, double *peak)
+#include "filter.func"
+
+static void inline
+gst_level_fast_8bit_chain (gint8* in, guint num, gint channels,
+ gint resolution, double *CS, double *peak)
+#include "filter.func"
+
static void
gst_level_chain (GstPad *pad, GstBuffer *buf)
{
GstLevel *filter;
gint16 *in_data;
- gint16 *out_data;
- GstBuffer* outbuf;
- gint width;
- GstCaps *caps;
+ double CS = 0.0;
+ gint num_samples = 0;
+ gint i;
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (buf != NULL);
+
+ g_print ("\nDEBUG: chain start\n");
filter = GST_LEVEL (GST_OBJECT_PARENT (pad));
g_return_if_fail (filter != NULL);
g_return_if_fail (GST_IS_LEVEL (filter));
- caps = NULL;
- caps = GST_PAD_CAPS (pad);
- if (caps == NULL)
+ for (i = 0; i < filter->channels; ++i)
+ filter->CS[i] = filter->peak[i] = filter->MS[i] = filter->RMS_dB[i] = 0.0;
+
+ in_data = (gint16 *) GST_BUFFER_DATA(buf);
+
+ num_samples = GST_BUFFER_SIZE (buf) / (filter->width / 8);
+ if (num_samples % filter->channels != 0)
+ g_warning ("WARNING: level: programming error, data not properly interleaved");
+
+ for (i = 0; i < filter->channels; ++i)
{
- /* FIXME : Please change this to a better warning method ! */
- g_error ("WARNING: level: Could not get pad caps - caps nego failed !\n");
+ switch (filter->width)
+ {
+ case 16:
+ gst_level_fast_16bit_chain (in_data + i, num_samples,
+ filter->channels, filter->width - 1,
+ &CS, &filter->peak[i]);
+ break;
+ case 8:
+ gst_level_fast_8bit_chain (((gint8 *) in_data) + i, num_samples,
+ filter->channels, filter->width - 1,
+ &CS, &filter->peak[i]);
+ break;
+ }
+ g_print ("DEBUG: CS %f, peak %f\n", CS, filter->peak[i]);
+ filter->CS[i] += CS;
+
}
+ gst_pad_push (filter->srcpad, buf);
- gst_caps_get_int (caps, "width", &width);
+ filter->num_samples += num_samples;
- in_data = (gint16 *) GST_BUFFER_DATA(buf);
- outbuf = gst_buffer_new();
- GST_BUFFER_DATA (outbuf) = (gchar *) g_new (gint16,
- GST_BUFFER_SIZE (buf) / 2);
- GST_BUFFER_SIZE (outbuf) = GST_BUFFER_SIZE (buf);
+ for (i = 0; i < filter->channels; ++i)
+ {
+ filter->decay_peak_age[i] += num_samples;
+ g_print ("filter peak info [%d]: peak %f, age %f\n", i,
+ filter->last_peak[i], filter->decay_peak_age[i]);
+ /* update running peak */
+ if (filter->peak[i] > filter->last_peak[i])
+ filter->last_peak[i] = filter->peak[i];
+
+ /* update decay peak */
+ if (filter->peak[i] >= filter->decay_peak[i])
+ {
+ g_print ("new peak, %f\n", filter->peak[i]);
+ filter->decay_peak[i] = filter->peak[i];
+ filter->decay_peak_age[i] = 0;
+ }
+ else
+ {
+ /* make decay peak fall off if too old */
+ if (filter->decay_peak_age[i] > filter->rate * filter->decay_peak_ttl)
+ {
+ double falloff_dB;
+ double falloff;
+ double length; /* length of buffer in seconds */
+
+
+ length = (double) num_samples / (filter->channels * filter->rate);
+ falloff_dB = filter->decay_peak_falloff * length;
+ falloff = pow (10, falloff_dB / -20.0);
+
+ g_print ("falloff: length %f, dB falloff %f, falloff factor %e\n",
+ length, falloff_dB, falloff);
+ filter->decay_peak[i] *= falloff;
+ g_print ("peak is %f samples old, decayed with factor %e to %f\n",
+ filter->decay_peak_age[i], falloff, filter->decay_peak[i]);
+ }
+ }
+ }
- out_data = (gint16 *) GST_BUFFER_DATA (outbuf);
+ /* do we need to emit ? */
- g_print ("%s: ", gst_element_get_name (GST_ELEMENT (filter)));
- switch (width) {
- case 16:
- gst_level_fast_16bit_chain (in_data, out_data,
- GST_BUFFER_SIZE (buf) / 2);
- break;
- case 8:
- gst_level_fast_8bit_chain ((gint8 *) in_data,
- (gint8 *) out_data, GST_BUFFER_SIZE(buf));
- break;
+ if (filter->num_samples >= filter->interval * (gdouble) filter->rate)
+ {
+ if (filter->signal)
+ {
+ gdouble RMS, peak;
+ for (i = 0; i < filter->channels; ++i)
+ {
+ RMS = sqrt (filter->CS[i] / (filter->num_samples / filter->channels));
+ peak = filter->last_peak[i];
+
+ g_signal_emit (G_OBJECT (filter), gst_filter_signals[SIGNAL_LEVEL], 0,
+ i, 20 * log10 (RMS), 20 * log10 (filter->last_peak[i]),
+ 20 * log10 (filter->decay_peak[i]));
+ /* we emitted, so reset cumulative and normal peak */
+ filter->CS[i] = 0.0;
+ filter->last_peak[i] = 0.0;
+ }
+ }
+ filter->num_samples = 0;
}
- gst_buffer_unref (buf);
- gst_pad_push (filter->srcpad,outbuf);
}
-static void inline
-gst_level_fast_16bit_chain (gint16* in_data, gint16* out_data,
- guint num_samples)
-#include "filter.func"
-
-static void inline
-gst_level_fast_8bit_chain (gint8* in_data, gint8* out_data,
- guint num_samples)
-#include "filter.func"
static void
gst_level_set_property (GObject *object, guint prop_id,
@@ -216,6 +320,18 @@ gst_level_set_property (GObject *object, guint prop_id,
filter = GST_LEVEL (object);
switch (prop_id) {
+ case ARG_SIGNAL_LEVEL:
+ filter->signal = g_value_get_boolean (value);
+ break;
+ case ARG_SIGNAL_INTERVAL:
+ filter->interval = g_value_get_double (value);
+ break;
+ case ARG_PEAK_TTL:
+ filter->decay_peak_ttl = g_value_get_double (value);
+ break;
+ case ARG_PEAK_FALLOFF:
+ filter->decay_peak_falloff = g_value_get_double (value);
+ break;
default:
break;
}
@@ -232,7 +348,19 @@ gst_level_get_property (GObject *object, guint prop_id,
filter = GST_LEVEL (object);
switch (prop_id) {
- default:
+ case ARG_SIGNAL_LEVEL:
+ g_value_set_boolean (value, filter->signal);
+ break;
+ case ARG_SIGNAL_INTERVAL:
+ g_value_set_double (value, filter->interval);
+ break;
+ case ARG_PEAK_TTL:
+ g_value_set_double (value, filter->decay_peak_ttl);
+ break;
+ case ARG_PEAK_FALLOFF:
+ g_value_set_double (value, filter->decay_peak_falloff);
+ break;
+ default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
@@ -248,9 +376,32 @@ gst_level_class_init (GstLevelClass *klass)
gstelement_class = (GstElementClass*) klass;
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_LEVEL,
+ g_param_spec_boolean ("signal", "Signal",
+ "Emit level signals for each interval",
+ TRUE, G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_INTERVAL,
+ g_param_spec_double ("interval", "Interval",
+ "Interval between emissions (in seconds)",
+ 0.01, 100.0, 0.1, G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PEAK_TTL,
+ g_param_spec_double ("peak_ttl", "Peak TTL",
+ "Time To Live of decay peak before it falls back",
+ 0, 100.0, 0.3, G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PEAK_FALLOFF,
+ g_param_spec_double ("peak_falloff", "Peak Falloff",
+ "Decay rate of decay peak after TTL (in dB/sec)",
+ 0.0, G_MAXDOUBLE, 10.0, G_PARAM_READWRITE));
gobject_class->set_property = gst_level_set_property;
gobject_class->get_property = gst_level_get_property;
+
+ gst_filter_signals[SIGNAL_LEVEL] =
+ g_signal_new ("level", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GstLevelClass, level), NULL, NULL,
+ gstlevel_cclosure_marshal_VOID__INT_DOUBLE_DOUBLE_DOUBLE,
+ G_TYPE_NONE, 4,
+ G_TYPE_INT, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
}
static void
@@ -265,6 +416,19 @@ gst_level_init (GstLevel *filter)
gst_pad_set_chain_function (filter->sinkpad, gst_level_chain);
filter->srcpad = gst_pad_new ("src", GST_PAD_SRC);
gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
+
+ filter->CS = NULL;
+ filter->peak = NULL;
+ filter->MS = NULL;
+ filter->RMS_dB = NULL;
+
+ filter->rate = 0;
+ filter->width = 0;
+ filter->channels = 0;
+
+ filter->interval = 0.1;
+ filter->decay_peak_ttl = 0.4;
+ filter->decay_peak_falloff = 10.0; /* dB falloff (/sec) */
}
static gboolean
diff --git a/gst/level/gstlevel.h b/gst/level/gstlevel.h
index dd5edab4..d5b8fd7e 100644
--- a/gst/level/gstlevel.h
+++ b/gst/level/gstlevel.h
@@ -1,6 +1,10 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
+ * gstlevel.c: signals RMS, peak and decaying peak levels
+ * Copyright (C) 2000,2001,2002,2003
+ * Thomas Vander Stichele <thomas at apestaart dot org>
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
@@ -24,8 +28,8 @@
#include <config.h>
#include <gst/gst.h>
-/* #include <gst/meta/audioraw.h> */
+#include "gstlevel-marshal.h"
#ifdef __cplusplus
extern "C" {
@@ -49,14 +53,32 @@ typedef struct _GstLevelClass GstLevelClass;
struct _GstLevel {
GstElement element;
- GstPad *sinkpad,*srcpad;
-
- /*MetaAudioRaw meta; */
-
+ GstPad *sinkpad, *srcpad;
+ gboolean signal; /* whether or not to emit signals */
+ gdouble interval; /* how many seconds between emits */
+
+ gint rate; /* caps variables */
+ gint width;
+ gint channels;
+
+ gdouble decay_peak_ttl; /* time to live for peak in seconds */
+ gdouble decay_peak_falloff; /* falloff in dB/sec */
+ gdouble num_samples; /* cumulative sample count */
+
+ /* per-channel arrays for intermediate values */
+ gdouble *CS; /* normalized Cumulative Square */
+ gdouble *peak; /* normalized Peak value over buffer */
+ gdouble *last_peak; /* last normalized Peak value over interval */
+ gdouble *decay_peak; /* running decaying normalized Peak */
+ gdouble *MS; /* normalized Mean Square of buffer */
+ gdouble *RMS_dB; /* RMS in dB to emit */
+ gdouble *decay_peak_age; /* age of last peak */
};
struct _GstLevelClass {
GstElementClass parent_class;
+ void (*level) (GstElement *element, gint channel,
+ gdouble RMS_dB, gdouble peak_dB, gdouble decay_peak_dB);
};
GType gst_level_get_type(void);