gstlevel.c 17.6 KB
Newer Older
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
1
/* GStreamer
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
2
 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3
 * Copyright (C) 2000,2001,2002,2003,2005
4 5
 *           Thomas Vander Stichele <thomas at apestaart dot org>
 *
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

22 23 24 25 26
/**
 * SECTION:element-level
 *
 * <refsect2>
 * <para>
27
 * Level analyses incoming audio buffers and, if the
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
28
 * <link linkend="GstLevel--message">message property</link> is #TRUE,
29 30 31 32
 * generates an application message named
 * <classname>&quot;level&quot;</classname>:
 * after each interval of time given by the
 * <link linkend="GstLevel--interval">interval property</link>.
33 34 35 36
 * The message's structure contains four fields:
 * <itemizedlist>
 * <listitem>
 *   <para>
37
 *   #GstClockTime
38
 *   <classname>&quot;endtime&quot;</classname>:
39 40
 *   the end time of the buffer that triggered the message
 *   </para>
41 42 43
 * </listitem>
 * <listitem>
 *   <para>
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
 *   #GstValueList of #gdouble
 *   <classname>&quot;peak&quot;</classname>:
 *   the peak power level in dB for each channel
 *   </para>
 * </listitem>
 * <listitem>
 *   <para>
 *   #GstValueList of #gdouble
 *   <classname>&quot;decay&quot;</classname>:
 *   the decaying peak power level in dB for each channel
 *   the decaying peak level follows the peak level, but starts dropping
 *   if no new peak is reached after the time given by
 *   the <link linkend="GstLevel--peak-ttl">the time to live</link>.
 *   When the decaying peak level drops, it does so at the decay rate
 *   as specified by the
 *   <link linkend="GstLevel--peak-falloff">the peak fallof rate</link>.
 *   </para>
 * </listitem>
 * <listitem>
 *   <para>
 *   #GstValueList of #gdouble
 *   <classname>&quot;rms&quot;</classname>:
 *   the Root Mean Square (or average power) level in dB for each channel
 *   </para>
68 69 70 71 72 73 74 75 76 77
 * </listitem>
  * </itemizedlist>
 * </para>
 * <title>Example application</title>
 * <para>
 * <include xmlns="http://www.w3.org/2003/XInclude" href="element-level-example.xml" />
 * </para>
 * </refsect2>
 */

78 79 80
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
81
#include <gst/gst.h>
82
#include <gst/audio/audio.h>
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
83 84 85
#include "gstlevel.h"
#include "math.h"

86 87 88
GST_DEBUG_CATEGORY (level_debug);
#define GST_CAT_DEFAULT level_debug

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
89 90
static GstElementDetails level_details = {
  "Level",
91
  "Filter/Analyzer/Audio",
92
  "RMS/Peak/Decaying Peak Level messager for audio/raw",
Ronald S. Bultje's avatar
*sigh*  
Ronald S. Bultje committed
93
  "Thomas <thomas@apestaart.org>"
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
94 95
};

David Schleef's avatar
David Schleef committed
96
static GstStaticPadTemplate sink_template_factory =
97
GST_STATIC_PAD_TEMPLATE ("sink",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
98 99
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
100 101
    GST_STATIC_CAPS ("audio/x-raw-int, "
        "rate = (int) [ 1, MAX ], "
102
        "channels = (int) [ 1, 8 ], "
103 104 105
        "endianness = (int) BYTE_ORDER, "
        "width = (int) { 8, 16 }, "
        "depth = (int) { 8, 16 }, " "signed = (boolean) true")
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
106
    );
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
107

David Schleef's avatar
David Schleef committed
108
static GstStaticPadTemplate src_template_factory =
109
GST_STATIC_PAD_TEMPLATE ("src",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
110 111
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
112 113
    GST_STATIC_CAPS ("audio/x-raw-int, "
        "rate = (int) [ 1, MAX ], "
114
        "channels = (int) [ 1, 8 ], "
115 116 117
        "endianness = (int) BYTE_ORDER, "
        "width = (int) { 8, 16 }, "
        "depth = (int) { 8, 16 }, " "signed = (boolean) true")
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
118
    );
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
119 120


Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
121 122
enum
{
123 124 125 126 127
  PROP_0,
  PROP_SIGNAL_LEVEL,
  PROP_SIGNAL_INTERVAL,
  PROP_PEAK_TTL,
  PROP_PEAK_FALLOFF
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
128 129
};

130 131 132 133

GST_BOILERPLATE (GstLevel, gst_level, GstBaseTransform,
    GST_TYPE_BASE_TRANSFORM);

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
134 135 136 137
static void gst_level_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec);
static void gst_level_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
138

139 140
static gboolean gst_level_set_caps (GstBaseTransform * trans, GstCaps * in,
    GstCaps * out);
141 142
static GstFlowReturn gst_level_transform_ip (GstBaseTransform * trans,
    GstBuffer * in);
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169


static void
gst_level_base_init (gpointer g_class)
{
  GstElementClass *element_class = g_class;

  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&sink_template_factory));
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&src_template_factory));
  gst_element_class_set_details (element_class, &level_details);
}

static void
gst_level_class_init (GstLevelClass * klass)
{
  GObjectClass *gobject_class;
  GstBaseTransformClass *trans_class;

  gobject_class = (GObjectClass *) klass;
  trans_class = (GstBaseTransformClass *) klass;

  gobject_class->set_property = gst_level_set_property;
  gobject_class->get_property = gst_level_get_property;

  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SIGNAL_LEVEL,
170
      g_param_spec_boolean ("message", "mesage",
171 172
          "Post a level message for each passed interval",
          TRUE, G_PARAM_READWRITE));
173
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SIGNAL_INTERVAL,
174 175 176
      g_param_spec_uint64 ("interval", "Interval",
          "Interval of time between message posts (in nanoseconds)",
          1, G_MAXUINT64, GST_SECOND / 10, G_PARAM_READWRITE));
177
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PEAK_TTL,
178 179 180
      g_param_spec_uint64 ("peak_ttl", "Peak TTL",
          "Time To Live of decay peak before it falls back (in nanoseconds)",
          0, G_MAXUINT64, GST_SECOND / 10 * 3, G_PARAM_READWRITE));
181 182 183 184 185 186 187 188
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PEAK_FALLOFF,
      g_param_spec_double ("peak_falloff", "Peak Falloff",
          "Decay rate of decay peak after TTL (in dB/sec)",
          0.0, G_MAXDOUBLE, 10.0, G_PARAM_READWRITE));

  GST_DEBUG_CATEGORY_INIT (level_debug, "level", 0, "Level calculation");

  trans_class->set_caps = gst_level_set_caps;
189 190
  trans_class->transform_ip = gst_level_transform_ip;
  trans_class->passthrough_on_same_caps = TRUE;
191 192 193
}

static void
194
gst_level_init (GstLevel * filter, GstLevelClass * g_class)
195 196 197 198 199 200 201 202 203
{
  filter->CS = NULL;
  filter->peak = NULL;
  filter->RMS_dB = NULL;

  filter->rate = 0;
  filter->width = 0;
  filter->channels = 0;

204 205
  filter->interval = GST_SECOND / 10;
  filter->decay_peak_ttl = GST_SECOND / 10 * 3;
206
  filter->decay_peak_falloff = 10.0;    /* dB falloff (/sec) */
207 208

  filter->message = TRUE;
209 210 211 212 213 214 215
}

static void
gst_level_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstLevel *filter = GST_LEVEL (object);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
216

217 218
  switch (prop_id) {
    case PROP_SIGNAL_LEVEL:
219
      filter->message = g_value_get_boolean (value);
220 221
      break;
    case PROP_SIGNAL_INTERVAL:
222
      filter->interval = g_value_get_uint64 (value);
223 224
      break;
    case PROP_PEAK_TTL:
225
      filter->decay_peak_ttl = g_value_get_uint64 (value);
226 227 228 229 230 231 232 233
      break;
    case PROP_PEAK_FALLOFF:
      filter->decay_peak_falloff = g_value_get_double (value);
      break;
    default:
      break;
  }
}
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
234

235 236 237
static void
gst_level_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
238
{
239 240 241 242
  GstLevel *filter = GST_LEVEL (object);

  switch (prop_id) {
    case PROP_SIGNAL_LEVEL:
243
      g_value_set_boolean (value, filter->message);
244 245
      break;
    case PROP_SIGNAL_INTERVAL:
246
      g_value_set_uint64 (value, filter->interval);
247 248
      break;
    case PROP_PEAK_TTL:
249
      g_value_set_uint64 (value, filter->decay_peak_ttl);
250 251 252 253 254 255 256
      break;
    case PROP_PEAK_FALLOFF:
      g_value_set_double (value, filter->decay_peak_falloff);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
257 258 259
  }
}

260 261 262 263 264 265 266 267 268 269 270 271 272
static gint
structure_get_int (GstStructure * structure, const gchar * field)
{
  gint ret;

  if (!gst_structure_get_int (structure, field, &ret))
    g_assert_not_reached ();

  return ret;
}

static gboolean
gst_level_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
273
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
274
  GstLevel *filter;
David Schleef's avatar
David Schleef committed
275
  GstStructure *structure;
276
  int i;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
277

278
  filter = GST_LEVEL (trans);
279

280
  filter->num_frames = 0;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
281

282 283 284 285
  structure = gst_caps_get_structure (in, 0);
  filter->rate = structure_get_int (structure, "rate");
  filter->width = structure_get_int (structure, "width");
  filter->channels = structure_get_int (structure, "channels");
286 287

  /* allocate channel variable arrays */
288 289 290 291 292 293
  g_free (filter->CS);
  g_free (filter->peak);
  g_free (filter->last_peak);
  g_free (filter->decay_peak);
  g_free (filter->decay_peak_age);
  g_free (filter->RMS_dB);
294 295 296 297
  filter->CS = g_new (double, filter->channels);
  filter->peak = g_new (double, filter->channels);
  filter->last_peak = g_new (double, filter->channels);
  filter->decay_peak = g_new (double, filter->channels);
298 299

  filter->decay_peak_age = g_new (GstClockTime, filter->channels);
300
  filter->RMS_dB = g_new (double, filter->channels);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
301

302 303
  for (i = 0; i < filter->channels; ++i) {
    filter->CS[i] = filter->peak[i] = filter->last_peak[i] =
304 305
        filter->decay_peak[i] = filter->RMS_dB[i] = 0.0;
    filter->decay_peak_age[i] = 0LL;
306 307
  }

308 309 310 311 312
  return TRUE;
}

/* process one (interleaved) channel of incoming samples
 * calculate square sum of samples
313 314 315 316
 * normalize and average over number of samples
 * returns a normalized average power value as CS, as a double between 0 and 1
 * also returns the normalized peak power (square of the highest amplitude)
 *
317
 * caller must assure num is a multiple of channels
318 319
 * samples for multiple channels are interleaved
 * input sample data enters in *in_data as 8 or 16 bit data
320
 * this filter only accepts signed audio data, so mid level is always 0
321 322 323
 *
 * for 16 bit, this code considers the non-existant 32768 value to be
 * full-scale; so 32767 will not map to 1.0
324
 */
325 326 327 328 329 330 331 332 333 334

#define DEFINE_LEVEL_CALCULATOR(TYPE)                                         \
static void inline                                                            \
gst_level_calculate_##TYPE (TYPE * in, guint num, gint channels,              \
                            gint resolution, double *CS, double *peak)        \
{                                                                             \
  register int j;                                                             \
  double squaresum = 0.0;        /* square sum of the integer samples */      \
  register double square = 0.0;	 /* Square */                                 \
  register double PSS = 0.0;     /* Peak Square Sample */                     \
335
  gdouble normalizer;            /* divisor to get a [-1.0, 1.0] range */     \
336 337 338 339 340 341 342 343 344 345 346 347 348 349
                                                                              \
  *CS = 0.0;                     /* Cumulative Square for this block */       \
                                                                              \
  normalizer = (double) (1 << resolution);                                    \
                                                                              \
  for (j = 0; j < num; j += channels)                                         \
  {                                                                           \
    square = ((double) in[j]) * in[j];                                        \
    if (square > PSS) PSS = square;                                           \
    squaresum += square;                                                      \
  }                                                                           \
                                                                              \
  *CS = squaresum / (normalizer * normalizer);                                \
  *peak = PSS / (normalizer * normalizer);                                    \
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
350 351
}

352 353 354 355
DEFINE_LEVEL_CALCULATOR (gint16);
DEFINE_LEVEL_CALCULATOR (gint8);

static GstMessage *
356
gst_level_message_new (GstLevel * l, GstClockTime endtime)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
357
{
358 359 360 361 362
  GstStructure *s;
  GValue v = { 0, };

  g_value_init (&v, GST_TYPE_LIST);

363 364
  s = gst_structure_new ("level", "endtime", GST_TYPE_CLOCK_TIME,
      endtime, NULL);
365 366 367 368 369
  /* will copy-by-value */
  gst_structure_set_value (s, "rms", &v);
  gst_structure_set_value (s, "peak", &v);
  gst_structure_set_value (s, "decay", &v);

370
  return gst_message_new_application (GST_OBJECT (l), s);
371
}
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
372

373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
static void
gst_level_message_append_channel (GstMessage * m, gdouble rms, gdouble peak,
    gdouble decay)
{
  GstStructure *s;
  GValue v = { 0, };
  GValue *l;

  g_value_init (&v, G_TYPE_DOUBLE);

  s = (GstStructure *) gst_message_get_structure (m);

  l = (GValue *) gst_structure_get_value (s, "rms");
  g_value_set_double (&v, rms);
  gst_value_list_append_value (l, &v);  /* copies by value */

  l = (GValue *) gst_structure_get_value (s, "peak");
  g_value_set_double (&v, peak);
  gst_value_list_append_value (l, &v);  /* copies by value */

  l = (GValue *) gst_structure_get_value (s, "decay");
  g_value_set_double (&v, decay);
  gst_value_list_append_value (l, &v);  /* copies by value */
}

static GstFlowReturn
399
gst_level_transform_ip (GstBaseTransform * trans, GstBuffer * in)
400 401 402
{
  GstLevel *filter;
  gpointer in_data;
403
  double CS = 0.0;
404 405 406
  gint num_frames = 0;
  gint num_int_samples = 0;     /* number of interleaved samples
                                 * ie. total count for all channels combined */
407
  gint i;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
408

409
  filter = GST_LEVEL (trans);
410

411
  for (i = 0; i < filter->channels; ++i)
412
    filter->peak[i] = filter->RMS_dB[i] = 0.0;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
413

414
  in_data = GST_BUFFER_DATA (in);
415
  num_int_samples = GST_BUFFER_SIZE (in) / (filter->width / 8);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
416

417 418
  g_return_val_if_fail (num_int_samples % filter->channels == 0,
      GST_FLOW_ERROR);
419

420 421
  num_frames = num_int_samples / filter->channels;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
422
  for (i = 0; i < filter->channels; ++i) {
423
    CS = 0.0;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
424
    switch (filter->width) {
425
      case 16:
426
        gst_level_calculate_gint16 (((gint16 *) in_data) + i, num_int_samples,
427 428
            filter->channels, filter->width - 1, &CS, &filter->peak[i]);
        break;
429
      case 8:
430
        gst_level_calculate_gint8 (((gint8 *) in_data) + i, num_int_samples,
431 432
            filter->channels, filter->width - 1, &CS, &filter->peak[i]);
        break;
433
    }
434
    GST_LOG_OBJECT (filter,
435
        "channel %d, cumulative sum %f, peak %f, over %d samples/%d channels",
436
        i, CS, filter->peak[i], num_int_samples, filter->channels);
437
    filter->CS[i] += CS;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
438 439
  }

440
  filter->num_frames += num_frames;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
441

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
442
  for (i = 0; i < filter->channels; ++i) {
443 444 445 446 447
    filter->decay_peak_age[i] +=
        GST_FRAMES_TO_CLOCK_TIME (num_frames, filter->rate);
    GST_LOG_OBJECT (filter, "filter peak info [%d]: peak %f, age %"
        GST_TIME_FORMAT, i,
        filter->last_peak[i], GST_TIME_ARGS (filter->decay_peak_age[i]));
448

449 450
    /* update running peak */
    if (filter->peak[i] > filter->last_peak[i])
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
451
      filter->last_peak[i] = filter->peak[i];
452 453

    /* update decay peak */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
454
    if (filter->peak[i] >= filter->decay_peak[i]) {
455
      GST_LOG_OBJECT (filter, "new peak, %f", filter->peak[i]);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
456
      filter->decay_peak[i] = filter->peak[i];
457
      filter->decay_peak_age[i] = 0LL;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
458
    } else {
459
      /* make decay peak fall off if too old */
460
      if (filter->decay_peak_age[i] > filter->decay_peak_ttl) {
461 462 463
        double falloff_dB;
        double falloff;
        double length;          /* length of buffer in seconds */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
464 465


466
        length = (double) num_frames / filter->rate;
467 468
        falloff_dB = filter->decay_peak_falloff * length;
        falloff = pow (10, falloff_dB / -20.0);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
469

470
        GST_LOG_OBJECT (filter,
471
            "falloff: length %f, dB falloff %f, falloff factor %e",
472
            length, falloff_dB, falloff);
473
        filter->decay_peak[i] *= falloff;
474
        GST_LOG_OBJECT (filter,
475 476 477
            "peak is %" GST_TIME_FORMAT " old, decayed with factor %e to %f",
            GST_TIME_ARGS (filter->decay_peak_age[i]), falloff,
            filter->decay_peak[i]);
478 479
      } else {
        GST_LOG_OBJECT (filter, "peak not old enough, not decaying");
480 481 482
      }
    }
  }
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
483

484
  /* do we need to emit ? */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
485

486 487
  if (filter->num_frames >=
      (gint) ((gdouble) filter->interval / GST_SECOND * filter->rate)) {
488
    if (filter->message) {
489
      GstMessage *m;
490 491
      GstClockTime endtime;
      double RMS;
492
      double RMSdB, lastdB, decaydB;
493

494
      /* FIXME: convert to a GstClockTime instead */
495 496
      endtime = GST_BUFFER_TIMESTAMP (in)
          + GST_FRAMES_TO_CLOCK_TIME (num_frames, filter->rate);
497 498

      m = gst_level_message_new (filter, endtime);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
499 500

      for (i = 0; i < filter->channels; ++i) {
501
        RMS = sqrt (filter->CS[i] / filter->num_frames);
502
        GST_LOG_OBJECT (filter,
503 504
            "CS: %f, num_frames %d, channel %d, RMS %f",
            filter->CS[i], filter->num_frames, i, RMS);
505 506 507 508 509 510 511
        /* RMS values are calculated in amplitude, so 20 * log 10 */
        RMSdB = 20 * log10 (RMS);
        /* peak values are square sums, ie. power, so 10 * log 10 */
        lastdB = 10 * log10 (filter->last_peak[i]);
        decaydB = 10 * log10 (filter->decay_peak[i]);

        GST_LOG_OBJECT (filter,
512 513 514
            "time %" GST_TIME_FORMAT
            ", channel %d, RMS %f dB, peak %f dB, decay %f dB",
            GST_TIME_ARGS (endtime), i, RMSdB, lastdB, decaydB);
515 516

        gst_level_message_append_channel (m, RMSdB, lastdB, decaydB);
517 518

        /* reset cumulative and normal peak */
519 520
        filter->CS[i] = 0.0;
        filter->last_peak[i] = 0.0;
521
      }
522 523

      gst_element_post_message (GST_ELEMENT (filter), m);
524
    }
525
    filter->num_frames = 0;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
526 527
  }

528
  return GST_FLOW_OK;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
529 530
}

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
531
static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
532
plugin_init (GstPlugin * plugin)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
533
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
534
  return gst_element_register (plugin, "level", GST_RANK_NONE, GST_TYPE_LEVEL);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
535 536
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
537 538 539 540 541
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
    GST_VERSION_MINOR,
    "level",
    "Audio level plugin",
    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)