e81828aa6fb9a9a92dd91a4a0f3c582c720067b7
[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 (
44   "level_sink",
45   GST_PAD_SINK,
46   GST_PAD_ALWAYS,
47   GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS)
48 );
49
50 static GstStaticPadTemplate src_template_factory =
51 GST_STATIC_PAD_TEMPLATE (
52   "level_src",
53   GST_PAD_SRC,
54   GST_PAD_ALWAYS,
55   GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS)
56 );
57
58 /* Filter signals and args */
59 enum {
60   /* FILL ME */
61   SIGNAL_LEVEL,
62   LAST_SIGNAL
63 };
64
65 enum {
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, const GValue *value, GParamSpec *pspec);
79 static void             gst_level_get_property                  (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
80
81 static void             gst_level_chain                 (GstPad *pad, GstData *_data);
82
83 static GstElementClass *parent_class = NULL;
84 static guint gst_filter_signals[LAST_SIGNAL] = { 0 };
85
86 GType
87 gst_level_get_type (void) 
88 {
89   static GType level_type = 0;
90
91   if (!level_type) 
92   {
93     static const GTypeInfo level_info = 
94     {
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) return GST_PAD_LINK_REFUSED;
136
137   /* allocate channel variable arrays */
138   if (filter->CS) g_free (filter->CS);
139   if (filter->peak) g_free (filter->peak);
140   if (filter->last_peak) g_free (filter->last_peak);
141   if (filter->decay_peak) g_free (filter->decay_peak);
142   if (filter->decay_peak_age) g_free (filter->decay_peak_age);
143   if (filter->MS) g_free (filter->MS);
144   if (filter->RMS_dB) g_free (filter->RMS_dB);
145   filter->CS = g_new (double, filter->channels);
146   filter->peak = g_new (double, filter->channels);
147   filter->last_peak = g_new (double, filter->channels);
148   filter->decay_peak = g_new (double, filter->channels);
149   filter->decay_peak_age = g_new (double, filter->channels);
150   filter->MS = g_new (double, filter->channels);
151   filter->RMS_dB = g_new (double, filter->channels);
152   for (i = 0; i < filter->channels; ++i) {
153     filter->CS[i] = filter->peak[i] = filter->last_peak[i] =
154                     filter->decay_peak[i] = filter->decay_peak_age[i] = 
155                     filter->MS[i] = filter->RMS_dB[i] = 0.0;
156   }
157
158   filter->inited = TRUE;
159
160   return GST_PAD_LINK_OK;
161 }
162
163 static void inline
164 gst_level_fast_16bit_chain (gint16* in, guint num, gint channels, 
165                             gint resolution, double *CS, double *peak)
166 #include "filter.func"
167
168 static void inline
169 gst_level_fast_8bit_chain (gint8* in, guint num, gint channels, 
170                            gint resolution, double *CS, double *peak)
171 #include "filter.func"
172
173 static void
174 gst_level_chain (GstPad *pad, GstData *_data)
175 {
176   GstBuffer *buf = GST_BUFFER (_data);
177   GstLevel *filter;
178   gint16 *in_data;
179
180   double CS = 0.0;
181   gint num_samples = 0;
182   gint i;
183
184   g_return_if_fail (pad != NULL);
185   g_return_if_fail (GST_IS_PAD (pad));
186   g_return_if_fail (buf != NULL);
187
188   filter = GST_LEVEL (GST_OBJECT_PARENT (pad));
189   g_return_if_fail (filter != NULL);
190   g_return_if_fail (GST_IS_LEVEL (filter));
191
192   for (i = 0; i < filter->channels; ++i)
193     filter->CS[i] = filter->peak[i] = filter->MS[i] = filter->RMS_dB[i] = 0.0;
194   
195   in_data = (gint16 *) GST_BUFFER_DATA (buf);
196   
197   num_samples = GST_BUFFER_SIZE (buf) / (filter->width / 8);
198   if (num_samples % filter->channels != 0)
199     g_warning ("WARNING: level: programming error, data not properly interleaved");
200
201   for (i = 0; i < filter->channels; ++i)
202   {
203     switch (filter->width)
204     {
205       case 16:
206           gst_level_fast_16bit_chain (in_data + i, num_samples,
207                                       filter->channels, filter->width - 1,
208                                       &CS, &filter->peak[i]);
209           break;
210       case 8:
211           gst_level_fast_8bit_chain (((gint8 *) in_data) + i, num_samples,
212                                      filter->channels, filter->width - 1,
213                                      &CS, &filter->peak[i]);
214           break;
215     }
216     /* g_print ("DEBUG: CS %f, peak %f\n", CS, filter->peak[i]); */
217     filter->CS[i] += CS;
218
219   }
220   gst_pad_push (filter->srcpad, GST_DATA (buf));
221
222   filter->num_samples += num_samples;
223
224   for (i = 0; i < filter->channels; ++i)
225   {
226     filter->decay_peak_age[i] += num_samples;
227     /* g_print ("filter peak info [%d]: peak %f, age %f\n", i, 
228              filter->last_peak[i], filter->decay_peak_age[i]); */
229     /* update running peak */
230     if (filter->peak[i] > filter->last_peak[i])
231         filter->last_peak[i] = filter->peak[i];
232
233     /* update decay peak */
234     if (filter->peak[i] >= filter->decay_peak[i])
235     {
236        /* g_print ("new peak, %f\n", filter->peak[i]); */
237        filter->decay_peak[i] = filter->peak[i];
238        filter->decay_peak_age[i] = 0;
239     }
240     else
241     {
242       /* make decay peak fall off if too old */
243       if (filter->decay_peak_age[i] > filter->rate * filter->decay_peak_ttl)
244       {
245         double falloff_dB;
246         double falloff;
247         double length;          /* length of buffer in seconds */
248
249  
250         length = (double) num_samples / (filter->channels * filter->rate);
251         falloff_dB = filter->decay_peak_falloff * length;
252         falloff = pow (10, falloff_dB / -20.0);
253
254         /* g_print ("falloff: length %f, dB falloff %f, falloff factor %e\n",
255                  length, falloff_dB, falloff); */
256         filter->decay_peak[i] *= falloff;
257         /* g_print ("peak is %f samples old, decayed with factor %e to %f\n",
258                  filter->decay_peak_age[i], falloff, filter->decay_peak[i]); */
259       }
260     }
261   }
262
263   /* do we need to emit ? */
264   
265   if (filter->num_samples >= filter->interval * (gdouble) filter->rate)
266   {
267     if (filter->signal)
268     {
269       gdouble RMS, peak, endtime;
270       for (i = 0; i < filter->channels; ++i)
271       {
272         RMS = sqrt (filter->CS[i] / (filter->num_samples / filter->channels));
273         peak = filter->last_peak[i];
274         num_samples = GST_BUFFER_SIZE (buf) / (filter->width / 8);
275         endtime = (double) GST_BUFFER_TIMESTAMP (buf) / GST_SECOND
276                 + (double) num_samples / (double) filter->rate;
277
278         g_signal_emit (G_OBJECT (filter), gst_filter_signals[SIGNAL_LEVEL], 0,
279                        endtime, i,
280                        20 * log10 (RMS), 20 * log10 (filter->last_peak[i]),
281                        20 * log10 (filter->decay_peak[i]));
282         /* we emitted, so reset cumulative and normal peak */
283         filter->CS[i] = 0.0;
284         filter->last_peak[i] = 0.0;
285       }
286     }
287     filter->num_samples = 0;
288   }
289 }
290
291 static GstElementStateReturn gst_level_change_state (GstElement *element)
292 {
293   GstLevel *filter = GST_LEVEL (element);
294
295   switch(GST_STATE_TRANSITION(element)){
296     case GST_STATE_PAUSED_TO_PLAYING:
297       if (!filter->inited) return GST_STATE_FAILURE;
298       break;
299     default:
300       break;
301   }
302
303   return GST_ELEMENT_CLASS(parent_class)->change_state(element);
304 }
305
306 static void
307 gst_level_set_property (GObject *object, guint prop_id, 
308                         const GValue *value, GParamSpec *pspec)
309 {
310   GstLevel *filter;
311
312   /* it's not null if we got it, but it might not be ours */
313   g_return_if_fail (GST_IS_LEVEL (object));
314   filter = GST_LEVEL (object);
315
316   switch (prop_id) {
317     case ARG_SIGNAL_LEVEL:
318       filter->signal = g_value_get_boolean (value);
319       break;
320     case ARG_SIGNAL_INTERVAL:
321       filter->interval = g_value_get_double (value);
322       break;
323     case ARG_PEAK_TTL:
324       filter->decay_peak_ttl = g_value_get_double (value);
325       break;
326     case ARG_PEAK_FALLOFF:
327       filter->decay_peak_falloff = g_value_get_double (value);
328       break;
329     default:
330       break;
331   }
332 }
333
334 static void
335 gst_level_get_property (GObject *object, guint prop_id, 
336                         GValue *value, GParamSpec *pspec)
337 {
338   GstLevel *filter;
339
340   /* it's not null if we got it, but it might not be ours */
341   g_return_if_fail (GST_IS_LEVEL (object));
342   filter = GST_LEVEL (object);
343
344   switch (prop_id) {
345     case ARG_SIGNAL_LEVEL:
346       g_value_set_boolean (value, filter->signal);
347       break;
348       case ARG_SIGNAL_INTERVAL:
349       g_value_set_double (value, filter->interval);
350       break;
351     case ARG_PEAK_TTL:
352       g_value_set_double (value, filter->decay_peak_ttl);
353       break;
354     case ARG_PEAK_FALLOFF:
355       g_value_set_double (value, filter->decay_peak_falloff);
356       break;
357    default:
358       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
359       break;
360   }
361 }
362
363 static void
364 gst_level_base_init (GstLevelClass *klass)
365 {
366   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
367
368   gst_element_class_add_pad_template (element_class,
369         gst_static_pad_template_get (&sink_template_factory));
370   gst_element_class_add_pad_template (element_class,
371         gst_static_pad_template_get (&src_template_factory));
372   gst_element_class_set_details (element_class, &level_details);
373
374   element_class->change_state = gst_level_change_state;
375 }
376
377 static void
378 gst_level_class_init (GstLevelClass *klass)
379 {
380   GObjectClass *gobject_class;
381   GstElementClass *gstelement_class;
382
383   gobject_class = (GObjectClass*) klass;
384   gstelement_class = (GstElementClass*) klass;
385
386   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
387   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_LEVEL,
388     g_param_spec_boolean ("signal", "Signal",
389                           "Emit level signals for each interval",
390                           TRUE, G_PARAM_READWRITE));
391   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_INTERVAL,
392     g_param_spec_double ("interval", "Interval",
393                          "Interval between emissions (in seconds)",
394                          0.01, 100.0, 0.1, G_PARAM_READWRITE));
395   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PEAK_TTL,
396     g_param_spec_double ("peak_ttl", "Peak TTL",
397                          "Time To Live of decay peak before it falls back",
398                          0, 100.0, 0.3, G_PARAM_READWRITE));
399   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PEAK_FALLOFF,
400     g_param_spec_double ("peak_falloff", "Peak Falloff",
401                          "Decay rate of decay peak after TTL (in dB/sec)",
402                          0.0, G_MAXDOUBLE, 10.0, G_PARAM_READWRITE));
403
404   gobject_class->set_property = gst_level_set_property;
405   gobject_class->get_property = gst_level_get_property;
406
407   gst_filter_signals[SIGNAL_LEVEL] = 
408     g_signal_new ("level", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
409                   G_STRUCT_OFFSET (GstLevelClass, level), NULL, NULL,
410                   gstlevel_cclosure_marshal_VOID__DOUBLE_INT_DOUBLE_DOUBLE_DOUBLE,
411                   G_TYPE_NONE, 5,
412                   G_TYPE_DOUBLE, G_TYPE_INT,
413                   G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
414 }
415
416 static void
417 gst_level_init (GstLevel *filter)
418 {
419   filter->sinkpad = gst_pad_new_from_template (gst_static_pad_template_get (&sink_template_factory), "sink");
420   gst_pad_set_link_function (filter->sinkpad, gst_level_link);
421   filter->srcpad = gst_pad_new_from_template (gst_static_pad_template_get (&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",
447                                GST_RANK_NONE, GST_TYPE_LEVEL);
448 }
449
450 GST_PLUGIN_DEFINE (
451   GST_VERSION_MAJOR,
452   GST_VERSION_MINOR,
453   "level",
454   "Audio level plugin",
455   plugin_init,
456   VERSION,
457   GST_LICENSE,
458   GST_PACKAGE,
459   GST_ORIGIN
460 )