/GstBuffer/GstData/ in the API where you can pass events. Fix the plugins to deal...
[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 #include <gst/gst.h>
25 #include "gstlevel.h"
26 #include "math.h"
27
28 /* elementfactory information */
29 static GstElementDetails level_details = {
30   "Level",
31   "Filter/Audio/Analysis",
32   "LGPL",
33   "RMS/Peak/Decaying Peak Level signaller for audio/raw",
34   VERSION,
35   "Thomas <thomas@apestaart.org>",
36   "(C) 2001, 2003, 2003",
37 };
38
39 /* pad templates */
40
41 GST_PAD_TEMPLATE_FACTORY (sink_template_factory,
42   "level_sink",
43   GST_PAD_SINK,
44   GST_PAD_ALWAYS,
45   GST_CAPS_NEW (
46     "level_sink",
47     "audio/x-raw-int",
48       "signed", GST_PROPS_BOOLEAN (TRUE),
49       "width", GST_PROPS_LIST (
50                  GST_PROPS_INT (8),
51                  GST_PROPS_INT (16)
52                ),
53       "depth", GST_PROPS_LIST (
54                  GST_PROPS_INT (8),
55                  GST_PROPS_INT (16)
56                ),
57       "rate", GST_PROPS_INT_RANGE (1, G_MAXINT),
58       "channels", GST_PROPS_INT_RANGE (1, 2)
59   )
60 )
61
62 GST_PAD_TEMPLATE_FACTORY (src_template_factory,
63   "level_src",
64   GST_PAD_SRC,
65   GST_PAD_ALWAYS,
66   GST_CAPS_NEW (
67     "level_src",
68     "audio/x-raw-int",
69     "signed", GST_PROPS_BOOLEAN (TRUE),
70     "width", GST_PROPS_LIST (
71                GST_PROPS_INT (8),
72                GST_PROPS_INT (16)
73              ),
74     "depth", GST_PROPS_LIST (
75                GST_PROPS_INT (8),
76                GST_PROPS_INT (16)
77              ),
78     "rate", GST_PROPS_INT_RANGE (1, G_MAXINT),
79     "channels", GST_PROPS_INT_RANGE (1, 2)
80   )
81 )
82
83 /* Filter signals and args */
84 enum {
85   /* FILL ME */
86   SIGNAL_LEVEL,
87   LAST_SIGNAL
88 };
89
90 enum {
91   ARG_0,
92   ARG_SIGNAL_LEVEL,
93   ARG_SIGNAL_INTERVAL,
94   ARG_PEAK_TTL,
95   ARG_PEAK_FALLOFF
96 };
97
98 static void             gst_level_class_init            (GstLevelClass *klass);
99 static void             gst_level_init                  (GstLevel *filter);
100
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);
103
104 static void             gst_level_chain                 (GstPad *pad, GstData *_data);
105
106 static GstElementClass *parent_class = NULL;
107 static guint gst_filter_signals[LAST_SIGNAL] = { 0 };
108
109 GType
110 gst_level_get_type (void) 
111 {
112   static GType level_type = 0;
113
114   if (!level_type) 
115   {
116     static const GTypeInfo level_info = 
117     {
118       sizeof (GstLevelClass), NULL, NULL,
119       (GClassInitFunc) gst_level_class_init, NULL, NULL,
120       sizeof (GstLevel), 0,
121       (GInstanceInitFunc) gst_level_init
122     };
123     level_type = g_type_register_static (GST_TYPE_ELEMENT, "GstLevel", 
124                                          &level_info, 0);
125   }
126   return level_type;
127 }
128
129 static GstPadLinkReturn
130 gst_level_connect (GstPad *pad, GstCaps *caps)
131 {
132   GstLevel *filter;
133   GstPad *otherpad;
134   GstPadLinkReturn res;
135   int i;
136
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);
141           
142   if (GST_CAPS_IS_FIXED (caps)) 
143   {
144     /* yep, got them */
145     res = gst_pad_try_set_caps (otherpad, caps);
146     /* if ok, set filter */
147     if (res == GST_PAD_LINK_OK)
148     {
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");
157
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)
174       {
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;
178       }
179     }
180     return res;
181   }
182   return GST_PAD_LINK_DELAYED;
183 }
184
185 static void inline
186 gst_level_fast_16bit_chain (gint16* in, guint num, gint channels, 
187                             gint resolution, double *CS, double *peak)
188 #include "filter.func"
189
190 static void inline
191 gst_level_fast_8bit_chain (gint8* in, guint num, gint channels, 
192                            gint resolution, double *CS, double *peak)
193 #include "filter.func"
194
195 static void
196 gst_level_chain (GstPad *pad, GstData *_data)
197 {
198   GstBuffer *buf = GST_BUFFER (_data);
199   GstLevel *filter;
200   gint16 *in_data;
201
202   double CS = 0.0;
203   gint num_samples = 0;
204   gint i;
205
206   g_return_if_fail (pad != NULL);
207   g_return_if_fail (GST_IS_PAD (pad));
208   g_return_if_fail (buf != NULL);
209
210
211   filter = GST_LEVEL (GST_OBJECT_PARENT (pad));
212   g_return_if_fail (filter != NULL);
213   g_return_if_fail (GST_IS_LEVEL (filter));
214
215   for (i = 0; i < filter->channels; ++i)
216     filter->CS[i] = filter->peak[i] = filter->MS[i] = filter->RMS_dB[i] = 0.0;
217   
218   in_data = (gint16 *) GST_BUFFER_DATA (buf);
219   
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");
223
224   for (i = 0; i < filter->channels; ++i)
225   {
226     switch (filter->width)
227     {
228       case 16:
229           gst_level_fast_16bit_chain (in_data + i, num_samples,
230                                       filter->channels, filter->width - 1,
231                                       &CS, &filter->peak[i]);
232           break;
233       case 8:
234           gst_level_fast_8bit_chain (((gint8 *) in_data) + i, num_samples,
235                                      filter->channels, filter->width - 1,
236                                      &CS, &filter->peak[i]);
237           break;
238     }
239     /* g_print ("DEBUG: CS %f, peak %f\n", CS, filter->peak[i]); */
240     filter->CS[i] += CS;
241
242   }
243   gst_pad_push (filter->srcpad, GST_DATA (buf));
244
245   filter->num_samples += num_samples;
246
247   for (i = 0; i < filter->channels; ++i)
248   {
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];
255
256     /* update decay peak */
257     if (filter->peak[i] >= filter->decay_peak[i])
258     {
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;
262     }
263     else
264     {
265       /* make decay peak fall off if too old */
266       if (filter->decay_peak_age[i] > filter->rate * filter->decay_peak_ttl)
267       {
268         double falloff_dB;
269         double falloff;
270         double length;          /* length of buffer in seconds */
271
272  
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);
276
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]); */
282       }
283     }
284   }
285
286   /* do we need to emit ? */
287   
288   if (filter->num_samples >= filter->interval * (gdouble) filter->rate)
289   {
290     if (filter->signal)
291     {
292       gdouble RMS, peak, endtime;
293       for (i = 0; i < filter->channels; ++i)
294       {
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;
300
301         g_signal_emit (G_OBJECT (filter), gst_filter_signals[SIGNAL_LEVEL], 0,
302                        endtime, i,
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 */
306         filter->CS[i] = 0.0;
307         filter->last_peak[i] = 0.0;
308       }
309     }
310     filter->num_samples = 0;
311   }
312 }
313
314
315 static void
316 gst_level_set_property (GObject *object, guint prop_id, 
317                         const GValue *value, GParamSpec *pspec)
318 {
319   GstLevel *filter;
320
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);
324
325   switch (prop_id) {
326     case ARG_SIGNAL_LEVEL:
327       filter->signal = g_value_get_boolean (value);
328       break;
329     case ARG_SIGNAL_INTERVAL:
330       filter->interval = g_value_get_double (value);
331       break;
332     case ARG_PEAK_TTL:
333       filter->decay_peak_ttl = g_value_get_double (value);
334       break;
335     case ARG_PEAK_FALLOFF:
336       filter->decay_peak_falloff = g_value_get_double (value);
337       break;
338     default:
339       break;
340   }
341 }
342
343 static void
344 gst_level_get_property (GObject *object, guint prop_id, 
345                         GValue *value, GParamSpec *pspec)
346 {
347   GstLevel *filter;
348
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);
352
353   switch (prop_id) {
354     case ARG_SIGNAL_LEVEL:
355       g_value_set_boolean (value, filter->signal);
356       break;
357       case ARG_SIGNAL_INTERVAL:
358       g_value_set_double (value, filter->interval);
359       break;
360     case ARG_PEAK_TTL:
361       g_value_set_double (value, filter->decay_peak_ttl);
362       break;
363     case ARG_PEAK_FALLOFF:
364       g_value_set_double (value, filter->decay_peak_falloff);
365       break;
366    default:
367       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
368       break;
369   }
370 }
371
372 static void
373 gst_level_class_init (GstLevelClass *klass)
374 {
375   GObjectClass *gobject_class;
376   GstElementClass *gstelement_class;
377
378   gobject_class = (GObjectClass*) klass;
379   gstelement_class = (GstElementClass*) klass;
380
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));
398
399   gobject_class->set_property = gst_level_set_property;
400   gobject_class->get_property = gst_level_get_property;
401
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,
406                   G_TYPE_NONE, 5,
407                   G_TYPE_DOUBLE, G_TYPE_INT,
408                   G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
409 }
410
411 static void
412 gst_level_init (GstLevel *filter)
413 {
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);
418
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);
423
424   filter->CS = NULL;
425   filter->peak = NULL;
426   filter->MS = NULL;
427   filter->RMS_dB = NULL;
428
429   filter->rate = 0;
430   filter->width = 0;
431   filter->channels = 0;
432
433   filter->interval = 0.1;
434   filter->decay_peak_ttl = 0.4;
435   filter->decay_peak_falloff = 10.0;    /* dB falloff (/sec) */
436 }
437
438 static gboolean
439 plugin_init (GModule *module, GstPlugin *plugin)
440 {
441   GstElementFactory *factory;
442
443   factory = gst_element_factory_new ("level", GST_TYPE_LEVEL,
444                                      &level_details);
445   g_return_val_if_fail (factory != NULL, FALSE);
446   
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));
449
450   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
451
452   return TRUE;
453 }
454
455 GstPluginDesc plugin_desc = {
456   GST_VERSION_MAJOR,
457   GST_VERSION_MINOR,
458   "level",
459   plugin_init
460 };