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",
40 /* Filter signals and args */
55 static GstPadTemplate*
56 level_src_factory (void)
58 static GstPadTemplate *template = NULL;
61 template = gst_pad_template_new (
69 "channels", GST_PROPS_INT_RANGE (1, 2),
70 "signed", GST_PROPS_BOOLEAN (TRUE),
77 static GstPadTemplate*
78 level_sink_factory (void)
80 static GstPadTemplate *template = NULL;
83 template = gst_pad_template_new (
91 "channels", GST_PROPS_INT_RANGE (1, 2),
92 "signed", GST_PROPS_BOOLEAN (TRUE),
99 static void gst_level_class_init (GstLevelClass *klass);
100 static void gst_level_init (GstLevel *filter);
102 static void gst_level_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
103 static void gst_level_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
105 static void gst_level_chain (GstPad *pad, GstBuffer *buf);
107 static GstElementClass *parent_class = NULL;
108 static guint gst_filter_signals[LAST_SIGNAL] = { 0 };
111 gst_level_get_type (void)
113 static GType level_type = 0;
117 static const GTypeInfo level_info =
119 sizeof (GstLevelClass), NULL, NULL,
120 (GClassInitFunc) gst_level_class_init, NULL, NULL,
121 sizeof (GstLevel), 0,
122 (GInstanceInitFunc) gst_level_init
124 level_type = g_type_register_static (GST_TYPE_ELEMENT, "GstLevel",
130 static GstPadLinkReturn
131 gst_level_connect (GstPad *pad, GstCaps *caps)
135 GstPadLinkReturn res;
138 filter = GST_LEVEL (gst_pad_get_parent (pad));
139 g_return_val_if_fail (filter != NULL, GST_PAD_LINK_REFUSED);
140 g_return_val_if_fail (GST_IS_LEVEL (filter), GST_PAD_LINK_REFUSED);
141 otherpad = (pad == filter->srcpad ? filter->sinkpad : filter->srcpad);
143 if (GST_CAPS_IS_FIXED (caps))
146 res = gst_pad_try_set_caps (otherpad, caps);
147 /* if ok, set filter */
148 if (res == GST_PAD_LINK_OK)
150 filter->num_samples = 0;
151 /* FIXME: error handling */
152 if (! gst_caps_get_int (caps, "rate", &(filter->rate)))
153 g_warning ("WARNING: level: Could not get rate from caps\n");
154 if (!gst_caps_get_int (caps, "width", &(filter->width)))
155 g_warning ("WARNING: level: Could not get width from caps\n");
156 if (!gst_caps_get_int (caps, "channels", &(filter->channels)))
157 g_warning ("WARNING: level: Could not get number of channels from caps\n");
159 /* allocate channel variable arrays */
160 if (filter->CS) g_free (filter->CS);
161 if (filter->peak) g_free (filter->peak);
162 if (filter->last_peak) g_free (filter->last_peak);
163 if (filter->decay_peak) g_free (filter->decay_peak);
164 if (filter->decay_peak_age) g_free (filter->decay_peak_age);
165 if (filter->MS) g_free (filter->MS);
166 if (filter->RMS_dB) g_free (filter->RMS_dB);
167 filter->CS = g_new (double, filter->channels);
168 filter->peak = g_new (double, filter->channels);
169 filter->last_peak = g_new (double, filter->channels);
170 filter->decay_peak = g_new (double, filter->channels);
171 filter->decay_peak_age = g_new (double, filter->channels);
172 filter->MS = g_new (double, filter->channels);
173 filter->RMS_dB = g_new (double, filter->channels);
174 for (i = 0; i < filter->channels; ++i)
176 filter->CS[i] = filter->peak[i] = filter->last_peak[i] =
177 filter->decay_peak[i] = filter->decay_peak_age[i] =
178 filter->MS[i] = filter->RMS_dB[i] = 0.0;
183 return GST_PAD_LINK_DELAYED;
187 gst_level_fast_16bit_chain (gint16* in, guint num, gint channels,
188 gint resolution, double *CS, double *peak)
189 #include "filter.func"
192 gst_level_fast_8bit_chain (gint8* in, guint num, gint channels,
193 gint resolution, double *CS, double *peak)
194 #include "filter.func"
197 gst_level_chain (GstPad *pad, GstBuffer *buf)
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 g_print ("\nDEBUG: chain start\n");
212 filter = GST_LEVEL (GST_OBJECT_PARENT (pad));
213 g_return_if_fail (filter != NULL);
214 g_return_if_fail (GST_IS_LEVEL (filter));
216 for (i = 0; i < filter->channels; ++i)
217 filter->CS[i] = filter->peak[i] = filter->MS[i] = filter->RMS_dB[i] = 0.0;
219 in_data = (gint16 *) GST_BUFFER_DATA(buf);
221 num_samples = GST_BUFFER_SIZE (buf) / (filter->width / 8);
222 if (num_samples % filter->channels != 0)
223 g_warning ("WARNING: level: programming error, data not properly interleaved");
225 for (i = 0; i < filter->channels; ++i)
227 switch (filter->width)
230 gst_level_fast_16bit_chain (in_data + i, num_samples,
231 filter->channels, filter->width - 1,
232 &CS, &filter->peak[i]);
235 gst_level_fast_8bit_chain (((gint8 *) in_data) + i, num_samples,
236 filter->channels, filter->width - 1,
237 &CS, &filter->peak[i]);
240 g_print ("DEBUG: CS %f, peak %f\n", CS, filter->peak[i]);
244 gst_pad_push (filter->srcpad, buf);
246 filter->num_samples += num_samples;
248 for (i = 0; i < filter->channels; ++i)
250 filter->decay_peak_age[i] += num_samples;
251 g_print ("filter peak info [%d]: peak %f, age %f\n", i,
252 filter->last_peak[i], filter->decay_peak_age[i]);
253 /* update running peak */
254 if (filter->peak[i] > filter->last_peak[i])
255 filter->last_peak[i] = filter->peak[i];
257 /* update decay peak */
258 if (filter->peak[i] >= filter->decay_peak[i])
260 g_print ("new peak, %f\n", filter->peak[i]);
261 filter->decay_peak[i] = filter->peak[i];
262 filter->decay_peak_age[i] = 0;
266 /* make decay peak fall off if too old */
267 if (filter->decay_peak_age[i] > filter->rate * filter->decay_peak_ttl)
271 double length; /* length of buffer in seconds */
274 length = (double) num_samples / (filter->channels * filter->rate);
275 falloff_dB = filter->decay_peak_falloff * length;
276 falloff = pow (10, falloff_dB / -20.0);
278 g_print ("falloff: length %f, dB falloff %f, falloff factor %e\n",
279 length, falloff_dB, falloff);
280 filter->decay_peak[i] *= falloff;
281 g_print ("peak is %f samples old, decayed with factor %e to %f\n",
282 filter->decay_peak_age[i], falloff, filter->decay_peak[i]);
287 /* do we need to emit ? */
289 if (filter->num_samples >= filter->interval * (gdouble) filter->rate)
294 for (i = 0; i < filter->channels; ++i)
296 RMS = sqrt (filter->CS[i] / (filter->num_samples / filter->channels));
297 peak = filter->last_peak[i];
299 g_signal_emit (G_OBJECT (filter), gst_filter_signals[SIGNAL_LEVEL], 0,
300 i, 20 * log10 (RMS), 20 * log10 (filter->last_peak[i]),
301 20 * log10 (filter->decay_peak[i]));
302 /* we emitted, so reset cumulative and normal peak */
304 filter->last_peak[i] = 0.0;
307 filter->num_samples = 0;
313 gst_level_set_property (GObject *object, guint prop_id,
314 const GValue *value, GParamSpec *pspec)
318 /* it's not null if we got it, but it might not be ours */
319 g_return_if_fail (GST_IS_LEVEL (object));
320 filter = GST_LEVEL (object);
323 case ARG_SIGNAL_LEVEL:
324 filter->signal = g_value_get_boolean (value);
326 case ARG_SIGNAL_INTERVAL:
327 filter->interval = g_value_get_double (value);
330 filter->decay_peak_ttl = g_value_get_double (value);
332 case ARG_PEAK_FALLOFF:
333 filter->decay_peak_falloff = g_value_get_double (value);
341 gst_level_get_property (GObject *object, guint prop_id,
342 GValue *value, GParamSpec *pspec)
346 /* it's not null if we got it, but it might not be ours */
347 g_return_if_fail (GST_IS_LEVEL (object));
348 filter = GST_LEVEL (object);
351 case ARG_SIGNAL_LEVEL:
352 g_value_set_boolean (value, filter->signal);
354 case ARG_SIGNAL_INTERVAL:
355 g_value_set_double (value, filter->interval);
358 g_value_set_double (value, filter->decay_peak_ttl);
360 case ARG_PEAK_FALLOFF:
361 g_value_set_double (value, filter->decay_peak_falloff);
364 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
370 gst_level_class_init (GstLevelClass *klass)
372 GObjectClass *gobject_class;
373 GstElementClass *gstelement_class;
375 gobject_class = (GObjectClass*) klass;
376 gstelement_class = (GstElementClass*) klass;
378 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
379 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_LEVEL,
380 g_param_spec_boolean ("signal", "Signal",
381 "Emit level signals for each interval",
382 TRUE, G_PARAM_READWRITE));
383 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_INTERVAL,
384 g_param_spec_double ("interval", "Interval",
385 "Interval between emissions (in seconds)",
386 0.01, 100.0, 0.1, G_PARAM_READWRITE));
387 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PEAK_TTL,
388 g_param_spec_double ("peak_ttl", "Peak TTL",
389 "Time To Live of decay peak before it falls back",
390 0, 100.0, 0.3, G_PARAM_READWRITE));
391 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PEAK_FALLOFF,
392 g_param_spec_double ("peak_falloff", "Peak Falloff",
393 "Decay rate of decay peak after TTL (in dB/sec)",
394 0.0, G_MAXDOUBLE, 10.0, G_PARAM_READWRITE));
396 gobject_class->set_property = gst_level_set_property;
397 gobject_class->get_property = gst_level_get_property;
399 gst_filter_signals[SIGNAL_LEVEL] =
400 g_signal_new ("level", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
401 G_STRUCT_OFFSET (GstLevelClass, level), NULL, NULL,
402 gstlevel_cclosure_marshal_VOID__INT_DOUBLE_DOUBLE_DOUBLE,
404 G_TYPE_INT, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
408 gst_level_init (GstLevel *filter)
410 filter->sinkpad = gst_pad_new_from_template (level_sink_factory (), "sink");
411 gst_pad_set_link_function (filter->sinkpad, gst_level_connect);
412 filter->srcpad = gst_pad_new_from_template (level_src_factory (), "src");
413 gst_pad_set_link_function (filter->srcpad, gst_level_connect);
415 gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
416 gst_pad_set_chain_function (filter->sinkpad, gst_level_chain);
417 filter->srcpad = gst_pad_new ("src", GST_PAD_SRC);
418 gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
423 filter->RMS_dB = NULL;
427 filter->channels = 0;
429 filter->interval = 0.1;
430 filter->decay_peak_ttl = 0.4;
431 filter->decay_peak_falloff = 10.0; /* dB falloff (/sec) */
435 plugin_init (GModule *module, GstPlugin *plugin)
437 GstElementFactory *factory;
439 factory = gst_element_factory_new ("level", GST_TYPE_LEVEL,
441 g_return_val_if_fail (factory != NULL, FALSE);
443 gst_element_factory_add_pad_template (factory, level_src_factory ());
444 gst_element_factory_add_pad_template (factory, level_sink_factory ());
446 gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
451 GstPluginDesc plugin_desc = {