gst-indent
[platform/upstream/gst-plugins-good.git] / gst / level / gstlevel.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
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>
7  *
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.
12  *
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.
17  *
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.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 #include <gst/gst.h>
28 #include <gst/audio/audio.h>
29 #include "gstlevel.h"
30 #include "math.h"
31
32 /* elementfactory information */
33 static GstElementDetails level_details = {
34   "Level",
35   "Filter/Analyzer/Audio",
36   "RMS/Peak/Decaying Peak Level signaller for audio/raw",
37   "Thomas <thomas@apestaart.org>"
38 };
39
40 /* pad templates */
41
42 static GstStaticPadTemplate sink_template_factory =
43 GST_STATIC_PAD_TEMPLATE ("level_sink",
44     GST_PAD_SINK,
45     GST_PAD_ALWAYS,
46     GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS)
47     );
48
49 static GstStaticPadTemplate src_template_factory =
50 GST_STATIC_PAD_TEMPLATE ("level_src",
51     GST_PAD_SRC,
52     GST_PAD_ALWAYS,
53     GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS)
54     );
55
56 /* Filter signals and args */
57 enum
58 {
59   /* FILL ME */
60   SIGNAL_LEVEL,
61   LAST_SIGNAL
62 };
63
64 enum
65 {
66   ARG_0,
67   ARG_SIGNAL_LEVEL,
68   ARG_SIGNAL_INTERVAL,
69   ARG_PEAK_TTL,
70   ARG_PEAK_FALLOFF
71 };
72
73 static void gst_level_class_init (GstLevelClass * klass);
74 static void gst_level_base_init (GstLevelClass * klass);
75 static void gst_level_init (GstLevel * filter);
76
77 static GstElementStateReturn gst_level_change_state (GstElement * element);
78 static void gst_level_set_property (GObject * object, guint prop_id,
79     const GValue * value, GParamSpec * pspec);
80 static void gst_level_get_property (GObject * object, guint prop_id,
81     GValue * value, GParamSpec * pspec);
82
83 static void gst_level_chain (GstPad * pad, GstData * _data);
84
85 static GstElementClass *parent_class = NULL;
86 static guint gst_filter_signals[LAST_SIGNAL] = { 0 };
87
88 GType
89 gst_level_get_type (void)
90 {
91   static GType level_type = 0;
92
93   if (!level_type) {
94     static const GTypeInfo level_info = {
95       sizeof (GstLevelClass),
96       (GBaseInitFunc) gst_level_base_init, NULL,
97       (GClassInitFunc) gst_level_class_init, NULL, NULL,
98       sizeof (GstLevel), 0,
99       (GInstanceInitFunc) gst_level_init
100     };
101     level_type = g_type_register_static (GST_TYPE_ELEMENT, "GstLevel",
102         &level_info, 0);
103   }
104   return level_type;
105 }
106
107 static GstPadLinkReturn
108 gst_level_link (GstPad * pad, const GstCaps * caps)
109 {
110   GstLevel *filter;
111   GstPad *otherpad;
112   GstPadLinkReturn res;
113   GstStructure *structure;
114   int i;
115   gboolean ret;
116
117   filter = GST_LEVEL (gst_pad_get_parent (pad));
118   g_return_val_if_fail (filter != NULL, GST_PAD_LINK_REFUSED);
119   g_return_val_if_fail (GST_IS_LEVEL (filter), GST_PAD_LINK_REFUSED);
120   otherpad = (pad == filter->srcpad ? filter->sinkpad : filter->srcpad);
121
122   res = gst_pad_try_set_caps (otherpad, caps);
123   /* if ok, set filter */
124   if (res != GST_PAD_LINK_OK && res != GST_PAD_LINK_DONE) {
125     return res;
126   }
127
128   filter->num_samples = 0;
129
130   structure = gst_caps_get_structure (caps, 0);
131   ret = gst_structure_get_int (structure, "rate", &filter->rate);
132   ret &= gst_structure_get_int (structure, "width", &filter->width);
133   ret &= gst_structure_get_int (structure, "channels", &filter->channels);
134
135   if (!ret)
136     return GST_PAD_LINK_REFUSED;
137
138   /* allocate channel variable arrays */
139   if (filter->CS)
140     g_free (filter->CS);
141   if (filter->peak)
142     g_free (filter->peak);
143   if (filter->last_peak)
144     g_free (filter->last_peak);
145   if (filter->decay_peak)
146     g_free (filter->decay_peak);
147   if (filter->decay_peak_age)
148     g_free (filter->decay_peak_age);
149   if (filter->MS)
150     g_free (filter->MS);
151   if (filter->RMS_dB)
152     g_free (filter->RMS_dB);
153   filter->CS = g_new (double, filter->channels);
154   filter->peak = g_new (double, filter->channels);
155   filter->last_peak = g_new (double, filter->channels);
156   filter->decay_peak = g_new (double, filter->channels);
157   filter->decay_peak_age = g_new (double, filter->channels);
158   filter->MS = g_new (double, filter->channels);
159   filter->RMS_dB = g_new (double, filter->channels);
160
161   for (i = 0; i < filter->channels; ++i) {
162     filter->CS[i] = filter->peak[i] = filter->last_peak[i] =
163         filter->decay_peak[i] = filter->decay_peak_age[i] =
164         filter->MS[i] = filter->RMS_dB[i] = 0.0;
165   }
166
167   filter->inited = TRUE;
168
169   return GST_PAD_LINK_OK;
170 }
171
172 static void inline
173 gst_level_fast_16bit_chain (gint16 * in, guint num, gint channels,
174     gint resolution, double *CS, double *peak)
175 #include "filter.func"
176      static void inline
177          gst_level_fast_8bit_chain (gint8 * in, guint num, gint channels,
178     gint resolution, double *CS, double *peak)
179 #include "filter.func"
180      static void gst_level_chain (GstPad * pad, GstData * _data)
181 {
182   GstBuffer *buf = GST_BUFFER (_data);
183   GstLevel *filter;
184   gint16 *in_data;
185
186   double CS = 0.0;
187   gint num_samples = 0;
188   gint i;
189
190   g_return_if_fail (pad != NULL);
191   g_return_if_fail (GST_IS_PAD (pad));
192   g_return_if_fail (buf != NULL);
193
194   filter = GST_LEVEL (GST_OBJECT_PARENT (pad));
195   g_return_if_fail (filter != NULL);
196   g_return_if_fail (GST_IS_LEVEL (filter));
197
198   for (i = 0; i < filter->channels; ++i)
199     filter->CS[i] = filter->peak[i] = filter->MS[i] = filter->RMS_dB[i] = 0.0;
200
201   in_data = (gint16 *) GST_BUFFER_DATA (buf);
202
203   num_samples = GST_BUFFER_SIZE (buf) / (filter->width / 8);
204   if (num_samples % filter->channels != 0)
205     g_warning
206         ("WARNING: level: programming error, data not properly interleaved");
207
208   for (i = 0; i < filter->channels; ++i) {
209     switch (filter->width) {
210       case 16:
211         gst_level_fast_16bit_chain (in_data + i, num_samples,
212             filter->channels, filter->width - 1, &CS, &filter->peak[i]);
213         break;
214       case 8:
215         gst_level_fast_8bit_chain (((gint8 *) in_data) + i, num_samples,
216             filter->channels, filter->width - 1, &CS, &filter->peak[i]);
217         break;
218     }
219     /* g_print ("DEBUG: CS %f, peak %f\n", CS, filter->peak[i]); */
220     filter->CS[i] += CS;
221
222   }
223   gst_pad_push (filter->srcpad, GST_DATA (buf));
224
225   filter->num_samples += num_samples;
226
227   for (i = 0; i < filter->channels; ++i) {
228     filter->decay_peak_age[i] += num_samples;
229     /* g_print ("filter peak info [%d]: peak %f, age %f\n", i, 
230        filter->last_peak[i], filter->decay_peak_age[i]); */
231     /* update running peak */
232     if (filter->peak[i] > filter->last_peak[i])
233       filter->last_peak[i] = filter->peak[i];
234
235     /* update decay peak */
236     if (filter->peak[i] >= filter->decay_peak[i]) {
237       /* g_print ("new peak, %f\n", filter->peak[i]); */
238       filter->decay_peak[i] = filter->peak[i];
239       filter->decay_peak_age[i] = 0;
240     } else {
241       /* make decay peak fall off if too old */
242       if (filter->decay_peak_age[i] > filter->rate * filter->decay_peak_ttl) {
243         double falloff_dB;
244         double falloff;
245         double length;          /* length of buffer in seconds */
246
247
248         length = (double) num_samples / (filter->channels * filter->rate);
249         falloff_dB = filter->decay_peak_falloff * length;
250         falloff = pow (10, falloff_dB / -20.0);
251
252         /* g_print ("falloff: length %f, dB falloff %f, falloff factor %e\n",
253            length, falloff_dB, falloff); */
254         filter->decay_peak[i] *= falloff;
255         /* g_print ("peak is %f samples old, decayed with factor %e to %f\n",
256            filter->decay_peak_age[i], falloff, filter->decay_peak[i]); */
257       }
258     }
259   }
260
261   /* do we need to emit ? */
262
263   if (filter->num_samples >= filter->interval * (gdouble) filter->rate) {
264     if (filter->signal) {
265       gdouble RMS, peak, endtime;
266
267       for (i = 0; i < filter->channels; ++i) {
268         RMS = sqrt (filter->CS[i] / (filter->num_samples / filter->channels));
269         peak = filter->last_peak[i];
270         num_samples = GST_BUFFER_SIZE (buf) / (filter->width / 8);
271         endtime = (double) GST_BUFFER_TIMESTAMP (buf) / GST_SECOND
272             + (double) num_samples / (double) filter->rate;
273
274         g_signal_emit (G_OBJECT (filter), gst_filter_signals[SIGNAL_LEVEL], 0,
275             endtime, i,
276             20 * log10 (RMS), 20 * log10 (filter->last_peak[i]),
277             20 * log10 (filter->decay_peak[i]));
278         /* we emitted, so reset cumulative and normal peak */
279         filter->CS[i] = 0.0;
280         filter->last_peak[i] = 0.0;
281       }
282     }
283     filter->num_samples = 0;
284   }
285 }
286
287 static GstElementStateReturn
288 gst_level_change_state (GstElement * element)
289 {
290   GstLevel *filter = GST_LEVEL (element);
291
292   switch (GST_STATE_TRANSITION (element)) {
293     case GST_STATE_PAUSED_TO_PLAYING:
294       if (!filter->inited)
295         return GST_STATE_FAILURE;
296       break;
297     default:
298       break;
299   }
300
301   return GST_ELEMENT_CLASS (parent_class)->change_state (element);
302 }
303
304 static void
305 gst_level_set_property (GObject * object, guint prop_id,
306     const GValue * value, GParamSpec * pspec)
307 {
308   GstLevel *filter;
309
310   /* it's not null if we got it, but it might not be ours */
311   g_return_if_fail (GST_IS_LEVEL (object));
312   filter = GST_LEVEL (object);
313
314   switch (prop_id) {
315     case ARG_SIGNAL_LEVEL:
316       filter->signal = g_value_get_boolean (value);
317       break;
318     case ARG_SIGNAL_INTERVAL:
319       filter->interval = g_value_get_double (value);
320       break;
321     case ARG_PEAK_TTL:
322       filter->decay_peak_ttl = g_value_get_double (value);
323       break;
324     case ARG_PEAK_FALLOFF:
325       filter->decay_peak_falloff = g_value_get_double (value);
326       break;
327     default:
328       break;
329   }
330 }
331
332 static void
333 gst_level_get_property (GObject * object, guint prop_id,
334     GValue * value, GParamSpec * pspec)
335 {
336   GstLevel *filter;
337
338   /* it's not null if we got it, but it might not be ours */
339   g_return_if_fail (GST_IS_LEVEL (object));
340   filter = GST_LEVEL (object);
341
342   switch (prop_id) {
343     case ARG_SIGNAL_LEVEL:
344       g_value_set_boolean (value, filter->signal);
345       break;
346     case ARG_SIGNAL_INTERVAL:
347       g_value_set_double (value, filter->interval);
348       break;
349     case ARG_PEAK_TTL:
350       g_value_set_double (value, filter->decay_peak_ttl);
351       break;
352     case ARG_PEAK_FALLOFF:
353       g_value_set_double (value, filter->decay_peak_falloff);
354       break;
355     default:
356       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
357       break;
358   }
359 }
360
361 static void
362 gst_level_base_init (GstLevelClass * klass)
363 {
364   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
365
366   gst_element_class_add_pad_template (element_class,
367       gst_static_pad_template_get (&sink_template_factory));
368   gst_element_class_add_pad_template (element_class,
369       gst_static_pad_template_get (&src_template_factory));
370   gst_element_class_set_details (element_class, &level_details);
371
372   element_class->change_state = gst_level_change_state;
373 }
374
375 static void
376 gst_level_class_init (GstLevelClass * klass)
377 {
378   GObjectClass *gobject_class;
379   GstElementClass *gstelement_class;
380
381   gobject_class = (GObjectClass *) klass;
382   gstelement_class = (GstElementClass *) klass;
383
384   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
385   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_LEVEL,
386       g_param_spec_boolean ("signal", "Signal",
387           "Emit level signals for each interval", TRUE, G_PARAM_READWRITE));
388   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_INTERVAL,
389       g_param_spec_double ("interval", "Interval",
390           "Interval between emissions (in seconds)",
391           0.01, 100.0, 0.1, G_PARAM_READWRITE));
392   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PEAK_TTL,
393       g_param_spec_double ("peak_ttl", "Peak TTL",
394           "Time To Live of decay peak before it falls back",
395           0, 100.0, 0.3, G_PARAM_READWRITE));
396   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PEAK_FALLOFF,
397       g_param_spec_double ("peak_falloff", "Peak Falloff",
398           "Decay rate of decay peak after TTL (in dB/sec)",
399           0.0, G_MAXDOUBLE, 10.0, G_PARAM_READWRITE));
400
401   gobject_class->set_property = gst_level_set_property;
402   gobject_class->get_property = gst_level_get_property;
403
404   gst_filter_signals[SIGNAL_LEVEL] =
405       g_signal_new ("level", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
406       G_STRUCT_OFFSET (GstLevelClass, level), NULL, NULL,
407       gstlevel_cclosure_marshal_VOID__DOUBLE_INT_DOUBLE_DOUBLE_DOUBLE,
408       G_TYPE_NONE, 5,
409       G_TYPE_DOUBLE, G_TYPE_INT, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
410 }
411
412 static void
413 gst_level_init (GstLevel * filter)
414 {
415   filter->sinkpad =
416       gst_pad_new_from_template (gst_static_pad_template_get
417       (&sink_template_factory), "sink");
418   gst_pad_set_link_function (filter->sinkpad, gst_level_link);
419   filter->srcpad =
420       gst_pad_new_from_template (gst_static_pad_template_get
421       (&src_template_factory), "src");
422   gst_pad_set_link_function (filter->srcpad, gst_level_link);
423
424   gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
425   gst_pad_set_chain_function (filter->sinkpad, gst_level_chain);
426   filter->srcpad = gst_pad_new ("src", GST_PAD_SRC);
427   gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
428
429   filter->CS = NULL;
430   filter->peak = NULL;
431   filter->MS = NULL;
432   filter->RMS_dB = NULL;
433
434   filter->rate = 0;
435   filter->width = 0;
436   filter->channels = 0;
437
438   filter->interval = 0.1;
439   filter->decay_peak_ttl = 0.4;
440   filter->decay_peak_falloff = 10.0;    /* dB falloff (/sec) */
441 }
442
443 static gboolean
444 plugin_init (GstPlugin * plugin)
445 {
446   return gst_element_register (plugin, "level", GST_RANK_NONE, GST_TYPE_LEVEL);
447 }
448
449 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
450     GST_VERSION_MINOR,
451     "level",
452     "Audio level plugin",
453     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)