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.
28 /* elementfactory information */
29 static GstElementDetails level_details = {
31 "Filter/Audio/Analysis",
33 "RMS/Peak/Decaying Peak Level signaller for audio/raw",
35 "Thomas <thomas@apestaart.org>",
36 "(C) 2001, 2003, 2003",
41 GST_PAD_TEMPLATE_FACTORY (sink_template_factory,
48 "signed", GST_PROPS_BOOLEAN (TRUE),
49 "width", GST_PROPS_LIST (
53 "depth", GST_PROPS_LIST (
57 "rate", GST_PROPS_INT_RANGE (1, G_MAXINT),
58 "channels", GST_PROPS_INT_RANGE (1, 2)
62 GST_PAD_TEMPLATE_FACTORY (src_template_factory,
69 "signed", GST_PROPS_BOOLEAN (TRUE),
70 "width", GST_PROPS_LIST (
74 "depth", GST_PROPS_LIST (
78 "rate", GST_PROPS_INT_RANGE (1, G_MAXINT),
79 "channels", GST_PROPS_INT_RANGE (1, 2)
83 /* Filter signals and args */
98 static void gst_level_class_init (GstLevelClass *klass);
99 static void gst_level_init (GstLevel *filter);
101 static void gst_level_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
102 static void gst_level_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
104 static void gst_level_chain (GstPad *pad, GstData *_data);
106 static GstElementClass *parent_class = NULL;
107 static guint gst_filter_signals[LAST_SIGNAL] = { 0 };
110 gst_level_get_type (void)
112 static GType level_type = 0;
116 static const GTypeInfo level_info =
118 sizeof (GstLevelClass), NULL, NULL,
119 (GClassInitFunc) gst_level_class_init, NULL, NULL,
120 sizeof (GstLevel), 0,
121 (GInstanceInitFunc) gst_level_init
123 level_type = g_type_register_static (GST_TYPE_ELEMENT, "GstLevel",
129 static GstPadLinkReturn
130 gst_level_connect (GstPad *pad, GstCaps *caps)
134 GstPadLinkReturn res;
137 filter = GST_LEVEL (gst_pad_get_parent (pad));
138 g_return_val_if_fail (filter != NULL, GST_PAD_LINK_REFUSED);
139 g_return_val_if_fail (GST_IS_LEVEL (filter), GST_PAD_LINK_REFUSED);
140 otherpad = (pad == filter->srcpad ? filter->sinkpad : filter->srcpad);
142 if (GST_CAPS_IS_FIXED (caps))
145 res = gst_pad_try_set_caps (otherpad, caps);
146 /* if ok, set filter */
147 if (res == GST_PAD_LINK_OK)
149 filter->num_samples = 0;
150 /* FIXME: error handling */
151 if (! gst_caps_get_int (caps, "rate", &(filter->rate)))
152 g_warning ("WARNING: level: Could not get rate from caps\n");
153 if (!gst_caps_get_int (caps, "width", &(filter->width)))
154 g_warning ("WARNING: level: Could not get width from caps\n");
155 if (!gst_caps_get_int (caps, "channels", &(filter->channels)))
156 g_warning ("WARNING: level: Could not get number of channels from caps\n");
158 /* allocate channel variable arrays */
159 if (filter->CS) g_free (filter->CS);
160 if (filter->peak) g_free (filter->peak);
161 if (filter->last_peak) g_free (filter->last_peak);
162 if (filter->decay_peak) g_free (filter->decay_peak);
163 if (filter->decay_peak_age) g_free (filter->decay_peak_age);
164 if (filter->MS) g_free (filter->MS);
165 if (filter->RMS_dB) g_free (filter->RMS_dB);
166 filter->CS = g_new (double, filter->channels);
167 filter->peak = g_new (double, filter->channels);
168 filter->last_peak = g_new (double, filter->channels);
169 filter->decay_peak = g_new (double, filter->channels);
170 filter->decay_peak_age = g_new (double, filter->channels);
171 filter->MS = g_new (double, filter->channels);
172 filter->RMS_dB = g_new (double, filter->channels);
173 for (i = 0; i < filter->channels; ++i)
175 filter->CS[i] = filter->peak[i] = filter->last_peak[i] =
176 filter->decay_peak[i] = filter->decay_peak_age[i] =
177 filter->MS[i] = filter->RMS_dB[i] = 0.0;
182 return GST_PAD_LINK_DELAYED;
186 gst_level_fast_16bit_chain (gint16* in, guint num, gint channels,
187 gint resolution, double *CS, double *peak)
188 #include "filter.func"
191 gst_level_fast_8bit_chain (gint8* in, guint num, gint channels,
192 gint resolution, double *CS, double *peak)
193 #include "filter.func"
196 gst_level_chain (GstPad *pad, GstData *_data)
198 GstBuffer *buf = GST_BUFFER (_data);
203 gint num_samples = 0;
206 g_return_if_fail (pad != NULL);
207 g_return_if_fail (GST_IS_PAD (pad));
208 g_return_if_fail (buf != NULL);
211 filter = GST_LEVEL (GST_OBJECT_PARENT (pad));
212 g_return_if_fail (filter != NULL);
213 g_return_if_fail (GST_IS_LEVEL (filter));
215 for (i = 0; i < filter->channels; ++i)
216 filter->CS[i] = filter->peak[i] = filter->MS[i] = filter->RMS_dB[i] = 0.0;
218 in_data = (gint16 *) GST_BUFFER_DATA (buf);
220 num_samples = GST_BUFFER_SIZE (buf) / (filter->width / 8);
221 if (num_samples % filter->channels != 0)
222 g_warning ("WARNING: level: programming error, data not properly interleaved");
224 for (i = 0; i < filter->channels; ++i)
226 switch (filter->width)
229 gst_level_fast_16bit_chain (in_data + i, num_samples,
230 filter->channels, filter->width - 1,
231 &CS, &filter->peak[i]);
234 gst_level_fast_8bit_chain (((gint8 *) in_data) + i, num_samples,
235 filter->channels, filter->width - 1,
236 &CS, &filter->peak[i]);
239 /* g_print ("DEBUG: CS %f, peak %f\n", CS, filter->peak[i]); */
243 gst_pad_push (filter->srcpad, GST_DATA (buf));
245 filter->num_samples += num_samples;
247 for (i = 0; i < filter->channels; ++i)
249 filter->decay_peak_age[i] += num_samples;
250 /* g_print ("filter peak info [%d]: peak %f, age %f\n", i,
251 filter->last_peak[i], filter->decay_peak_age[i]); */
252 /* update running peak */
253 if (filter->peak[i] > filter->last_peak[i])
254 filter->last_peak[i] = filter->peak[i];
256 /* update decay peak */
257 if (filter->peak[i] >= filter->decay_peak[i])
259 /* g_print ("new peak, %f\n", filter->peak[i]); */
260 filter->decay_peak[i] = filter->peak[i];
261 filter->decay_peak_age[i] = 0;
265 /* make decay peak fall off if too old */
266 if (filter->decay_peak_age[i] > filter->rate * filter->decay_peak_ttl)
270 double length; /* length of buffer in seconds */
273 length = (double) num_samples / (filter->channels * filter->rate);
274 falloff_dB = filter->decay_peak_falloff * length;
275 falloff = pow (10, falloff_dB / -20.0);
277 /* g_print ("falloff: length %f, dB falloff %f, falloff factor %e\n",
278 length, falloff_dB, falloff); */
279 filter->decay_peak[i] *= falloff;
280 /* g_print ("peak is %f samples old, decayed with factor %e to %f\n",
281 filter->decay_peak_age[i], falloff, filter->decay_peak[i]); */
286 /* do we need to emit ? */
288 if (filter->num_samples >= filter->interval * (gdouble) filter->rate)
292 gdouble RMS, peak, endtime;
293 for (i = 0; i < filter->channels; ++i)
295 RMS = sqrt (filter->CS[i] / (filter->num_samples / filter->channels));
296 peak = filter->last_peak[i];
297 num_samples = GST_BUFFER_SIZE (buf) / (filter->width / 8);
298 endtime = (double) GST_BUFFER_TIMESTAMP (buf) / GST_SECOND
299 + (double) num_samples / (double) filter->rate;
301 g_signal_emit (G_OBJECT (filter), gst_filter_signals[SIGNAL_LEVEL], 0,
303 20 * log10 (RMS), 20 * log10 (filter->last_peak[i]),
304 20 * log10 (filter->decay_peak[i]));
305 /* we emitted, so reset cumulative and normal peak */
307 filter->last_peak[i] = 0.0;
310 filter->num_samples = 0;
316 gst_level_set_property (GObject *object, guint prop_id,
317 const GValue *value, GParamSpec *pspec)
321 /* it's not null if we got it, but it might not be ours */
322 g_return_if_fail (GST_IS_LEVEL (object));
323 filter = GST_LEVEL (object);
326 case ARG_SIGNAL_LEVEL:
327 filter->signal = g_value_get_boolean (value);
329 case ARG_SIGNAL_INTERVAL:
330 filter->interval = g_value_get_double (value);
333 filter->decay_peak_ttl = g_value_get_double (value);
335 case ARG_PEAK_FALLOFF:
336 filter->decay_peak_falloff = g_value_get_double (value);
344 gst_level_get_property (GObject *object, guint prop_id,
345 GValue *value, GParamSpec *pspec)
349 /* it's not null if we got it, but it might not be ours */
350 g_return_if_fail (GST_IS_LEVEL (object));
351 filter = GST_LEVEL (object);
354 case ARG_SIGNAL_LEVEL:
355 g_value_set_boolean (value, filter->signal);
357 case ARG_SIGNAL_INTERVAL:
358 g_value_set_double (value, filter->interval);
361 g_value_set_double (value, filter->decay_peak_ttl);
363 case ARG_PEAK_FALLOFF:
364 g_value_set_double (value, filter->decay_peak_falloff);
367 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
373 gst_level_class_init (GstLevelClass *klass)
375 GObjectClass *gobject_class;
376 GstElementClass *gstelement_class;
378 gobject_class = (GObjectClass*) klass;
379 gstelement_class = (GstElementClass*) klass;
381 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
382 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_LEVEL,
383 g_param_spec_boolean ("signal", "Signal",
384 "Emit level signals for each interval",
385 TRUE, G_PARAM_READWRITE));
386 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_INTERVAL,
387 g_param_spec_double ("interval", "Interval",
388 "Interval between emissions (in seconds)",
389 0.01, 100.0, 0.1, G_PARAM_READWRITE));
390 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PEAK_TTL,
391 g_param_spec_double ("peak_ttl", "Peak TTL",
392 "Time To Live of decay peak before it falls back",
393 0, 100.0, 0.3, G_PARAM_READWRITE));
394 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PEAK_FALLOFF,
395 g_param_spec_double ("peak_falloff", "Peak Falloff",
396 "Decay rate of decay peak after TTL (in dB/sec)",
397 0.0, G_MAXDOUBLE, 10.0, G_PARAM_READWRITE));
399 gobject_class->set_property = gst_level_set_property;
400 gobject_class->get_property = gst_level_get_property;
402 gst_filter_signals[SIGNAL_LEVEL] =
403 g_signal_new ("level", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
404 G_STRUCT_OFFSET (GstLevelClass, level), NULL, NULL,
405 gstlevel_cclosure_marshal_VOID__DOUBLE_INT_DOUBLE_DOUBLE_DOUBLE,
407 G_TYPE_DOUBLE, G_TYPE_INT,
408 G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
412 gst_level_init (GstLevel *filter)
414 filter->sinkpad = gst_pad_new_from_template (GST_PAD_TEMPLATE_GET (sink_template_factory), "sink");
415 gst_pad_set_link_function (filter->sinkpad, gst_level_connect);
416 filter->srcpad = gst_pad_new_from_template (GST_PAD_TEMPLATE_GET (src_template_factory), "src");
417 gst_pad_set_link_function (filter->srcpad, gst_level_connect);
419 gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
420 gst_pad_set_chain_function (filter->sinkpad, gst_level_chain);
421 filter->srcpad = gst_pad_new ("src", GST_PAD_SRC);
422 gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
427 filter->RMS_dB = NULL;
431 filter->channels = 0;
433 filter->interval = 0.1;
434 filter->decay_peak_ttl = 0.4;
435 filter->decay_peak_falloff = 10.0; /* dB falloff (/sec) */
439 plugin_init (GModule *module, GstPlugin *plugin)
441 GstElementFactory *factory;
443 factory = gst_element_factory_new ("level", GST_TYPE_LEVEL,
445 g_return_val_if_fail (factory != NULL, FALSE);
447 gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (sink_template_factory));
448 gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (src_template_factory));
450 gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
455 GstPluginDesc plugin_desc = {