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
* loudness filter. XFilter[ctx->sample_rate_index] gives the array
* of the X coefficients (A or B) for the configured sample rate. */
-#ifdef G_OS_WIN32
+#ifdef _MSC_VER
/* Disable double-to-float warning: */
+/* A better solution would be to append 'f' to each constant, but that
+ * makes the code ugly. */
#pragma warning ( disable : 4305 )
#endif
{0.94597685600279, -1.89195371200558, 0.94597685600279}
};
-#ifdef G_OS_WIN32
+#ifdef _MSC_VER
#pragma warning ( default : 4305 )
#endif
yule_filter (const gfloat * input, gfloat * output,
const gfloat * a, const gfloat * b)
{
- output[0] = input[0] * b[0]
+ /* 1e-10 is added below to avoid running into denormals when operating on
+ * near silence. */
+
+ output[0] = 1e-10 + input[0] * b[0]
+ input[-1] * b[1] - output[-1] * a[1]
+ input[-2] * b[2] - output[-2] * a[2]
+ input[-3] * b[3] - output[-3] * a[3]
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
/ 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);
gint32 peak_sample = 0;
const gint16 *samples = (gint16 *) data;
guint n_samples = size / sizeof (gint16);
- gint shift = sizeof (gint16) * 8 - depth;
+ gint shift = 1 << (sizeof (gint16) * 8 - depth);
gint i;
g_return_if_fail (depth <= (sizeof (gint16) * 8));
n_samples -= n;
for (i = 0; i < n; i++) {
- gint16 old_sample = samples[i] << shift;
+ gint16 old_sample = samples[i] * shift;
peak_sample = MAX (peak_sample, ABS ((gint32) old_sample));
conv_samples[i] = (gfloat) old_sample;
gint32 peak_sample = 0;
const gint16 *samples = (gint16 *) data;
guint n_frames = size / (sizeof (gint16) * 2);
- gint shift = sizeof (gint16) * 8 - depth;
+ gint shift = 1 << (sizeof (gint16) * 8 - depth);
gint i;
g_return_if_fail (depth <= (sizeof (gint16) * 8));
for (i = 0; i < n; i++) {
gint16 old_sample;
- old_sample = samples[2 * i] << shift;
+ old_sample = samples[2 * i] * shift;
peak_sample = MAX (peak_sample, ABS ((gint32) old_sample));
conv_samples_l[i] = (gfloat) old_sample;
- old_sample = samples[2 * i + 1] << shift;
+ old_sample = samples[2 * i + 1] * shift;
peak_sample = MAX (peak_sample, ABS ((gint32) old_sample));
conv_samples_r[i] = (gfloat) old_sample;
}
* 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);
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
+ + gst_util_uint64_scale_int_ceil (GST_SECOND,
+ ctx->buffer_n_samples_done,
+ 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.;
accumulator_clear (&ctx->track);
reset_filters (ctx);
+ reset_silence_detection (ctx);
return result;
}
reset_filters (ctx);
accumulator_clear (&ctx->track);
accumulator_clear (&ctx->album);
+ reset_silence_detection (ctx);
}