[pulseaudio-discuss] [PATCH 2/2] volume: Add LFE balance API

David Henningsson david.henningsson at canonical.com
Fri Sep 18 05:47:23 PDT 2015


The gnome/unity-control-center UIs have a master volume slider, and
three sub-sliders: balance, fade, and subwoofer. Balance and fade
use PA's set_balance and set_fade APIs accordingly, but the subwoofer
slider sometimes does unintuitive things.

In order to make that slider behave better, let's add a LFE balance
API that these volume control UIs can use instead. With this API,
the UI can balance between "no subwoofer" and "only subwoofer" with
"equal balance" in the middle, which would make it more consistent
with the behaviour of the other sliders.

BugLink: https://bugzilla.gnome.org/show_bug.cgi?id=753847

Signed-off-by: David Henningsson <david.henningsson at canonical.com>
---
 src/map-file           |  3 +++
 src/pulse/channelmap.c | 13 +++++++++++++
 src/pulse/channelmap.h |  5 +++++
 src/pulse/volume.c     | 40 ++++++++++++++++++++++++++++++++++++++++
 src/pulse/volume.h     | 18 ++++++++++++++++++
 5 files changed, 79 insertions(+)

diff --git a/src/map-file b/src/map-file
index 5159829..93a62b8 100644
--- a/src/map-file
+++ b/src/map-file
@@ -7,6 +7,7 @@ pa_bytes_snprint;
 pa_bytes_to_usec;
 pa_channel_map_can_balance;
 pa_channel_map_can_fade;
+pa_channel_map_can_lfe_balance;
 pa_channel_map_compatible;
 pa_channel_map_equal;
 pa_channel_map_has_position;
@@ -127,6 +128,7 @@ pa_cvolume_dec;
 pa_cvolume_equal;
 pa_cvolume_get_balance;
 pa_cvolume_get_fade;
+pa_cvolume_get_lfe_balance;
 pa_cvolume_get_position;
 pa_cvolume_inc;
 pa_cvolume_inc_clamp;
@@ -142,6 +144,7 @@ pa_cvolume_scale_mask;
 pa_cvolume_set;
 pa_cvolume_set_balance;
 pa_cvolume_set_fade;
+pa_cvolume_set_lfe_balance;
 pa_cvolume_set_position;
 pa_cvolume_snprint;
 pa_cvolume_snprint_verbose;
diff --git a/src/pulse/channelmap.c b/src/pulse/channelmap.c
index c342ef6..ab343bc 100644
--- a/src/pulse/channelmap.c
+++ b/src/pulse/channelmap.c
@@ -684,6 +684,19 @@ int pa_channel_map_can_fade(const pa_channel_map *map) {
         (PA_CHANNEL_POSITION_MASK_REAR & m);
 }
 
+int pa_channel_map_can_lfe_balance(const pa_channel_map *map) {
+    pa_channel_position_mask_t l, m;
+
+    pa_assert(map);
+    pa_return_val_if_fail(pa_channel_map_valid(map), 0);
+
+    m = pa_channel_map_mask(map);
+    l = PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_LFE);
+
+    return
+        (l & m) && ((~l) & m);
+}
+
 const char* pa_channel_map_to_name(const pa_channel_map *map) {
     pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
     unsigned c;
diff --git a/src/pulse/channelmap.h b/src/pulse/channelmap.h
index 30904ef..6eabe20 100644
--- a/src/pulse/channelmap.h
+++ b/src/pulse/channelmap.h
@@ -338,6 +338,11 @@ int pa_channel_map_can_balance(const pa_channel_map *map) PA_GCC_PURE;
  * there are front/rear channels available. \since 0.9.15 */
 int pa_channel_map_can_fade(const pa_channel_map *map) PA_GCC_PURE;
 
+/** Returns non-zero if it makes sense to apply a volume 'lfe balance'
+ * (i.e.\ 'balance' between LFE and non-LFE channels) with this mapping,
+ *  i.e.\ if there are LFE and non-LFE channels available. \since 8.0 */
+int pa_channel_map_can_lfe_balance(const pa_channel_map *map) PA_GCC_PURE;
+
 /** Tries to find a well-known channel mapping name for this channel
  * mapping, i.e.\ "stereo", "surround-71" and so on. If the channel
  * mapping is unknown NULL will be returned. This name can be parsed
diff --git a/src/pulse/volume.c b/src/pulse/volume.c
index 2b34ded..91906be 100644
--- a/src/pulse/volume.c
+++ b/src/pulse/volume.c
@@ -552,6 +552,10 @@ static bool on_center(pa_channel_position_t p) {
     return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_CENTER);
 }
 
+static bool on_hfe(pa_channel_position_t p) {
+    return !(p == PA_CHANNEL_POSITION_LFE);
+}
+
 static bool on_lfe(pa_channel_position_t p) {
     return p == PA_CHANNEL_POSITION_LFE;
 }
@@ -829,6 +833,42 @@ pa_cvolume* pa_cvolume_set_fade(pa_cvolume *v, const pa_channel_map *map, float
     return set_balance(v, map, new_fade, on_rear, on_front);
 }
 
+float pa_cvolume_get_lfe_balance(const pa_cvolume *v, const pa_channel_map *map) {
+    pa_volume_t hfe, lfe;
+
+    pa_assert(v);
+    pa_assert(map);
+
+    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f);
+
+    if (!pa_channel_map_can_lfe_balance(map))
+        return 0.0f;
+
+    get_avg(map, v, &hfe, &lfe, on_hfe, on_lfe);
+
+    if (hfe == lfe)
+        return 0.0f;
+
+    if (hfe > lfe)
+        return -1.0f + ((float) lfe / (float) hfe);
+    else
+        return 1.0f - ((float) hfe / (float) lfe);
+}
+
+pa_cvolume* pa_cvolume_set_lfe_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance) {
+    pa_assert(map);
+    pa_assert(v);
+
+    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL);
+    pa_return_val_if_fail(new_balance >= -1.0f, NULL);
+    pa_return_val_if_fail(new_balance <= 1.0f, NULL);
+
+    if (!pa_channel_map_can_lfe_balance(map))
+        return v;
+
+    return set_balance(v, map, new_balance, on_hfe, on_lfe);
+}
+
 pa_cvolume* pa_cvolume_set_position(
         pa_cvolume *cv,
         const pa_channel_map *map,
diff --git a/src/pulse/volume.h b/src/pulse/volume.h
index ec777b2..d749dda 100644
--- a/src/pulse/volume.h
+++ b/src/pulse/volume.h
@@ -372,6 +372,24 @@ float pa_cvolume_get_fade(const pa_cvolume *v, const pa_channel_map *map) PA_GCC
  * pa_channel_map_can_fade(). \since 0.9.15 */
 pa_cvolume* pa_cvolume_set_fade(pa_cvolume *v, const pa_channel_map *map, float new_fade);
 
+/** Calculate a 'lfe balance' value for the specified volume with
+ * the specified channel map. The return value will range from
+ * -1.0f (no lfe) to +1.0f (only lfe), where 0.0f is balanced.
+ * If no value is applicable to this channel map the return value
+ * will always be 0.0f. See pa_channel_map_can_fade(). \since 8.0 */
+float pa_cvolume_get_lfe_balance(const pa_cvolume *v, const pa_channel_map *map) PA_GCC_PURE;
+
+/** Adjust the 'lfe balance' value for the specified volume with
+ * the specified channel map. v will be modified in place and returned.
+ * The balance is a value between -1.0f (no lfe) and +1.0f (only lfe).
+ * This operation might not be reversible! Also, after this call
+ * pa_cvolume_get_lfe_balance() is not guaranteed to actually
+ * return the requested value (e.g. when the input volume was
+ * zero anyway for all channels). If no lfe balance value is applicable to
+ * this channel map the volume will not be modified. See
+ * pa_channel_map_can_lfe_balance(). \since 8.0 */
+pa_cvolume* pa_cvolume_set_lfe_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance);
+
 /** Scale the passed pa_cvolume structure so that the maximum volume
  * of all channels equals max. The proportions between the channel
  * volumes are kept. \since 0.9.15 */
-- 
1.9.1



More information about the pulseaudio-discuss mailing list