From 6e44a9c61858764e50a6593f15994fdd5a73c8af Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Wed, 21 Feb 2007 10:18:12 +0000 Subject: gst/level/gstlevel.*: Use function pointer for process function and add process functions for float audio. Original commit message from CVS: * gst/level/gstlevel.c: (gst_level_init), (gst_level_set_caps), (gst_level_transform_ip): * gst/level/gstlevel.h: Use function pointer for process function and add process functions for float audio. --- gst/level/gstlevel.c | 191 +++++++++++++++++++++++++++++++++------------------ gst/level/gstlevel.h | 8 ++- 2 files changed, 132 insertions(+), 67 deletions(-) (limited to 'gst/level') diff --git a/gst/level/gstlevel.c b/gst/level/gstlevel.c index fcb0907c..bc1c42e1 100644 --- a/gst/level/gstlevel.c +++ b/gst/level/gstlevel.c @@ -78,6 +78,7 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif +#include #include #include #include "gstlevel.h" @@ -92,7 +93,7 @@ static const GstElementDetails level_details = GST_ELEMENT_DETAILS ("Level", "Thomas Vander Stichele "); static GstStaticPadTemplate sink_template_factory = -GST_STATIC_PAD_TEMPLATE ("sink", + GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/x-raw-int, " @@ -100,11 +101,16 @@ GST_STATIC_PAD_TEMPLATE ("sink", "channels = (int) [ 1, MAX ], " "endianness = (int) BYTE_ORDER, " "width = (int) { 8, 16 }, " - "depth = (int) { 8, 16 }, " "signed = (boolean) true") + "depth = (int) { 8, 16 }, " + "signed = (boolean) true; " + "audio/x-raw-float, " + "rate = (int) [ 1, MAX ], " + "channels = (int) [ 1, MAX ], " + "endianness = (int) BYTE_ORDER, " "width = (int) {32, 64} ") ); static GstStaticPadTemplate src_template_factory = -GST_STATIC_PAD_TEMPLATE ("src", + GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/x-raw-int, " @@ -112,7 +118,12 @@ GST_STATIC_PAD_TEMPLATE ("src", "channels = (int) [ 1, MAX ], " "endianness = (int) BYTE_ORDER, " "width = (int) { 8, 16 }, " - "depth = (int) { 8, 16 }, " "signed = (boolean) true") + "depth = (int) { 8, 16 }, " + "signed = (boolean) true; " + "audio/x-raw-float, " + "rate = (int) [ 1, MAX ], " + "channels = (int) [ 1, MAX ], " + "endianness = (int) BYTE_ORDER, " "width = (int) {32, 64} ") ); enum @@ -203,6 +214,8 @@ gst_level_init (GstLevel * filter, GstLevelClass * g_class) filter->decay_peak_falloff = 10.0; /* dB falloff (/sec) */ filter->message = TRUE; + + filter->process = NULL; } static void @@ -277,6 +290,82 @@ gst_level_get_property (GObject * object, guint prop_id, } } + +/* process one (interleaved) channel of incoming samples + * calculate square sum of samples + * normalize and average over number of samples + * returns a normalized cumulative square value, which can be averaged + * to return the average power as a double between 0 and 1 + * also returns the normalized peak power (square of the highest amplitude) + * + * caller must assure num is a multiple of channels + * samples for multiple channels are interleaved + * input sample data enters in *in_data as 8 or 16 bit data + * this filter only accepts signed audio data, so mid level is always 0 + * + * for 16 bit, this code considers the non-existant 32768 value to be + * full-scale; so 32767 will not map to 1.0 + */ + +#define DEFINE_INT_LEVEL_CALCULATOR(TYPE, RESOLUTION) \ +static void inline \ +gst_level_calculate_##TYPE (gpointer data, guint num, guint channels, \ + gdouble *NCS, gdouble *NPS) \ +{ \ + TYPE * in = (TYPE *)data; \ + register guint j; \ + gdouble squaresum = 0.0; /* square sum of the integer samples */ \ + register gdouble square = 0.0; /* Square */ \ + register gdouble peaksquare = 0.0; /* Peak Square Sample */ \ + gdouble normalizer; /* divisor to get a [-1.0, 1.0] range */ \ + \ + *NCS = 0.0; /* Normalized Cumulative Square */ \ + *NPS = 0.0; /* Normalized Peask Square */ \ + \ + normalizer = (gdouble) (1 << (RESOLUTION * 2)); \ + \ + for (j = 0; j < num; j += channels) \ + { \ + square = ((gdouble) in[j]) * in[j]; \ + if (square > peaksquare) peaksquare = square; \ + squaresum += square; \ + } \ + \ + *NCS = squaresum / normalizer; \ + *NPS = peaksquare / normalizer; \ +} + +DEFINE_INT_LEVEL_CALCULATOR (gint16, 15); +DEFINE_INT_LEVEL_CALCULATOR (gint8, 7); + +#define DEFINE_FLOAT_LEVEL_CALCULATOR(TYPE) \ +static void inline \ +gst_level_calculate_##TYPE (gpointer data, guint num, guint channels, \ + gdouble *NCS, gdouble *NPS) \ +{ \ + TYPE * in = (TYPE *)data; \ + register guint j; \ + gdouble squaresum = 0.0; /* square sum of the integer samples */ \ + register gdouble square = 0.0; /* Square */ \ + register gdouble peaksquare = 0.0; /* Peak Square Sample */ \ + \ + *NCS = 0.0; /* Normalized Cumulative Square */ \ + *NPS = 0.0; /* Normalized Peask Square */ \ + \ + for (j = 0; j < num; j += channels) \ + { \ + square = ((gdouble) in[j]) * in[j]; \ + if (square > peaksquare) peaksquare = square; \ + squaresum += square; \ + } \ + \ + *NCS = squaresum; \ + *NPS = peaksquare; \ +} + +DEFINE_FLOAT_LEVEL_CALCULATOR (gfloat); +DEFINE_FLOAT_LEVEL_CALCULATOR (gdouble); + static gint structure_get_int (GstStructure * structure, const gchar * field) { @@ -291,18 +380,42 @@ structure_get_int (GstStructure * structure, const gchar * field) static gboolean gst_level_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out) { - GstLevel *filter; + GstLevel *filter = GST_LEVEL (trans); + const gchar *mimetype; GstStructure *structure; int i; - filter = GST_LEVEL (trans); - filter->num_frames = 0; structure = gst_caps_get_structure (in, 0); filter->rate = structure_get_int (structure, "rate"); filter->width = structure_get_int (structure, "width"); filter->channels = structure_get_int (structure, "channels"); + mimetype = gst_structure_get_name (structure); + + /* FIXME: set calculator func depending on caps */ + filter->process = NULL; + if (strcmp (mimetype, "audio/x-raw-int") == 0) { + GST_DEBUG_OBJECT (filter, "use int: %u", filter->width); + switch (filter->width) { + case 8: + filter->process = gst_level_calculate_gint8; + break; + case 16: + filter->process = gst_level_calculate_gint16; + break; + } + } else if (strcmp (mimetype, "audio/x-raw-float") == 0) { + GST_DEBUG_OBJECT (filter, "use float, %u", filter->width); + switch (filter->width) { + case 32: + filter->process = gst_level_calculate_gfloat; + break; + case 64: + filter->process = gst_level_calculate_gdouble; + break; + } + } /* allocate channel variable arrays */ g_free (filter->CS); @@ -328,52 +441,6 @@ gst_level_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out) return TRUE; } -/* process one (interleaved) channel of incoming samples - * calculate square sum of samples - * normalize and average over number of samples - * returns a normalized cumulative square value, which can be averaged - * to return the average power as a double between 0 and 1 - * also returns the normalized peak power (square of the highest amplitude) - * - * caller must assure num is a multiple of channels - * samples for multiple channels are interleaved - * input sample data enters in *in_data as 8 or 16 bit data - * this filter only accepts signed audio data, so mid level is always 0 - * - * for 16 bit, this code considers the non-existant 32768 value to be - * full-scale; so 32767 will not map to 1.0 - */ - -#define DEFINE_LEVEL_CALCULATOR(TYPE, RESOLUTION) \ -static void inline \ -gst_level_calculate_##TYPE (TYPE * in, guint num, gint channels, \ - double *NCS, double *NPS) \ -{ \ - register int j; \ - double squaresum = 0.0; /* square sum of the integer samples */ \ - register double square = 0.0; /* Square */ \ - register double peaksquare = 0.0; /* Peak Square Sample */ \ - gdouble normalizer; /* divisor to get a [-1.0, 1.0] range */ \ - \ - *NCS = 0.0; /* Normalized Cumulative Square */ \ - *NPS = 0.0; /* Normalized Peask Square */ \ - \ - normalizer = (double) (1 << (RESOLUTION * 2)); \ - \ - for (j = 0; j < num; j += channels) \ - { \ - square = ((double) in[j]) * in[j]; \ - if (square > peaksquare) peaksquare = square; \ - squaresum += square; \ - } \ - \ - *NCS = squaresum / normalizer; \ - *NPS = peaksquare / normalizer; \ -} - -DEFINE_LEVEL_CALCULATOR (gint16, 15); -DEFINE_LEVEL_CALCULATOR (gint8, 7); - static GstMessage * gst_level_message_new (GstLevel * l, GstClockTime endtime) { @@ -427,10 +494,10 @@ gst_level_transform_ip (GstBaseTransform * trans, GstBuffer * in) GstLevel *filter; gpointer in_data; double CS = 0.0; - gint num_frames = 0; - gint num_int_samples = 0; /* number of interleaved samples + guint num_frames = 0; + guint num_int_samples = 0; /* number of interleaved samples * ie. total count for all channels combined */ - gint i; + guint i; filter = GST_LEVEL (trans); @@ -447,16 +514,8 @@ gst_level_transform_ip (GstBaseTransform * trans, GstBuffer * in) for (i = 0; i < filter->channels; ++i) { CS = 0.0; - switch (filter->width) { - case 16: - gst_level_calculate_gint16 (((gint16 *) in_data) + i, num_int_samples, - filter->channels, &CS, &filter->peak[i]); - break; - case 8: - gst_level_calculate_gint8 (((gint8 *) in_data) + i, num_int_samples, - filter->channels, &CS, &filter->peak[i]); - break; - } + filter->process (in_data + i, num_int_samples, filter->channels, &CS, + &filter->peak[i]); GST_LOG_OBJECT (filter, "channel %d, cumulative sum %f, peak %f, over %d samples/%d channels", i, CS, filter->peak[i], num_int_samples, filter->channels); diff --git a/gst/level/gstlevel.h b/gst/level/gstlevel.h index ead53547..3cd5d3a8 100644 --- a/gst/level/gstlevel.h +++ b/gst/level/gstlevel.h @@ -48,7 +48,11 @@ G_BEGIN_DECLS typedef struct _GstLevel GstLevel; typedef struct _GstLevelClass GstLevelClass; - +/** + * GstLevel: + * + * Opaque data structure. + */ struct _GstLevel { GstBaseTransform element; @@ -73,6 +77,8 @@ struct _GstLevel { gdouble *MS; /* normalized Mean Square of buffer */ gdouble *RMS_dB; /* RMS in dB to emit */ GstClockTime *decay_peak_age; /* age of last peak */ + + void (*process)(gpointer, guint, guint, gdouble*, gdouble*); }; struct _GstLevelClass { -- cgit