mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 02:01:12 +00:00
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.
This commit is contained in:
parent
6ecea15a25
commit
1bb14f4e48
6 changed files with 320 additions and 112 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
1
gst/level/gstlevel-marshal.list
Normal file
1
gst/level/gstlevel-marshal.list
Normal file
|
@ -0,0 +1 @@
|
|||
VOID:INT,DOUBLE,DOUBLE,DOUBLE
|
|
@ -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)
|
||||
{
|
||||
/* FIXME : Please change this to a better warning method ! */
|
||||
g_error ("WARNING: level: Could not get pad caps - caps nego failed !\n");
|
||||
}
|
||||
|
||||
gst_caps_get_int (caps, "width", &width);
|
||||
|
||||
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);
|
||||
|
||||
out_data = (gint16 *) GST_BUFFER_DATA (outbuf);
|
||||
for (i = 0; i < filter->channels; ++i)
|
||||
filter->CS[i] = filter->peak[i] = filter->MS[i] = filter->RMS_dB[i] = 0.0;
|
||||
|
||||
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;
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
filter->num_samples += num_samples;
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* do we need to emit ? */
|
||||
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
GstPad *sinkpad, *srcpad;
|
||||
gboolean signal; /* whether or not to emit signals */
|
||||
gdouble interval; /* how many seconds between emits */
|
||||
|
||||
/*MetaAudioRaw meta; */
|
||||
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);
|
||||
|
|
Loading…
Reference in a new issue