diff --git a/RELEASENOTES.md b/RELEASENOTES.md index a0dc9ae8..7ad0bfe2 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,3 +1,8 @@ +Version 2.5.0.9 +---- +**New Feature** +* Set Volume Range. This is a new setting that allows you to use just a portion of the full range of attenuation offered by a mixer. For example, if a mixer has a minimum volume of -80 dB and a maximum of +20 dB, you might wish to use only 60 dB of the 100 dB available. This might be because the sound becomes inaudible at the lowest setting and unbearably loud at the highest setting. Or it might be because the range specified by the mixer does not match the capabilities of the device. For example, the Raspberry Pi's DAC that feeds the built-in audio jack claims a range of 106 dB but has a useful range of only about 35dB. The new `volume_range_db` setting in the `general` stanza allows you to specify the maximum range from highest to lowest. Many domestic Hi Fi systems have a range of 60 to 80 dB. The range suggested for the Raspberry Pi's built-in audio DAC, which feeds the headphone jack, is 35. Using it in this case gives the volume control a much more useful range of volumes. + Version 2.5.0.8 ---- **Bug fix** diff --git a/audio_alsa.c b/audio_alsa.c index e050e88a..3cfacea1 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -234,6 +234,13 @@ static int init(int argc, char **argv) { } debug(1, "Hardware mixer has dB volume from %f to %f.", (1.0 * alsa_mix_mindb) / 100.0, (1.0 * alsa_mix_maxdb) / 100.0); + if (config.volume_range_db) { + long suggested_alsa_min_db = alsa_mix_maxdb - (long)trunc(config.volume_range_db*100); + if (suggested_alsa_min_db > alsa_mix_mindb) + alsa_mix_mindb = suggested_alsa_min_db; + else + inform("The volume_range_db setting, %f is greater than the native range of the mixer %f, so it is ignored.",config.volume_range_db,(alsa_mix_maxdb-alsa_mix_mindb)/100.0); + } } else { // use the linear scale and do the db conversion ourselves debug(1, "note: the hardware mixer specified -- \"%s\" -- does not have a dB volume scale, so it can't be used.",alsa_mix_ctrl); diff --git a/common.h b/common.h index 0f51a4b3..ef3f84b3 100644 --- a/common.h +++ b/common.h @@ -81,6 +81,7 @@ typedef struct { int32_t audio_backend_buffer_desired_length; // this will be the desired number of frames in the // audio backend buffer -- the DAC buffer for ALSA int32_t audio_backend_latency_offset; // this will be the offset to compensate for any fixed latency + uint32_t volume_range_db; // the range, in dB, from max dB to min dB. Zero means use the mixer's native range. // there might be in the audio } shairport_cfg; diff --git a/configure.ac b/configure.ac index f6f0f70f..6b15fef9 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.50]) -AC_INIT([shairport-sync], [2.5.0.8], [mikebrady@eircom.net]) +AC_INIT([shairport-sync], [2.5.0.9], [mikebrady@eircom.net]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([shairport.c]) AC_CONFIG_HEADERS([config.h]) diff --git a/player.c b/player.c index 557eb52a..52a93f5f 100644 --- a/player.c +++ b/player.c @@ -1219,11 +1219,7 @@ void player_volume(double f) { // Thus, we ask our vol2attn function for an appropriate dB between -96.3 and 0 dB and translate // it back to a number. - double scaled_volume = vol2attn(f, 0, -9630); - double linear_volume = pow(10, scaled_volume / 2000); - - if (f == -144.0) - linear_volume = 0.0; + double linear_volume = 0.0; if (config.output->volume) { // debug(1,"Set volume to %f.",f); @@ -1234,12 +1230,23 @@ void player_volume(double f) { if (config.output->parameters) config.output->parameters(&audio_information); else { + long mindb = -9630; + if (config.volume_range_db) { + long suggested_alsa_min_db = -(long)trunc(config.volume_range_db*100); + if (suggested_alsa_min_db > mindb) + mindb = suggested_alsa_min_db; + else + inform("The volume_range_db setting, %f is greater than the native range of the mixer %f, so it is ignored.",config.volume_range_db,mindb/100.0); + } + double scaled_volume = vol2attn(f, 0, mindb); + linear_volume = pow(10, scaled_volume / 2000); audio_information.airplay_volume = f; - audio_information.minimum_volume_dB = -9630; + audio_information.minimum_volume_dB = mindb; audio_information.maximum_volume_dB = 0; audio_information.current_volume_dB = scaled_volume; audio_information.has_true_mute = 0; audio_information.is_muted = 0; + // debug(1,"Minimum software volume set to %d centi-dB",f,mindb); } audio_information.valid = 1; // debug(1,"Software volume set to %f on scale with a %f dB",f,linear_volume); diff --git a/scripts/shairport-sync.conf b/scripts/shairport-sync.conf index 8a4dbf72..28eca89e 100644 --- a/scripts/shairport-sync.conf +++ b/scripts/shairport-sync.conf @@ -17,6 +17,7 @@ general = // resync_threshold = 2205; // a synchronisation error greater than this will cause resynchronisation; 0 disables it // log_verbosity = 0; // "0" means no debug verbosity, "3" is most verbose. // 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 to set the range, in dB, you want between the maximum volume and the minimum volume. Range is 30 to 150 dB. Omit to use mixer's native range. }; // How to deal with metadata, including artwork diff --git a/shairport.c b/shairport.c index beb8d21b..91f2fb85 100644 --- a/shairport.c +++ b/shairport.c @@ -399,7 +399,16 @@ int parse_options(int argc, char **argv) { die("Invalid ignore_volume_control option choice \"%s\". It should be \"yes\" or \"no\""); } - /* Get the default latency. Deprecated! */ + /* Get the volume range, in dB, that should be used If not set, it means you just use the range set by the mixer. */ + if (config_lookup_int(config.cfg, "general.volume_range_db", &value)) { + if ((value < 30) || (value > 150)) + die("Invalid volume range \"%sd\". It should be between 30 and 150 dB. Zero means use the mixer's native range", + value); + else + config.volume_range_db = value; + } + +/* Get the default latency. Deprecated! */ if (config_lookup_int(config.cfg, "latencies.default", &value)) config.userSuppliedLatency = value; @@ -893,7 +902,7 @@ int main(int argc, char **argv) { debug(2, "audio backend desired buffer length is %d.", config.audio_backend_buffer_desired_length); debug(2, "audio backend latency offset is %d.", config.audio_backend_latency_offset); - debug(2, "use_negotiated_latencies %d.", config.use_negotiated_latencies); + debug(2, "volume range in dB (zero means use the range specified by the mixer): %u.", config.volume_range_db); char *realConfigPath = realpath(config.configfile,NULL); if (realConfigPath) {