Merge pull request #1699 from dasl-/log-vol

Add new "dasl_tapered" volume control profile. Thanks to [David Leiboic](https://github.com/dasl-) for this contribution.
This commit is contained in:
Mike Brady
2023-07-17 13:28:58 +02:00
committed by GitHub
6 changed files with 53 additions and 3 deletions
+27
View File
@@ -37,6 +37,7 @@
#include <fcntl.h>
#include <inttypes.h> // PRIdPTR
#include <libgen.h>
#include <math.h>
#include <memory.h>
#include <poll.h>
#include <popt.h>
@@ -1205,6 +1206,32 @@ double flat_vol2attn(double vol, long max_db, long min_db) {
}
return vol_setting;
}
double dasl_tapered_vol2attn(double vol, long max_db, long min_db) {
double vol_setting = min_db; // if all else fails, set this, for safety
if ((vol <= 0.0) && (vol >= -30.0)) {
double vol_pct = 1 - (vol / -30.0); // This will be in the range [0, 1]
if (vol_pct <= 0) {
return min_db;
}
vol_setting = max_db + 1000 * log10(vol_pct) / log10(2); // This will be in the range [-inf, max_db]
if (vol_setting < min_db) {
return min_db;
}
if (vol_setting > max_db) {
return max_db;
}
return vol_setting;
} else if (vol != -144.0) {
debug(1,
"dasl_tapered 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.
+9 -1
View File
@@ -73,6 +73,7 @@ typedef enum {
typedef enum {
VCP_standard = 0,
VCP_flat,
VCP_dasl_tapered,
} volume_control_profile_type;
typedef enum {
@@ -387,9 +388,16 @@ char *base64_enc(uint8_t *input, int length);
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
// dB), return an attenuation depending on a linear interpolation 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 a logarithmic interpolation along the range.
// The intention behind this attenuation function is that a given percentage change in volume
// should result in the same percentage change in perceived loudness. For instance, a doubling
// (100% increase) of volume level should result in a doubling of perceived loudness.
double dasl_tapered_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);
+7
View File
@@ -765,6 +765,8 @@ gboolean notify_volume_control_profile_callback(ShairportSync *skeleton,
config.volume_control_profile = VCP_standard;
else if (strcasecmp(th, "flat") == 0)
config.volume_control_profile = VCP_flat;
else if (strcasecmp(th, "dasl_tapered") == 0)
config.volume_control_profile = VCP_dasl_tapered;
else {
warn("Unrecognised Volume Control Profile: \"%s\".", th);
switch (config.volume_control_profile) {
@@ -774,6 +776,9 @@ gboolean notify_volume_control_profile_callback(ShairportSync *skeleton,
case VCP_flat:
shairport_sync_set_volume_control_profile(skeleton, "flat");
break;
case VCP_dasl_tapered:
shairport_sync_set_volume_control_profile(skeleton, "dasl_tapered");
break;
default:
debug(1, "This should never happen!");
shairport_sync_set_volume_control_profile(skeleton, "standard");
@@ -1065,6 +1070,8 @@ static void on_dbus_name_acquired(GDBusConnection *connection, const gchar *name
if (config.volume_control_profile == VCP_standard)
shairport_sync_set_volume_control_profile(SHAIRPORT_SYNC(shairportSyncSkeleton), "standard");
else if (config.volume_control_profile == VCP_dasl_tapered)
shairport_sync_set_volume_control_profile(SHAIRPORT_SYNC(shairportSyncSkeleton), "dasl_tapered");
else
shairport_sync_set_volume_control_profile(SHAIRPORT_SYNC(shairportSyncSkeleton), "flat");
+3
View File
@@ -3432,6 +3432,9 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
else if (config.volume_control_profile == VCP_flat)
scaled_attenuation =
flat_vol2attn(airplay_volume, max_db, min_db); // no cancellation points
else if (config.volume_control_profile == VCP_dasl_tapered)
scaled_attenuation =
dasl_tapered_vol2attn(airplay_volume, max_db, min_db); // no cancellation points
else
debug(1, "player_volume_without_notification: unrecognised volume control profile");
}
+3
View File
@@ -42,6 +42,9 @@ general =
// 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 at lower volumes and slower at higher volumes.
// "flat" makes the volume change at the same rate at all volumes.
// "dasl_tapered" is similar to "standard" - it makes the volume change more quickly at lower volumes and slower at higher volumes.
// The intention behind dasl_tapered is that a given percentage change in volume should result in the same percentage change in
// perceived loudness. For instance, a doubling (100% increase) of volume level should result in a doubling of perceived loudness.
// volume_control_combined_hardware_priority = "no"; // when extending the volume range by combining the built-in software attenuator with the hardware mixer attenuator, set this to "yes" to reduce volume by using the hardware mixer first, then the built-in software attenuator.
// default_airplay_volume = -24.0; // this is the suggested volume after a reset or after the high_volume_threshold has been exceed and the high_volume_idle_timeout_in_minutes has passed
+4 -2
View File
@@ -905,9 +905,11 @@ int parse_options(int argc, char **argv) {
config.volume_control_profile = VCP_standard;
else if (strcasecmp(str, "flat") == 0)
config.volume_control_profile = VCP_flat;
else if (strcasecmp(str, "dasl_tapered") == 0)
config.volume_control_profile = VCP_dasl_tapered;
else
die("Invalid volume_control_profile choice \"%s\". It should be \"standard\" (default) "
"or \"flat\"",
die("Invalid volume_control_profile choice \"%s\". It should be \"standard\" (default), "
"\"dasl_tapered\", or \"flat\"",
str);
}