2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
4 * gstlevel.c: signals RMS, peak and decaying peak levels
5 * Copyright (C) 2000,2001,2002,2003
6 * Thomas Vander Stichele <thomas at apestaart dot org>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
31 GST_DEBUG_CATEGORY (level_debug);
32 #define GST_CAT_DEFAULT level_debug
34 static GstElementDetails level_details = {
36 "Filter/Analyzer/Audio",
37 "RMS/Peak/Decaying Peak Level signaller for audio/raw",
38 "Thomas <thomas@apestaart.org>"
41 static GstStaticPadTemplate sink_template_factory =
42 GST_STATIC_PAD_TEMPLATE ("sink",
45 GST_STATIC_CAPS ("audio/x-raw-int, "
46 "rate = (int) [ 1, MAX ], "
47 "channels = (int) [ 1, 2 ], "
48 "endianness = (int) BYTE_ORDER, "
49 "width = (int) { 8, 16 }, "
50 "depth = (int) { 8, 16 }, " "signed = (boolean) true")
53 static GstStaticPadTemplate src_template_factory =
54 GST_STATIC_PAD_TEMPLATE ("src",
57 GST_STATIC_CAPS ("audio/x-raw-int, "
58 "rate = (int) [ 1, MAX ], "
59 "channels = (int) [ 1, 2 ], "
60 "endianness = (int) BYTE_ORDER, "
61 "width = (int) { 8, 16 }, "
62 "depth = (int) { 8, 16 }, " "signed = (boolean) true")
76 GST_BOILERPLATE (GstLevel, gst_level, GstBaseTransform,
77 GST_TYPE_BASE_TRANSFORM);
80 static void gst_level_set_property (GObject * object, guint prop_id,
81 const GValue * value, GParamSpec * pspec);
82 static void gst_level_get_property (GObject * object, guint prop_id,
83 GValue * value, GParamSpec * pspec);
85 static gboolean gst_level_set_caps (GstBaseTransform * trans, GstCaps * in,
87 static GstFlowReturn gst_level_transform (GstBaseTransform * trans,
88 GstBuffer * in, GstBuffer * out);
92 gst_level_base_init (gpointer g_class)
94 GstElementClass *element_class = g_class;
96 gst_element_class_add_pad_template (element_class,
97 gst_static_pad_template_get (&sink_template_factory));
98 gst_element_class_add_pad_template (element_class,
99 gst_static_pad_template_get (&src_template_factory));
100 gst_element_class_set_details (element_class, &level_details);
104 gst_level_class_init (GstLevelClass * klass)
106 GObjectClass *gobject_class;
107 GstBaseTransformClass *trans_class;
109 gobject_class = (GObjectClass *) klass;
110 trans_class = (GstBaseTransformClass *) klass;
112 gobject_class->set_property = gst_level_set_property;
113 gobject_class->get_property = gst_level_get_property;
115 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SIGNAL_LEVEL,
116 g_param_spec_boolean ("signal", "Signal",
117 "Emit level signals for each interval", TRUE, G_PARAM_READWRITE));
118 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SIGNAL_INTERVAL,
119 g_param_spec_double ("interval", "Interval",
120 "Interval between emissions (in seconds)",
121 0.01, 100.0, 0.1, G_PARAM_READWRITE));
122 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PEAK_TTL,
123 g_param_spec_double ("peak_ttl", "Peak TTL",
124 "Time To Live of decay peak before it falls back",
125 0, 100.0, 0.3, G_PARAM_READWRITE));
126 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PEAK_FALLOFF,
127 g_param_spec_double ("peak_falloff", "Peak Falloff",
128 "Decay rate of decay peak after TTL (in dB/sec)",
129 0.0, G_MAXDOUBLE, 10.0, G_PARAM_READWRITE));
131 GST_DEBUG_CATEGORY_INIT (level_debug, "level", 0, "Level calculation");
133 trans_class->set_caps = gst_level_set_caps;
134 trans_class->transform = gst_level_transform;
138 gst_level_init (GstLevel * filter)
143 filter->RMS_dB = NULL;
147 filter->channels = 0;
149 filter->interval = 0.1;
150 filter->decay_peak_ttl = 0.4;
151 filter->decay_peak_falloff = 10.0; /* dB falloff (/sec) */
155 gst_level_set_property (GObject * object, guint prop_id,
156 const GValue * value, GParamSpec * pspec)
158 GstLevel *filter = GST_LEVEL (object);
161 case PROP_SIGNAL_LEVEL:
162 filter->signal = g_value_get_boolean (value);
164 case PROP_SIGNAL_INTERVAL:
165 filter->interval = g_value_get_double (value);
168 filter->decay_peak_ttl = g_value_get_double (value);
170 case PROP_PEAK_FALLOFF:
171 filter->decay_peak_falloff = g_value_get_double (value);
179 gst_level_get_property (GObject * object, guint prop_id,
180 GValue * value, GParamSpec * pspec)
182 GstLevel *filter = GST_LEVEL (object);
185 case PROP_SIGNAL_LEVEL:
186 g_value_set_boolean (value, filter->signal);
188 case PROP_SIGNAL_INTERVAL:
189 g_value_set_double (value, filter->interval);
192 g_value_set_double (value, filter->decay_peak_ttl);
194 case PROP_PEAK_FALLOFF:
195 g_value_set_double (value, filter->decay_peak_falloff);
198 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
204 structure_get_int (GstStructure * structure, const gchar * field)
208 if (!gst_structure_get_int (structure, field, &ret))
209 g_assert_not_reached ();
215 gst_level_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
218 GstStructure *structure;
221 filter = GST_LEVEL (trans);
223 filter->num_samples = 0;
225 structure = gst_caps_get_structure (in, 0);
226 filter->rate = structure_get_int (structure, "rate");
227 filter->width = structure_get_int (structure, "width");
228 filter->channels = structure_get_int (structure, "channels");
230 /* allocate channel variable arrays */
232 g_free (filter->peak);
233 g_free (filter->last_peak);
234 g_free (filter->decay_peak);
235 g_free (filter->decay_peak_age);
237 g_free (filter->RMS_dB);
238 filter->CS = g_new (double, filter->channels);
239 filter->peak = g_new (double, filter->channels);
240 filter->last_peak = g_new (double, filter->channels);
241 filter->decay_peak = g_new (double, filter->channels);
242 filter->decay_peak_age = g_new (double, filter->channels);
243 filter->MS = g_new (double, filter->channels);
244 filter->RMS_dB = g_new (double, filter->channels);
246 for (i = 0; i < filter->channels; ++i) {
247 filter->CS[i] = filter->peak[i] = filter->last_peak[i] =
248 filter->decay_peak[i] = filter->decay_peak_age[i] =
249 filter->MS[i] = filter->RMS_dB[i] = 0.0;
256 #define DEBUG(str,...) g_print (str, ...)
258 #define DEBUG(str,...) /*nop */
261 /* process one (interleaved) channel of incoming samples
262 * calculate square sum of samples
263 * normalize and return normalized Cumulative Square
264 * caller must assure num is a multiple of channels
265 * this filter only accepts signed audio data, so mid level is always 0
267 #define DEFINE_LEVEL_CALCULATOR(TYPE) \
269 gst_level_calculate_##TYPE (TYPE * in, guint num, gint channels, \
270 gint resolution, double *CS, double *peak) \
273 double squaresum = 0.0; /* square sum of the integer samples */ \
274 register double square = 0.0; /* Square */ \
275 register double PSS = 0.0; /* Peak Square Sample */ \
276 gdouble normalizer; \
278 *CS = 0.0; /* Cumulative Square for this block */ \
280 normalizer = (double) (1 << resolution); \
283 * process data here \
284 * input sample data enters in *in_data as 8 or 16 bit data \
285 * samples for left and right channel are interleaved \
286 * returns the Mean Square of the samples as a double between 0 and 1 \
289 for (j = 0; j < num; j += channels) \
291 DEBUG ("ch %d -> smp %d\n", j, in[j]); \
292 square = (double) (in[j] * in[j]); \
293 if (square > PSS) PSS = square; \
294 squaresum += square; \
296 *peak = PSS / ((double) normalizer * (double) normalizer); \
298 /* return normalized cumulative square */ \
299 *CS = squaresum / ((double) normalizer * (double) normalizer); \
302 DEFINE_LEVEL_CALCULATOR (gint16);
303 DEFINE_LEVEL_CALCULATOR (gint8);
306 gst_level_message_new (GstLevel * l, gdouble endtime)
311 g_value_init (&v, GST_TYPE_LIST);
313 s = gst_structure_new ("level", "endtime", G_TYPE_DOUBLE, endtime, NULL);
314 /* will copy-by-value */
315 gst_structure_set_value (s, "rms", &v);
316 gst_structure_set_value (s, "peak", &v);
317 gst_structure_set_value (s, "decay", &v);
319 return gst_message_new_application (GST_OBJECT (l), s);
323 gst_level_message_append_channel (GstMessage * m, gdouble rms, gdouble peak,
330 g_value_init (&v, G_TYPE_DOUBLE);
332 s = (GstStructure *) gst_message_get_structure (m);
334 l = (GValue *) gst_structure_get_value (s, "rms");
335 g_value_set_double (&v, rms);
336 gst_value_list_append_value (l, &v); /* copies by value */
338 l = (GValue *) gst_structure_get_value (s, "peak");
339 g_value_set_double (&v, peak);
340 gst_value_list_append_value (l, &v); /* copies by value */
342 l = (GValue *) gst_structure_get_value (s, "decay");
343 g_value_set_double (&v, decay);
344 gst_value_list_append_value (l, &v); /* copies by value */
348 gst_level_transform (GstBaseTransform * trans, GstBuffer * in, GstBuffer * out)
353 gint num_samples = 0;
356 filter = GST_LEVEL (trans);
358 for (i = 0; i < filter->channels; ++i)
359 filter->CS[i] = filter->peak[i] = filter->MS[i] = filter->RMS_dB[i] = 0.0;
361 in_data = GST_BUFFER_DATA (in);
362 num_samples = GST_BUFFER_SIZE (in) / (filter->width / 8);
364 g_return_val_if_fail (num_samples % filter->channels == 0, GST_FLOW_ERROR);
366 for (i = 0; i < filter->channels; ++i) {
367 switch (filter->width) {
369 gst_level_calculate_gint16 (in_data + i, num_samples,
370 filter->channels, filter->width - 1, &CS, &filter->peak[i]);
373 gst_level_calculate_gint8 (((gint8 *) in_data) + i, num_samples,
374 filter->channels, filter->width - 1, &CS, &filter->peak[i]);
377 GST_LOG_OBJECT (filter, "channel %d, cumulative sum %f, peak %f", i, CS,
383 filter->num_samples += num_samples;
385 for (i = 0; i < filter->channels; ++i) {
386 filter->decay_peak_age[i] += num_samples;
387 DEBUG ("filter peak info [%d]: peak %f, age %f\n", i,
388 filter->last_peak[i], filter->decay_peak_age[i]);
389 /* update running peak */
390 if (filter->peak[i] > filter->last_peak[i])
391 filter->last_peak[i] = filter->peak[i];
393 /* update decay peak */
394 if (filter->peak[i] >= filter->decay_peak[i]) {
395 DEBUG ("new peak, %f\n", filter->peak[i]);
396 filter->decay_peak[i] = filter->peak[i];
397 filter->decay_peak_age[i] = 0;
399 /* make decay peak fall off if too old */
400 if (filter->decay_peak_age[i] > filter->rate * filter->decay_peak_ttl) {
403 double length; /* length of buffer in seconds */
406 length = (double) num_samples / (filter->channels * filter->rate);
407 falloff_dB = filter->decay_peak_falloff * length;
408 falloff = pow (10, falloff_dB / -20.0);
410 DEBUG ("falloff: length %f, dB falloff %f, falloff factor %e\n",
411 length, falloff_dB, falloff);
412 filter->decay_peak[i] *= falloff;
413 DEBUG ("peak is %f samples old, decayed with factor %e to %f\n",
414 filter->decay_peak_age[i], falloff, filter->decay_peak[i]);
419 /* do we need to emit ? */
421 if (filter->num_samples >= filter->interval * (gdouble) filter->rate) {
422 if (filter->signal) {
426 endtime = (double) GST_BUFFER_TIMESTAMP (in) / GST_SECOND
427 + (double) num_samples / (double) filter->rate;
429 m = gst_level_message_new (filter, endtime);
431 for (i = 0; i < filter->channels; ++i) {
432 RMS = sqrt (filter->CS[i] / (filter->num_samples / filter->channels));
434 gst_level_message_append_channel (m, 20 * log10 (RMS),
435 20 * log10 (filter->last_peak[i]),
436 20 * log10 (filter->decay_peak[i]));
438 /* reset cumulative and normal peak */
440 filter->last_peak[i] = 0.0;
443 gst_element_post_message (GST_ELEMENT (filter), m);
445 filter->num_samples = 0;
452 plugin_init (GstPlugin * plugin)
454 return gst_element_register (plugin, "level", GST_RANK_NONE, GST_TYPE_LEVEL);
457 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
460 "Audio level plugin",
461 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)