]> code.delx.au - pulseaudio/blobdiff - src/modules/module-virtual-surround-sink.c
virtual-surround-sink: Move normalization heuristic to its own function
[pulseaudio] / src / modules / module-virtual-surround-sink.c
index bcca8d0f45873abe9c96c08209510c9c7ff3fd65..34f23fd21b78e817c6851d513c0ba2076b82f053 100644 (file)
@@ -48,7 +48,7 @@
 PA_MODULE_AUTHOR("Niels Ole Salscheider");
 PA_MODULE_DESCRIPTION(_("Virtual surround sink"));
 PA_MODULE_VERSION(PACKAGE_VERSION);
-PA_MODULE_LOAD_ONCE(FALSE);
+PA_MODULE_LOAD_ONCE(false);
 PA_MODULE_USAGE(
         _("sink_name=<name for the sink> "
           "sink_properties=<properties for the sink> "
@@ -68,14 +68,14 @@ struct userdata {
     pa_module *module;
 
     /* FIXME: Uncomment this and take "autoloaded" as a modarg if this is a filter */
-    /* pa_bool_t autoloaded; */
+    /* bool autoloaded; */
 
     pa_sink *sink;
     pa_sink_input *sink_input;
 
     pa_memblockq *memblockq;
 
-    pa_bool_t auto_desc;
+    bool auto_desc;
     unsigned channels;
     unsigned hrir_channels;
 
@@ -165,7 +165,7 @@ static void sink_request_rewind_cb(pa_sink *s) {
     /* Just hand this one over to the master sink */
     pa_sink_input_request_rewind(u->sink_input,
                                  s->thread_info.rewind_nbytes +
-                                 pa_memblockq_get_length(u->memblockq), TRUE, FALSE, FALSE);
+                                 pa_memblockq_get_length(u->memblockq), true, false, false);
 }
 
 /* Called from I/O thread context */
@@ -196,7 +196,7 @@ static void sink_set_volume_cb(pa_sink *s) {
         !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
         return;
 
-    pa_sink_input_set_volume(u->sink_input, &s->real_volume, s->save_volume, TRUE);
+    pa_sink_input_set_volume(u->sink_input, &s->real_volume, s->save_volume, true);
 }
 
 /* Called from main context */
@@ -303,7 +303,7 @@ static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
         u->sink->thread_info.rewind_nbytes = 0;
 
         if (amount > 0) {
-            pa_memblockq_seek(u->memblockq, - (int64_t) amount, PA_SEEK_RELATIVE, TRUE);
+            pa_memblockq_seek(u->memblockq, - (int64_t) amount, PA_SEEK_RELATIVE, true);
 
             /* Reset the input buffer */
             memset(u->input_buffer, 0, u->hrir_samples * u->sink_fs);
@@ -410,7 +410,7 @@ static void sink_input_kill_cb(pa_sink_input *i) {
     pa_sink_unref(u->sink);
     u->sink = NULL;
 
-    pa_module_unload_request(u->module, TRUE);
+    pa_module_unload_request(u->module, true);
 }
 
 /* Called from IO thread context */
@@ -425,7 +425,7 @@ static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t s
     if (PA_SINK_INPUT_IS_LINKED(state) &&
         i->thread_info.state == PA_SINK_INPUT_INIT) {
         pa_log_debug("Requesting rewind due to state change.");
-        pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
+        pa_sink_input_request_rewind(i, 0, false, true, true);
     }
 }
 
@@ -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;
@@ -527,13 +566,12 @@ int pa__init(pa_module*m) {
     pa_sink *master=NULL;
     pa_sink_input_new_data sink_input_data;
     pa_sink_new_data sink_data;
-    pa_bool_t use_volume_sharing = TRUE;
-    pa_bool_t force_flat_volume = FALSE;
+    bool use_volume_sharing = true;
+    bool force_flat_volume = false;
     pa_memchunk silence;
 
     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;
@@ -568,8 +606,6 @@ int pa__init(pa_module*m) {
 
     /* Initialize hrir and input buffer */
     /* this is the hrir file for the left ear! */
-    hrir_file = pa_modargs_get_value(ma, "hrir", NULL);
-
     if (!(hrir_file = pa_modargs_get_value(ma, "hrir", NULL))) {
         pa_log("The mandatory 'hrir' module argument is missing.");
         goto fail;
@@ -661,7 +697,7 @@ int pa__init(pa_module*m) {
     pa_sink_set_set_mute_callback(u->sink, sink_set_mute_cb);
     if (!use_volume_sharing) {
         pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
-        pa_sink_enable_decibel_volume(u->sink, TRUE);
+        pa_sink_enable_decibel_volume(u->sink, true);
     }
     /* Normally this flag would be enabled automatically be we can force it. */
     if (force_flat_volume)
@@ -674,7 +710,7 @@ int pa__init(pa_module*m) {
     pa_sink_input_new_data_init(&sink_input_data);
     sink_input_data.driver = __FILE__;
     sink_input_data.module = m;
-    pa_sink_input_new_data_set_sink(&sink_input_data, master, FALSE);
+    pa_sink_input_new_data_set_sink(&sink_input_data, master, false);
     sink_input_data.origin_sink = u->sink;
     pa_proplist_setf(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Virtual Surround Sink Stream from %s", pa_proplist_gets(u->sink->proplist, PA_PROP_DEVICE_DESCRIPTION));
     pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
@@ -760,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);