Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new "dasl_tapered" volume control profile #1699

Merged
merged 4 commits into from
Jul 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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.
Expand Down
10 changes: 9 additions & 1 deletion common.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ typedef enum {
typedef enum {
VCP_standard = 0,
VCP_flat,
VCP_dasl_tapered,
} volume_control_profile_type;

typedef enum {
Expand Down Expand Up @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions dbus-service.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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");
Expand Down Expand Up @@ -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");

Expand Down
3 changes: 3 additions & 0 deletions player.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down
3 changes: 3 additions & 0 deletions scripts/shairport-sync.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions shairport.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down