various cosmetic fixes
[platform/upstream/gst-plugins-good.git] / gst / level / gstlevel.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) 2000,2001,2002,2003,2005
4  *           Thomas Vander Stichele <thomas at apestaart dot org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /**
23  * SECTION:element-level
24  *
25  * <refsect2>
26  * <para>
27  * Level analyses incoming audio buffers and, if the
28  * <link linkend="GstLevel--message">message property</link> is #TRUE,
29  * generates an element message named
30  * <classname>&quot;level&quot;</classname>:
31  * after each interval of time given by the
32  * <link linkend="GstLevel--interval">interval property</link>.
33  * The message's structure contains four fields:
34  * <itemizedlist>
35  * <listitem>
36  *   <para>
37  *   #GstClockTime
38  *   <classname>&quot;endtime&quot;</classname>:
39  *   the end time of the buffer that triggered the message
40  *   </para>
41  * </listitem>
42  * <listitem>
43  *   <para>
44  *   #GstValueList of #gdouble
45  *   <classname>&quot;peak&quot;</classname>:
46  *   the peak power level in dB for each channel
47  *   </para>
48  * </listitem>
49  * <listitem>
50  *   <para>
51  *   #GstValueList of #gdouble
52  *   <classname>&quot;decay&quot;</classname>:
53  *   the decaying peak power level in dB for each channel
54  *   the decaying peak level follows the peak level, but starts dropping
55  *   if no new peak is reached after the time given by
56  *   the <link linkend="GstLevel--peak-ttl">the time to live</link>.
57  *   When the decaying peak level drops, it does so at the decay rate
58  *   as specified by the
59  *   <link linkend="GstLevel--peak-falloff">the peak falloff rate</link>.
60  *   </para>
61  * </listitem>
62  * <listitem>
63  *   <para>
64  *   #GstValueList of #gdouble
65  *   <classname>&quot;rms&quot;</classname>:
66  *   the Root Mean Square (or average power) level in dB for each channel
67  *   </para>
68  * </listitem>
69   * </itemizedlist>
70  * </para>
71  * <title>Example application</title>
72  * <para>
73  * <include xmlns="http://www.w3.org/2003/XInclude" href="element-level-example.xml" />
74  * </para>
75  * </refsect2>
76  */
77
78 #ifdef HAVE_CONFIG_H
79 #include "config.h"
80 #endif
81 #include <gst/gst.h>
82 #include <gst/audio/audio.h>
83 #include "gstlevel.h"
84 #include "math.h"
85
86 GST_DEBUG_CATEGORY (level_debug);
87 #define GST_CAT_DEFAULT level_debug
88
89 static GstElementDetails level_details = {
90   "Level",
91   "Filter/Analyzer/Audio",
92   "RMS/Peak/Decaying Peak Level messager for audio/raw",
93   "Thomas Vander Stichele <thomas at apestaart dot org>"
94 };
95
96 static GstStaticPadTemplate sink_template_factory =
97 GST_STATIC_PAD_TEMPLATE ("sink",
98     GST_PAD_SINK,
99     GST_PAD_ALWAYS,
100     GST_STATIC_CAPS ("audio/x-raw-int, "
101         "rate = (int) [ 1, MAX ], "
102         "channels = (int) [ 1, MAX ], "
103         "endianness = (int) BYTE_ORDER, "
104         "width = (int) { 8, 16 }, "
105         "depth = (int) { 8, 16 }, " "signed = (boolean) true")
106     );
107
108 static GstStaticPadTemplate src_template_factory =
109 GST_STATIC_PAD_TEMPLATE ("src",
110     GST_PAD_SRC,
111     GST_PAD_ALWAYS,
112     GST_STATIC_CAPS ("audio/x-raw-int, "
113         "rate = (int) [ 1, MAX ], "
114         "channels = (int) [ 1, MAX ], "
115         "endianness = (int) BYTE_ORDER, "
116         "width = (int) { 8, 16 }, "
117         "depth = (int) { 8, 16 }, " "signed = (boolean) true")
118     );
119
120 enum
121 {
122   PROP_0,
123   PROP_SIGNAL_LEVEL,
124   PROP_SIGNAL_INTERVAL,
125   PROP_PEAK_TTL,
126   PROP_PEAK_FALLOFF
127 };
128
129 GST_BOILERPLATE (GstLevel, gst_level, GstBaseTransform,
130     GST_TYPE_BASE_TRANSFORM);
131
132 static void gst_level_set_property (GObject * object, guint prop_id,
133     const GValue * value, GParamSpec * pspec);
134 static void gst_level_get_property (GObject * object, guint prop_id,
135     GValue * value, GParamSpec * pspec);
136
137 static gboolean gst_level_set_caps (GstBaseTransform * trans, GstCaps * in,
138     GstCaps * out);
139 static GstFlowReturn gst_level_transform_ip (GstBaseTransform * trans,
140     GstBuffer * in);
141
142
143 static void
144 gst_level_base_init (gpointer g_class)
145 {
146   GstElementClass *element_class = g_class;
147
148   gst_element_class_add_pad_template (element_class,
149       gst_static_pad_template_get (&sink_template_factory));
150   gst_element_class_add_pad_template (element_class,
151       gst_static_pad_template_get (&src_template_factory));
152   gst_element_class_set_details (element_class, &level_details);
153 }
154
155 static void
156 gst_level_class_init (GstLevelClass * klass)
157 {
158   GObjectClass *gobject_class;
159   GstBaseTransformClass *trans_class;
160
161   gobject_class = (GObjectClass *) klass;
162   trans_class = (GstBaseTransformClass *) klass;
163
164   gobject_class->set_property = gst_level_set_property;
165   gobject_class->get_property = gst_level_get_property;
166
167   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SIGNAL_LEVEL,
168       g_param_spec_boolean ("message", "mesage",
169           "Post a level message for each passed interval",
170           TRUE, G_PARAM_READWRITE));
171   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SIGNAL_INTERVAL,
172       g_param_spec_uint64 ("interval", "Interval",
173           "Interval of time between message posts (in nanoseconds)",
174           1, G_MAXUINT64, GST_SECOND / 10, G_PARAM_READWRITE));
175   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PEAK_TTL,
176       g_param_spec_uint64 ("peak-ttl", "Peak TTL",
177           "Time To Live of decay peak before it falls back (in nanoseconds)",
178           0, G_MAXUINT64, GST_SECOND / 10 * 3, G_PARAM_READWRITE));
179   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PEAK_FALLOFF,
180       g_param_spec_double ("peak-falloff", "Peak Falloff",
181           "Decay rate of decay peak after TTL (in dB/sec)",
182           0.0, G_MAXDOUBLE, 10.0, G_PARAM_READWRITE));
183
184   GST_DEBUG_CATEGORY_INIT (level_debug, "level", 0, "Level calculation");
185
186   trans_class->set_caps = gst_level_set_caps;
187   trans_class->transform_ip = gst_level_transform_ip;
188   trans_class->passthrough_on_same_caps = TRUE;
189 }
190
191 static void
192 gst_level_init (GstLevel * filter, GstLevelClass * g_class)
193 {
194   filter->CS = NULL;
195   filter->peak = NULL;
196
197   filter->rate = 0;
198   filter->width = 0;
199   filter->channels = 0;
200
201   filter->interval = GST_SECOND / 10;
202   filter->decay_peak_ttl = GST_SECOND / 10 * 3;
203   filter->decay_peak_falloff = 10.0;    /* dB falloff (/sec) */
204
205   filter->message = TRUE;
206 }
207
208 static void
209 gst_level_set_property (GObject * object, guint prop_id,
210     const GValue * value, GParamSpec * pspec)
211 {
212   GstLevel *filter = GST_LEVEL (object);
213
214   switch (prop_id) {
215     case PROP_SIGNAL_LEVEL:
216       filter->message = g_value_get_boolean (value);
217       break;
218     case PROP_SIGNAL_INTERVAL:
219       filter->interval = g_value_get_uint64 (value);
220       break;
221     case PROP_PEAK_TTL:
222       filter->decay_peak_ttl = g_value_get_uint64 (value);
223       break;
224     case PROP_PEAK_FALLOFF:
225       filter->decay_peak_falloff = g_value_get_double (value);
226       break;
227     default:
228       break;
229   }
230 }
231
232 static void
233 gst_level_get_property (GObject * object, guint prop_id,
234     GValue * value, GParamSpec * pspec)
235 {
236   GstLevel *filter = GST_LEVEL (object);
237
238   switch (prop_id) {
239     case PROP_SIGNAL_LEVEL:
240       g_value_set_boolean (value, filter->message);
241       break;
242     case PROP_SIGNAL_INTERVAL:
243       g_value_set_uint64 (value, filter->interval);
244       break;
245     case PROP_PEAK_TTL:
246       g_value_set_uint64 (value, filter->decay_peak_ttl);
247       break;
248     case PROP_PEAK_FALLOFF:
249       g_value_set_double (value, filter->decay_peak_falloff);
250       break;
251     default:
252       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
253       break;
254   }
255 }
256
257 static gint
258 structure_get_int (GstStructure * structure, const gchar * field)
259 {
260   gint ret;
261
262   if (!gst_structure_get_int (structure, field, &ret))
263     g_assert_not_reached ();
264
265   return ret;
266 }
267
268 static gboolean
269 gst_level_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
270 {
271   GstLevel *filter;
272   GstStructure *structure;
273   int i;
274
275   filter = GST_LEVEL (trans);
276
277   filter->num_frames = 0;
278
279   structure = gst_caps_get_structure (in, 0);
280   filter->rate = structure_get_int (structure, "rate");
281   filter->width = structure_get_int (structure, "width");
282   filter->channels = structure_get_int (structure, "channels");
283
284   /* allocate channel variable arrays */
285   g_free (filter->CS);
286   g_free (filter->peak);
287   g_free (filter->last_peak);
288   g_free (filter->decay_peak);
289   g_free (filter->decay_peak_base);
290   g_free (filter->decay_peak_age);
291   filter->CS = g_new (double, filter->channels);
292   filter->peak = g_new (double, filter->channels);
293   filter->last_peak = g_new (double, filter->channels);
294   filter->decay_peak = g_new (double, filter->channels);
295   filter->decay_peak_base = g_new (double, filter->channels);
296
297   filter->decay_peak_age = g_new (GstClockTime, filter->channels);
298
299   for (i = 0; i < filter->channels; ++i) {
300     filter->CS[i] = filter->peak[i] = filter->last_peak[i] =
301         filter->decay_peak[i] = filter->decay_peak_base[i] = 0.0;
302     filter->decay_peak_age[i] = 0LL;
303   }
304
305   return TRUE;
306 }
307
308 /* process one (interleaved) channel of incoming samples
309  * calculate square sum of samples
310  * normalize and average over number of samples
311  * returns a normalized cumulative square value, which can be averaged
312  * to return the average power as a double between 0 and 1
313  * also returns the normalized peak power (square of the highest amplitude)
314  *
315  * caller must assure num is a multiple of channels
316  * samples for multiple channels are interleaved
317  * input sample data enters in *in_data as 8 or 16 bit data
318  * this filter only accepts signed audio data, so mid level is always 0
319  *
320  * for 16 bit, this code considers the non-existant 32768 value to be
321  * full-scale; so 32767 will not map to 1.0
322  */
323
324 #define DEFINE_LEVEL_CALCULATOR(TYPE, RESOLUTION)                             \
325 static void inline                                                            \
326 gst_level_calculate_##TYPE (TYPE * in, guint num, gint channels,              \
327                             double *CS, double *peak)                         \
328 {                                                                             \
329   register int j;                                                             \
330   double squaresum = 0.0;        /* square sum of the integer samples */      \
331   register double square = 0.0;  /* Square */                                 \
332   register double PSS = 0.0;     /* Peak Square Sample */                     \
333   gdouble normalizer;            /* divisor to get a [-1.0, 1.0] range */     \
334                                                                               \
335   *CS = 0.0;                     /* Cumulative Square for this block */       \
336                                                                               \
337   normalizer = (double) (1 << RESOLUTION);                                    \
338                                                                               \
339   for (j = 0; j < num; j += channels)                                         \
340   {                                                                           \
341     square = ((double) in[j]) * in[j];                                        \
342     if (square > PSS) PSS = square;                                           \
343     squaresum += square;                                                      \
344   }                                                                           \
345                                                                               \
346   *CS = squaresum / (normalizer * normalizer);                                \
347   *peak = PSS / (normalizer * normalizer);                                    \
348 }
349
350 DEFINE_LEVEL_CALCULATOR (gint16, 15);
351 DEFINE_LEVEL_CALCULATOR (gint8, 7);
352
353 static GstMessage *
354 gst_level_message_new (GstLevel * l, GstClockTime endtime)
355 {
356   GstStructure *s;
357   GValue v = { 0, };
358
359   g_value_init (&v, GST_TYPE_LIST);
360
361   s = gst_structure_new ("level", "endtime", GST_TYPE_CLOCK_TIME,
362       endtime, NULL);
363   /* will copy-by-value */
364   gst_structure_set_value (s, "rms", &v);
365   gst_structure_set_value (s, "peak", &v);
366   gst_structure_set_value (s, "decay", &v);
367
368   return gst_message_new_element (GST_OBJECT (l), s);
369 }
370
371 static void
372 gst_level_message_append_channel (GstMessage * m, gdouble rms, gdouble peak,
373     gdouble decay)
374 {
375   GstStructure *s;
376   GValue v = { 0, };
377   GValue *l;
378
379   g_value_init (&v, G_TYPE_DOUBLE);
380
381   s = (GstStructure *) gst_message_get_structure (m);
382
383   l = (GValue *) gst_structure_get_value (s, "rms");
384   g_value_set_double (&v, rms);
385   gst_value_list_append_value (l, &v);  /* copies by value */
386
387   l = (GValue *) gst_structure_get_value (s, "peak");
388   g_value_set_double (&v, peak);
389   gst_value_list_append_value (l, &v);  /* copies by value */
390
391   l = (GValue *) gst_structure_get_value (s, "decay");
392   g_value_set_double (&v, decay);
393   gst_value_list_append_value (l, &v);  /* copies by value */
394 }
395
396 static GstFlowReturn
397 gst_level_transform_ip (GstBaseTransform * trans, GstBuffer * in)
398 {
399   GstLevel *filter;
400   gpointer in_data;
401   double CS = 0.0;
402   gint num_frames = 0;
403   gint num_int_samples = 0;     /* number of interleaved samples
404                                  * ie. total count for all channels combined */
405   gint i;
406
407   filter = GST_LEVEL (trans);
408
409   for (i = 0; i < filter->channels; ++i)
410     filter->peak[i] = 0.0;
411
412   in_data = GST_BUFFER_DATA (in);
413   num_int_samples = GST_BUFFER_SIZE (in) / (filter->width / 8);
414
415   g_return_val_if_fail (num_int_samples % filter->channels == 0,
416       GST_FLOW_ERROR);
417
418   num_frames = num_int_samples / filter->channels;
419
420   for (i = 0; i < filter->channels; ++i) {
421     CS = 0.0;
422     switch (filter->width) {
423       case 16:
424         gst_level_calculate_gint16 (((gint16 *) in_data) + i, num_int_samples,
425             filter->channels, &CS, &filter->peak[i]);
426         break;
427       case 8:
428         gst_level_calculate_gint8 (((gint8 *) in_data) + i, num_int_samples,
429             filter->channels, &CS, &filter->peak[i]);
430         break;
431     }
432     GST_LOG_OBJECT (filter,
433         "channel %d, cumulative sum %f, peak %f, over %d samples/%d channels",
434         i, CS, filter->peak[i], num_int_samples, filter->channels);
435     filter->CS[i] += CS;
436   }
437
438   filter->num_frames += num_frames;
439
440   for (i = 0; i < filter->channels; ++i) {
441     filter->decay_peak_age[i] +=
442         GST_FRAMES_TO_CLOCK_TIME (num_frames, filter->rate);
443     GST_LOG_OBJECT (filter, "filter peak info [%d]: decay peak %f, age %"
444         GST_TIME_FORMAT, i,
445         filter->decay_peak[i], GST_TIME_ARGS (filter->decay_peak_age[i]));
446
447     /* update running peak */
448     if (filter->peak[i] > filter->last_peak[i])
449       filter->last_peak[i] = filter->peak[i];
450
451     /* make decay peak fall off if too old */
452     if (filter->decay_peak_age[i] > filter->decay_peak_ttl) {
453       double falloff_dB;
454       double falloff;
455       GstClockTimeDiff falloff_time;
456       double length;            /* length of falloff time in seconds */
457
458       falloff_time = GST_CLOCK_DIFF (filter->decay_peak_ttl,
459           filter->decay_peak_age[i]);
460       length = (gdouble) falloff_time / GST_SECOND;
461       falloff_dB = filter->decay_peak_falloff * length;
462       falloff = pow (10, falloff_dB / -20.0);
463
464       GST_LOG_OBJECT (filter,
465           "falloff: current %f, base %f, interval %" GST_TIME_FORMAT
466           ", dB falloff %f, factor %e",
467           filter->decay_peak[i], filter->decay_peak_base[i],
468           GST_TIME_ARGS (falloff_time), falloff_dB, falloff);
469       filter->decay_peak[i] = filter->decay_peak_base[i] * falloff;
470       GST_LOG_OBJECT (filter,
471           "peak is %" GST_TIME_FORMAT " old, decayed with factor %e to %f",
472           GST_TIME_ARGS (filter->decay_peak_age[i]), falloff,
473           filter->decay_peak[i]);
474     } else {
475       GST_LOG_OBJECT (filter, "peak not old enough, not decaying");
476     }
477
478     /* if the peak of this run is higher, the decay peak gets reset */
479     if (filter->peak[i] >= filter->decay_peak[i]) {
480       GST_LOG_OBJECT (filter, "new peak, %f", filter->peak[i]);
481       filter->decay_peak[i] = filter->peak[i];
482       filter->decay_peak_base[i] = filter->peak[i];
483       filter->decay_peak_age[i] = 0LL;
484     }
485   }
486
487   /* do we need to message ? */
488   if (filter->num_frames >=
489       GST_CLOCK_TIME_TO_FRAMES (filter->interval, filter->rate)) {
490     if (filter->message) {
491       GstMessage *m;
492       GstClockTime endtime;
493
494       endtime = GST_BUFFER_TIMESTAMP (in)
495           + GST_FRAMES_TO_CLOCK_TIME (num_frames, filter->rate);
496
497       m = gst_level_message_new (filter, endtime);
498
499       GST_LOG_OBJECT (filter,
500           "message: end time %" GST_TIME_FORMAT ", num_frames %d",
501           GST_TIME_ARGS (endtime), filter->num_frames);
502
503       for (i = 0; i < filter->channels; ++i) {
504         double RMS;
505         double RMSdB, lastdB, decaydB;
506
507         RMS = sqrt (filter->CS[i] / filter->num_frames);
508         GST_LOG_OBJECT (filter,
509             "message: channel %d, CS %f, num_frames %d, RMS %f",
510             i, filter->CS[i], filter->num_frames, RMS);
511         GST_LOG_OBJECT (filter,
512             "message: last_peak: %f, decay_peak: %f",
513             filter->last_peak[i], filter->decay_peak[i]);
514         /* RMS values are calculated in amplitude, so 20 * log 10 */
515         RMSdB = 20 * log10 (RMS);
516         /* peak values are square sums, ie. power, so 10 * log 10 */
517         lastdB = 10 * log10 (filter->last_peak[i]);
518         decaydB = 10 * log10 (filter->decay_peak[i]);
519
520         if (filter->decay_peak[i] < filter->last_peak[i]) {
521           GST_ERROR_OBJECT (filter,
522               "message: decay peak dB %f smaller than last peak dB %f",
523               decaydB, lastdB);
524         }
525         GST_LOG_OBJECT (filter,
526             "message: RMS %f dB, peak %f dB, decay %f dB",
527             RMSdB, lastdB, decaydB);
528
529         gst_level_message_append_channel (m, RMSdB, lastdB, decaydB);
530
531         /* reset cumulative and normal peak */
532         filter->CS[i] = 0.0;
533         filter->last_peak[i] = 0.0;
534       }
535
536       gst_element_post_message (GST_ELEMENT (filter), m);
537     }
538     filter->num_frames = 0;
539   }
540
541   return GST_FLOW_OK;
542 }
543
544 static gboolean
545 plugin_init (GstPlugin * plugin)
546 {
547   return gst_element_register (plugin, "level", GST_RANK_NONE, GST_TYPE_LEVEL);
548 }
549
550 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
551     GST_VERSION_MINOR,
552     "level",
553     "Audio level plugin",
554     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);