rganalysis: Add ability to post level messages
authorGabriel Bouvigne <bouvigne@mp3-tech.org>
Thu, 7 May 2009 14:25:41 +0000 (16:25 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Thu, 7 May 2009 14:25:41 +0000 (16:25 +0200)
Fixes bug #581568.

gst/replaygain/gstrganalysis.c
gst/replaygain/gstrganalysis.h
gst/replaygain/rganalysis.c
gst/replaygain/rganalysis.h

index 982c8a7f4127220655ad1874b21a695ac51bb0d3..1c6d1e84caedd05ad8825f63a37ab11782559b51 100644 (file)
@@ -95,13 +95,15 @@ static const GstElementDetails rganalysis_details = {
 
 /* Default property value. */
 #define FORCED_DEFAULT TRUE
+#define DEFAULT_MESSAGE FALSE
 
 enum
 {
   PROP_0,
   PROP_NUM_TRACKS,
   PROP_FORCED,
-  PROP_REFERENCE_LEVEL
+  PROP_REFERENCE_LEVEL,
+  PROP_MESSAGE
 };
 
 /* The ReplayGain algorithm is intended for use with mono and stereo
@@ -272,6 +274,11 @@ gst_rg_analysis_class_init (GstRgAnalysisClass * klass)
           "Reference level [dB]", 0.0, 150., RG_REFERENCE_LEVEL,
           G_PARAM_READWRITE));
 
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MESSAGE,
+      g_param_spec_boolean ("message", "Message",
+          "Post statics messages",
+          DEFAULT_MESSAGE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
   trans_class = (GstBaseTransformClass *) klass;
   trans_class->start = GST_DEBUG_FUNCPTR (gst_rg_analysis_start);
   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_rg_analysis_set_caps);
@@ -290,6 +297,7 @@ gst_rg_analysis_init (GstRgAnalysis * filter, GstRgAnalysisClass * gclass)
 
   filter->num_tracks = 0;
   filter->forced = FORCED_DEFAULT;
+  filter->message = DEFAULT_MESSAGE;
   filter->reference_level = RG_REFERENCE_LEVEL;
 
   filter->ctx = NULL;
@@ -302,6 +310,7 @@ gst_rg_analysis_set_property (GObject * object, guint prop_id,
 {
   GstRgAnalysis *filter = GST_RG_ANALYSIS (object);
 
+  GST_OBJECT_LOCK (filter);
   switch (prop_id) {
     case PROP_NUM_TRACKS:
       filter->num_tracks = g_value_get_int (value);
@@ -312,10 +321,14 @@ gst_rg_analysis_set_property (GObject * object, guint prop_id,
     case PROP_REFERENCE_LEVEL:
       filter->reference_level = g_value_get_double (value);
       break;
+    case PROP_MESSAGE:
+      filter->message = g_value_get_boolean (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
   }
+  GST_OBJECT_UNLOCK (filter);
 }
 
 static void
@@ -324,6 +337,7 @@ gst_rg_analysis_get_property (GObject * object, guint prop_id,
 {
   GstRgAnalysis *filter = GST_RG_ANALYSIS (object);
 
+  GST_OBJECT_LOCK (filter);
   switch (prop_id) {
     case PROP_NUM_TRACKS:
       g_value_set_int (value, filter->num_tracks);
@@ -334,12 +348,35 @@ gst_rg_analysis_get_property (GObject * object, guint prop_id,
     case PROP_REFERENCE_LEVEL:
       g_value_set_double (value, filter->reference_level);
       break;
+    case PROP_MESSAGE:
+      g_value_set_boolean (value, filter->message);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
   }
+  GST_OBJECT_UNLOCK (filter);
 }
 
+static void
+gst_rg_analysis_post_message (gpointer rganalysis, GstClockTime timestamp,
+    GstClockTime duration, gdouble rglevel)
+{
+  GstRgAnalysis *filter = GST_RG_ANALYSIS (rganalysis);
+  if (filter->message) {
+    GstMessage *m;
+
+    m = gst_message_new_element (GST_OBJECT_CAST (rganalysis),
+        gst_structure_new ("rganalysis",
+            "timestamp", G_TYPE_UINT64, timestamp,
+            "duration", G_TYPE_UINT64, duration,
+            "rglevel", G_TYPE_DOUBLE, rglevel, NULL));
+
+    gst_element_post_message (GST_ELEMENT_CAST (rganalysis), m);
+  }
+}
+
+
 static gboolean
 gst_rg_analysis_start (GstBaseTransform * base)
 {
@@ -353,6 +390,10 @@ gst_rg_analysis_start (GstBaseTransform * base)
   filter->has_album_peak = FALSE;
 
   filter->ctx = rg_analysis_new ();
+  GST_OBJECT_LOCK (filter);
+  rg_analysis_init_silence_detection (filter->ctx, gst_rg_analysis_post_message,
+      filter);
+  GST_OBJECT_UNLOCK (filter);
   filter->analyze = NULL;
 
   GST_LOG_OBJECT (filter, "started");
@@ -452,13 +493,10 @@ gst_rg_analysis_transform_ip (GstBaseTransform * base, GstBuffer * buf)
   if (filter->skip)
     return GST_FLOW_OK;
 
-  /* Buffers made up of silence have no influence on the analysis: */
-  if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP))
-    return GST_FLOW_OK;
-
   GST_LOG_OBJECT (filter, "processing buffer of size %u",
       GST_BUFFER_SIZE (buf));
 
+  rg_analysis_start_buffer (filter->ctx, GST_BUFFER_TIMESTAMP (buf));
   filter->analyze (filter->ctx, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
       filter->depth);
 
index fbf46830a3965d73c802bdc3669d57a56a20d6c4..0d68e6309b0ec057750f2b1742187d2524a2a086 100644 (file)
@@ -63,6 +63,7 @@ struct _GstRgAnalysis
   guint num_tracks;
   gdouble reference_level;
   gboolean forced;
+  gboolean message;
 
   /* State machinery for skipping. */
   gboolean ignore_tags;
index 147eef85d32b7d713fc6216212d2d57a9d40abdd..9787c6884e8dff7f69581bec6b4f058d33870998 100644 (file)
@@ -109,6 +109,14 @@ struct _RgAnalysisCtx
 
   RgAnalysisAcc track;
   RgAnalysisAcc album;
+  void (*post_message) (gpointer analysis,
+      GstClockTime timestamp, GstClockTime duration, gdouble rglevel);
+  gpointer analysis;
+  /* The timestamp of the current incoming buffer. */
+  GstClockTime buffer_timestamp;
+  /* Number of samples processed in current buffer, during emit_signal,
+     this will always be on an RMS window boundary. */
+  guint buffer_n_samples_done;
 };
 
 /* Filter coefficients for the IIR filters that form the equal
@@ -406,6 +414,13 @@ rg_analysis_new (void)
   return ctx;
 }
 
+static void
+reset_silence_detection (RgAnalysisCtx * ctx)
+{
+  ctx->buffer_timestamp = GST_CLOCK_TIME_NONE;
+  ctx->buffer_n_samples_done = 0;
+}
+
 /* Adapt to given sample rate.  Does nothing if already the current
  * rate (returns TRUE then).  Returns FALSE only if given sample rate
  * is not supported.  If the configured rate changes, the last
@@ -458,10 +473,28 @@ rg_analysis_set_sample_rate (RgAnalysisCtx * ctx, gint sample_rate)
       / 1000);
 
   reset_filters (ctx);
+  reset_silence_detection (ctx);
 
   return TRUE;
 }
 
+void
+rg_analysis_init_silence_detection (RgAnalysisCtx * ctx,
+    void (*post_message) (gpointer analysis, GstClockTime timestamp,
+        GstClockTime duration, gdouble rglevel), gpointer analysis)
+{
+  ctx->post_message = post_message;
+  ctx->analysis = analysis;
+  reset_silence_detection (ctx);
+}
+
+void
+rg_analysis_start_buffer (RgAnalysisCtx * ctx, GstClockTime buffer_timestamp)
+{
+  ctx->buffer_timestamp = buffer_timestamp;
+  ctx->buffer_n_samples_done = 0;
+}
+
 void
 rg_analysis_destroy (RgAnalysisCtx * ctx)
 {
@@ -665,6 +698,7 @@ rg_analysis_analyze (RgAnalysisCtx * ctx, const gfloat * samples_l,
           * ctx->out_r[ctx->window_n_samples_done + i];
 
     ctx->window_n_samples_done += n_samples_current;
+    ctx->buffer_n_samples_done += n_samples_current;
 
     g_return_if_fail (ctx->window_n_samples_done <= ctx->window_n_samples);
 
@@ -674,6 +708,15 @@ rg_analysis_analyze (RgAnalysisCtx * ctx, const gfloat * samples_l,
           ctx->window_n_samples * 0.5 + 1.e-37);
       gint ival = CLAMP ((gint) val, 0,
           (gint) G_N_ELEMENTS (ctx->track.histogram) - 1);
+      /* Compute the per-window gain */
+      const gdouble gain = PINK_REF - (gdouble) ival / STEPS_PER_DB;
+      const GstClockTime timestamp = (ctx->buffer_timestamp
+          + ctx->buffer_n_samples_done * GST_SECOND / ctx->sample_rate
+          - RMS_WINDOW_MSECS * GST_MSECOND);
+
+      ctx->post_message (ctx->analysis, timestamp,
+          RMS_WINDOW_MSECS * GST_MSECOND, -gain);
+
 
       ctx->track.histogram[ival]++;
       ctx->window_square_sum = 0.;
@@ -736,6 +779,7 @@ rg_analysis_track_result (RgAnalysisCtx * ctx, gdouble * gain, gdouble * peak)
   accumulator_clear (&ctx->track);
 
   reset_filters (ctx);
+  reset_silence_detection (ctx);
 
   return result;
 }
@@ -774,4 +818,5 @@ rg_analysis_reset (RgAnalysisCtx * ctx)
   reset_filters (ctx);
   accumulator_clear (&ctx->track);
   accumulator_clear (&ctx->album);
+  reset_silence_detection (ctx);
 }
index 16247361a3062d41bd1b2f992c6d3baa6f6b695e..f57ad0a34435359300b7d5b781196d57ca3ac909 100644 (file)
@@ -26,6 +26,7 @@
 #define __RG_ANALYSIS_H__
 
 #include <glib.h>
+#include <gst/gst.h>
 
 G_BEGIN_DECLS
 
@@ -47,6 +48,12 @@ gboolean rg_analysis_track_result (RgAnalysisCtx * ctx, gdouble * gain,
     gdouble * peak);
 gboolean rg_analysis_album_result (RgAnalysisCtx * ctx, gdouble * gain,
     gdouble * peak);
+void rg_analysis_init_silence_detection (
+    RgAnalysisCtx * ctx,
+    void (*post_message) (gpointer analysis, GstClockTime timestamp, GstClockTime duration, gdouble rglevel),
+    gpointer analysis);
+void rg_analysis_start_buffer (RgAnalysisCtx * ctx,
+                               GstClockTime buffer_timestamp);
 void rg_analysis_reset_album (RgAnalysisCtx * ctx);
 void rg_analysis_reset (RgAnalysisCtx * ctx);
 void rg_analysis_destroy (RgAnalysisCtx * ctx);