]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Add the option to use a flat volume control profile.
authorMike Brady <mikebrady@eircom.net>
Mon, 29 Jan 2018 22:28:22 +0000 (22:28 +0000)
committerMike Brady <mikebrady@eircom.net>
Mon, 29 Jan 2018 22:28:22 +0000 (22:28 +0000)
audio_alsa.c
common.c
common.h
player.c
scripts/shairport-sync.conf
shairport.c

index 3315ed970830490d20b388f1f878e2d9b9746a02..977e2517eb4188e7deb1ba0b36a0624fbfc19320 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * libalsa output driver. This file is part of Shairport.
  * Copyright (c) Muffinman, Skaman 2013
+ * Copyright (c) Mike Brady 2014 -- 2018
  * All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person
index f2d714d9227781649fe5e6f1f8cdf5f1f6a58a87..dd12d6cd24cefb40f399770f0dcec3e87166314d 100644 (file)
--- a/common.c
+++ b/common.c
@@ -664,6 +664,19 @@ uint32_t uatoi(const char *nptr) {
   return r;
 }
 
+
+double flat_vol2attn(double vol, long max_db, long min_db) {
+  double vol_setting = min_db;
+
+  if ((vol <= 0.0) && (vol >= -30.0)) {
+    vol_setting = ((max_db - min_db)*(30.0+vol)/30)+min_db;
+    debug(2,"Linear Volume Setting: %f in range %ld to %ld.",vol_setting,min_db,max_db);
+  } else if (vol != -144.0) {
+    debug(1, "Linear volume request value %f is out of range: should be from 0.0 to -30.0 or -144.0.",
+          vol);
+  }
+  return vol_setting;
+}
 // Given a volume (0 to -30) and high and low attenuations available in the mixer in dB, return an
 // attenuation depending on the volume and the function's transfer function
 // See http://tangentsoft.net/audio/atten.html for data on good attenuators.
@@ -725,6 +738,7 @@ double vol2attn(double vol, long max_db, long min_db) {
     vol_setting = min_db; // for safety, return the lowest setting...
   }
   // debug(1,"returning an attenuation of %f.",vol_setting);
+  debug(2,"Standard profile Volume Setting for Airplay vol %f: %f in range %ld to %ld.",vol,vol_setting,min_db,max_db);
   return vol_setting;
 }
 
index 86ea7dc17bc0ae74fa66c6b64727b319c71c740f..e36aae9a4b6690dd7a1f955c875512a7b846ecbd 100644 (file)
--- a/common.h
+++ b/common.h
@@ -61,6 +61,11 @@ enum playback_mode_type {
   ST_right_only,
 } playback_mode_type;
 
+enum volume_control_profile_type {
+  VCP_standard = 0,
+  VCP_flat,
+} volume_control_profile_type;
+
 enum decoders_supported_type {
   decoder_hammerton = 0,
   decoder_apple_alac,
@@ -157,6 +162,7 @@ typedef struct {
   uint32_t volume_range_db; // the range, in dB, from max dB to min dB. Zero means use the mixer's
                             // native range.
   enum sps_format_t output_format;
+  enum volume_control_profile_type volume_control_profile;
   int output_rate;
 
 #ifdef CONFIG_CONVOLUTION
@@ -219,6 +225,10 @@ char *base64_enc(uint8_t *input, int length);
 #define RSA_MODE_KEY (1)
 uint8_t *rsa_apply(uint8_t *input, int inlen, int *outlen, int mode);
 
+// given a volume (0 to -30) and high and low attenuations in dB*100 (e.g. 0 to -6000 for 0 to -60
+// dB), return an attenuation depending on a linear interpolation along along the range
+double flat_vol2attn(double vol, long max_db, long min_db);
+
 // given a volume (0 to -30) and high and low attenuations in dB*100 (e.g. 0 to -6000 for 0 to -60
 // dB), return an attenuation depending on the transfer function
 double vol2attn(double vol, long max_db, long min_db);
index 459a90f6a7015b0b22e448bbf58fcfbb1d8a10d5..790ced474ac9b7edd749cf2a7903e424da330731 100644 (file)
--- a/player.c
+++ b/player.c
@@ -2416,8 +2416,12 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
       config.output->mute(0); // unmute mute if it's there
     if (config.ignore_volume_control == 1)
       scaled_attenuation = max_db;
-    else
-      scaled_attenuation = vol2attn(airplay_volume, max_db, min_db);
+    else if (config.volume_control_profile == VCP_standard)
+        scaled_attenuation = vol2attn(airplay_volume, max_db, min_db);
+    else if (config.volume_control_profile == VCP_flat)
+        scaled_attenuation = flat_vol2attn(airplay_volume, max_db, min_db); 
+    else debug(1,"Unrecognised volume control profile");
+
     if (hw_range_db) {
       // if there is a hardware mixer
       if (scaled_attenuation <= hw_max_db) {
index 896ed1f90f4fbf89f8bcdb48a3e8e571ff022168..f65ee917228b58aafdc9fb80e49a2a5ae88e4a3c 100644 (file)
@@ -24,6 +24,9 @@ general =
 //     ignore_volume_control = "no"; // set this to "yes" if you want the volume to be at 100% no matter what the source's volume control is set to.
 //     volume_range_db = 60 ; // use this advanced setting to set the range, in dB, you want between the maximum volume and the minimum volume. Range is 30 to 150 dB. Leave it commented out to use mixer's native range.
 //     volume_max_db = 0.0 ; // use this advanced setting, which must have a decimal point in it, to set the maximum volume, in dB, you wish to use.
+//     volume_control_profile = "standard" ; // use this advanced setting to specify how the airplay volume is transferred to the mixer volume.
+//             "standard" makes the volume change more quickly than logarithmically at lower values and slower at higher values.
+//             "flat" makes the volume change logarithmically at all values.
 //             The setting is for the hardware mixer, if chosen, or the software mixer otherwise. The value must be in the mixer's range (0.0 to -96.2 for the software mixer).
 //             Leave it commented out to use mixer's maximum volume.
 //  run_this_when_volume_is_set = "/full/path/to/application/and/args"; //  Run the specified application whenever the volume control is set or changed.
index 99df5cc184f3c4135e219ee2961aaf43cf71bbe1..6193857df162029076a2e1343d11160908019c68 100644 (file)
@@ -622,6 +622,16 @@ int parse_options(int argc, char **argv) {
               "\"reverse stereo\", \"both left\", \"both right\"");
       }
 
+      /* Get the volume control profile setting -- "standard" or "flat" */
+      if (config_lookup_string(config.cfg, "general.volume_control_profile", &str)) {
+        if (strcasecmp(str, "standard") == 0)
+          config.volume_control_profile = VCP_standard;
+        else if (strcasecmp(str, "flat") == 0)
+          config.volume_control_profile = VCP_flat;
+        else
+          die("Invalid volume_control_profile choice \"%s\". It should be \"standard\" (default) or \"flat\"");
+      }
+
       /* Get the interface to listen on, if specified Default is all interfaces */
       /* we keep the interface name and the index */