From 3e0f1b84a4af33ef90da5f0f039f8f2c2cd62e81 Mon Sep 17 00:00:00 2001 From: Gabriel Bouvigne Date: Thu, 7 May 2009 16:25:41 +0200 Subject: [PATCH] rganalysis: Add ability to post level messages Fixes bug #581568. --- gst/replaygain/gstrganalysis.c | 48 +++++++++++++++++++++++++++++++++++++----- gst/replaygain/gstrganalysis.h | 1 + gst/replaygain/rganalysis.c | 45 +++++++++++++++++++++++++++++++++++++++ gst/replaygain/rganalysis.h | 7 ++++++ 4 files changed, 96 insertions(+), 5 deletions(-) diff --git a/gst/replaygain/gstrganalysis.c b/gst/replaygain/gstrganalysis.c index 982c8a7..1c6d1e8 100644 --- a/gst/replaygain/gstrganalysis.c +++ b/gst/replaygain/gstrganalysis.c @@ -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); diff --git a/gst/replaygain/gstrganalysis.h b/gst/replaygain/gstrganalysis.h index fbf4683..0d68e63 100644 --- a/gst/replaygain/gstrganalysis.h +++ b/gst/replaygain/gstrganalysis.h @@ -63,6 +63,7 @@ struct _GstRgAnalysis guint num_tracks; gdouble reference_level; gboolean forced; + gboolean message; /* State machinery for skipping. */ gboolean ignore_tags; diff --git a/gst/replaygain/rganalysis.c b/gst/replaygain/rganalysis.c index 147eef8..9787c68 100644 --- a/gst/replaygain/rganalysis.c +++ b/gst/replaygain/rganalysis.c @@ -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,11 +473,29 @@ 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) { g_free (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); } diff --git a/gst/replaygain/rganalysis.h b/gst/replaygain/rganalysis.h index 1624736..f57ad0a 100644 --- a/gst/replaygain/rganalysis.h +++ b/gst/replaygain/rganalysis.h @@ -26,6 +26,7 @@ #define __RG_ANALYSIS_H__ #include +#include 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); -- 2.7.4