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