]> code.delx.au - pulseaudio/commitdiff
virtual-surround-sink: Move normalization heuristic to its own function
authorNiels Ole Salscheider <niels_ole@salscheider-online.de>
Wed, 2 Apr 2014 20:32:34 +0000 (22:32 +0200)
committerTanu Kaskinen <tanu.kaskinen@linux.intel.com>
Thu, 17 Apr 2014 07:46:26 +0000 (10:46 +0300)
This patch also adds a description how the heuristic works and mentions that
there is a scaling factor that can be adjusted if there is audible clipping.

src/modules/module-virtual-surround-sink.c

index 1d6cfc699de89b17c8994b07d5de0d127ec4b528..34f23fd21b78e817c6851d513c0ba2076b82f053 100644 (file)
@@ -519,6 +519,45 @@ static pa_channel_position_t mirror_channel(pa_channel_position_t channel) {
     }
 }
 
+static void normalize_hrir(struct userdata *u) {
+    /* normalize hrir to avoid audible clipping
+     *
+     * The following heuristic tries to avoid audible clipping. It cannot avoid
+     * clipping in the worst case though, because the scaling factor would
+     * become too large resulting in a too quiet signal.
+     * The idea of the heuristic is to avoid clipping when a single click is
+     * played back on all channels. The scaling factor describes the additional
+     * factor that is necessary to avoid clipping for "normal" signals.
+     *
+     * This algorithm doesn't pretend to be perfect, it's just something that
+     * appears to work (not too quiet, no audible clipping) on the material that
+     * it has been tested on. If you find a real-world example where this
+     * algorithm results in audible clipping, please write a patch that adjusts
+     * the scaling factor constants or improves the algorithm (or if you can't
+     * write a patch, at least report the problem to the PulseAudio mailing list
+     * or bug tracker). */
+
+    const float scaling_factor = 2.5;
+
+    float hrir_sum, hrir_max;
+    unsigned i, j;
+
+    hrir_max = 0;
+    for (i = 0; i < u->hrir_samples; i++) {
+        hrir_sum = 0;
+        for (j = 0; j < u->hrir_channels; j++)
+            hrir_sum += fabs(u->hrir_data[i * u->hrir_channels + j]);
+
+        if (hrir_sum > hrir_max)
+            hrir_max = hrir_sum;
+    }
+
+    for (i = 0; i < u->hrir_samples; i++) {
+        for (j = 0; j < u->hrir_channels; j++)
+            u->hrir_data[i * u->hrir_channels + j] /= hrir_max * scaling_factor;
+    }
+}
+
 int pa__init(pa_module*m) {
     struct userdata *u;
     pa_sample_spec ss, sink_input_ss;
@@ -533,7 +572,6 @@ int pa__init(pa_module*m) {
 
     const char *hrir_file;
     unsigned i, j, found_channel_left, found_channel_right;
-    float hrir_sum, hrir_max;
     float *hrir_data;
 
     pa_sample_spec hrir_ss;
@@ -758,22 +796,7 @@ int pa__init(pa_module*m) {
         goto fail;
     }
 
-    /* normalize hrir to avoid clipping */
-    hrir_max = 0;
-    for (i = 0; i < u->hrir_samples; i++) {
-        hrir_sum = 0;
-        for (j = 0; j < u->hrir_channels; j++)
-            hrir_sum += fabs(u->hrir_data[i * u->hrir_channels + j]);
-
-        if (hrir_sum > hrir_max)
-            hrir_max = hrir_sum;
-    }
-    if (hrir_max > 1) {
-        for (i = 0; i < u->hrir_samples; i++) {
-            for (j = 0; j < u->hrir_channels; j++)
-                u->hrir_data[i * u->hrir_channels + j] /= hrir_max * 1.2;
-        }
-    }
+    normalize_hrir(u);
 
     /* create mapping between hrir and input */
     u->mapping_left = (unsigned *) pa_xnew0(unsigned, u->channels);